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