1 /*++
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   VfrCompiler.cpp
15 
16 Abstract:
17 
18 --*/
19 
20 #include "stdio.h"
21 #include "string.h"
22 #include "process.h"
23 #include "VfrCompiler.h"
24 
25 
26 VOID
SET_RUN_STATUS(IN COMPILER_RUN_STATUS Status)27 CVfrCompiler::SET_RUN_STATUS (
28   IN COMPILER_RUN_STATUS Status
29   )
30 {
31   mRunStatus = Status;
32 }
33 
34 BOOLEAN
IS_RUN_STATUS(IN COMPILER_RUN_STATUS Status)35 CVfrCompiler::IS_RUN_STATUS (
36   IN COMPILER_RUN_STATUS Status
37   )
38 {
39   return mRunStatus == Status;
40 }
41 
42 VOID
OptionInitialization(IN INT32 Argc,IN INT8 ** Argv)43 CVfrCompiler::OptionInitialization (
44   IN INT32      Argc,
45   IN INT8       **Argv
46   )
47 {
48   INT32         Index;
49 
50   mOptions.VfrFileName[0]                = '\0';
51   mOptions.RecordListFile[0]             = '\0';
52   mOptions.CreateRecordListFile          = FALSE;
53   mOptions.CreateIfrPkgFile              = FALSE;
54   mOptions.PkgOutputFileName[0]          = '\0';
55   mOptions.COutputFileName[0]            = '\0';
56   mOptions.OutputDirectory[0]            = '\0';
57   mOptions.PreprocessorOutputFileName[0] = '\0';
58   mOptions.VfrBaseFileName[0]            = '\0';
59   mOptions.IncludePaths                  = NULL;
60   mOptions.SkipCPreprocessor             = FALSE;
61   mOptions.CPreprocessorOptions          = NULL;
62 
63   for (Index = 1; (Index < Argc) && (Argv[Index][0] == '-'); Index++) {
64     if ((_stricmp(Argv[Index], "-?") == 0) || (_stricmp(Argv[Index], "-h") == 0)) {
65       Usage ();
66       SET_RUN_STATUS (STATUS_DEAD);
67       return;
68     } else if (_stricmp(Argv[Index], "-l") == 0) {
69       mOptions.CreateRecordListFile = TRUE;
70       gCIfrRecordInfoDB.TurnOn ();
71     } else if (_stricmp(Argv[Index], "-i") == 0) {
72       Index++;
73       if ((Index >= Argc) || (Argv[Index][0] == '-')) {
74         printf ("%s -i - missing path argument\n", UTILITY_NAME);
75         goto Fail;
76       }
77 
78       AppendIncludePath(Argv[Index]);
79     } else if (_stricmp(Argv[Index], "-od") == 0) {
80       Index++;
81       if ((Index >= Argc) || (Argv[Index][0] == '-')) {
82         printf ("%s -od - missing output directory name\n", UTILITY_NAME);
83         goto Fail;
84       }
85       strcpy (mOptions.OutputDirectory, Argv[Index]);
86       strcat (mOptions.OutputDirectory, "\\");
87     } else if (_stricmp(Argv[Index], "-ibin") == 0) {
88       mOptions.CreateIfrPkgFile = TRUE;
89     } else if (_stricmp(Argv[Index], "-nostrings") == 0) {
90     } else if (_stricmp(Argv[Index], "-nopp") == 0) {
91       mOptions.SkipCPreprocessor = TRUE;
92     } else if (_stricmp(Argv[Index], "-ppflag") == 0) {
93       Index++;
94       if ((Index >= Argc) || (Argv[Index][0] == '-')) {
95         printf ("%s -od - missing C-preprocessor argument\n", UTILITY_NAME);
96         goto Fail;
97       }
98 
99       AppendCPreprocessorOptions (Argv[Index]);
100     } else {
101       printf ("%s unrecognized option %s\n", UTILITY_NAME, Argv[Index]);
102       Usage ();
103       goto Fail;
104     }
105   }
106 
107   if (Index != Argc - 1) {
108     printf ("%s must specify VFR file name\n", UTILITY_NAME);
109     Usage ();
110     goto Fail;
111   } else {
112     strcpy (mOptions.VfrFileName, Argv[Index]);
113   }
114 
115   if (SetBaseFileName() != 0) {
116     goto Fail;
117   }
118   if (SetPkgOutputFileName () != 0) {
119     goto Fail;
120   }
121   if (SetCOutputFileName() != 0) {
122     goto Fail;
123   }
124   if (SetPreprocessorOutputFileName () != 0) {
125     goto Fail;
126   }
127   if (SetRecordListFileName () != 0) {
128     goto Fail;
129   }
130   return;
131 
132 Fail:
133   SET_RUN_STATUS (STATUS_FAILED);
134 
135   mOptions.VfrFileName[0]                = '\0';
136   mOptions.RecordListFile[0]             = '\0';
137   mOptions.CreateRecordListFile          = FALSE;
138   mOptions.CreateIfrPkgFile              = FALSE;
139   mOptions.PkgOutputFileName[0]          = '\0';
140   mOptions.COutputFileName[0]            = '\0';
141   mOptions.OutputDirectory[0]            = '\0';
142   mOptions.PreprocessorOutputFileName[0] = '\0';
143   mOptions.VfrBaseFileName[0]            = '\0';
144   if (mOptions.IncludePaths != NULL) {
145     delete mOptions.IncludePaths;
146     mOptions.IncludePaths                = NULL;
147   }
148   if (mOptions.CPreprocessorOptions != NULL) {
149     delete mOptions.CPreprocessorOptions;
150     mOptions.CPreprocessorOptions        = NULL;
151   }
152 }
153 
154 VOID
AppendIncludePath(IN INT8 * PathStr)155 CVfrCompiler::AppendIncludePath (
156   IN INT8       *PathStr
157   )
158 {
159   UINT32  Len           = 0;
160   INT8    *IncludePaths = NULL;
161 
162   Len = strlen (" -I ") + strlen (PathStr) + 1;
163   if (mOptions.IncludePaths != NULL) {
164     Len += strlen (mOptions.IncludePaths);
165   }
166   IncludePaths = new INT8[Len];
167   if (IncludePaths == NULL) {
168     printf ("%s memory allocation failure\n", UTILITY_NAME);
169     return;
170   }
171   IncludePaths[0] = '\0';
172   if (mOptions.IncludePaths != NULL) {
173     strcat (IncludePaths, mOptions.IncludePaths);
174   }
175   strcat (IncludePaths, " -I ");
176   strcat (IncludePaths, PathStr);
177   if (mOptions.IncludePaths != NULL) {
178     delete mOptions.IncludePaths;
179   }
180   mOptions.IncludePaths = IncludePaths;
181 }
182 
183 VOID
AppendCPreprocessorOptions(IN INT8 * Options)184 CVfrCompiler::AppendCPreprocessorOptions (
185   IN INT8       *Options
186   )
187 {
188   UINT32  Len           = 0;
189   INT8    *Opt          = NULL;
190 
191   Len = strlen (Options) + strlen (" ") + 1;
192   if (mOptions.CPreprocessorOptions != NULL) {
193     Len += strlen (mOptions.CPreprocessorOptions);
194   }
195   Opt = new INT8[Len];
196   if (Opt == NULL) {
197     printf ("%s memory allocation failure\n", UTILITY_NAME);
198     return;
199   }
200   Opt[0] = 0;
201   if (mOptions.CPreprocessorOptions != NULL) {
202     strcat (Opt, mOptions.CPreprocessorOptions);
203   }
204   strcat (Opt, " ");
205   strcat (Opt, Options);
206   if (mOptions.CPreprocessorOptions != NULL) {
207     delete mOptions.CPreprocessorOptions;
208   }
209   mOptions.CPreprocessorOptions = Opt;
210 }
211 
212 INT8
SetBaseFileName(VOID)213 CVfrCompiler::SetBaseFileName (
214   VOID
215   )
216 {
217   INT8          *pFileName, *pPath, *pExt;
218 
219   if (mOptions.VfrFileName[0] == '\0') {
220     return -1;
221   }
222 
223   pFileName = mOptions.VfrFileName;
224   while (
225     ((pPath = strchr (pFileName, '\\')) != NULL) ||
226     ((pPath = strchr (pFileName, '/')) != NULL)
227     )
228   {
229     pFileName = pPath + 1;
230   }
231 
232   if (pFileName == NULL) {
233     return -1;
234   }
235 
236   if ((pExt = strchr (pFileName, '.')) == NULL) {
237     return -1;
238   }
239 
240   strncpy (mOptions.VfrBaseFileName, pFileName, pExt - pFileName);
241   mOptions.VfrBaseFileName[pExt - pFileName] = '\0';
242 
243   return 0;
244 }
245 
246 INT8
SetPkgOutputFileName(VOID)247 CVfrCompiler::SetPkgOutputFileName (
248   VOID
249   )
250 {
251   if (mOptions.VfrBaseFileName[0] == '\0') {
252     return -1;
253   }
254 
255   strcpy (mOptions.PkgOutputFileName, mOptions.OutputDirectory);
256   strcat (mOptions.PkgOutputFileName, mOptions.VfrBaseFileName);
257   strcat (mOptions.PkgOutputFileName, VFR_PACKAGE_FILENAME_EXTENSION);
258 
259   return 0;
260 }
261 
262 INT8
SetCOutputFileName(VOID)263 CVfrCompiler::SetCOutputFileName (
264   VOID
265   )
266 {
267   if (mOptions.VfrBaseFileName[0] == '\0') {
268     return -1;
269   }
270 
271   strcpy (mOptions.COutputFileName, mOptions.OutputDirectory);
272   strcat (mOptions.COutputFileName, mOptions.VfrBaseFileName);
273   strcat (mOptions.COutputFileName, ".c");
274 
275   return 0;
276 }
277 
278 INT8
SetPreprocessorOutputFileName(VOID)279 CVfrCompiler::SetPreprocessorOutputFileName (
280   VOID
281   )
282 {
283   if (mOptions.VfrBaseFileName[0] == '\0') {
284     return -1;
285   }
286 
287   strcpy (mOptions.PreprocessorOutputFileName, mOptions.OutputDirectory);
288   strcat (mOptions.PreprocessorOutputFileName, mOptions.VfrBaseFileName);
289   strcat (mOptions.PreprocessorOutputFileName, VFR_PREPROCESS_FILENAME_EXTENSION);
290 
291   return 0;
292 }
293 
294 INT8
SetRecordListFileName(VOID)295 CVfrCompiler::SetRecordListFileName (
296   VOID
297   )
298 {
299   if (mOptions.VfrBaseFileName[0] == '\0') {
300     return -1;
301   }
302 
303   strcpy (mOptions.RecordListFile, mOptions.OutputDirectory);
304   strcat (mOptions.RecordListFile, mOptions.VfrBaseFileName);
305   strcat (mOptions.RecordListFile, VFR_RECORDLIST_FILENAME_EXTENSION);
306 
307   return 0;
308 }
309 
CVfrCompiler(IN INT32 Argc,IN INT8 ** Argv)310 CVfrCompiler::CVfrCompiler (
311   IN INT32      Argc,
312   IN INT8       **Argv
313   )
314 {
315   mPreProcessCmd = PREPROCESSOR_COMMAND;
316   mPreProcessOpt = PREPROCESSOR_OPTIONS;
317 
318   OptionInitialization(Argc, Argv);
319 
320   if ((IS_RUN_STATUS(STATUS_FAILED)) || (IS_RUN_STATUS(STATUS_DEAD))) {
321     return;
322   }
323 
324   SET_RUN_STATUS(STATUS_INITIALIZED);
325 }
326 
~CVfrCompiler(VOID)327 CVfrCompiler::~CVfrCompiler (
328   VOID
329   )
330 {
331   if (mOptions.IncludePaths != NULL) {
332     delete mOptions.IncludePaths;
333     mOptions.IncludePaths = NULL;
334   }
335 
336   if (mOptions.CPreprocessorOptions != NULL) {
337     delete mOptions.CPreprocessorOptions;
338     mOptions.CPreprocessorOptions = NULL;
339   }
340 
341   SET_RUN_STATUS(STATUS_DEAD);
342 }
343 
344 VOID
Usage(VOID)345 CVfrCompiler::Usage (
346   VOID
347   )
348 {
349   int          Index;
350   const char   *Str[] = {
351     UTILITY_NAME" "UTILITY_VERSION" - Intel UEFI VFR Compiler Utility",
352     "  Copyright (C), 2004 - 2008 Intel Corporation",
353 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
354     "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
355 #endif
356     "",
357     "Usage:",
358     "  "UTILITY_NAME" [OPTION] VFRFILE",
359     "Description:",
360     "  Compile VFRFILE.",
361     "Options:",
362     "  -? or -h        print this help",
363     "  -l              create an output IFR listing file",
364     "  -i IncPath      add IncPath to the search path for VFR included files",
365     "  -od OutputDir   deposit all output files to directory OutputDir (default=cwd)",
366     "  -ibin           create an IFR HII pack file",
367     "  -ppflag CFlags  pass Flags as C-preprocessor-flag",
368     "  -v or -version  print version information",
369     NULL
370   };
371 
372   for (Index = 0; Str[Index] != NULL; Index++) {
373     fprintf (stdout, "%s\n", Str[Index]);
374   }
375 }
376 
377 
378 VOID
PreProcess(VOID)379 CVfrCompiler::PreProcess (
380   VOID
381   )
382 {
383   FILE    *pVfrFile      = NULL;
384   UINT32  CmdLen         = 0;
385   INT8    *PreProcessCmd = NULL;
386 
387   if (!IS_RUN_STATUS(STATUS_INITIALIZED)) {
388     goto Fail;
389   }
390 
391   if (mOptions.SkipCPreprocessor == TRUE) {
392     goto Out;
393   }
394 
395   if ((pVfrFile = fopen (mOptions.VfrFileName, "r")) == NULL) {
396     printf ("%s could not open input VFR file - %s\n", UTILITY_NAME, mOptions.VfrFileName);
397     goto Fail;
398   }
399   fclose (pVfrFile);
400 
401   CmdLen = strlen (mPreProcessCmd) + strlen (mPreProcessOpt) +
402   	       strlen (mOptions.VfrFileName) + strlen (mOptions.PreprocessorOutputFileName);
403   if (mOptions.CPreprocessorOptions != NULL) {
404     CmdLen += strlen (mOptions.CPreprocessorOptions);
405   }
406   if (mOptions.IncludePaths != NULL) {
407     CmdLen += strlen (mOptions.IncludePaths);
408   }
409 
410   PreProcessCmd = new INT8[CmdLen + 10];
411   if (PreProcessCmd == NULL) {
412     printf ("%s could not allocate memory\n", UTILITY_NAME);
413     goto Fail;
414   }
415   strcpy (PreProcessCmd, mPreProcessCmd), strcat (PreProcessCmd, " ");
416   strcat (PreProcessCmd, mPreProcessOpt), strcat (PreProcessCmd, " ");
417   if (mOptions.IncludePaths != NULL) {
418     strcat (PreProcessCmd, mOptions.IncludePaths), strcat (PreProcessCmd, " ");
419   }
420   if (mOptions.CPreprocessorOptions != NULL) {
421     strcat (PreProcessCmd, mOptions.CPreprocessorOptions), strcat (PreProcessCmd, " ");
422   }
423   strcat (PreProcessCmd, mOptions.VfrFileName), strcat (PreProcessCmd, " > ");
424   strcat (PreProcessCmd, mOptions.PreprocessorOutputFileName);
425 
426   if (system (PreProcessCmd) != 0) {
427     printf ("%s failed to spawn C preprocessor on VFR file \n\t - %s\n", UTILITY_NAME, PreProcessCmd);
428     goto Fail;
429   }
430 
431   delete PreProcessCmd;
432 
433 Out:
434   SET_RUN_STATUS (STATUS_PREPROCESSED);
435   return;
436 
437 Fail:
438   if (!IS_RUN_STATUS(STATUS_DEAD)) {
439     SET_RUN_STATUS (STATUS_FAILED);
440   }
441   delete PreProcessCmd;
442 }
443 
444 extern UINT8 VfrParserStart (IN FILE *);
445 
446 VOID
Compile(VOID)447 CVfrCompiler::Compile (
448   VOID
449   )
450 {
451   FILE *pInFile    = NULL;
452   INT8 *InFileName = NULL;
453 
454   if (!IS_RUN_STATUS(STATUS_PREPROCESSED)) {
455     goto Fail;
456   }
457 
458   InFileName = (mOptions.SkipCPreprocessor == TRUE) ? mOptions.VfrFileName : mOptions.PreprocessorOutputFileName;
459 
460   gCVfrErrorHandle.SetInputFile (InFileName);
461 
462   if ((pInFile = fopen (InFileName, "r")) == NULL) {
463     printf ("%s failed to open input file - %s\n", UTILITY_NAME, InFileName);
464     goto Fail;
465   }
466 
467   if (VfrParserStart (pInFile) != 0) {
468     goto Fail;
469   }
470 
471   fclose (pInFile);
472 
473   if (gCFormPkg.HavePendingUnassigned () == TRUE) {
474     gCFormPkg.PendingAssignPrintAll ();
475     goto Fail;
476   }
477 
478   SET_RUN_STATUS (STATUS_COMPILEED);
479   return;
480 
481 Fail:
482   if (!IS_RUN_STATUS(STATUS_DEAD)) {
483     printf ("%s compile error!\n", UTILITY_NAME);
484     SET_RUN_STATUS (STATUS_FAILED);
485   }
486   if (pInFile != NULL) {
487     fclose (pInFile);
488   }
489 }
490 
491 VOID
GenBinary(VOID)492 CVfrCompiler::GenBinary (
493   VOID
494   )
495 {
496   FILE                    *pFile = NULL;
497 
498   if (!IS_RUN_STATUS(STATUS_COMPILEED)) {
499     goto Fail;
500   }
501 
502   if (mOptions.CreateIfrPkgFile == TRUE) {
503     if ((pFile = fopen (mOptions.PkgOutputFileName, "wb")) == NULL) {
504       printf ("can not open %s\n", mOptions.PkgOutputFileName);
505       goto Fail;
506     }
507     if (gCFormPkg.BuildPkg (pFile) != VFR_RETURN_SUCCESS) {
508       fclose (pFile);
509       goto Fail;
510     }
511     fclose (pFile);
512   }
513 
514   SET_RUN_STATUS (STATUS_GENBINARY);
515   return;
516 
517 Fail:
518   if (!IS_RUN_STATUS(STATUS_DEAD)) {
519     SET_RUN_STATUS (STATUS_FAILED);
520   }
521 }
522 
523 static const char *gSourceFileHeader[] = {
524   "//",
525   "//  DO NOT EDIT -- auto-generated file",
526   "//",
527   "//  This file is generated by the vfrcompiler utility",
528   "//",
529   NULL
530 };
531 
532 VOID
GenCFile(VOID)533 CVfrCompiler::GenCFile (
534   VOID
535   )
536 {
537   FILE                    *pFile;
538   UINT32                  Index;
539 
540   if (!IS_RUN_STATUS(STATUS_GENBINARY)) {
541     goto Fail;
542   }
543 
544   if ((pFile = fopen (mOptions.COutputFileName, "w")) == NULL) {
545     printf ("failed to open output C file - %s\n", mOptions.COutputFileName);
546     goto Fail;
547   }
548 
549   for (Index = 0; gSourceFileHeader[Index] != NULL; Index++) {
550     fprintf (pFile, "%s\n", gSourceFileHeader[Index]);
551   }
552 
553   gCVfrBufferConfig.OutputCFile (pFile, mOptions.VfrBaseFileName);
554 
555   if (gCFormPkg.GenCFile (mOptions.VfrBaseFileName, pFile) != VFR_RETURN_SUCCESS) {
556     fclose (pFile);
557     goto Fail;
558   }
559   fclose (pFile);
560 
561   SET_RUN_STATUS (STATUS_FINISHED);
562   return;
563 
564 Fail:
565   if (!IS_RUN_STATUS(STATUS_DEAD)) {
566     SET_RUN_STATUS (STATUS_FAILED);
567   }
568 }
569 
570 VOID
GenRecordListFile(VOID)571 CVfrCompiler::GenRecordListFile (
572   VOID
573   )
574 {
575   INT8   *InFileName = NULL;
576   FILE   *pInFile    = NULL;
577   FILE   *pOutFile   = NULL;
578   INT8   LineBuf[MAX_LINE_LEN];
579   UINT32 LineNo;
580 
581   InFileName = (mOptions.SkipCPreprocessor == TRUE) ? mOptions.VfrFileName : mOptions.PreprocessorOutputFileName;
582 
583   if (mOptions.CreateRecordListFile == TRUE) {
584     if ((InFileName[0] == '\0') || (mOptions.RecordListFile[0] == '\0')) {
585       return;
586     }
587 
588     if ((pInFile = fopen (InFileName, "r")) == NULL) {
589       printf ("%s failed to open input VFR preprocessor output file - %s\n", UTILITY_NAME, InFileName);
590       return;
591     }
592 
593     if ((pOutFile = fopen (mOptions.RecordListFile, "w")) == NULL) {
594       printf ("%s failed to open record list file for writing - %s\n", UTILITY_NAME, mOptions.RecordListFile);
595       goto Err1;
596     }
597 
598     fprintf (pOutFile, "//\n//  VFR compiler version " UTILITY_VERSION "\n//\n");
599     LineNo = 0;
600     while (!feof (pInFile)) {
601       if (fgets (LineBuf, MAX_LINE_LEN, pInFile) != NULL) {
602         fprintf (pOutFile, "%s", LineBuf);
603         LineNo++;
604         gCIfrRecordInfoDB.IfrRecordOutput (pOutFile, LineNo);
605       }
606     }
607 
608     fclose (pOutFile);
609     fclose (pInFile);
610   }
611 
612   return;
613 
614 Err1:
615   fclose (pInFile);
616 }
617 
618 INT32
main(IN INT32 Argc,IN INT8 ** Argv)619 main (
620   IN INT32             Argc,
621   IN INT8              **Argv
622   )
623 {
624   COMPILER_RUN_STATUS  Status;
625   CVfrCompiler         Compiler(Argc, Argv);
626 
627   Compiler.PreProcess();
628   Compiler.Compile();
629   Compiler.GenBinary();
630   Compiler.GenCFile();
631   Compiler.GenRecordListFile ();
632 
633   Status = Compiler.RunStatus ();
634   if ((Status == STATUS_DEAD) || (Status == STATUS_FAILED)) {
635     return 2;
636   }
637 
638   return 0;
639 }
640 
641