]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/ParseInf.c
BaseTools: Clear build versions to sync with buildtools/BaseTools
[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
8b7ebdb0 239 CHAR8 *Delimiter;\r
30fdf114
LG
240 BOOLEAN ParseError;\r
241 BOOLEAN ReadError;\r
242 UINTN Occurrance;\r
243\r
244 //\r
245 // Check input parameters\r
246 //\r
247 if (InputFile->FileImage == NULL ||\r
248 InputFile->Eof == NULL ||\r
249 InputFile->CurrentFilePointer == NULL ||\r
250 Section == NULL ||\r
251 strlen (Section) == 0 ||\r
252 Token == NULL ||\r
253 strlen (Token) == 0 ||\r
254 Value == NULL\r
255 ) {\r
256 return EFI_INVALID_PARAMETER;\r
257 }\r
258 //\r
259 // Initialize error codes\r
260 //\r
261 ParseError = FALSE;\r
262 ReadError = FALSE;\r
263\r
264 //\r
265 // Initialize our instance counter for the search token\r
266 //\r
267 Occurrance = 0;\r
268\r
269 if (FindSection (InputFile, Section)) {\r
270 //\r
271 // Found the desired section, find and read the desired token\r
272 //\r
273 do {\r
274 //\r
275 // Read a line from the file\r
276 //\r
277 if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) {\r
278 //\r
279 // Error reading from input file\r
280 //\r
281 ReadError = TRUE;\r
282 break;\r
283 }\r
284 //\r
285 // Get the first non-whitespace string\r
286 //\r
8b7ebdb0
LG
287 Delimiter = strchr (InputBuffer, '=');\r
288 if (Delimiter != NULL) {\r
289 *Delimiter = 0;\r
290 }\r
291\r
30fdf114 292 CurrentToken = strtok (InputBuffer, " \t\n");\r
8b7ebdb0 293 if (CurrentToken == NULL || Delimiter == NULL) {\r
30fdf114
LG
294 //\r
295 // Whitespace line found (or comment) so continue\r
296 //\r
297 CurrentToken = InputBuffer;\r
298 continue;\r
299 }\r
300 //\r
301 // Make sure we have not reached the end of the current section\r
302 //\r
303 if (CurrentToken[0] == '[') {\r
304 break;\r
305 }\r
306 //\r
307 // Compare the current token with the desired token\r
308 //\r
309 if (strcmp (CurrentToken, Token) == 0) {\r
310 //\r
311 // Found it\r
312 //\r
313 //\r
314 // Check if it is the correct instance\r
315 //\r
316 if (Instance == Occurrance) {\r
317 //\r
318 // Copy the contents following the =\r
319 //\r
8b7ebdb0
LG
320 CurrentToken = Delimiter + 1;\r
321 if (*CurrentToken == 0) {\r
30fdf114
LG
322 //\r
323 // Nothing found, parsing error\r
324 //\r
325 ParseError = TRUE;\r
326 } else {\r
8b7ebdb0
LG
327 //\r
328 // Strip leading white space\r
329 //\r
330 while (*CurrentToken == ' ' || *CurrentToken == '\t') {\r
331 CurrentToken++;\r
332 }\r
30fdf114
LG
333 //\r
334 // Copy the current token to the output value\r
335 //\r
336 strcpy (Value, CurrentToken);\r
8b7ebdb0
LG
337 //\r
338 // Strip trailing white space\r
339 //\r
340 while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) {\r
341 *(Value + strlen(Value) - 1) = 0;\r
342 }\r
30fdf114
LG
343 return EFI_SUCCESS;\r
344 }\r
345 } else {\r
346 //\r
347 // Increment the occurrance found\r
348 //\r
349 Occurrance++;\r
350 }\r
351 }\r
352 } while (\r
353 !ParseError &&\r
354 !ReadError &&\r
355 InputFile->CurrentFilePointer < InputFile->Eof &&\r
356 CurrentToken[0] != '[' &&\r
357 Occurrance <= Instance\r
358 );\r
359 }\r
360 //\r
361 // Distinguish between read errors and INF file format errors.\r
362 //\r
363 if (ReadError) {\r
364 return EFI_LOAD_ERROR;\r
365 }\r
366\r
367 if (ParseError) {\r
368 return EFI_ABORTED;\r
369 }\r
370\r
371 return EFI_NOT_FOUND;\r
372}\r
373\r
374EFI_STATUS\r
375StringToGuid (\r
376 IN CHAR8 *AsciiGuidBuffer,\r
377 OUT EFI_GUID *GuidBuffer\r
378 )\r
379/*++\r
380\r
381Routine Description: \r
382\r
383 Converts a string to an EFI_GUID. The string must be in the \r
384 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.\r
385\r
386Arguments: \r
387\r
388 AsciiGuidBuffer - pointer to ascii string\r
389 GuidBuffer - pointer to destination Guid\r
390\r
391Returns: \r
392\r
393 EFI_ABORTED Could not convert the string\r
394 EFI_SUCCESS The string was successfully converted\r
395 EFI_INVALID_PARAMETER Input parameter is invalid.\r
396\r
397--*/\r
398{\r
399 INT32 Index;\r
fd171542 400 unsigned Data1;\r
401 unsigned Data2;\r
402 unsigned Data3;\r
403 unsigned Data4[8];\r
30fdf114
LG
404\r
405 if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) {\r
406 return EFI_INVALID_PARAMETER;\r
407 }\r
408 //\r
409 // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\r
410 //\r
411 for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) {\r
412 if (Index == 8 || Index == 13 || Index == 18 || Index == 23) {\r
413 if (AsciiGuidBuffer[Index] != '-') {\r
414 break;\r
415 }\r
416 } else {\r
417 if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) || \r
418 ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) ||\r
419 ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) {\r
420 continue;\r
421 } else {\r
422 break;\r
423 }\r
424 }\r
425 }\r
426 \r
427 if (Index < 36 || AsciiGuidBuffer[36] != '\0') {\r
428 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);\r
429 return EFI_ABORTED;\r
430 }\r
431 \r
432 //\r
433 // Scan the guid string into the buffer\r
434 //\r
435 Index = sscanf (\r
436 AsciiGuidBuffer,\r
fd171542 437 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",\r
30fdf114
LG
438 &Data1,\r
439 &Data2,\r
440 &Data3,\r
441 &Data4[0],\r
442 &Data4[1],\r
443 &Data4[2],\r
444 &Data4[3],\r
445 &Data4[4],\r
446 &Data4[5],\r
447 &Data4[6],\r
448 &Data4[7]\r
449 );\r
450\r
451 //\r
452 // Verify the correct number of items were scanned.\r
453 //\r
454 if (Index != 11) {\r
455 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);\r
456 return EFI_ABORTED;\r
457 }\r
458 //\r
459 // Copy the data into our GUID.\r
460 //\r
461 GuidBuffer->Data1 = (UINT32) Data1;\r
462 GuidBuffer->Data2 = (UINT16) Data2;\r
463 GuidBuffer->Data3 = (UINT16) Data3;\r
464 GuidBuffer->Data4[0] = (UINT8) Data4[0];\r
465 GuidBuffer->Data4[1] = (UINT8) Data4[1];\r
466 GuidBuffer->Data4[2] = (UINT8) Data4[2];\r
467 GuidBuffer->Data4[3] = (UINT8) Data4[3];\r
468 GuidBuffer->Data4[4] = (UINT8) Data4[4];\r
469 GuidBuffer->Data4[5] = (UINT8) Data4[5];\r
470 GuidBuffer->Data4[6] = (UINT8) Data4[6];\r
471 GuidBuffer->Data4[7] = (UINT8) Data4[7];\r
472\r
473 return EFI_SUCCESS;\r
474}\r
475\r
476EFI_STATUS\r
477AsciiStringToUint64 (\r
478 IN CONST CHAR8 *AsciiString,\r
479 IN BOOLEAN IsHex,\r
480 OUT UINT64 *ReturnValue\r
481 )\r
482/*++\r
483\r
484Routine Description:\r
485\r
486 Converts a null terminated ascii string that represents a number into a \r
487 UINT64 value. A hex number may be preceeded by a 0x, but may not be \r
488 succeeded by an h. A number without 0x or 0X is considered to be base 10 \r
489 unless the IsHex input is true.\r
490\r
491Arguments:\r
492\r
493 AsciiString The string to convert.\r
494 IsHex Force the string to be treated as a hex number.\r
495 ReturnValue The return value.\r
496\r
497Returns:\r
498\r
499 EFI_SUCCESS Number successfully converted.\r
500 EFI_ABORTED Invalid character encountered.\r
501\r
502--*/\r
503{\r
504 UINT8 Index;\r
52302d4d 505 UINT64 Value;\r
30fdf114
LG
506 CHAR8 CurrentChar;\r
507 \r
508 //\r
509 // Initialize the result\r
510 //\r
52302d4d
LG
511 Value = 0;\r
512 Index = 0;\r
30fdf114
LG
513 \r
514 //\r
515 // Check input paramter\r
516 //\r
517 if (AsciiString == NULL || ReturnValue == NULL) {\r
518 return EFI_INVALID_PARAMETER;\r
519 }\r
52302d4d
LG
520 while (AsciiString[Index] == ' ') {\r
521 Index ++;\r
522 }\r
523 \r
30fdf114
LG
524 //\r
525 // Add each character to the result\r
526 //\r
64137027
LG
527 \r
528 //\r
529 // Skip first two chars only if the string starts with '0x' or '0X'\r
530 //\r
531 if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) {\r
532 IsHex = TRUE;\r
533 Index += 2;\r
534 }\r
535 if (IsHex) {\r
30fdf114
LG
536 //\r
537 // Convert the hex string.\r
538 //\r
64137027 539 for (; AsciiString[Index] != '\0'; Index++) {\r
30fdf114 540 CurrentChar = AsciiString[Index];\r
52302d4d
LG
541 if (CurrentChar == ' ') {\r
542 break;\r
543 }\r
544 //\r
545 // Verify Hex string\r
546 //\r
547 if (isxdigit ((int)CurrentChar) == 0) {\r
548 return EFI_ABORTED;\r
549 }\r
550 //\r
551 // Add hex value\r
552 //\r
553 Value *= 16;\r
30fdf114 554 if (CurrentChar >= '0' && CurrentChar <= '9') {\r
52302d4d 555 Value += CurrentChar - '0';\r
30fdf114 556 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {\r
52302d4d 557 Value += CurrentChar - 'a' + 10;\r
30fdf114 558 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {\r
52302d4d 559 Value += CurrentChar - 'A' + 10;\r
30fdf114
LG
560 }\r
561 }\r
562\r
52302d4d 563 *ReturnValue = Value;\r
30fdf114
LG
564 } else {\r
565 //\r
52302d4d 566 // Convert dec string is a number\r
30fdf114 567 //\r
52302d4d
LG
568 for (; Index < strlen (AsciiString); Index++) {\r
569 CurrentChar = AsciiString[Index];\r
570 if (CurrentChar == ' ') {\r
571 break;\r
572 }\r
573 //\r
574 // Verify Dec string\r
575 //\r
576 if (isdigit ((int)CurrentChar) == 0) {\r
30fdf114
LG
577 return EFI_ABORTED;\r
578 }\r
52302d4d
LG
579 //\r
580 // Add dec value\r
581 //\r
582 Value = Value * 10;\r
583 Value += CurrentChar - '0';\r
30fdf114
LG
584 }\r
585\r
52302d4d 586 *ReturnValue = Value;\r
30fdf114
LG
587 }\r
588\r
589 return EFI_SUCCESS;\r
590}\r
591\r
592CHAR8 *\r
593ReadLineInStream (\r
594 IN FILE *InputFile,\r
595 IN OUT CHAR8 *InputBuffer\r
596 )\r
597/*++\r
598\r
599Routine Description:\r
600\r
601 This function reads a line, stripping any comments.\r
602 // BUGBUG: This is obsolete once genmake goes away...\r
603\r
604Arguments:\r
605\r
606 InputFile Stream pointer.\r
607 InputBuffer Buffer to read into, must be _MAX_PATH size.\r
608\r
609Returns:\r
610\r
611 NULL if error or EOF\r
612 InputBuffer otherwise\r
613\r
614--*/\r
615{\r
616 CHAR8 *CharPtr;\r
617\r
618 //\r
619 // Verify input parameters are not null\r
620 //\r
621 assert (InputFile);\r
622 assert (InputBuffer);\r
623\r
624 //\r
625 // Read a line\r
626 //\r
627 if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {\r
628 return NULL;\r
629 }\r
630 //\r
631 // Strip any comments\r
632 //\r
633 CharPtr = strstr (InputBuffer, "//");\r
634 if (CharPtr != 0) {\r
635 CharPtr[0] = 0;\r
636 }\r
637\r
638 CharPtr = strstr (InputBuffer, "#");\r
639 if (CharPtr != 0) {\r
640 CharPtr[0] = 0;\r
641 }\r
642 //\r
643 // Return the string\r
644 //\r
645 return InputBuffer;\r
646}\r
647\r
648BOOLEAN\r
649FindSectionInStream (\r
650 IN FILE *InputFile,\r
651 IN CHAR8 *Section\r
652 )\r
653/*++\r
654\r
655Routine Description:\r
656\r
657 This function parses a stream file from the beginning to find a section.\r
658 The section string may be anywhere within a line.\r
659 // BUGBUG: This is obsolete once genmake goes away...\r
660\r
661Arguments:\r
662\r
663 InputFile Stream pointer.\r
664 Section Section to search for\r
665\r
666Returns:\r
667\r
668 FALSE if error or EOF\r
669 TRUE if section found\r
670\r
671--*/\r
672{\r
673 CHAR8 InputBuffer[_MAX_PATH];\r
674 CHAR8 *CurrentToken;\r
675\r
676 //\r
677 // Verify input is not NULL\r
678 //\r
679 assert (InputFile);\r
680 assert (Section);\r
681\r
682 //\r
683 // Rewind to beginning of file\r
684 //\r
685 if (fseek (InputFile, 0, SEEK_SET) != 0) {\r
686 return FALSE;\r
687 }\r
688 //\r
689 // Read lines until the section is found\r
690 //\r
691 while (feof (InputFile) == 0) {\r
692 //\r
693 // Read a line\r
694 //\r
695 ReadLineInStream (InputFile, InputBuffer);\r
696\r
697 //\r
698 // Check if the section is found\r
699 //\r
700 CurrentToken = strstr (InputBuffer, Section);\r
701 if (CurrentToken != NULL) {\r
702 return TRUE;\r
703 }\r
704 }\r
705\r
706 return FALSE;\r
707}\r