]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/ParseInf.c
Sync EDKII BaseTools to BaseTools project r2100.
[mirror_edk2.git] / BaseTools / Source / C / Common / ParseInf.c
CommitLineData
30fdf114
LG
1/** @file\r
2\r
40d841f6
LG
3Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
4This program and the accompanying materials \r
30fdf114
LG
5are licensed and made available under the terms and conditions of the BSD License \r
6which accompanies this distribution. The full text of the license may be found at \r
7http://opensource.org/licenses/bsd-license.php \r
8 \r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
11\r
12Module Name:\r
13\r
14 ParseInf.c\r
15\r
16Abstract:\r
17\r
18 This contains some useful functions for parsing INF files.\r
19\r
20--*/\r
21\r
22#include <assert.h>\r
23#include <string.h>\r
24#include <ctype.h>\r
25#include <stdlib.h>\r
26#include "EfiUtilityMsgs.h"\r
27#include "ParseInf.h"\r
28\r
29CHAR8 *\r
30ReadLine (\r
31 IN MEMORY_FILE *InputFile,\r
32 IN OUT CHAR8 *InputBuffer,\r
33 IN UINTN MaxLength\r
34 )\r
35/*++\r
36\r
37Routine Description:\r
38\r
39 This function reads a line, stripping any comments.\r
40 The function reads a string from the input stream argument and stores it in \r
41 the input string. ReadLine reads characters from the current file position \r
42 to and including the first newline character, to the end of the stream, or \r
43 until the number of characters read is equal to MaxLength - 1, whichever \r
44 comes first. The newline character, if read, is replaced with a \0. \r
45\r
46Arguments:\r
47\r
48 InputFile Memory file image.\r
49 InputBuffer Buffer to read into, must be _MAX_PATH size.\r
50 MaxLength The maximum size of the input buffer.\r
51\r
52Returns:\r
53\r
54 NULL if error or EOF\r
55 InputBuffer otherwise\r
56\r
57--*/\r
58{\r
59 CHAR8 *CharPtr;\r
60 CHAR8 *EndOfLine;\r
61 UINTN CharsToCopy;\r
62\r
63 //\r
64 // Verify input parameters are not null\r
65 //\r
66 assert (InputBuffer);\r
67 assert (InputFile->FileImage);\r
68 assert (InputFile->Eof);\r
69 assert (InputFile->CurrentFilePointer);\r
70\r
71 //\r
72 // Check for end of file condition\r
73 //\r
74 if (InputFile->CurrentFilePointer >= InputFile->Eof) {\r
75 return NULL;\r
76 }\r
77 //\r
78 // Find the next newline char\r
79 //\r
80 EndOfLine = strchr (InputFile->CurrentFilePointer, '\n');\r
81\r
82 //\r
83 // Determine the number of characters to copy.\r
84 //\r
85 if (EndOfLine == 0) {\r
86 //\r
87 // If no newline found, copy to the end of the file.\r
88 //\r
89 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;\r
90 } else if (EndOfLine >= InputFile->Eof) {\r
91 //\r
92 // If the newline found was beyond the end of file, copy to the eof.\r
93 //\r
94 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;\r
95 } else {\r
96 //\r
97 // Newline found in the file.\r
98 //\r
99 CharsToCopy = EndOfLine - InputFile->CurrentFilePointer;\r
100 }\r
101 //\r
102 // If the end of line is too big for the current buffer, set it to the max\r
103 // size of the buffer (leaving room for the \0.\r
104 //\r
105 if (CharsToCopy > MaxLength - 1) {\r
106 CharsToCopy = MaxLength - 1;\r
107 }\r
108 //\r
109 // Copy the line.\r
110 //\r
111 memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy);\r
112\r
113 //\r
114 // Add the null termination over the 0x0D\r
115 //\r
116 if (InputBuffer[CharsToCopy - 1] == '\r') {\r
117\r
118 InputBuffer[CharsToCopy - 1] = '\0';\r
119\r
120 } else {\r
121\r
122 InputBuffer[CharsToCopy] = '\0';\r
123\r
124 }\r
125\r
126 //\r
127 // Increment the current file pointer (include the 0x0A)\r
128 //\r
129 InputFile->CurrentFilePointer += CharsToCopy + 1;\r
130\r
131 //\r
132 // Strip any comments\r
133 //\r
134 CharPtr = strstr (InputBuffer, "//");\r
135 if (CharPtr != 0) {\r
136 CharPtr[0] = 0;\r
137 }\r
138 //\r
139 // Return the string\r
140 //\r
141 return InputBuffer;\r
142}\r
143\r
144BOOLEAN\r
145FindSection (\r
146 IN MEMORY_FILE *InputFile,\r
147 IN CHAR8 *Section\r
148 )\r
149/*++\r
150\r
151Routine Description:\r
152\r
153 This function parses a file from the beginning to find a section.\r
154 The section string may be anywhere within a line.\r
155\r
156Arguments:\r
157\r
158 InputFile Memory file image.\r
159 Section Section to search for\r
160\r
161Returns:\r
162\r
163 FALSE if error or EOF\r
164 TRUE if section found\r
165\r
166--*/\r
167{\r
168 CHAR8 InputBuffer[_MAX_PATH];\r
169 CHAR8 *CurrentToken;\r
170\r
171 //\r
172 // Verify input is not NULL\r
173 //\r
174 assert (InputFile->FileImage);\r
175 assert (InputFile->Eof);\r
176 assert (InputFile->CurrentFilePointer);\r
177 assert (Section);\r
178\r
179 //\r
180 // Rewind to beginning of file\r
181 //\r
182 InputFile->CurrentFilePointer = InputFile->FileImage;\r
183\r
184 //\r
185 // Read lines until the section is found\r
186 //\r
187 while (InputFile->CurrentFilePointer < InputFile->Eof) {\r
188 //\r
189 // Read a line\r
190 //\r
191 ReadLine (InputFile, InputBuffer, _MAX_PATH);\r
192\r
193 //\r
194 // Check if the section is found\r
195 //\r
196 CurrentToken = strstr (InputBuffer, Section);\r
197 if (CurrentToken != NULL) {\r
198 return TRUE;\r
199 }\r
200 }\r
201\r
202 return FALSE;\r
203}\r
204\r
205EFI_STATUS\r
206FindToken (\r
207 IN MEMORY_FILE *InputFile,\r
208 IN CHAR8 *Section,\r
209 IN CHAR8 *Token,\r
210 IN UINTN Instance,\r
211 OUT CHAR8 *Value\r
212 )\r
213/*++\r
214\r
215Routine Description:\r
216\r
217 Finds a token value given the section and token to search for.\r
218\r
219Arguments:\r
220\r
221 InputFile Memory file image.\r
222 Section The section to search for, a string within [].\r
223 Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file.\r
224 Instance The instance of the token to search for. Zero is the first instance.\r
225 Value The string that holds the value following the =. Must be _MAX_PATH in size.\r
226\r
227Returns:\r
228\r
229 EFI_SUCCESS Value found.\r
230 EFI_ABORTED Format error detected in INF file.\r
231 EFI_INVALID_PARAMETER Input argument was null.\r
232 EFI_LOAD_ERROR Error reading from the file.\r
233 EFI_NOT_FOUND Section/Token/Value not found.\r
234\r
235--*/\r
236{\r
237 CHAR8 InputBuffer[_MAX_PATH];\r
238 CHAR8 *CurrentToken;\r
239 BOOLEAN ParseError;\r
240 BOOLEAN ReadError;\r
241 UINTN Occurrance;\r
242\r
243 //\r
244 // Check input parameters\r
245 //\r
246 if (InputFile->FileImage == NULL ||\r
247 InputFile->Eof == NULL ||\r
248 InputFile->CurrentFilePointer == NULL ||\r
249 Section == NULL ||\r
250 strlen (Section) == 0 ||\r
251 Token == NULL ||\r
252 strlen (Token) == 0 ||\r
253 Value == NULL\r
254 ) {\r
255 return EFI_INVALID_PARAMETER;\r
256 }\r
257 //\r
258 // Initialize error codes\r
259 //\r
260 ParseError = FALSE;\r
261 ReadError = FALSE;\r
262\r
263 //\r
264 // Initialize our instance counter for the search token\r
265 //\r
266 Occurrance = 0;\r
267\r
268 if (FindSection (InputFile, Section)) {\r
269 //\r
270 // Found the desired section, find and read the desired token\r
271 //\r
272 do {\r
273 //\r
274 // Read a line from the file\r
275 //\r
276 if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) {\r
277 //\r
278 // Error reading from input file\r
279 //\r
280 ReadError = TRUE;\r
281 break;\r
282 }\r
283 //\r
284 // Get the first non-whitespace string\r
285 //\r
286 CurrentToken = strtok (InputBuffer, " \t\n");\r
287 if (CurrentToken == NULL) {\r
288 //\r
289 // Whitespace line found (or comment) so continue\r
290 //\r
291 CurrentToken = InputBuffer;\r
292 continue;\r
293 }\r
294 //\r
295 // Make sure we have not reached the end of the current section\r
296 //\r
297 if (CurrentToken[0] == '[') {\r
298 break;\r
299 }\r
300 //\r
301 // Compare the current token with the desired token\r
302 //\r
303 if (strcmp (CurrentToken, Token) == 0) {\r
304 //\r
305 // Found it\r
306 //\r
307 //\r
308 // Check if it is the correct instance\r
309 //\r
310 if (Instance == Occurrance) {\r
311 //\r
312 // Copy the contents following the =\r
313 //\r
314 CurrentToken = strtok (NULL, "= \t\n");\r
315 if (CurrentToken == NULL) {\r
316 //\r
317 // Nothing found, parsing error\r
318 //\r
319 ParseError = TRUE;\r
320 } else {\r
321 //\r
322 // Copy the current token to the output value\r
323 //\r
324 strcpy (Value, CurrentToken);\r
325 return EFI_SUCCESS;\r
326 }\r
327 } else {\r
328 //\r
329 // Increment the occurrance found\r
330 //\r
331 Occurrance++;\r
332 }\r
333 }\r
334 } while (\r
335 !ParseError &&\r
336 !ReadError &&\r
337 InputFile->CurrentFilePointer < InputFile->Eof &&\r
338 CurrentToken[0] != '[' &&\r
339 Occurrance <= Instance\r
340 );\r
341 }\r
342 //\r
343 // Distinguish between read errors and INF file format errors.\r
344 //\r
345 if (ReadError) {\r
346 return EFI_LOAD_ERROR;\r
347 }\r
348\r
349 if (ParseError) {\r
350 return EFI_ABORTED;\r
351 }\r
352\r
353 return EFI_NOT_FOUND;\r
354}\r
355\r
356EFI_STATUS\r
357StringToGuid (\r
358 IN CHAR8 *AsciiGuidBuffer,\r
359 OUT EFI_GUID *GuidBuffer\r
360 )\r
361/*++\r
362\r
363Routine Description: \r
364\r
365 Converts a string to an EFI_GUID. The string must be in the \r
366 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.\r
367\r
368Arguments: \r
369\r
370 AsciiGuidBuffer - pointer to ascii string\r
371 GuidBuffer - pointer to destination Guid\r
372\r
373Returns: \r
374\r
375 EFI_ABORTED Could not convert the string\r
376 EFI_SUCCESS The string was successfully converted\r
377 EFI_INVALID_PARAMETER Input parameter is invalid.\r
378\r
379--*/\r
380{\r
381 INT32 Index;\r
fd171542 382 unsigned Data1;\r
383 unsigned Data2;\r
384 unsigned Data3;\r
385 unsigned Data4[8];\r
30fdf114
LG
386\r
387 if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) {\r
388 return EFI_INVALID_PARAMETER;\r
389 }\r
390 //\r
391 // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
392 //\r
393 for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) {\r
394 if (Index == 8 || Index == 13 || Index == 18 || Index == 23) {\r
395 if (AsciiGuidBuffer[Index] != '-') {\r
396 break;\r
397 }\r
398 } else {\r
399 if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) || \r
400 ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) ||\r
401 ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) {\r
402 continue;\r
403 } else {\r
404 break;\r
405 }\r
406 }\r
407 }\r
408 \r
409 if (Index < 36 || AsciiGuidBuffer[36] != '\0') {\r
410 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);\r
411 return EFI_ABORTED;\r
412 }\r
413 \r
414 //\r
415 // Scan the guid string into the buffer\r
416 //\r
417 Index = sscanf (\r
418 AsciiGuidBuffer,\r
fd171542 419 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",\r
30fdf114
LG
420 &Data1,\r
421 &Data2,\r
422 &Data3,\r
423 &Data4[0],\r
424 &Data4[1],\r
425 &Data4[2],\r
426 &Data4[3],\r
427 &Data4[4],\r
428 &Data4[5],\r
429 &Data4[6],\r
430 &Data4[7]\r
431 );\r
432\r
433 //\r
434 // Verify the correct number of items were scanned.\r
435 //\r
436 if (Index != 11) {\r
437 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);\r
438 return EFI_ABORTED;\r
439 }\r
440 //\r
441 // Copy the data into our GUID.\r
442 //\r
443 GuidBuffer->Data1 = (UINT32) Data1;\r
444 GuidBuffer->Data2 = (UINT16) Data2;\r
445 GuidBuffer->Data3 = (UINT16) Data3;\r
446 GuidBuffer->Data4[0] = (UINT8) Data4[0];\r
447 GuidBuffer->Data4[1] = (UINT8) Data4[1];\r
448 GuidBuffer->Data4[2] = (UINT8) Data4[2];\r
449 GuidBuffer->Data4[3] = (UINT8) Data4[3];\r
450 GuidBuffer->Data4[4] = (UINT8) Data4[4];\r
451 GuidBuffer->Data4[5] = (UINT8) Data4[5];\r
452 GuidBuffer->Data4[6] = (UINT8) Data4[6];\r
453 GuidBuffer->Data4[7] = (UINT8) Data4[7];\r
454\r
455 return EFI_SUCCESS;\r
456}\r
457\r
458EFI_STATUS\r
459AsciiStringToUint64 (\r
460 IN CONST CHAR8 *AsciiString,\r
461 IN BOOLEAN IsHex,\r
462 OUT UINT64 *ReturnValue\r
463 )\r
464/*++\r
465\r
466Routine Description:\r
467\r
468 Converts a null terminated ascii string that represents a number into a \r
469 UINT64 value. A hex number may be preceeded by a 0x, but may not be \r
470 succeeded by an h. A number without 0x or 0X is considered to be base 10 \r
471 unless the IsHex input is true.\r
472\r
473Arguments:\r
474\r
475 AsciiString The string to convert.\r
476 IsHex Force the string to be treated as a hex number.\r
477 ReturnValue The return value.\r
478\r
479Returns:\r
480\r
481 EFI_SUCCESS Number successfully converted.\r
482 EFI_ABORTED Invalid character encountered.\r
483\r
484--*/\r
485{\r
486 UINT8 Index;\r
52302d4d 487 UINT64 Value;\r
30fdf114
LG
488 CHAR8 CurrentChar;\r
489 \r
490 //\r
491 // Initialize the result\r
492 //\r
52302d4d
LG
493 Value = 0;\r
494 Index = 0;\r
30fdf114
LG
495 \r
496 //\r
497 // Check input paramter\r
498 //\r
499 if (AsciiString == NULL || ReturnValue == NULL) {\r
500 return EFI_INVALID_PARAMETER;\r
501 }\r
52302d4d
LG
502 while (AsciiString[Index] == ' ') {\r
503 Index ++;\r
504 }\r
505 \r
30fdf114
LG
506 //\r
507 // Add each character to the result\r
508 //\r
64137027
LG
509 \r
510 //\r
511 // Skip first two chars only if the string starts with '0x' or '0X'\r
512 //\r
513 if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) {\r
514 IsHex = TRUE;\r
515 Index += 2;\r
516 }\r
517 if (IsHex) {\r
30fdf114
LG
518 //\r
519 // Convert the hex string.\r
520 //\r
64137027 521 for (; AsciiString[Index] != '\0'; Index++) {\r
30fdf114 522 CurrentChar = AsciiString[Index];\r
52302d4d
LG
523 if (CurrentChar == ' ') {\r
524 break;\r
525 }\r
526 //\r
527 // Verify Hex string\r
528 //\r
529 if (isxdigit ((int)CurrentChar) == 0) {\r
530 return EFI_ABORTED;\r
531 }\r
532 //\r
533 // Add hex value\r
534 //\r
535 Value *= 16;\r
30fdf114 536 if (CurrentChar >= '0' && CurrentChar <= '9') {\r
52302d4d 537 Value += CurrentChar - '0';\r
30fdf114 538 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {\r
52302d4d 539 Value += CurrentChar - 'a' + 10;\r
30fdf114 540 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {\r
52302d4d 541 Value += CurrentChar - 'A' + 10;\r
30fdf114
LG
542 }\r
543 }\r
544\r
52302d4d 545 *ReturnValue = Value;\r
30fdf114
LG
546 } else {\r
547 //\r
52302d4d 548 // Convert dec string is a number\r
30fdf114 549 //\r
52302d4d
LG
550 for (; Index < strlen (AsciiString); Index++) {\r
551 CurrentChar = AsciiString[Index];\r
552 if (CurrentChar == ' ') {\r
553 break;\r
554 }\r
555 //\r
556 // Verify Dec string\r
557 //\r
558 if (isdigit ((int)CurrentChar) == 0) {\r
30fdf114
LG
559 return EFI_ABORTED;\r
560 }\r
52302d4d
LG
561 //\r
562 // Add dec value\r
563 //\r
564 Value = Value * 10;\r
565 Value += CurrentChar - '0';\r
30fdf114
LG
566 }\r
567\r
52302d4d 568 *ReturnValue = Value;\r
30fdf114
LG
569 }\r
570\r
571 return EFI_SUCCESS;\r
572}\r
573\r
574CHAR8 *\r
575ReadLineInStream (\r
576 IN FILE *InputFile,\r
577 IN OUT CHAR8 *InputBuffer\r
578 )\r
579/*++\r
580\r
581Routine Description:\r
582\r
583 This function reads a line, stripping any comments.\r
584 // BUGBUG: This is obsolete once genmake goes away...\r
585\r
586Arguments:\r
587\r
588 InputFile Stream pointer.\r
589 InputBuffer Buffer to read into, must be _MAX_PATH size.\r
590\r
591Returns:\r
592\r
593 NULL if error or EOF\r
594 InputBuffer otherwise\r
595\r
596--*/\r
597{\r
598 CHAR8 *CharPtr;\r
599\r
600 //\r
601 // Verify input parameters are not null\r
602 //\r
603 assert (InputFile);\r
604 assert (InputBuffer);\r
605\r
606 //\r
607 // Read a line\r
608 //\r
609 if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {\r
610 return NULL;\r
611 }\r
612 //\r
613 // Strip any comments\r
614 //\r
615 CharPtr = strstr (InputBuffer, "//");\r
616 if (CharPtr != 0) {\r
617 CharPtr[0] = 0;\r
618 }\r
619\r
620 CharPtr = strstr (InputBuffer, "#");\r
621 if (CharPtr != 0) {\r
622 CharPtr[0] = 0;\r
623 }\r
624 //\r
625 // Return the string\r
626 //\r
627 return InputBuffer;\r
628}\r
629\r
630BOOLEAN\r
631FindSectionInStream (\r
632 IN FILE *InputFile,\r
633 IN CHAR8 *Section\r
634 )\r
635/*++\r
636\r
637Routine Description:\r
638\r
639 This function parses a stream file from the beginning to find a section.\r
640 The section string may be anywhere within a line.\r
641 // BUGBUG: This is obsolete once genmake goes away...\r
642\r
643Arguments:\r
644\r
645 InputFile Stream pointer.\r
646 Section Section to search for\r
647\r
648Returns:\r
649\r
650 FALSE if error or EOF\r
651 TRUE if section found\r
652\r
653--*/\r
654{\r
655 CHAR8 InputBuffer[_MAX_PATH];\r
656 CHAR8 *CurrentToken;\r
657\r
658 //\r
659 // Verify input is not NULL\r
660 //\r
661 assert (InputFile);\r
662 assert (Section);\r
663\r
664 //\r
665 // Rewind to beginning of file\r
666 //\r
667 if (fseek (InputFile, 0, SEEK_SET) != 0) {\r
668 return FALSE;\r
669 }\r
670 //\r
671 // Read lines until the section is found\r
672 //\r
673 while (feof (InputFile) == 0) {\r
674 //\r
675 // Read a line\r
676 //\r
677 ReadLineInStream (InputFile, InputBuffer);\r
678\r
679 //\r
680 // Check if the section is found\r
681 //\r
682 CurrentToken = strstr (InputBuffer, Section);\r
683 if (CurrentToken != NULL) {\r
684 return TRUE;\r
685 }\r
686 }\r
687\r
688 return FALSE;\r
689}\r