1 /*++
2 
3  Copyright (c) 2006 - 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 
13 Module Name:
14 
15   GenAprioriFile.c
16 
17 Abstract:
18 
19   Given an input file containing a list of GUIDs (or Guided file names),
20   convert the file to an Apriori file consumable by the dispatcher.
21 
22 --*/
23 
24 #include <stdio.h>
25 #include <string.h>
26 #include <ctype.h>
27 
28 #include "EfiCommon.h"
29 #include "ParseInf.h"
30 #include "CommonLib.h"  // for compare guid
31 #include "EfiUtilityMsgs.h"
32 
33 #define MAX_LINE_LEN  200
34 #define MAX_PATH      200
35 
36 //
37 // typedef unsigned int          STATUS;
38 // #define STATUS_SUCCESS        0
39 // #define STATUS_WARNING        1
40 // #define STATUS_ERROR          2
41 //
42 #define UTILITY_NAME    "GenAprioriFile"
43 #define UTILITY_VERSION "v1.0"
44 //
45 // Here's all our globals.
46 //
47 static struct {
48   FILE    *BinFptr; // output dependencies to this file
49   INT8    *AprioriFileName;
50   INT8    *OutputFileName;
51   BOOLEAN Intelligent;
52   BOOLEAN Verbose;
53   BOOLEAN NullTerminate;
54 } mGlobals;
55 
56 static
57 STATUS
58 ProcessArgs (
59   int   Argc,
60   char  *Argv[]
61   );
62 
63 static
64 BOOLEAN
65 IsCommentLine (
66   INT8    *Line
67   );
68 
69 static
70 void
71 Usage (
72   VOID
73   );
74 
75 int
main(int Argc,char * Argv[])76 main (
77   int   Argc,
78   char  *Argv[]
79   )
80 /*++
81 
82 Routine Description:
83 
84   Call the routine to parse the command-line options, then process the
85   Apriori list file and generate the GUID file.
86 
87 Arguments:
88 
89   Standard C main() argc and argv.
90 
91 Returns:
92 
93   0       if successful
94   nonzero otherwise
95 
96 --*/
97 // GC_TODO:    Argc - add argument and description to function comment
98 // GC_TODO:    ] - add argument and description to function comment
99 {
100   STATUS    Status;
101   FILE      *AprioriFptr;
102   FILE      *BinFptr;
103   INT8      Line[MAX_LINE_LEN];
104   EFI_GUID  Guid;
105   EFI_GUID  GuidIn;
106   EFI_GUID  ZeroGuid;
107   UINT32    LineCounter;
108   //
109   // Initialize the error printing routines
110   //
111   SetUtilityName (UTILITY_NAME);
112   //
113   // Clear our globals
114   //
115   memset ((char *) &mGlobals, 0, sizeof (mGlobals));
116   memset ((char *) &ZeroGuid, 0, sizeof (ZeroGuid));
117   AprioriFptr = NULL;
118   BinFptr     = NULL;
119 
120   //
121   // Process the command-line arguments
122   //
123   Status = ProcessArgs (Argc, Argv);
124   if (Status != STATUS_SUCCESS) {
125     return Status;
126   }
127   //
128   // If arguments were ok, then open the Apriori file and process it.
129   //
130   if ((AprioriFptr = fopen (mGlobals.AprioriFileName, "r")) == NULL) {
131     Error (NULL, 0, 0, mGlobals.AprioriFileName, "failed to open file for reading");
132     goto FinishUp;
133   }
134   //
135   // If -i intelligent option specified, then attempt to read and
136   // existing output file and see if we'd be creating an identical file.
137   //
138   if (mGlobals.Intelligent) {
139     if ((BinFptr = fopen (mGlobals.OutputFileName, "rb")) == NULL) {
140       if (mGlobals.Verbose) {
141         DebugMsg (NULL, 0, 0, "Creating new apriori file -- no existing file", NULL);
142       }
143 
144       goto CreateFile;
145     }
146     //
147     // Read lines from the input file until done. Convert each to a guid, then
148     // read a guid from the input file and compare them.
149     //
150     while (fgets (Line, sizeof (Line), AprioriFptr) != NULL) {
151 
152       if (IsCommentLine (Line)) {
153         continue;
154       }
155       //
156       // Convert to a guid
157       //
158       if (StringToGuid (Line, &Guid) != EFI_SUCCESS) {
159         if (mGlobals.Verbose) {
160           DebugMsg (NULL, 0, 0, "failed to read GUID from input text file -- creating new file", NULL);
161         }
162 
163         goto CreateFile;
164       }
165       //
166       // Read guid from input file, then compare
167       //
168       if (fread (&GuidIn, sizeof (GuidIn), 1, BinFptr) != 1) {
169         if (mGlobals.Verbose) {
170           DebugMsg (NULL, 0, 0, "failed to read GUID from input binary file -- creating new file", NULL);
171         }
172 
173         goto CreateFile;
174       }
175 
176       if (CompareGuid (&Guid, &GuidIn) != 0) {
177         if (mGlobals.Verbose) {
178           DebugMsg (NULL, 0, 0, "GUID comparison failed -- creating new file", NULL);
179         }
180 
181         goto CreateFile;
182       }
183     }
184     //
185     // May be one more NULL guid in the binary file
186     //
187     if (mGlobals.NullTerminate) {
188       if (fread (&GuidIn, sizeof (GuidIn), 1, BinFptr) != 1) {
189         if (mGlobals.Verbose) {
190           DebugMsg (NULL, 0, 0, "failed to read NULL GUID from input binary file -- creating new file", NULL);
191         }
192 
193         goto CreateFile;
194       }
195 
196       if (CompareGuid (&GuidIn, &ZeroGuid) != 0) {
197         if (mGlobals.Verbose) {
198           DebugMsg (NULL, 0, 0, "NULL GUID comparison failed -- creating new file", NULL);
199         }
200 
201         goto CreateFile;
202       }
203     }
204     //
205     // Make sure we're at the end of both files.
206     //
207     if ((fgets (Line, sizeof (Line), AprioriFptr) != NULL) || (fread (&GuidIn, 1, 1, BinFptr) != 0)) {
208       if (mGlobals.Verbose) {
209         DebugMsg (NULL, 0, 0, "file sizes different, -i test failed -- creating new file", NULL);
210       }
211 
212       goto CreateFile;
213     }
214 
215     if (mGlobals.Verbose) {
216       DebugMsg (NULL, 0, 0, "existing file would be unchanged -- keeping existing apriori file", NULL);
217     }
218 
219     goto FinishUp;
220   }
221 
222 CreateFile:
223   //
224   // Rewind the Apriori file in case -i was specified. Also
225   // try to close the output file for the case where we prescanned
226   // it (again, because of -i).
227   //
228   rewind (AprioriFptr);
229   if (BinFptr != NULL) {
230     fclose (BinFptr);
231   }
232   //
233   // Open the output file
234   //
235   if ((BinFptr = fopen (mGlobals.OutputFileName, "wb")) == NULL) {
236     Error (NULL, 0, 0, mGlobals.OutputFileName, "could not open input file");
237     goto FinishUp;
238   }
239   //
240   // Read lines until we're done
241   //
242   LineCounter = 0;
243   while (fgets (Line, sizeof (Line), AprioriFptr) != NULL) {
244     LineCounter++;
245     if (IsCommentLine (Line)) {
246       continue;
247     }
248     //
249     // Convert to a GUID
250     //
251     if (StringToGuid (Line, &Guid) != EFI_SUCCESS) {
252       Error (mGlobals.AprioriFileName, LineCounter, 0, "failed to convert GUID", NULL);
253       goto FinishUp;
254     }
255     //
256     // Write the guid to the output file
257     //
258     if (fwrite (&Guid, sizeof (Guid), 1, BinFptr) != 1) {
259       Error (NULL, 0, 0, mGlobals.OutputFileName, "failed to write GUID to output file");
260       goto FinishUp;
261     }
262   }
263   //
264   // Write a null guid out to terminate the list
265   //
266   if (mGlobals.NullTerminate) {
267     memset ((void *) &Guid, 0, sizeof (Guid));
268     if (fwrite (&Guid, sizeof (Guid), 1, BinFptr) != 1) {
269       Error (NULL, 0, 0, mGlobals.OutputFileName, "failed to write NULL termination GUID to output file");
270     }
271   }
272 
273 FinishUp:
274 
275   if (AprioriFptr != NULL) {
276     fclose (AprioriFptr);
277   }
278 
279   if (BinFptr != NULL) {
280     fclose (BinFptr);
281   }
282 
283   return GetUtilityStatus ();
284 }
285 
286 static
287 BOOLEAN
IsCommentLine(INT8 * Line)288 IsCommentLine (
289   INT8    *Line
290   )
291 /*++
292 
293 Routine Description:
294 
295   GC_TODO: Add function description
296 
297 Arguments:
298 
299   Line  - GC_TODO: add argument description
300 
301 Returns:
302 
303   GC_TODO: add return values
304 
305 --*/
306 {
307   for (; isspace (*Line) && *Line; Line++)
308     ;
309 
310   //
311   // Allow # or // comments
312   //
313   if ((*Line == '#') || ((*Line == '/') && (*(Line + 1) == '/')) || (*Line == '\n') || (*Line == 0)) {
314     return TRUE;
315   }
316 
317   return FALSE;
318 }
319 //
320 // Process the command-line arguments
321 //
322 static
323 STATUS
ProcessArgs(int Argc,char * Argv[])324 ProcessArgs (
325   int   Argc,
326   char  *Argv[]
327   )
328 /*++
329 
330 Routine Description:
331 
332   GC_TODO: Add function description
333 
334 Arguments:
335 
336   Argc  - GC_TODO: add argument description
337   ]     - GC_TODO: add argument description
338 
339 Returns:
340 
341   GC_TODO: add return values
342 
343 --*/
344 {
345   //
346   // Skip program name
347   //
348   Argc--;
349   Argv++;
350 
351   //
352   // Process until no more args
353   //
354   while (Argc) {
355     //
356     // -f AprioriFile
357     //
358     if (_stricmp (Argv[0], "-f") == 0) {
359       //
360       // check for one more arg
361       //
362       if (Argc > 1) {
363         mGlobals.AprioriFileName = Argv[1];
364       } else {
365         Error (NULL, 0, 0, NULL, "missing filename with %s", Argv[0]);
366         Usage ();
367         return STATUS_ERROR;
368       }
369 
370       Argc--;
371       Argv++;
372     } else if (_stricmp (Argv[0], "-i") == 0) {
373       //
374       // intelligent creation of output file. That is to say, if
375       // there's already a file there, and it's the same as what
376       // we'd create, then don't re-create. This is to support
377       // incremental builds (that is to say, running nmake a second time
378       // does nothing).
379       //
380       mGlobals.Intelligent = TRUE;
381     } else if (_stricmp (Argv[0], "-v") == 0) {
382       mGlobals.Verbose = TRUE;
383     } else if (_stricmp (Argv[0], "-null") == 0) {
384       mGlobals.NullTerminate = TRUE;
385     } else if (_stricmp (Argv[0], "-o") == 0) {
386       //
387       // -o OutputFileName
388       // check for one more arg
389       //
390       if (Argc > 1) {
391         mGlobals.OutputFileName = Argv[1];
392       } else {
393         Error (NULL, 0, 0, NULL, "missing filename argument with %s", Argv[0]);
394         Usage ();
395         return STATUS_ERROR;
396       }
397 
398       Argc--;
399       Argv++;
400     } else if ((_stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {
401       Usage ();
402       return STATUS_ERROR;
403     } else {
404       Error (NULL, 0, 0, Argv[0], "unrecognized option");
405       Usage ();
406       return STATUS_ERROR;
407     }
408 
409     Argc--;
410     Argv++;
411   }
412   //
413   // Had to specify the apriori input file and output file names
414   //
415   if (mGlobals.AprioriFileName == NULL) {
416     Error (NULL, 0, 0, "must specify -f AprioriFile", NULL);
417     Usage ();
418     return STATUS_ERROR;
419   }
420 
421   if (mGlobals.OutputFileName == NULL) {
422     Error (NULL, 0, 0, "must specify -o OutputFile", NULL);
423     Usage ();
424     return STATUS_ERROR;
425   }
426 
427   return STATUS_SUCCESS;
428 }
429 
430 static
431 void
Usage(VOID)432 Usage (
433   VOID
434   )
435 /*++
436 
437 Routine Description:
438 
439   Print usage information for this utility.
440 
441 Arguments:
442 
443   None.
444 
445 Returns:
446 
447   Nothing.
448 
449 --*/
450 {
451   int        Index;
452   const char *Str[] = {
453     UTILITY_NAME" "UTILITY_VERSION" - Intel Generate Apriori File Utility",
454     "  Copyright (C), 2006 - 2008 Intel Corporation",
455 
456 #if ( defined(UTILITY_BUILD) && defined(UTILITY_VENDOR) )
457     "  Built from "UTILITY_BUILD", project of "UTILITY_VENDOR,
458 #endif
459     "",
460     "Usage:",
461     "  "UTILITY_NAME" [OPTION]...",
462     "Description:",
463     "  Generate an Apriori file consumable by the DXE or PEI dispatcher.",
464     "Options:",
465     "  -h or -?         for this help information",
466     "  -f AprioriFile   parse the GUID'ed files in AprioriFile (required)",
467     "  -o OutputFile    write output to OutputFile (required)",
468     "  -i               for intelligent re-creation of OutputFile",
469     "  -null            to terminate the output file with a NULL GUID",
470     "  -v               verbose option",
471     NULL
472   };
473   for (Index = 0; Str[Index] != NULL; Index++) {
474     fprintf (stdout, "%s\n", Str[Index]);
475   }
476 }
477