]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/ParseInf.c
Sync EDKII BaseTools to BaseTools project r1971
[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
52302d4d 509 if (IsHex || (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X'))) {\r
30fdf114
LG
510 //\r
511 // Convert the hex string.\r
512 //\r
52302d4d 513 for (Index = Index + 2; AsciiString[Index] != '\0'; Index++) {\r
30fdf114 514 CurrentChar = AsciiString[Index];\r
52302d4d
LG
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
30fdf114 528 if (CurrentChar >= '0' && CurrentChar <= '9') {\r
52302d4d 529 Value += CurrentChar - '0';\r
30fdf114 530 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {\r
52302d4d 531 Value += CurrentChar - 'a' + 10;\r
30fdf114 532 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {\r
52302d4d 533 Value += CurrentChar - 'A' + 10;\r
30fdf114
LG
534 }\r
535 }\r
536\r
52302d4d 537 *ReturnValue = Value;\r
30fdf114
LG
538 } else {\r
539 //\r
52302d4d 540 // Convert dec string is a number\r
30fdf114 541 //\r
52302d4d
LG
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
30fdf114
LG
551 return EFI_ABORTED;\r
552 }\r
52302d4d
LG
553 //\r
554 // Add dec value\r
555 //\r
556 Value = Value * 10;\r
557 Value += CurrentChar - '0';\r
30fdf114
LG
558 }\r
559\r
52302d4d 560 *ReturnValue = Value;\r
30fdf114
LG
561 }\r
562\r
563 return EFI_SUCCESS;\r
564}\r
565\r
566CHAR8 *\r
567ReadLineInStream (\r
568 IN FILE *InputFile,\r
569 IN OUT CHAR8 *InputBuffer\r
570 )\r
571/*++\r
572\r
573Routine 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
578Arguments:\r
579\r
580 InputFile Stream pointer.\r
581 InputBuffer Buffer to read into, must be _MAX_PATH size.\r
582\r
583Returns:\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
622BOOLEAN\r
623FindSectionInStream (\r
624 IN FILE *InputFile,\r
625 IN CHAR8 *Section\r
626 )\r
627/*++\r
628\r
629Routine 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
635Arguments:\r
636\r
637 InputFile Stream pointer.\r
638 Section Section to search for\r
639\r
640Returns:\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