]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/Common/ParseInf.c
Sync tool code to BuildTools project r1783.
[mirror_edk2.git] / BaseTools / Source / C / Common / ParseInf.c
CommitLineData
30fdf114
LG
1/** @file\r
2\r
3Copyright (c) 2004 - 2008, Intel Corporation \r
4All rights reserved. This program and the accompanying materials \r
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
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
a709adfa 509 if (isxdigit ((int)AsciiString[Index]) == 0) {\r
30fdf114
LG
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
a709adfa 539 if (isdigit ((int)AsciiString[Index]) == 0) {\r
30fdf114
LG
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
550CHAR8 *\r
551ReadLineInStream (\r
552 IN FILE *InputFile,\r
553 IN OUT CHAR8 *InputBuffer\r
554 )\r
555/*++\r
556\r
557Routine 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
562Arguments:\r
563\r
564 InputFile Stream pointer.\r
565 InputBuffer Buffer to read into, must be _MAX_PATH size.\r
566\r
567Returns:\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
606BOOLEAN\r
607FindSectionInStream (\r
608 IN FILE *InputFile,\r
609 IN CHAR8 *Section\r
610 )\r
611/*++\r
612\r
613Routine 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
619Arguments:\r
620\r
621 InputFile Stream pointer.\r
622 Section Section to search for\r
623\r
624Returns:\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