]> git.proxmox.com Git - mirror_edk2.git/blob - BaseTools/Source/C/Common/ParseInf.c
Sync EDKII BaseTools to BaseTools project r1971
[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 if (IsHex || (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X'))) {
510 //
511 // Convert the hex string.
512 //
513 for (Index = Index + 2; AsciiString[Index] != '\0'; Index++) {
514 CurrentChar = AsciiString[Index];
515 if (CurrentChar == ' ') {
516 break;
517 }
518 //
519 // Verify Hex string
520 //
521 if (isxdigit ((int)CurrentChar) == 0) {
522 return EFI_ABORTED;
523 }
524 //
525 // Add hex value
526 //
527 Value *= 16;
528 if (CurrentChar >= '0' && CurrentChar <= '9') {
529 Value += CurrentChar - '0';
530 } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {
531 Value += CurrentChar - 'a' + 10;
532 } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {
533 Value += CurrentChar - 'A' + 10;
534 }
535 }
536
537 *ReturnValue = Value;
538 } else {
539 //
540 // Convert dec string is a number
541 //
542 for (; Index < strlen (AsciiString); Index++) {
543 CurrentChar = AsciiString[Index];
544 if (CurrentChar == ' ') {
545 break;
546 }
547 //
548 // Verify Dec string
549 //
550 if (isdigit ((int)CurrentChar) == 0) {
551 return EFI_ABORTED;
552 }
553 //
554 // Add dec value
555 //
556 Value = Value * 10;
557 Value += CurrentChar - '0';
558 }
559
560 *ReturnValue = Value;
561 }
562
563 return EFI_SUCCESS;
564 }
565
566 CHAR8 *
567 ReadLineInStream (
568 IN FILE *InputFile,
569 IN OUT CHAR8 *InputBuffer
570 )
571 /*++
572
573 Routine Description:
574
575 This function reads a line, stripping any comments.
576 // BUGBUG: This is obsolete once genmake goes away...
577
578 Arguments:
579
580 InputFile Stream pointer.
581 InputBuffer Buffer to read into, must be _MAX_PATH size.
582
583 Returns:
584
585 NULL if error or EOF
586 InputBuffer otherwise
587
588 --*/
589 {
590 CHAR8 *CharPtr;
591
592 //
593 // Verify input parameters are not null
594 //
595 assert (InputFile);
596 assert (InputBuffer);
597
598 //
599 // Read a line
600 //
601 if (fgets (InputBuffer, _MAX_PATH, InputFile) == NULL) {
602 return NULL;
603 }
604 //
605 // Strip any comments
606 //
607 CharPtr = strstr (InputBuffer, "//");
608 if (CharPtr != 0) {
609 CharPtr[0] = 0;
610 }
611
612 CharPtr = strstr (InputBuffer, "#");
613 if (CharPtr != 0) {
614 CharPtr[0] = 0;
615 }
616 //
617 // Return the string
618 //
619 return InputBuffer;
620 }
621
622 BOOLEAN
623 FindSectionInStream (
624 IN FILE *InputFile,
625 IN CHAR8 *Section
626 )
627 /*++
628
629 Routine Description:
630
631 This function parses a stream file from the beginning to find a section.
632 The section string may be anywhere within a line.
633 // BUGBUG: This is obsolete once genmake goes away...
634
635 Arguments:
636
637 InputFile Stream pointer.
638 Section Section to search for
639
640 Returns:
641
642 FALSE if error or EOF
643 TRUE if section found
644
645 --*/
646 {
647 CHAR8 InputBuffer[_MAX_PATH];
648 CHAR8 *CurrentToken;
649
650 //
651 // Verify input is not NULL
652 //
653 assert (InputFile);
654 assert (Section);
655
656 //
657 // Rewind to beginning of file
658 //
659 if (fseek (InputFile, 0, SEEK_SET) != 0) {
660 return FALSE;
661 }
662 //
663 // Read lines until the section is found
664 //
665 while (feof (InputFile) == 0) {
666 //
667 // Read a line
668 //
669 ReadLineInStream (InputFile, InputBuffer);
670
671 //
672 // Check if the section is found
673 //
674 CurrentToken = strstr (InputBuffer, Section);
675 if (CurrentToken != NULL) {
676 return TRUE;
677 }
678 }
679
680 return FALSE;
681 }