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 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 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 * 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 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 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 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 * 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 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 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