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