1 /****************************************************************************** 2 * 3 * Module Name: prutils - Preprocessor utilities 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44 #include <contrib/dev/acpica/compiler/aslcompiler.h> 45 #include <contrib/dev/acpica/compiler/dtcompiler.h> 46 47 48 #define _COMPONENT ASL_PREPROCESSOR 49 ACPI_MODULE_NAME ("prutils") 50 51 52 /******************************************************************************* 53 * 54 * FUNCTION: PrSetLineNumber 55 * 56 * PARAMETERS: OriginalLineNumber - Line number in original source file, 57 * or include file 58 * PreprocessorLineNumber - Line number in the preprocessed file 59 * 60 * RETURN: None 61 * 62 * DESCRIPTION: Insert this mapping into the mapping data structure, for use 63 * in possible error/warning messages. 64 * 65 * Line number mapping functions. 66 * For error messages, we need to keep track of the line number in the 67 * original file, versus the preprocessed (.i) file. 68 * 69 ******************************************************************************/ 70 71 void 72 PrSetLineNumber ( 73 UINT32 OriginalLineNumber, 74 UINT32 PreprocessorLineNumber) 75 { 76 UINT32 Entry; 77 PR_LINE_MAPPING *Block; 78 UINT32 Index; 79 UINT32 i; 80 81 82 Entry = PreprocessorLineNumber / PR_LINES_PER_BLOCK; 83 Index = PreprocessorLineNumber % PR_LINES_PER_BLOCK; 84 Block = Gbl_MapBlockHead; 85 86 for (i = 0; i < Entry; i++) 87 { 88 /* Allocate new mapping blocks as necessary */ 89 90 if (!Block->Next) 91 { 92 Block->Next = UtLocalCalloc (sizeof (PR_LINE_MAPPING)); 93 Block->Next->Map = UtLocalCalloc (PR_LINES_PER_BLOCK * sizeof (UINT32)); 94 } 95 96 Block = Block->Next; 97 } 98 99 Block->Map[Index] = OriginalLineNumber; 100 } 101 102 103 /******************************************************************************* 104 * 105 * FUNCTION: PrGetLineNumber 106 * 107 * PARAMETERS: PreprocessorLineNumber - Line number in the preprocessed file 108 * (or, the "logical line number) 109 * 110 * RETURN: The line number in the original source file or include file. 111 * 112 * DESCRIPTION: Return the mapped value of a line number in the preprocessed 113 * source file to the actual line number in the original source 114 * file. 115 * 116 ******************************************************************************/ 117 118 UINT32 119 PrGetLineNumber ( 120 UINT32 PreprocessorLineNumber) 121 { 122 UINT32 Entry; 123 PR_LINE_MAPPING *Block; 124 UINT32 Index; 125 UINT32 i; 126 127 128 Entry = PreprocessorLineNumber / PR_LINES_PER_BLOCK; 129 Index = PreprocessorLineNumber % PR_LINES_PER_BLOCK; 130 Block = Gbl_MapBlockHead; 131 132 for (i = 0; i < Entry; i++) 133 { 134 Block = Block->Next; 135 if (!Block) 136 { 137 /* Bad error, should not happen */ 138 return (0); 139 } 140 } 141 142 return (Block->Map[Index]); 143 } 144 145 146 /****************************************************************************** 147 * 148 * FUNCTION: PrGetNextToken 149 * 150 * PARAMETERS: Buffer - Current line buffer 151 * MatchString - String with valid token delimiters 152 * Next - Set to next possible token in buffer 153 * 154 * RETURN: Next token (null-terminated). Modifies the input line. 155 * Remainder of line is stored in *Next. 156 * 157 * DESCRIPTION: Local implementation of strtok() with local storage for the 158 * next pointer. Not only thread-safe, but allows multiple 159 * parsing of substrings such as expressions. 160 * 161 *****************************************************************************/ 162 163 char * 164 PrGetNextToken ( 165 char *Buffer, 166 char *MatchString, 167 char **Next) 168 { 169 char *TokenStart; 170 171 172 if (!Buffer) 173 { 174 /* Use Next if it is valid */ 175 176 Buffer = *Next; 177 if (!(*Next)) 178 { 179 return (NULL); 180 } 181 } 182 183 /* Skip any leading delimiters */ 184 185 while (*Buffer) 186 { 187 if (strchr (MatchString, *Buffer)) 188 { 189 Buffer++; 190 } 191 else 192 { 193 break; 194 } 195 } 196 197 /* Anything left on the line? */ 198 199 if (!(*Buffer)) 200 { 201 *Next = NULL; 202 return (NULL); 203 } 204 205 TokenStart = Buffer; 206 207 /* Find the end of this token */ 208 209 while (*Buffer) 210 { 211 if (strchr (MatchString, *Buffer)) 212 { 213 *Buffer = 0; 214 *Next = Buffer+1; 215 if (!**Next) 216 { 217 *Next = NULL; 218 } 219 return (TokenStart); 220 } 221 Buffer++; 222 } 223 224 *Next = NULL; 225 return (TokenStart); 226 } 227 228 229 /******************************************************************************* 230 * 231 * FUNCTION: PrError 232 * 233 * PARAMETERS: Level - Seriousness (Warning/error, etc.) 234 * MessageId - Index into global message buffer 235 * Column - Column in current line 236 * 237 * RETURN: None 238 * 239 * DESCRIPTION: Preprocessor error reporting. Front end to AslCommonError2 240 * 241 ******************************************************************************/ 242 243 void 244 PrError ( 245 UINT8 Level, 246 UINT8 MessageId, 247 UINT32 Column) 248 { 249 #if 0 250 AcpiOsPrintf ("%s (%u) : %s", Gbl_Files[ASL_FILE_INPUT].Filename, 251 Gbl_CurrentLineNumber, Gbl_CurrentLineBuffer); 252 #endif 253 254 255 if (Column > 120) 256 { 257 Column = 0; 258 } 259 260 /* TBD: Need Logical line number? */ 261 262 AslCommonError2 (Level, MessageId, 263 Gbl_CurrentLineNumber, Column, 264 Gbl_CurrentLineBuffer, 265 Gbl_Files[ASL_FILE_INPUT].Filename, "Preprocessor"); 266 267 Gbl_PreprocessorError = TRUE; 268 } 269 270 271 /******************************************************************************* 272 * 273 * FUNCTION: PrReplaceData 274 * 275 * PARAMETERS: Buffer - Original(target) buffer pointer 276 * LengthToRemove - Length to be removed from target buffer 277 * BufferToAdd - Data to be inserted into target buffer 278 * LengthToAdd - Length of BufferToAdd 279 * 280 * RETURN: None 281 * 282 * DESCRIPTION: Generic buffer data replacement. 283 * 284 ******************************************************************************/ 285 286 void 287 PrReplaceData ( 288 char *Buffer, 289 UINT32 LengthToRemove, 290 char *BufferToAdd, 291 UINT32 LengthToAdd) 292 { 293 UINT32 BufferLength; 294 295 296 /* Buffer is a string, so the length must include the terminating zero */ 297 298 BufferLength = strlen (Buffer) + 1; 299 300 if (LengthToRemove != LengthToAdd) 301 { 302 /* 303 * Move some of the existing data 304 * 1) If adding more bytes than removing, make room for the new data 305 * 2) if removing more bytes than adding, delete the extra space 306 */ 307 if (LengthToRemove > 0) 308 { 309 memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove), 310 (BufferLength - LengthToRemove)); 311 } 312 } 313 314 /* Now we can move in the new data */ 315 316 if (LengthToAdd > 0) 317 { 318 memmove (Buffer, BufferToAdd, LengthToAdd); 319 } 320 } 321 322 323 /******************************************************************************* 324 * 325 * FUNCTION: PrOpenIncludeFile 326 * 327 * PARAMETERS: Filename - Filename or pathname for include file 328 * 329 * RETURN: None. 330 * 331 * DESCRIPTION: Open an include file and push it on the input file stack. 332 * 333 ******************************************************************************/ 334 335 void 336 PrOpenIncludeFile ( 337 char *Filename) 338 { 339 FILE *IncludeFile; 340 ASL_INCLUDE_DIR *NextDir; 341 342 343 /* 344 * start the actual include file on the next line 345 */ 346 Gbl_CurrentLineOffset++; 347 348 /* Attempt to open the include file */ 349 350 /* If the file specifies an absolute path, just open it */ 351 352 if ((Filename[0] == '/') || 353 (Filename[0] == '\\') || 354 (Filename[1] == ':')) 355 { 356 IncludeFile = PrOpenIncludeWithPrefix ("", Filename); 357 if (!IncludeFile) 358 { 359 goto ErrorExit; 360 } 361 return; 362 } 363 364 /* 365 * The include filename is not an absolute path. 366 * 367 * First, search for the file within the "local" directory -- meaning 368 * the same directory that contains the source file. 369 * 370 * Construct the file pathname from the global directory name. 371 */ 372 IncludeFile = PrOpenIncludeWithPrefix (Gbl_DirectoryPath, Filename); 373 if (IncludeFile) 374 { 375 return; 376 } 377 378 /* 379 * Second, search for the file within the (possibly multiple) 380 * directories specified by the -I option on the command line. 381 */ 382 NextDir = Gbl_IncludeDirList; 383 while (NextDir) 384 { 385 IncludeFile = PrOpenIncludeWithPrefix (NextDir->Dir, Filename); 386 if (IncludeFile) 387 { 388 return; 389 } 390 391 NextDir = NextDir->Next; 392 } 393 394 /* We could not open the include file after trying very hard */ 395 396 ErrorExit: 397 sprintf (Gbl_MainTokenBuffer, "%s, %s", Filename, strerror (errno)); 398 PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0); 399 } 400 401 402 /******************************************************************************* 403 * 404 * FUNCTION: FlOpenIncludeWithPrefix 405 * 406 * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero 407 * length string. 408 * Filename - The include filename from the source ASL. 409 * 410 * RETURN: Valid file descriptor if successful. Null otherwise. 411 * 412 * DESCRIPTION: Open an include file and push it on the input file stack. 413 * 414 ******************************************************************************/ 415 416 FILE * 417 PrOpenIncludeWithPrefix ( 418 char *PrefixDir, 419 char *Filename) 420 { 421 FILE *IncludeFile; 422 char *Pathname; 423 424 425 /* Build the full pathname to the file */ 426 427 Pathname = ACPI_ALLOCATE (strlen (PrefixDir) + strlen (Filename) + 1); 428 429 strcpy (Pathname, PrefixDir); 430 strcat (Pathname, Filename); 431 432 DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID 433 "Opening include file: path %s\n", 434 Gbl_CurrentLineNumber, Pathname); 435 436 /* Attempt to open the file, push if successful */ 437 438 IncludeFile = fopen (Pathname, "r"); 439 if (IncludeFile) 440 { 441 /* Push the include file on the open input file stack */ 442 443 PrPushInputFileStack (IncludeFile, Pathname); 444 return (IncludeFile); 445 } 446 447 ACPI_FREE (Pathname); 448 return (NULL); 449 } 450 451 452 /******************************************************************************* 453 * 454 * FUNCTION: AslPushInputFileStack 455 * 456 * PARAMETERS: InputFile - Open file pointer 457 * Filename - Name of the file 458 * 459 * RETURN: None 460 * 461 * DESCRIPTION: Push the InputFile onto the file stack, and point the parser 462 * to this file. Called when an include file is successfully 463 * opened. 464 * 465 ******************************************************************************/ 466 467 void 468 PrPushInputFileStack ( 469 FILE *InputFile, 470 char *Filename) 471 { 472 PR_FILE_NODE *Fnode; 473 474 475 /* Save the current state in an Fnode */ 476 477 Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE)); 478 479 Fnode->File = Gbl_Files[ASL_FILE_INPUT].Handle; 480 Fnode->Next = Gbl_InputFileList; 481 Fnode->Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 482 Fnode->CurrentLineNumber = Gbl_CurrentLineNumber; 483 484 /* Push it on the stack */ 485 486 Gbl_InputFileList = Fnode; 487 488 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 489 "Push InputFile Stack, returning %p\n\n", 490 Gbl_CurrentLineNumber, InputFile); 491 492 /* Reset the global line count and filename */ 493 494 Gbl_Files[ASL_FILE_INPUT].Filename = Filename; 495 Gbl_Files[ASL_FILE_INPUT].Handle = InputFile; 496 Gbl_CurrentLineNumber = 1; 497 } 498 499 500 /******************************************************************************* 501 * 502 * FUNCTION: AslPopInputFileStack 503 * 504 * PARAMETERS: None 505 * 506 * RETURN: 0 if a node was popped, -1 otherwise 507 * 508 * DESCRIPTION: Pop the top of the input file stack and point the parser to 509 * the saved parse buffer contained in the fnode. Also, set the 510 * global line counters to the saved values. This function is 511 * called when an include file reaches EOF. 512 * 513 ******************************************************************************/ 514 515 BOOLEAN 516 PrPopInputFileStack ( 517 void) 518 { 519 PR_FILE_NODE *Fnode; 520 521 522 Fnode = Gbl_InputFileList; 523 DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID 524 "Pop InputFile Stack, Fnode %p\n\n", 525 Gbl_CurrentLineNumber, Fnode); 526 527 if (!Fnode) 528 { 529 return (FALSE); 530 } 531 532 /* Close the current include file */ 533 534 fclose (Gbl_Files[ASL_FILE_INPUT].Handle); 535 536 /* Update the top-of-stack */ 537 538 Gbl_InputFileList = Fnode->Next; 539 540 /* Reset global line counter and filename */ 541 542 Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename; 543 Gbl_Files[ASL_FILE_INPUT].Handle = Fnode->File; 544 Gbl_CurrentLineNumber = Fnode->CurrentLineNumber; 545 546 /* All done with this node */ 547 548 ACPI_FREE (Fnode); 549 return (TRUE); 550 } 551