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