3 Copyright (c) 2004 - 2006, 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
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.
18 Generate Dependency Expression ("GenDepex")
20 Infix to Postfix Algorithm
22 This code has been scrubbed to be free of having any EFI core tree dependencies.
23 It should build in any environment that supports a standard C-library w/ string
24 operations and File I/O services.
26 As an example of usage, consider the following:
28 The input user file could be something like "Sample.DXS" whose contents are
33 NOT (DISK_IO_PROTOCOL AND SIMPLE_FILE_SYSTEM_PROTOCOL)
34 OR EFI_PXE_BASE_CODE_PROTOCOL
37 This file is then washed through the C-preprocessor, viz.,
39 cl /EP Sample.DXS > Sample.TMP1
41 This yields the following file "Sample.TMP1" whose contents are
44 NOT ({ 0xce345171, 0xba0b, 0x11d2, 0x8e, 0x4f, 0x0, 0xa0, 0xc9, 0x69, 0x72,
45 0x3b } AND { 0x964e5b22, 0x6459, 0x11d2, 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69,
46 0x72, 0x3b }) OR { 0x03c4e603, 0xac28, 0x11d3, 0x9a, 0x2d, 0x00, 0x90, 0x27,
50 This file, in turn, will be fed into the utility, viz.,
52 GenDepex Sample.TMP1 Sample.TMP2
54 With a file that is 55 bytes long:
56 55 bytes for the grammar binary
58 GUID Instance - 16 bytes
60 GUID Instance - 16 bytes
64 GUID Instance - 16 bytes
68 The file "Sample.TMP2" could be fed via a Section-builder utility
69 (GenSection) that would be used for the creation of a dependency
70 section file (.DPX) which in turn would be used by a generate FFS
71 utility (GenFfsFile) to produce a DXE driver/core (.DXE) or
72 a DXE application (.APP) file.
74 Complies with Tiano C Coding Standards Document, version 0.31, 12 Dec 2000.
80 #define TOOL_NAME "GenDepex"
90 PrintGenDepexUtilityInfo (
97 Displays the standard utility information to SDTOUT.
110 "%s, Tiano Dependency Expression Generation Utility. Version %d.%d.\n",
112 UTILITY_MAJOR_VERSION
,
113 UTILITY_MINOR_VERSION
115 printf ("Copyright (C) 1996-2002 Intel Corporation. All rights reserved.\n\n");
119 PrintGenDepexUsageInfo (
126 Displays the utility usage syntax to STDOUT.
139 "Usage: %s -I <INFILE> -O <OUTFILE> [-P <Optional Boundary for padding up>] \n",
142 printf (" Where:\n");
143 printf (" <INFILE> is the input pre-processed dependency text files name.\n");
144 printf (" <OUTFILE> is the output binary dependency files name.\n");
145 printf (" <Optional Boundary for padding up> is the padding integer value.\n");
146 printf (" This is the boundary to align the output file size to.\n");
157 Pop an element from the Opcode stack.
161 Stack Current top of the OpCode stack location
165 DEPENDENCY_OPCODE OpCode at the top of the OpCode stack.
166 Stack New top of the OpCode stack location
171 DEPENDENCY_OPCODE
*OpCodePtr
;
182 IN DEPENDENCY_OPCODE OpCode
188 Push an element onto the Opcode Stack
192 Stack Current top of the OpCode stack location
193 OpCode OpCode to push onto the stack
197 Stack New top of the OpCode stack location
201 DEPENDENCY_OPCODE
*OpCodePtr
;
210 GenerateDependencyExpression (
212 IN OUT
FILE *OutFile
,
213 IN UINT8 Padding OPTIONAL
219 This takes the pre-compiled dependency text file and
220 converts it into a binary dependency file.
222 The BNF for the dependency expression is as follows
223 (from the DXE 1.0 Draft specification).
225 The inputted BNF grammar is thus:
226 <depex> ::= sor <dep> |
233 <bool> ::= <bool> and <term> |
237 <term> ::= not <factor> |
240 <factor> ::= ( <bool> ) |
248 The outputed binary grammer is thus:
249 <depex> ::= sor <dep> |
250 before <depinst> <dep> |
251 after <depinst> <dep> |
256 <bool> ::= <bool> and <term> |
257 <bool> or <term> | <term>
259 <term> ::= not <factor> |
262 <factor> ::= ( <bool> ) |
271 <depinst> ::= push GUID
275 BugBug: A correct grammer is parsed correctly. A file that violates the
276 grammer may parse when it should generate an error. There is some
277 error checking and it covers most of the case when it's an include
278 of definition issue. An ill formed expresion may not be detected.
282 InFile - Input pre-compiled text file of the dependency expression.
283 This needs to be in ASCII.
284 The file pointer can not be NULL.
286 OutFile - Binary dependency file.
287 The file pointer can not be NULL.
289 Padding - OPTIONAL integer value to pad the output file to.
294 EFI_SUCCESS The function completed successfully.
295 EFI_INVALID_PARAMETER One of the parameters in the text file was invalid.
296 EFI_OUT_OF_RESOURCES Unable to allocate memory.
297 EFI_ABORTED An misc error occurred.
303 INT8
*EvaluationStack
;
317 UINTN ArgCountParsed
;
318 DEPENDENCY_OPCODE Opcode
;
325 memset (Line
, 0, LINESIZE
);
329 EvaluationStack
= (INT8
*) malloc (EVAL_STACK_SIZE
);
331 if (EvaluationStack
!= NULL
) {
332 StackPtr
= EvaluationStack
;
334 printf ("Unable to allocate memory to EvaluationStack - Out of resources\n");
335 return EFI_OUT_OF_RESOURCES
;
338 Results
= (UINTN
) fseek (InFile
, 0, SEEK_END
);
341 printf ("FSEEK failed - Aborted\n");
345 FileSize
= ftell (InFile
);
347 if (FileSize
== -1L) {
348 printf ("FTELL failed - Aborted\n");
352 Buffer
= (INT8
*) malloc (FileSize
+ BUFFER_SIZE
);
354 if (Buffer
== NULL
) {
355 printf ("Unable to allocate memory to Buffer - Out of resources\n");
356 free (EvaluationStack
);
358 Results
= (UINTN
) fclose (InFile
);
360 printf ("FCLOSE failed\n");
363 Results
= (UINTN
) fclose (OutFile
);
365 printf ("FCLOSE failed\n");
368 return EFI_OUT_OF_RESOURCES
;
371 Results
= (UINTN
) fseek (InFile
, 0, SEEK_SET
);
374 printf ("FSEEK failed - Aborted\n");
378 fread (Buffer
, FileSize
, 1, InFile
);
381 Pend
= Ptrx
+ FileSize
- strlen (DEPENDENCY_END
);
385 while ((Index
--) && NotDone
) {
387 if (strncmp (Pend
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
395 printf ("Couldn't find end string %s\n", DEPENDENCY_END
);
397 Results
= (UINTN
) fclose (InFile
);
399 printf ("FCLOSE failed\n");
402 Results
= (UINTN
) fclose (OutFile
);
404 printf ("FCLOSE failed\n");
408 free (EvaluationStack
);
410 return EFI_INVALID_PARAMETER
;
416 while ((Index
--) && NotDone
) {
418 if (strncmp (Ptrx
, DEPENDENCY_START
, strlen (DEPENDENCY_START
)) == 0) {
419 Ptrx
+= strlen (DEPENDENCY_START
);
422 // BUGBUG -- should Index be decremented by sizeof(DEPENDENCY_START)?
430 printf ("Couldn't find start string %s\n", DEPENDENCY_START
);
432 Results
= (UINTN
) fclose (InFile
);
434 printf ("FCLOSE failed\n");
437 Results
= (UINTN
) fclose (OutFile
);
439 printf ("FCLOSE failed\n");
443 free (EvaluationStack
);
445 return EFI_INVALID_PARAMETER
;
448 // validate the syntax of expression
450 if (!ParseDepex (Ptrx
, Pend
- Ptrx
- 1)) {
451 printf ("The syntax of expression is wrong\n");
453 Results
= (UINTN
) fclose (InFile
);
455 printf ("FCLOSE failed\n");
458 Results
= (UINTN
) fclose (OutFile
);
460 printf ("FCLOSE failed\n");
464 free (EvaluationStack
);
466 return EFI_INVALID_PARAMETER
;
471 while ((Index
--) && NotDone
) {
475 } else if (*Ptrx
== '\n' || *Ptrx
== '\r') {
477 } else if (strncmp (Ptrx
, OPERATOR_SOR
, strlen (OPERATOR_SOR
)) == 0) {
479 // Checks for some invalid dependencies
483 printf ("A BEFORE operator was detected.\n");
484 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
485 return EFI_INVALID_PARAMETER
;
487 } else if (After_Flag
) {
489 printf ("An AFTER operator was detected.\n");
490 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
491 return EFI_INVALID_PARAMETER
;
493 } else if (SOR_Flag
) {
495 printf ("Another SOR operator was detected.\n");
496 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
497 return EFI_INVALID_PARAMETER
;
499 } else if (Dep_Flag
) {
501 printf ("The Schedule On Request - SOR operator must be the first operator following DEPENDENCY_START\n");
502 return EFI_INVALID_PARAMETER
;
506 // BUGBUG - This was not in the spec but is in the CORE code
507 // An OPERATOR_SOR has to be first - following the DEPENDENCY_START
509 fputc (EFI_DEP_SOR
, OutFile
);
511 Ptrx
+= strlen (OPERATOR_SOR
);
515 } else if (strncmp (Ptrx
, OPERATOR_BEFORE
, strlen (OPERATOR_BEFORE
)) == 0) {
517 // Checks for some invalid dependencies
521 printf ("Another BEFORE operator was detected.\n");
522 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
523 return EFI_INVALID_PARAMETER
;
525 } else if (After_Flag
) {
527 printf ("An AFTER operator was detected.\n");
528 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
529 return EFI_INVALID_PARAMETER
;
531 } else if (SOR_Flag
) {
533 printf ("A SOR operator was detected.\n");
534 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
535 return EFI_INVALID_PARAMETER
;
537 } else if (Dep_Flag
) {
539 printf ("The BEFORE operator must be the first operator following DEPENDENCY_START\n");
540 return EFI_INVALID_PARAMETER
;
543 fputc (EFI_DEP_BEFORE
, OutFile
);
545 Ptrx
+= strlen (OPERATOR_BEFORE
);
548 } else if (strncmp (Ptrx
, OPERATOR_AFTER
, strlen (OPERATOR_AFTER
)) == 0) {
550 // Checks for some invalid dependencies
554 printf ("A BEFORE operator was detected.\n");
555 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
556 return EFI_INVALID_PARAMETER
;
558 } else if (After_Flag
) {
560 printf ("Another AFTER operator was detected.\n");
561 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
562 return EFI_INVALID_PARAMETER
;
564 } else if (SOR_Flag
) {
566 printf ("A SOR operator was detected.\n");
567 printf ("There can only be one SOR or one AFTER or one BEFORE operator\n");
568 return EFI_INVALID_PARAMETER
;
570 } else if (Dep_Flag
) {
572 printf ("The AFTER operator must be the first operator following DEPENDENCY_START\n");
573 return EFI_INVALID_PARAMETER
;
576 fputc (EFI_DEP_AFTER
, OutFile
);
578 Ptrx
+= strlen (OPERATOR_AFTER
);
582 } else if (strncmp (Ptrx
, OPERATOR_AND
, strlen (OPERATOR_AND
)) == 0) {
583 while (StackPtr
!= EvaluationStack
) {
584 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
585 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
586 fputc (Opcode
, OutFile
);
589 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
594 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_AND
);
595 Ptrx
+= strlen (OPERATOR_AND
);
598 } else if (strncmp (Ptrx
, OPERATOR_OR
, strlen (OPERATOR_OR
)) == 0) {
599 while (StackPtr
!= EvaluationStack
) {
600 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
601 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
602 fputc (Opcode
, OutFile
);
605 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
610 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_OR
);
611 Ptrx
+= strlen (OPERATOR_OR
);
614 } else if (strncmp (Ptrx
, OPERATOR_NOT
, strlen (OPERATOR_NOT
)) == 0) {
615 while (StackPtr
!= EvaluationStack
) {
616 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
617 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
618 fputc (Opcode
, OutFile
);
621 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
626 PushOpCode ((VOID
**) &StackPtr
, EFI_DEP_NOT
);
627 Ptrx
+= strlen (OPERATOR_NOT
);
630 } else if (*Ptrx
== '\t') {
632 printf ("File contains tabs. This violates the coding standard\n");
633 return EFI_INVALID_PARAMETER
;
635 } else if (*Ptrx
== '\n') {
637 // Skip the newline character in the file
641 } else if (strncmp (Ptrx
, OPERATOR_LEFT_PARENTHESIS
, strlen (OPERATOR_LEFT_PARENTHESIS
)) == 0) {
642 PushOpCode ((VOID
**) &StackPtr
, DXE_DEP_LEFT_PARENTHESIS
);
644 Ptrx
+= strlen (OPERATOR_LEFT_PARENTHESIS
);
647 } else if (strncmp (Ptrx
, OPERATOR_RIGHT_PARENTHESIS
, strlen (OPERATOR_RIGHT_PARENTHESIS
)) == 0) {
648 while (StackPtr
!= EvaluationStack
) {
649 Opcode
= PopOpCode ((VOID
**) &StackPtr
);
650 if (Opcode
!= DXE_DEP_LEFT_PARENTHESIS
) {
651 fputc (Opcode
, OutFile
);
658 Ptrx
+= strlen (OPERATOR_RIGHT_PARENTHESIS
);
661 } else if (strncmp (Ptrx
, OPERATOR_TRUE
, strlen (OPERATOR_TRUE
)) == 0) {
663 fputc (EFI_DEP_TRUE
, OutFile
);
668 // OutFileSize += sizeof (EFI_DEP_TRUE);
672 Ptrx
+= strlen (OPERATOR_TRUE
);
674 } else if (strncmp (Ptrx
, OPERATOR_FALSE
, strlen (OPERATOR_FALSE
)) == 0) {
676 fputc (EFI_DEP_FALSE
, OutFile
);
681 // OutFileSize += sizeof (EFI_DEP_FALSE);
685 Ptrx
+= strlen (OPERATOR_FALSE
);
687 } else if (*Ptrx
== '{') {
694 ArgCountParsed
= sscanf (
696 "%x, %x, %x, %x, %x, %x, %x, %x, %x, %x, %x",
710 if (ArgCountParsed
!= 11) {
711 printf ("We have found an illegal GUID\n");
712 printf ("Fix your depex\n");
716 while (*Ptrx
!= '}') {
720 // Absorb the closing }
725 // Don't provide a PUSH Opcode for the Before and After case
727 if ((!Before_Flag
) && (!After_Flag
)) {
728 fputc (EFI_DEP_PUSH
, OutFile
);
732 fwrite (&Guid
, sizeof (EFI_GUID
), 1, OutFile
);
734 OutFileSize
+= sizeof (EFI_GUID
);
737 } else if (strncmp (Ptrx
, DEPENDENCY_END
, strlen (DEPENDENCY_END
)) == 0) {
741 // Not a valid construct. Null terminate somewhere out there and
742 // print an error message.
745 printf (TOOL_NAME
" ERROR: Unrecognized input at: \"%s\"...\n", Ptrx
);
746 return EFI_INVALID_PARAMETER
;
752 while (StackPtr
!= EvaluationStack
) {
753 fputc (PopOpCode ((VOID
**) &StackPtr
), OutFile
);
757 if (OutFileSize
== 0) {
758 printf ("Grammer contains no operators or constants\n");
759 return EFI_INVALID_PARAMETER
;
762 fputc (EFI_DEP_END
, OutFile
);
767 // Checks for invalid padding values
771 printf ("The inputted padding value was %d\n", Padding
);
772 printf ("The optional padding value can not be less than ZERO\n");
773 return EFI_INVALID_PARAMETER
;
775 } else if (Padding
> 0) {
777 while ((OutFileSize
% Padding
) != 0) {
779 fputc (' ', OutFile
);
784 Results
= (UINTN
) fclose (InFile
);
786 printf ("FCLOSE failed\n");
789 Results
= (UINTN
) fclose (OutFile
);
791 printf ("FCLOSE failed\n");
795 free (EvaluationStack
);
798 } // End GenerateDependencyExpression function
809 Parse user entries. Print some rudimentary help
813 argc The count of input arguments
814 argv The input arguments string array
818 EFI_SUCCESS The function completed successfully.
819 EFI_INVALID_PARAMETER One of the input parameters was invalid or one of the parameters in the text file was invalid.
820 EFI_OUT_OF_RESOURCES Unable to allocate memory.
821 EFI_ABORTED Unable to open/create a file or a misc error.
824 // TODO: ] - add argument and description to function comment
842 // Output the calling arguments
845 for (Index
= 0; Index
< argc
; Index
++) {
846 printf ("%s ", argv
[Index
]);
852 printf ("Not enough arguments\n");
853 PrintGenDepexUsageInfo ();
854 return EFI_INVALID_PARAMETER
;
857 for (Index
= 1; Index
< argc
- 1; Index
++) {
859 if ((strcmp (argv
[Index
], "-I") == 0) || (strcmp (argv
[Index
], "-i") == 0)) {
863 InFile
= fopen (argv
[Index
+ 1], "rb");
867 printf ("GenDepex only allows one INPUT (-I) argument\n");
868 return EFI_INVALID_PARAMETER
;
871 } else if ((strcmp (argv
[Index
], "-O") == 0) || (strcmp (argv
[Index
], "-o") == 0)) {
875 OutFile
= fopen (argv
[Index
+ 1], "wb");
879 printf ("GenDepex only allows one OUTPUT (-O) argument\n");
880 return EFI_INVALID_PARAMETER
;
883 } else if ((strcmp (argv
[Index
], "-P") == 0) || (strcmp (argv
[Index
], "-p") == 0)) {
887 Padding
= (UINT8
) atoi (argv
[Index
+ 1]);
891 printf ("GenDepex only allows one PADDING (-P) argument\n");
892 return EFI_INVALID_PARAMETER
;
897 PrintGenDepexUtilityInfo ();
899 if (InFile
== NULL
) {
900 printf ("Can not open <INFILE> for reading.\n");
901 PrintGenDepexUsageInfo ();
905 if (OutFile
== NULL
) {
906 printf ("Can not open <OUTFILE> for writting.\n");
907 PrintGenDepexUsageInfo ();
911 return GenerateDependencyExpression (InFile
, OutFile
, Padding
);