1/*++ 2 3Copyright (c) 2004 - 2007, Intel Corporation. All rights reserved.<BR> 4This program and the accompanying materials 5are licensed and made available under the terms and conditions of the BSD License 6which accompanies this distribution. The full text of the license may be found at 7http://opensource.org/licenses/bsd-license.php 8 9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 10WITHOUT 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 38static 39void 40DSCFileFree ( 41 DSC_FILE *DSC 42 ); 43 44static 45STATUS 46DSCParseInclude ( 47 DSC_FILE *DSC, 48 char *FileName, 49 int NestLevel 50 ); 51 52// 53// Constructor for a DSC file 54// 55int 56DSCFileInit ( 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// 67int 68DSCFileDestroy ( 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// 79char * 80DSCFileGetLine ( 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 113int 114DSCFileSetFile ( 115 DSC_FILE *DSC, 116 char *FileName 117 ) 118/*++ 119 120Routine 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 125Arguments: 126 127 DSC - pointer to a DSC structure (this pointer) 128 FileName - name of the file to process 129 130Returns: 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 145static 146STATUS 147DSCParseInclude ( 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 433Done: 434 fclose (FilePtr); 435 return Status; 436} 437// 438// Free up memory allocated for DSC file handling. 439// 440static 441void 442DSCFileFree ( 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 475SECTION * 476DSCFileFindSection ( 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 502int 503DSCFileSavePosition ( 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 521int 522DSCFileRestorePosition ( 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