cd10da9b2dd872ab3b79255013c20becf23bd4a6
[efi/edk2/.git] / edk2 / BaseTools / Source / C / Common / ParseInf.c
1 /** @file\r
2 \r
3 Copyright (c) 2004 - 2008, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   ParseInf.c\r
15 \r
16 Abstract:\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
29 CHAR8 *\r
30 ReadLine (\r
31   IN MEMORY_FILE    *InputFile,\r
32   IN OUT CHAR8      *InputBuffer,\r
33   IN UINTN          MaxLength\r
34   )\r
35 /*++\r
36 \r
37 Routine 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
46 Arguments:\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
52 Returns:\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
144 BOOLEAN\r
145 FindSection (\r
146   IN MEMORY_FILE    *InputFile,\r
147   IN CHAR8          *Section\r
148   )\r
149 /*++\r
150 \r
151 Routine 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
156 Arguments:\r
157 \r
158   InputFile     Memory file image.\r
159   Section       Section to search for\r
160 \r
161 Returns:\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
205 EFI_STATUS\r
206 FindToken (\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
215 Routine Description:\r
216 \r
217   Finds a token value given the section and token to search for.\r
218 \r
219 Arguments:\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
227 Returns:\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
356 EFI_STATUS\r
357 StringToGuid (\r
358   IN CHAR8      *AsciiGuidBuffer,\r
359   OUT EFI_GUID  *GuidBuffer\r
360   )\r
361 /*++\r
362 \r
363 Routine 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
368 Arguments:  \r
369 \r
370   AsciiGuidBuffer - pointer to ascii string\r
371   GuidBuffer      - pointer to destination Guid\r
372 \r
373 Returns:  \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
382   unsigned Data1;\r
383   unsigned Data2;\r
384   unsigned Data3;\r
385   unsigned Data4[8];\r
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
419             "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",\r
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
458 EFI_STATUS\r
459 AsciiStringToUint64 (\r
460   IN CONST CHAR8  *AsciiString,\r
461   IN BOOLEAN      IsHex,\r
462   OUT UINT64      *ReturnValue\r
463   )\r
464 /*++\r
465 \r
466 Routine 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
473 Arguments:\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
479 Returns:\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
487   UINT64  HexNumber;\r
488   CHAR8   CurrentChar;\r
489   \r
490   //\r
491   // Initialize the result\r
492   //\r
493   HexNumber = 0;\r
494   \r
495   //\r
496   // Check input paramter\r
497   //\r
498   if (AsciiString == NULL || ReturnValue == NULL) {\r
499     return EFI_INVALID_PARAMETER;\r
500   }\r
501   //\r
502   // Add each character to the result\r
503   //\r
504   if (IsHex || (AsciiString[0] == '0' && (AsciiString[1] == 'x' || AsciiString[1] == 'X'))) {\r
505     //\r
506     // Verify string is a hex number\r
507     //\r
508     for (Index = 2; Index < strlen (AsciiString); Index++) {\r
509       if (isxdigit ((int)AsciiString[Index]) == 0) {\r
510         return EFI_ABORTED;\r
511       }\r
512     }\r
513     //\r
514     // Convert the hex string.\r
515     //\r
516     for (Index = 2; AsciiString[Index] != '\0'; Index++) {\r
517       CurrentChar = AsciiString[Index];\r
518       HexNumber *= 16;\r
519       if (CurrentChar >= '0' && CurrentChar <= '9') {\r
520         HexNumber += CurrentChar - '0';\r
521       } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {\r
522         HexNumber += CurrentChar - 'a' + 10;\r
523       } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {\r
524         HexNumber += CurrentChar - 'A' + 10;\r
525       } else {\r
526         //\r
527         // Unrecognized character\r
528         //\r
529         return EFI_ABORTED;\r
530       }\r
531     }\r
532 \r
533     *ReturnValue = HexNumber;\r
534   } else {\r
535     //\r
536     // Verify string is a number\r
537     //\r
538     for (Index = 0; Index < strlen (AsciiString); Index++) {\r
539       if (isdigit ((int)AsciiString[Index]) == 0) {\r
540         return EFI_ABORTED;\r
541       }\r
542     }\r
543 \r
544     *ReturnValue = atol (AsciiString);\r
545   }\r
546 \r
547   return EFI_SUCCESS;\r
548 }\r
549 \r
550 CHAR8 *\r
551 ReadLineInStream (\r
552   IN FILE       *InputFile,\r
553   IN OUT CHAR8  *InputBuffer\r
554   )\r
555 /*++\r
556 \r
557 Routine Description:\r
558 \r
559   This function reads a line, stripping any comments.\r
560   // BUGBUG:  This is obsolete once genmake goes away...\r
561 \r
562 Arguments:\r
563 \r
564   InputFile     Stream pointer.\r
565   InputBuffer   Buffer to read into, must be _MAX_PATH size.\r
566 \r
567 Returns:\r
568 \r
569   NULL if error or EOF\r
570   InputBuffer otherwise\r
571 \r
572 --*/\r
573 {\r
574   CHAR8 *CharPtr;\r
575 \r
576   //\r
577   // Verify input parameters are not null\r
578   //\r
579   assert (InputFile);\r
580   assert (InputBuffer);\r
581 \r
582   //\r
583   // Read a line\r
584   //\r
585   if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {\r
586     return NULL;\r
587   }\r
588   //\r
589   // Strip any comments\r
590   //\r
591   CharPtr = strstr (InputBuffer, "//");\r
592   if (CharPtr != 0) {\r
593     CharPtr[0] = 0;\r
594   }\r
595 \r
596   CharPtr = strstr (InputBuffer, "#");\r
597   if (CharPtr != 0) {\r
598     CharPtr[0] = 0;\r
599   }\r
600   //\r
601   // Return the string\r
602   //\r
603   return InputBuffer;\r
604 }\r
605 \r
606 BOOLEAN\r
607 FindSectionInStream (\r
608   IN FILE       *InputFile,\r
609   IN CHAR8      *Section\r
610   )\r
611 /*++\r
612 \r
613 Routine Description:\r
614 \r
615   This function parses a stream file from the beginning to find a section.\r
616   The section string may be anywhere within a line.\r
617   // BUGBUG:  This is obsolete once genmake goes away...\r
618 \r
619 Arguments:\r
620 \r
621   InputFile     Stream pointer.\r
622   Section       Section to search for\r
623 \r
624 Returns:\r
625 \r
626   FALSE if error or EOF\r
627   TRUE if section found\r
628 \r
629 --*/\r
630 {\r
631   CHAR8 InputBuffer[_MAX_PATH];\r
632   CHAR8 *CurrentToken;\r
633 \r
634   //\r
635   // Verify input is not NULL\r
636   //\r
637   assert (InputFile);\r
638   assert (Section);\r
639 \r
640   //\r
641   // Rewind to beginning of file\r
642   //\r
643   if (fseek (InputFile, 0, SEEK_SET) != 0) {\r
644     return FALSE;\r
645   }\r
646   //\r
647   // Read lines until the section is found\r
648   //\r
649   while (feof (InputFile) == 0) {\r
650     //\r
651     // Read a line\r
652     //\r
653     ReadLineInStream (InputFile, InputBuffer);\r
654 \r
655     //\r
656     // Check if the section is found\r
657     //\r
658     CurrentToken = strstr (InputBuffer, Section);\r
659     if (CurrentToken != NULL) {\r
660       return TRUE;\r
661     }\r
662   }\r
663 \r
664   return FALSE;\r
665 }\r