]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/ParseInf.c
385758f8366f5412b8f9a93510e84a9e13f49dde
[mirror_edk2.git] / BaseTools / Source / C / Common / ParseInf.c
1 /** @file
2
3 Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11
12 Module Name:
13
14 ParseInf.c
15
16 Abstract:
17
18 This contains some useful functions for parsing INF files.
19
20 --*/
21
22 #include <assert.h>
23 #include <string.h>
24 #include <ctype.h>
25 #include <stdlib.h>
26 #include "EfiUtilityMsgs.h"
27 #include "ParseInf.h"
28
29 CHAR8 *
30 ReadLine (
31 IN MEMORY_FILE *InputFile,
32 IN OUT CHAR8 *InputBuffer,
33 IN UINTN MaxLength
34 )
35 /*++
36
37 Routine Description:
38
39 This function reads a line, stripping any comments.
40 The function reads a string from the input stream argument and stores it in
41 the input string. ReadLine reads characters from the current file position
42 to and including the first newline character, to the end of the stream, or
43 until the number of characters read is equal to MaxLength - 1, whichever
44 comes first. The newline character, if read, is replaced with a \0.
45
46 Arguments:
47
48 InputFile Memory file image.
49 InputBuffer Buffer to read into, must be _MAX_PATH size.
50 MaxLength The maximum size of the input buffer.
51
52 Returns:
53
54 NULL if error or EOF
55 InputBuffer otherwise
56
57 --*/
58 {
59 CHAR8 *CharPtr;
60 CHAR8 *EndOfLine;
61 UINTN CharsToCopy;
62
63 //
64 // Verify input parameters are not null
65 //
66 assert (InputBuffer);
67 assert (InputFile->FileImage);
68 assert (InputFile->Eof);
69 assert (InputFile->CurrentFilePointer);
70
71 //
72 // Check for end of file condition
73 //
74 if (InputFile->CurrentFilePointer >= InputFile->Eof) {
75 return NULL;
76 }
77 //
78 // Find the next newline char
79 //
80 EndOfLine = strchr (InputFile->CurrentFilePointer, '\n');
81
82 //
83 // Determine the number of characters to copy.
84 //
85 if (EndOfLine == 0) {
86 //
87 // If no newline found, copy to the end of the file.
88 //
89 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
90 } else if (EndOfLine >= InputFile->Eof) {
91 //
92 // If the newline found was beyond the end of file, copy to the eof.
93 //
94 CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
95 } else {
96 //
97 // Newline found in the file.
98 //
99 CharsToCopy = EndOfLine - InputFile->CurrentFilePointer;
100 }
101 //
102 // If the end of line is too big for the current buffer, set it to the max
103 // size of the buffer (leaving room for the \0.
104 //
105 if (CharsToCopy > MaxLength - 1) {
106 CharsToCopy = MaxLength - 1;
107 }
108 //
109 // Copy the line.
110 //
111 memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy);
112
113 //
114 // Add the null termination over the 0x0D
115 //
116 if (InputBuffer[CharsToCopy - 1] == '\r') {
117
118 InputBuffer[CharsToCopy - 1] = '\0';
119
120 } else {
121
122 InputBuffer[CharsToCopy] = '\0';
123
124 }
125
126 //
127 // Increment the current file pointer (include the 0x0A)
128 //
129 InputFile->CurrentFilePointer += CharsToCopy + 1;
130
131 //
132 // Strip any comments
133 //
134 CharPtr = strstr (InputBuffer, "//");
135 if (CharPtr != 0) {
136 CharPtr[0] = 0;
137 }
138 //
139 // Return the string
140 //
141 return InputBuffer;
142 }
143
144 BOOLEAN
145 FindSection (
146 IN MEMORY_FILE *InputFile,
147 IN CHAR8 *Section
148 )
149 /*++
150
151 Routine Description:
152
153 This function parses a file from the beginning to find a section.
154 The section string may be anywhere within a line.
155
156 Arguments:
157
158 InputFile Memory file image.
159 Section Section to search for
160
161 Returns:
162
163 FALSE if error or EOF
164 TRUE if section found
165
166 --*/
167 {
168 CHAR8 InputBuffer[_MAX_PATH];
169 CHAR8 *CurrentToken;
170
171 //
172 // Verify input is not NULL
173 //
174 assert (InputFile->FileImage);
175 assert (InputFile->Eof);
176 assert (InputFile->CurrentFilePointer);
177 assert (Section);
178
179 //
180 // Rewind to beginning of file
181 //
182 InputFile->CurrentFilePointer = InputFile->FileImage;
183
184 //
185 // Read lines until the section is found
186 //
187 while (InputFile->CurrentFilePointer < InputFile->Eof) {
188 //
189 // Read a line
190 //
191 ReadLine (InputFile, InputBuffer, _MAX_PATH);
192
193 //
194 // Check if the section is found
195 //
196 CurrentToken = strstr (InputBuffer, Section);
197 if (CurrentToken != NULL) {
198 return TRUE;
199 }
200 }
201
202 return FALSE;
203 }
204
205 EFI_STATUS
206 FindToken (
207 IN MEMORY_FILE *InputFile,
208 IN CHAR8 *Section,
209 IN CHAR8 *Token,
210 IN UINTN Instance,
211 OUT CHAR8 *Value
212 )
213 /*++
214
215 Routine Description:
216
217 Finds a token value given the section and token to search for.
218
219 Arguments:
220
221 InputFile Memory file image.
222 Section The section to search for, a string within [].
223 Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file.
224 Instance The instance of the token to search for. Zero is the first instance.
225 Value The string that holds the value following the =. Must be _MAX_PATH in size.
226
227 Returns:
228
229 EFI_SUCCESS Value found.
230 EFI_ABORTED Format error detected in INF file.
231 EFI_INVALID_PARAMETER Input argument was null.
232 EFI_LOAD_ERROR Error reading from the file.
233 EFI_NOT_FOUND Section/Token/Value not found.
234
235 --*/
236 {
237 CHAR8 InputBuffer[_MAX_PATH];
238 CHAR8 *CurrentToken;
239 CHAR8 *Delimiter;
240 BOOLEAN ParseError;
241 BOOLEAN ReadError;
242 UINTN Occurrance;
243
244 //
245 // Check input parameters
246 //
247 if (InputFile->FileImage == NULL ||
248 InputFile->Eof == NULL ||
249 InputFile->CurrentFilePointer == NULL ||
250 Section == NULL ||
251 strlen (Section) == 0 ||
252 Token == NULL ||
253 strlen (Token) == 0 ||
254 Value == NULL
255 ) {
256 return EFI_INVALID_PARAMETER;
257 }
258 //
259 // Initialize error codes
260 //
261 ParseError = FALSE;
262 ReadError = FALSE;
263
264 //
265 // Initialize our instance counter for the search token
266 //
267 Occurrance = 0;
268
269 if (FindSection (InputFile, Section)) {
270 //
271 // Found the desired section, find and read the desired token
272 //
273 do {
274 //
275 // Read a line from the file
276 //
277 if (ReadLine (InputFile, InputBuffer, _MAX_PATH) == NULL) {
278 //
279 // Error reading from input file
280 //
281 ReadError = TRUE;
282 break;
283 }
284 //
285 // Get the first non-whitespace string
286 //
287 Delimiter = strchr (InputBuffer, '=');
288 if (Delimiter != NULL) {
289 *Delimiter = 0;
290 }
291
292 CurrentToken = strtok (InputBuffer, " \t\n");
293 if (CurrentToken == NULL || Delimiter == NULL) {
294 //
295 // Whitespace line found (or comment) so continue
296 //
297 CurrentToken = InputBuffer;
298 continue;
299 }
300 //
301 // Make sure we have not reached the end of the current section
302 //
303 if (CurrentToken[0] == '[') {
304 break;
305 }
306 //
307 // Compare the current token with the desired token
308 //
309 if (strcmp (CurrentToken, Token) == 0) {
310 //
311 // Found it
312 //
313 //
314 // Check if it is the correct instance
315 //
316 if (Instance == Occurrance) {
317 //
318 // Copy the contents following the =
319 //
320 CurrentToken = Delimiter + 1;
321 if (*CurrentToken == 0) {
322 //
323 // Nothing found, parsing error
324 //
325 ParseError = TRUE;
326 } else {
327 //
328 // Strip leading white space
329 //
330 while (*CurrentToken == ' ' || *CurrentToken == '\t') {
331 CurrentToken++;
332 }
333 //
334 // Copy the current token to the output value
335 //
336 strcpy (Value, CurrentToken);
337 //
338 // Strip trailing white space
339 //
340 while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) {
341 *(Value + strlen(Value) - 1) = 0;
342 }
343 return EFI_SUCCESS;
344 }
345 } else {
346 //
347 // Increment the occurrance found
348 //
349 Occurrance++;
350 }
351 }
352 } while (
353 !ParseError &&
354 !ReadError &&
355 InputFile->CurrentFilePointer < InputFile->Eof &&
356 CurrentToken[0] != '[' &&
357 Occurrance <= Instance
358 );
359 }
360 //
361 // Distinguish between read errors and INF file format errors.
362 //
363 if (ReadError) {
364 return EFI_LOAD_ERROR;
365 }
366
367 if (ParseError) {
368 return EFI_ABORTED;
369 }
370
371 return EFI_NOT_FOUND;
372 }
373
374 EFI_STATUS
375 StringToGuid (
376 IN CHAR8 *AsciiGuidBuffer,
377 OUT EFI_GUID *GuidBuffer
378 )
379 /*++
380
381 Routine Description:
382
383 Converts a string to an EFI_GUID. The string must be in the
384 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
385
386 Arguments:
387
388 AsciiGuidBuffer - pointer to ascii string
389 GuidBuffer - pointer to destination Guid
390
391 Returns:
392
393 EFI_ABORTED Could not convert the string
394 EFI_SUCCESS The string was successfully converted
395 EFI_INVALID_PARAMETER Input parameter is invalid.
396
397 --*/
398 {
399 INT32 Index;
400 unsigned Data1;
401 unsigned Data2;
402 unsigned Data3;
403 unsigned Data4[8];
404
405 if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) {
406 return EFI_INVALID_PARAMETER;
407 }
408 //
409 // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
410 //
411 for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) {
412 if (Index == 8 || Index == 13 || Index == 18 || Index == 23) {
413 if (AsciiGuidBuffer[Index] != '-') {
414 break;
415 }
416 } else {
417 if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) ||
418 ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) ||
419 ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) {
420 continue;
421 } else {
422 break;
423 }
424 }
425 }
426
427 if (Index < 36 || AsciiGuidBuffer[36] != '\0') {
428 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);
429 return EFI_ABORTED;
430 }
431
432 //
433 // Scan the guid string into the buffer
434 //
435 Index = sscanf (
436 AsciiGuidBuffer,
437 "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
438 &Data1,
439 &Data2,
440 &Data3,
441 &Data4[0],
442 &Data4[1],
443 &Data4[2],
444 &Data4[3],
445 &Data4[4],
446 &Data4[5],
447 &Data4[6],
448 &Data4[7]
449 );
450
451 //
452 // Verify the correct number of items were scanned.
453 //
454 if (Index != 11) {
455 Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);
456 return EFI_ABORTED;
457 }
458 //
459 // Copy the data into our GUID.
460 //
461 GuidBuffer->Data1 = (UINT32) Data1;
462 GuidBuffer->Data2 = (UINT16) Data2;
463 GuidBuffer->Data3 = (UINT16) Data3;
464 GuidBuffer->Data4[0] = (UINT8) Data4[0];
465 GuidBuffer->Data4[1] = (UINT8) Data4[1];
466 GuidBuffer->Data4[2] = (UINT8) Data4[2];
467 GuidBuffer->Data4[3] = (UINT8) Data4[3];
468 GuidBuffer->Data4[4] = (UINT8) Data4[4];
469 GuidBuffer->Data4[5] = (UINT8) Data4[5];
470 GuidBuffer->Data4[6] = (UINT8) Data4[6];
471 GuidBuffer->Data4[7] = (UINT8) Data4[7];
472
473 return EFI_SUCCESS;
474 }
475
476 EFI_STATUS
477 AsciiStringToUint64 (
478 IN CONST CHAR8 *AsciiString,
479 IN BOOLEAN IsHex,
480 OUT UINT64 *ReturnValue
481 )
482 /*++
483
484 Routine Description:
485
486 Converts a null terminated ascii string that represents a number into a
487 UINT64 value. A hex number may be preceeded by a 0x, but may not be
488 succeeded by an h. A number without 0x or 0X is considered to be base 10
489 unless the IsHex input is true.
490
491 Arguments:
492
493 AsciiString The string to convert.
494 IsHex Force the string to be treated as a hex number.
495 ReturnValue The return value.
496
497 Returns:
498
499 EFI_SUCCESS Number successfully converted.
500 EFI_ABORTED Invalid character encountered.
501
502 --*/
503 {
504 UINT8 Index;
505 UINT64 Value;
506 CHAR8 CurrentChar;
507
508 //
509 // Initialize the result
510 //
511 Value = 0;
512 Index = 0;
513
514 //
515 // Check input paramter
516 //
517 if (AsciiString == NULL || ReturnValue == NULL) {
518 return EFI_INVALID_PARAMETER;
519 }
520 while (AsciiString[Index] == ' ') {
521 Index ++;
522 }
523
524 //
525 // Add each character to the result
526 //
527
528 //
529 // Skip first two chars only if the string starts with '0x' or '0X'
530 //
531 if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) {
532 IsHex = TRUE;
533 Index += 2;
534 }
535 if (IsHex) {
536 //
537 // Convert the hex string.
538 //
539 for (; AsciiString[Index] != '\0'; Index++) {
540 CurrentChar = AsciiString[Index];
541 if (CurrentChar == ' ') {
542 break;
543 }
544 //
545 // Verify Hex string
546 //
547 if (isxdigit ((int)CurrentChar) == 0) {
548 return EFI_ABORTED;
549 }
550 //
551 // Add hex value
552 //
553 Value *= 16;
554 if (CurrentChar >= '0' && CurrentChar <= '9') {
555 Value += CurrentChar - '0';
556 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {
557 Value += CurrentChar - 'a' + 10;
558 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {
559 Value += CurrentChar - 'A' + 10;
560 }
561 }
562
563 *ReturnValue = Value;
564 } else {
565 //
566 // Convert dec string is a number
567 //
568 for (; Index < strlen (AsciiString); Index++) {
569 CurrentChar = AsciiString[Index];
570 if (CurrentChar == ' ') {
571 break;
572 }
573 //
574 // Verify Dec string
575 //
576 if (isdigit ((int)CurrentChar) == 0) {
577 return EFI_ABORTED;
578 }
579 //
580 // Add dec value
581 //
582 Value = Value * 10;
583 Value += CurrentChar - '0';
584 }
585
586 *ReturnValue = Value;
587 }
588
589 return EFI_SUCCESS;
590 }
591
592 CHAR8 *
593 ReadLineInStream (
594 IN FILE *InputFile,
595 IN OUT CHAR8 *InputBuffer
596 )
597 /*++
598
599 Routine Description:
600
601 This function reads a line, stripping any comments.
602 // BUGBUG: This is obsolete once genmake goes away...
603
604 Arguments:
605
606 InputFile Stream pointer.
607 InputBuffer Buffer to read into, must be _MAX_PATH size.
608
609 Returns:
610
611 NULL if error or EOF
612 InputBuffer otherwise
613
614 --*/
615 {
616 CHAR8 *CharPtr;
617
618 //
619 // Verify input parameters are not null
620 //
621 assert (InputFile);
622 assert (InputBuffer);
623
624 //
625 // Read a line
626 //
627 if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {
628 return NULL;
629 }
630 //
631 // Strip any comments
632 //
633 CharPtr = strstr (InputBuffer, "//");
634 if (CharPtr != 0) {
635 CharPtr[0] = 0;
636 }
637
638 CharPtr = strstr (InputBuffer, "#");
639 if (CharPtr != 0) {
640 CharPtr[0] = 0;
641 }
642 //
643 // Return the string
644 //
645 return InputBuffer;
646 }
647
648 BOOLEAN
649 FindSectionInStream (
650 IN FILE *InputFile,
651 IN CHAR8 *Section
652 )
653 /*++
654
655 Routine Description:
656
657 This function parses a stream file from the beginning to find a section.
658 The section string may be anywhere within a line.
659 // BUGBUG: This is obsolete once genmake goes away...
660
661 Arguments:
662
663 InputFile Stream pointer.
664 Section Section to search for
665
666 Returns:
667
668 FALSE if error or EOF
669 TRUE if section found
670
671 --*/
672 {
673 CHAR8 InputBuffer[_MAX_PATH];
674 CHAR8 *CurrentToken;
675
676 //
677 // Verify input is not NULL
678 //
679 assert (InputFile);
680 assert (Section);
681
682 //
683 // Rewind to beginning of file
684 //
685 if (fseek (InputFile, 0, SEEK_SET) != 0) {
686 return FALSE;
687 }
688 //
689 // Read lines until the section is found
690 //
691 while (feof (InputFile) == 0) {
692 //
693 // Read a line
694 //
695 ReadLineInStream (InputFile, InputBuffer);
696
697 //
698 // Check if the section is found
699 //
700 CurrentToken = strstr (InputBuffer, Section);
701 if (CurrentToken != NULL) {
702 return TRUE;
703 }
704 }
705
706 return FALSE;
707 }