Sync EDKII BaseTools to BaseTools project r1903.
[efi/edk2/.git] / edk2 / BaseTools / Source / C / Common / ParseInf.c
1 /** @file\r
2 \r
3 Copyright (c) 2004 - 2010, 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  Value;\r
488   CHAR8   CurrentChar;\r
489   \r
490   //\r
491   // Initialize the result\r
492   //\r
493   Value = 0;\r
494   Index = 0;\r
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
502   while (AsciiString[Index] == ' ') {\r
503     Index ++;\r
504   }\r
505   \r
506   //\r
507   // Add each character to the result\r
508   //\r
509   if (IsHex || (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X'))) {\r
510     //\r
511     // Convert the hex string.\r
512     //\r
513     for (Index = Index + 2; AsciiString[Index] != '\0'; Index++) {\r
514       CurrentChar = AsciiString[Index];\r
515       if (CurrentChar == ' ') {\r
516         break;\r
517       }\r
518       //\r
519       // Verify Hex string\r
520       //\r
521       if (isxdigit ((int)CurrentChar) == 0) {\r
522         return EFI_ABORTED;\r
523       }\r
524       //\r
525       // Add hex value\r
526       //\r
527       Value *= 16;\r
528       if (CurrentChar >= '0' && CurrentChar <= '9') {\r
529         Value += CurrentChar - '0';\r
530       } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {\r
531         Value += CurrentChar - 'a' + 10;\r
532       } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {\r
533         Value += CurrentChar - 'A' + 10;\r
534       }\r
535     }\r
536 \r
537     *ReturnValue = Value;\r
538   } else {\r
539     //\r
540     // Convert dec string is a number\r
541     //\r
542     for (; Index < strlen (AsciiString); Index++) {\r
543       CurrentChar = AsciiString[Index];\r
544       if (CurrentChar == ' ') {\r
545         break;\r
546       }\r
547       //\r
548       // Verify Dec string\r
549       //\r
550       if (isdigit ((int)CurrentChar) == 0) {\r
551         return EFI_ABORTED;\r
552       }\r
553       //\r
554       // Add dec value\r
555       //\r
556       Value = Value * 10;\r
557       Value += CurrentChar - '0';\r
558     }\r
559 \r
560     *ReturnValue = Value;\r
561   }\r
562 \r
563   return EFI_SUCCESS;\r
564 }\r
565 \r
566 CHAR8 *\r
567 ReadLineInStream (\r
568   IN FILE       *InputFile,\r
569   IN OUT CHAR8  *InputBuffer\r
570   )\r
571 /*++\r
572 \r
573 Routine Description:\r
574 \r
575   This function reads a line, stripping any comments.\r
576   // BUGBUG:  This is obsolete once genmake goes away...\r
577 \r
578 Arguments:\r
579 \r
580   InputFile     Stream pointer.\r
581   InputBuffer   Buffer to read into, must be _MAX_PATH size.\r
582 \r
583 Returns:\r
584 \r
585   NULL if error or EOF\r
586   InputBuffer otherwise\r
587 \r
588 --*/\r
589 {\r
590   CHAR8 *CharPtr;\r
591 \r
592   //\r
593   // Verify input parameters are not null\r
594   //\r
595   assert (InputFile);\r
596   assert (InputBuffer);\r
597 \r
598   //\r
599   // Read a line\r
600   //\r
601   if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {\r
602     return NULL;\r
603   }\r
604   //\r
605   // Strip any comments\r
606   //\r
607   CharPtr = strstr (InputBuffer, "//");\r
608   if (CharPtr != 0) {\r
609     CharPtr[0] = 0;\r
610   }\r
611 \r
612   CharPtr = strstr (InputBuffer, "#");\r
613   if (CharPtr != 0) {\r
614     CharPtr[0] = 0;\r
615   }\r
616   //\r
617   // Return the string\r
618   //\r
619   return InputBuffer;\r
620 }\r
621 \r
622 BOOLEAN\r
623 FindSectionInStream (\r
624   IN FILE       *InputFile,\r
625   IN CHAR8      *Section\r
626   )\r
627 /*++\r
628 \r
629 Routine Description:\r
630 \r
631   This function parses a stream file from the beginning to find a section.\r
632   The section string may be anywhere within a line.\r
633   // BUGBUG:  This is obsolete once genmake goes away...\r
634 \r
635 Arguments:\r
636 \r
637   InputFile     Stream pointer.\r
638   Section       Section to search for\r
639 \r
640 Returns:\r
641 \r
642   FALSE if error or EOF\r
643   TRUE if section found\r
644 \r
645 --*/\r
646 {\r
647   CHAR8 InputBuffer[_MAX_PATH];\r
648   CHAR8 *CurrentToken;\r
649 \r
650   //\r
651   // Verify input is not NULL\r
652   //\r
653   assert (InputFile);\r
654   assert (Section);\r
655 \r
656   //\r
657   // Rewind to beginning of file\r
658   //\r
659   if (fseek (InputFile, 0, SEEK_SET) != 0) {\r
660     return FALSE;\r
661   }\r
662   //\r
663   // Read lines until the section is found\r
664   //\r
665   while (feof (InputFile) == 0) {\r
666     //\r
667     // Read a line\r
668     //\r
669     ReadLineInStream (InputFile, InputBuffer);\r
670 \r
671     //\r
672     // Check if the section is found\r
673     //\r
674     CurrentToken = strstr (InputBuffer, Section);\r
675     if (CurrentToken != NULL) {\r
676       return TRUE;\r
677     }\r
678   }\r
679 \r
680   return FALSE;\r
681 }\r