1 /*++
2 
3 Copyright (c) 2004 - 2007, 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     DscFile.c
15 
16   Abstract:
17 
18     This module is used to process description files at a high level. For the
19     most part, it pre-parses the file to find and save off positions of all
20     the sections ([section.subsection.subsection]) in a linked list, then
21     provides services to find the sections by name, and read the lines from
22     the section until you run into the next section.
23 
24   NOTE: DSC file is synonomous with section file. A DSC file is simply a file
25     containing bracketed section names [section.subsection.subsection...]
26 
27 --*/
28 
29 #include <stdio.h>  // for file ops
30 #include <string.h>
31 #include <ctype.h>
32 #include <stdlib.h> // for malloc
33 #include "Common.h"
34 #include "DSCFile.h"
35 
36 #define MAX_INCLUDE_NEST_LEVEL  20
37 
38 static
39 void
40 DSCFileFree (
41   DSC_FILE *DSC
42   );
43 
44 static
45 STATUS
46 DSCParseInclude (
47   DSC_FILE  *DSC,
48   char      *FileName,
49   int       NestLevel
50   );
51 
52 //
53 // Constructor for a DSC file
54 //
55 int
DSCFileInit(DSC_FILE * DSC)56 DSCFileInit (
57   DSC_FILE *DSC
58   )
59 {
60   memset ((char *) DSC, 0, sizeof (DSC_FILE));
61   DSC->SavedPositionIndex = -1;
62   return STATUS_SUCCESS;
63 }
64 //
65 // Destructor for a DSC file
66 //
67 int
DSCFileDestroy(DSC_FILE * DSC)68 DSCFileDestroy (
69   DSC_FILE *DSC
70   )
71 {
72   DSC->SavedPositionIndex = -1;
73   DSCFileFree (DSC);
74   return STATUS_SUCCESS;
75 }
76 //
77 // Get the next line from a DSC file.
78 //
79 char *
DSCFileGetLine(DSC_FILE * DSC,char * Line,int LineLen)80 DSCFileGetLine (
81   DSC_FILE  *DSC,
82   char      *Line,
83   int       LineLen
84   )
85 {
86   char  *Cptr;
87 
88   if (DSC->CurrentLine == NULL) {
89     return NULL;
90   }
91   //
92   // Check for running into next section
93   //
94   if (DSC->CurrentLine->Line[0] == '[') {
95     return NULL;
96   }
97   //
98   // Allow special case where the line starts with backslash-bracket. If we
99   // see this, then shift everything left one character.
100   //
101   if ((DSC->CurrentLine->Line[0] == '\\') && (DSC->CurrentLine->Line[1] == '[')) {
102     Cptr = DSC->CurrentLine->Line + 1;
103   } else {
104     Cptr = DSC->CurrentLine->Line;
105   }
106 
107   strncpy (Line, Cptr, LineLen);
108   ParserSetPosition (DSC->CurrentLine->FileName, DSC->CurrentLine->LineNum);
109   DSC->CurrentLine = DSC->CurrentLine->Next;
110   return Line;
111 }
112 
113 int
DSCFileSetFile(DSC_FILE * DSC,char * FileName)114 DSCFileSetFile (
115   DSC_FILE  *DSC,
116   char      *FileName
117   )
118 /*++
119 
120 Routine Description:
121 
122   Pre-scan a section file to find all the sections. Then we can speed up
123   searching for the different sections.
124 
125 Arguments:
126 
127   DSC       - pointer to a DSC structure (this pointer)
128   FileName  - name of the file to process
129 
130 Returns:
131 
132   STATUS_SUCCESS if everything went well.
133 
134 --*/
135 {
136   STATUS  Status;
137 
138   //
139   // Called to open a new sectioned file.
140   //
141   Status = DSCParseInclude (DSC, FileName, 1);
142   return Status;
143 }
144 
145 static
146 STATUS
DSCParseInclude(DSC_FILE * DSC,char * FileName,int NestLevel)147 DSCParseInclude (
148   DSC_FILE    *DSC,
149   char        *FileName,
150   int         NestLevel
151   )
152 {
153   SECTION       *NewSect;
154   SECTION_LINE  *NewLine;
155   DSC_FILE_NAME *NewDscFileName;
156   char          Line[MAX_LINE_LEN];
157   char          *Start;
158   char          *End;
159   char          SaveChar;
160   char          *TempCptr;
161   char          ShortHandSectionName[MAX_LINE_LEN];
162   char          ThisSectionName[MAX_LINE_LEN];
163   SECTION       *CurrSect;
164   SECTION       *TempSect;
165   FILE          *FilePtr;
166   STATUS        Status;
167   UINT32        LineNum;
168 
169   //
170   // Make sure we haven't exceeded our maximum nesting level
171   //
172   if (NestLevel > MAX_INCLUDE_NEST_LEVEL) {
173     Error (NULL, 0, 0, "application error", "maximum !include nesting level exceeded");
174     return STATUS_ERROR;
175   }
176   //
177   // Try to open the file
178   //
179   if ((FilePtr = fopen (FileName, "r")) == NULL) {
180     //
181     // This function is called to handle the DSC file from the command line too,
182     // so differentiate whether this file is an include file or the main file
183     // by examining the nest level.
184     //
185     if (NestLevel == 1) {
186       Error (NULL, 0, 0, FileName, "could not open DSC file for reading");
187     } else {
188       Error (NULL, 0, 0, FileName, "could not open !include DSC file for reading");
189     }
190 
191     return STATUS_ERROR;
192   }
193   //
194   // We keep a linked list of files we parse for error reporting purposes.
195   //
196   NewDscFileName = malloc (sizeof (DSC_FILE_NAME));
197   if (NewDscFileName == NULL) {
198     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
199     return STATUS_ERROR;
200   }
201 
202   memset (NewDscFileName, 0, sizeof (DSC_FILE_NAME));
203   NewDscFileName->FileName = (INT8 *) malloc (strlen (FileName) + 1);
204   if (NewDscFileName->FileName == NULL) {
205     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
206     return STATUS_ERROR;
207   }
208 
209   strcpy (NewDscFileName->FileName, FileName);
210   if (DSC->FileName == NULL) {
211     DSC->FileName = NewDscFileName;
212   } else {
213     DSC->LastFileName->Next = NewDscFileName;
214   }
215 
216   DSC->LastFileName = NewDscFileName;
217   //
218   // Read lines and process until done
219   //
220   Status  = STATUS_SUCCESS;
221   LineNum = 0;
222   for (;;) {
223     if (fgets (Line, sizeof (Line), FilePtr) == NULL) {
224       break;
225     }
226 
227     LineNum++;
228     ParserSetPosition (FileName, LineNum);
229     //
230     // Add the line to our list if it's not a !include line
231     //
232     if ((strncmp (Line, "!include", 8) == 0) && (isspace (Line[8]))) {
233       Start = Line + 9;
234       while (*Start && (*Start != '"')) {
235         Start++;
236       }
237 
238       if (*Start != '"') {
239         Error (FileName, LineNum, 0, NULL, "invalid format for !include");
240         Status = STATUS_ERROR;
241         goto Done;
242       }
243 
244       Start++;
245       for (End = Start; *End && (*End != '"'); End++)
246         ;
247       if (*End != '"') {
248         Error (FileName, LineNum, 0, NULL, "invalid format for !include");
249         Status = STATUS_ERROR;
250         goto Done;
251       }
252 
253       *End = 0;
254       //
255       // Expand symbols. Use 'ThisSectionName' as scratchpad
256       //
257       ExpandSymbols (Start, ThisSectionName, sizeof (ThisSectionName), EXPANDMODE_NO_UNDEFS);
258       Status = DSCParseInclude (DSC, ThisSectionName, NestLevel + 1);
259       if (Status != STATUS_SUCCESS) {
260         Error (FileName, LineNum, 0, NULL, "failed to parse !include file");
261         goto Done;
262       }
263     } else {
264       NewLine = (SECTION_LINE *) malloc (sizeof (SECTION_LINE));
265       if (NewLine == NULL) {
266         Error (NULL, 0, 0, NULL, "failed to allocate memory");
267         Status = STATUS_ERROR;
268         goto Done;
269       }
270 
271       memset ((char *) NewLine, 0, sizeof (SECTION_LINE));
272       NewLine->LineNum  = LineNum;
273       NewLine->FileName = NewDscFileName->FileName;
274       NewLine->Line     = (char *) malloc (strlen (Line) + 1);
275       if (NewLine->Line == NULL) {
276         Error (NULL, 0, 0, NULL, "failed to allocate memory");
277         Status = STATUS_ERROR;
278         goto Done;
279       }
280 
281       strcpy (NewLine->Line, Line);
282       if (DSC->Lines == NULL) {
283         DSC->Lines = NewLine;
284       } else {
285         DSC->LastLine->Next = NewLine;
286       }
287 
288       DSC->LastLine = NewLine;
289       //
290       // Parse the line for []. Ignore [] and [----] delimiters. The
291       // line may have multiple definitions separated by commas, so
292       // take each separately
293       //
294       Start = Line;
295       if ((Line[0] == '[') && ((Line[1] != ']') && (Line[1] != '-'))) {
296         //
297         // Skip over open bracket and preceeding spaces
298         //
299         Start++;
300         ShortHandSectionName[0] = 0;
301 
302         while (*Start && (*Start != ']')) {
303           while (isspace (*Start)) {
304             Start++;
305           }
306           //
307           // Hack off closing bracket or trailing spaces or comma separator.
308           // Also allow things like [section.subsection1|subsection2], which
309           // is shorthand for [section.subsection1,section.subsection2]
310           //
311           End = Start;
312           while (*End && (*End != ']') && !isspace (*End) && (*End != ',') && (*End != '|')) {
313             End++;
314           }
315           //
316           // Save the character and null-terminate the string
317           //
318           SaveChar  = *End;
319           *End      = 0;
320           //
321           // Now allocate space for a new section and add it to the linked list.
322           // If the previous section ended with the shorthand indicator, then
323           // the section name was saved off. Append this section name to it.
324           //
325           strcpy (ThisSectionName, ShortHandSectionName);
326           if (*Start == '.') {
327             strcat (ThisSectionName, Start + 1);
328           } else {
329             strcat (ThisSectionName, Start);
330           }
331           //
332           // Allocate memory for the section. Then clear it out.
333           //
334           NewSect = (SECTION *) malloc (sizeof (SECTION));
335           if (NewSect == NULL) {
336             Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");
337             Status = STATUS_ERROR;
338             goto Done;
339           }
340 
341           memset ((char *) NewSect, 0, sizeof (SECTION));
342           NewSect->FirstLine  = NewLine;
343           NewSect->Name       = (char *) malloc (strlen (ThisSectionName) + 1);
344           if (NewSect->Name == NULL) {
345             Error (NULL, 0, 0, NULL, "failed to allocation memory for sections");
346             Status = STATUS_ERROR;
347             goto Done;
348           }
349 
350           strcpy (NewSect->Name, ThisSectionName);
351           if (DSC->Sections == NULL) {
352             DSC->Sections = NewSect;
353           } else {
354             DSC->LastSection->Next = NewSect;
355           }
356 
357           DSC->LastSection  = NewSect;
358           *End              = SaveChar;
359           //
360           // If the name ended in a shorthand indicator, then save the
361           // section name and truncate it at the last dot.
362           //
363           if (SaveChar == '|') {
364             strcpy (ShortHandSectionName, ThisSectionName);
365             for (TempCptr = ShortHandSectionName + strlen (ShortHandSectionName) - 1;
366                  (TempCptr != ShortHandSectionName) && (*TempCptr != '.');
367                  TempCptr--
368                 )
369               ;
370             //
371             // If we didn't find a dot, then hopefully they have [name1|name2]
372             // instead of [name1,name2].
373             //
374             if (TempCptr == ShortHandSectionName) {
375               ShortHandSectionName[0] = 0;
376             } else {
377               //
378               // Truncate after the dot
379               //
380               *(TempCptr + 1) = 0;
381             }
382           } else {
383             //
384             // Kill the shorthand string
385             //
386             ShortHandSectionName[0] = 0;
387           }
388           //
389           // Skip to next section name or closing bracket
390           //
391           while (*End && ((*End == ',') || isspace (*End) || (*End == '|'))) {
392             End++;
393           }
394 
395           Start = End;
396         }
397       }
398     }
399   }
400   //
401   // Look through all the sections to make sure we don't have any duplicates.
402   // Allow [----] and [====] section separators
403   //
404   CurrSect = DSC->Sections;
405   while (CurrSect != NULL) {
406     TempSect = CurrSect->Next;
407     while (TempSect != NULL) {
408       if (isalpha (CurrSect->Name[0]) && (_stricmp (CurrSect->Name, TempSect->Name) == 0)) {
409         Error (
410           TempSect->FirstLine->FileName,
411           TempSect->FirstLine->LineNum,
412           0,
413           TempSect->Name,
414           "duplicate section found"
415           );
416         Error (
417           CurrSect->FirstLine->FileName,
418           CurrSect->FirstLine->LineNum,
419           0,
420           TempSect->Name,
421           "first definition of duplicate section"
422           );
423         Status = STATUS_ERROR;
424         goto Done;
425       }
426 
427       TempSect = TempSect->Next;
428     }
429 
430     CurrSect = CurrSect->Next;
431   }
432 
433 Done:
434   fclose (FilePtr);
435   return Status;
436 }
437 //
438 // Free up memory allocated for DSC file handling.
439 //
440 static
441 void
DSCFileFree(DSC_FILE * DSC)442 DSCFileFree (
443   DSC_FILE *DSC
444   )
445 {
446   SECTION       *NextSection;
447   SECTION_LINE  *NextLine;
448   DSC_FILE_NAME *NextName;
449 
450   while (DSC->Sections != NULL) {
451     NextSection = DSC->Sections->Next;
452     if (DSC->Sections->Name != NULL) {
453       free (DSC->Sections->Name);
454     }
455 
456     free (DSC->Sections);
457     DSC->Sections = NextSection;
458   }
459 
460   while (DSC->Lines != NULL) {
461     NextLine = DSC->Lines->Next;
462     free (DSC->Lines->Line);
463     free (DSC->Lines);
464     DSC->Lines = NextLine;
465   }
466 
467   while (DSC->FileName != NULL) {
468     NextName = DSC->FileName->Next;
469     free (DSC->FileName->FileName);
470     free (DSC->FileName);
471     DSC->FileName = NextName;
472   }
473 }
474 
475 SECTION *
DSCFileFindSection(DSC_FILE * DSC,char * Name)476 DSCFileFindSection (
477   DSC_FILE  *DSC,
478   char      *Name
479   )
480 {
481   SECTION *Sect;
482 
483   //
484   // Look through all the sections to find one with this name (case insensitive)
485   //
486   Sect = DSC->Sections;
487   while (Sect != NULL) {
488     if (_stricmp (Name, Sect->Name) == 0) {
489       //
490       // Position within file
491       //
492       DSC->CurrentLine = Sect->FirstLine->Next;
493       return Sect;
494     }
495 
496     Sect = Sect->Next;
497   }
498 
499   return NULL;
500 }
501 
502 int
DSCFileSavePosition(DSC_FILE * DSC)503 DSCFileSavePosition (
504   DSC_FILE *DSC
505   )
506 {
507   //
508   // Advance to next slot
509   //
510   DSC->SavedPositionIndex++;
511   if (DSC->SavedPositionIndex >= MAX_SAVES) {
512     DSC->SavedPositionIndex--;
513     Error (NULL, 0, 0, "APP ERROR", "max nesting of saved section file positions exceeded");
514     return STATUS_ERROR;
515   }
516 
517   DSC->SavedPosition[DSC->SavedPositionIndex] = DSC->CurrentLine;
518   return STATUS_SUCCESS;
519 }
520 
521 int
DSCFileRestorePosition(DSC_FILE * DSC)522 DSCFileRestorePosition (
523   DSC_FILE *DSC
524   )
525 {
526   if (DSC->SavedPositionIndex < 0) {
527     Error (NULL, 0, 0, "APP ERROR", "underflow of saved positions in section file");
528     return STATUS_ERROR;
529   }
530 
531   DSC->CurrentLine = DSC->SavedPosition[DSC->SavedPositionIndex];
532   DSC->SavedPositionIndex--;
533   return STATUS_SUCCESS;
534 }
535