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