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