1 /****************************************************************************** 2 * 3 * Module Name: prutils - Preprocessor utilities 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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: PrGetNextToken 55 * 56 * PARAMETERS: Buffer - Current line buffer 57 * MatchString - String with valid token delimiters 58 * Next - Set to next possible token in buffer 59 * 60 * RETURN: Next token (null-terminated). Modifies the input line. 61 * Remainder of line is stored in *Next. 62 * 63 * DESCRIPTION: Local implementation of strtok() with local storage for the 64 * next pointer. Not only thread-safe, but allows multiple 65 * parsing of substrings such as expressions. 66 * 67 *****************************************************************************/ 68 69 char * 70 PrGetNextToken ( 71 char *Buffer, 72 char *MatchString, 73 char **Next) 74 { 75 char *TokenStart; 76 77 78 if (!Buffer) 79 { 80 /* Use Next if it is valid */ 81 82 Buffer = *Next; 83 if (!(*Next)) 84 { 85 return (NULL); 86 } 87 } 88 89 /* Skip any leading delimiters */ 90 91 while (*Buffer) 92 { 93 if (strchr (MatchString, *Buffer)) 94 { 95 Buffer++; 96 } 97 else 98 { 99 break; 100 } 101 } 102 103 /* Anything left on the line? */ 104 105 if (!(*Buffer)) 106 { 107 *Next = NULL; 108 return (NULL); 109 } 110 111 TokenStart = Buffer; 112 113 /* Find the end of this token */ 114 115 while (*Buffer) 116 { 117 if (strchr (MatchString, *Buffer)) 118 { 119 *Buffer = 0; 120 *Next = Buffer+1; 121 if (!**Next) 122 { 123 *Next = NULL; 124 } 125 return (TokenStart); 126 } 127 Buffer++; 128 } 129 130 *Next = NULL; 131 return (TokenStart); 132 } 133 134 135 /******************************************************************************* 136 * 137 * FUNCTION: PrError 138 * 139 * PARAMETERS: Level - Seriousness (Warning/error, etc.) 140 * MessageId - Index into global message buffer 141 * Column - Column in current line 142 * 143 * RETURN: None 144 * 145 * DESCRIPTION: Preprocessor error reporting. Front end to AslCommonError2 146 * 147 ******************************************************************************/ 148 149 void 150 PrError ( 151 UINT8 Level, 152 UINT16 MessageId, 153 UINT32 Column) 154 { 155 #if 0 156 AcpiOsPrintf ("%s (%u) : %s", Gbl_Files[ASL_FILE_INPUT].Filename, 157 Gbl_CurrentLineNumber, Gbl_CurrentLineBuffer); 158 #endif 159 160 161 if (Column > 120) 162 { 163 Column = 0; 164 } 165 166 /* TBD: Need Logical line number? */ 167 168 AslCommonError2 (Level, MessageId, 169 Gbl_CurrentLineNumber, Column, 170 Gbl_CurrentLineBuffer, 171 Gbl_Files[ASL_FILE_INPUT].Filename, "Preprocessor"); 172 173 Gbl_PreprocessorError = TRUE; 174 } 175 176 177 /******************************************************************************* 178 * 179 * FUNCTION: PrReplaceData 180 * 181 * PARAMETERS: Buffer - Original(target) buffer pointer 182 * LengthToRemove - Length to be removed from target buffer 183 * BufferToAdd - Data to be inserted into target buffer 184 * LengthToAdd - Length of BufferToAdd 185 * 186 * RETURN: None 187 * 188 * DESCRIPTION: Generic buffer data replacement. 189 * 190 ******************************************************************************/ 191 192 void 193 PrReplaceData ( 194 char *Buffer, 195 UINT32 LengthToRemove, 196 char *BufferToAdd, 197 UINT32 LengthToAdd) 198 { 199 UINT32 BufferLength; 200 201 202 /* Buffer is a string, so the length must include the terminating zero */ 203 204 BufferLength = strlen (Buffer) + 1; 205 206 if (LengthToRemove != LengthToAdd) 207 { 208 /* 209 * Move some of the existing data 210 * 1) If adding more bytes than removing, make room for the new data 211 * 2) if removing more bytes than adding, delete the extra space 212 */ 213 if (LengthToRemove > 0) 214 { 215 memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove), 216 (BufferLength - LengthToRemove)); 217 } 218 } 219 220 /* Now we can move in the new data */ 221 222 if (LengthToAdd > 0) 223 { 224 memmove (Buffer, BufferToAdd, LengthToAdd); 225 } 226 } 227 228 229 /******************************************************************************* 230 * 231 * FUNCTION: PrOpenIncludeFile 232 * 233 * PARAMETERS: Filename - Filename or pathname for include file 234 * 235 * RETURN: None. 236 * 237 * DESCRIPTION: Open an include file and push it on the input file stack. 238 * 239 ******************************************************************************/ 240 241 FILE * 242 PrOpenIncludeFile ( 243 char *Filename, 244 char *OpenMode, 245 char **FullPathname) 246 { 247 FILE *IncludeFile; 248 ASL_INCLUDE_DIR *NextDir; 249 250 251 /* Start the actual include file on the next line */ 252 253 Gbl_CurrentLineOffset++; 254 255 /* Attempt to open the include file */ 256 /* If the file specifies an absolute path, just open it */ 257 258 if ((Filename[0] == '/') || 259 (Filename[0] == '\\') || 260 (Filename[1] == ':')) 261 { 262 IncludeFile = PrOpenIncludeWithPrefix ( 263 "", Filename, OpenMode, FullPathname); 264 if (!IncludeFile) 265 { 266 goto ErrorExit; 267 } 268 return (IncludeFile); 269 } 270 271 /* 272 * The include filename is not an absolute path. 273 * 274 * First, search for the file within the "local" directory -- meaning 275 * the same directory that contains the source file. 276 * 277 * Construct the file pathname from the global directory name. 278 */ 279 IncludeFile = PrOpenIncludeWithPrefix ( 280 Gbl_DirectoryPath, Filename, OpenMode, FullPathname); 281 if (IncludeFile) 282 { 283 return (IncludeFile); 284 } 285 286 /* 287 * Second, search for the file within the (possibly multiple) 288 * directories specified by the -I option on the command line. 289 */ 290 NextDir = Gbl_IncludeDirList; 291 while (NextDir) 292 { 293 IncludeFile = PrOpenIncludeWithPrefix ( 294 NextDir->Dir, Filename, OpenMode, FullPathname); 295 if (IncludeFile) 296 { 297 return (IncludeFile); 298 } 299 300 NextDir = NextDir->Next; 301 } 302 303 /* We could not open the include file after trying very hard */ 304 305 ErrorExit: 306 sprintf (Gbl_MainTokenBuffer, "%s, %s", Filename, strerror (errno)); 307 PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0); 308 return (NULL); 309 } 310 311 312 /******************************************************************************* 313 * 314 * FUNCTION: FlOpenIncludeWithPrefix 315 * 316 * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero 317 * length string. 318 * Filename - The include filename from the source ASL. 319 * 320 * RETURN: Valid file descriptor if successful. Null otherwise. 321 * 322 * DESCRIPTION: Open an include file and push it on the input file stack. 323 * 324 ******************************************************************************/ 325 326 FILE * 327 PrOpenIncludeWithPrefix ( 328 char *PrefixDir, 329 char *Filename, 330 char *OpenMode, 331 char **FullPathname) 332 { 333 FILE *IncludeFile; 334 char *Pathname; 335 336 337 /* Build the full pathname to the file */ 338 339 Pathname = FlMergePathnames (PrefixDir, Filename); 340 341 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 342 "Include: Opening file - \"%s\"\n", 343 Gbl_CurrentLineNumber, Pathname); 344 345 /* Attempt to open the file, push if successful */ 346 347 IncludeFile = fopen (Pathname, OpenMode); 348 if (!IncludeFile) 349 { 350 fprintf (stderr, "Could not open include file %s\n", Pathname); 351 return (NULL); 352 } 353 354 /* Push the include file on the open input file stack */ 355 356 PrPushInputFileStack (IncludeFile, Pathname); 357 *FullPathname = Pathname; 358 return (IncludeFile); 359 } 360 361 362 /******************************************************************************* 363 * 364 * FUNCTION: AslPushInputFileStack 365 * 366 * PARAMETERS: InputFile - Open file pointer 367 * Filename - Name of the file 368 * 369 * RETURN: None 370 * 371 * DESCRIPTION: Push the InputFile onto the file stack, and point the parser 372 * to this file. Called when an include file is successfully 373 * opened. 374 * 375 ******************************************************************************/ 376 377 void 378 PrPushInputFileStack ( 379 FILE *InputFile, 380 char *Filename) 381 { 382 PR_FILE_NODE *Fnode; 383 384 385 Gbl_HasIncludeFiles = TRUE; 386 387 /* Save the current state in an Fnode */ 388 389 Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE)); 390 391 Fnode->File = Gbl_Files[ASL_FILE_INPUT].Handle; 392 Fnode->Next = Gbl_InputFileList; 393 Fnode->Filename = Gbl_Files[ASL_FILE_INPUT].Filename; 394 Fnode->CurrentLineNumber = Gbl_CurrentLineNumber; 395 396 /* Push it on the stack */ 397 398 Gbl_InputFileList = Fnode; 399 400 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID 401 "Push InputFile Stack: handle %p\n\n", 402 Gbl_CurrentLineNumber, InputFile); 403 404 /* Reset the global line count and filename */ 405 406 Gbl_Files[ASL_FILE_INPUT].Filename = 407 UtStringCacheCalloc (strlen (Filename) + 1); 408 strcpy (Gbl_Files[ASL_FILE_INPUT].Filename, Filename); 409 410 Gbl_Files[ASL_FILE_INPUT].Handle = InputFile; 411 Gbl_CurrentLineNumber = 1; 412 413 /* Emit a new #line directive for the include file */ 414 415 Gbl_CurrentLineNumber = 1; 416 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 1, Filename); 417 } 418 419 420 /******************************************************************************* 421 * 422 * FUNCTION: AslPopInputFileStack 423 * 424 * PARAMETERS: None 425 * 426 * RETURN: 0 if a node was popped, -1 otherwise 427 * 428 * DESCRIPTION: Pop the top of the input file stack and point the parser to 429 * the saved parse buffer contained in the fnode. Also, set the 430 * global line counters to the saved values. This function is 431 * called when an include file reaches EOF. 432 * 433 ******************************************************************************/ 434 435 BOOLEAN 436 PrPopInputFileStack ( 437 void) 438 { 439 PR_FILE_NODE *Fnode; 440 441 442 Fnode = Gbl_InputFileList; 443 DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID 444 "Pop InputFile Stack, Fnode %p\n\n", 445 Gbl_CurrentLineNumber, Fnode); 446 447 if (!Fnode) 448 { 449 return (FALSE); 450 } 451 452 /* Close the current include file */ 453 454 fclose (Gbl_Files[ASL_FILE_INPUT].Handle); 455 456 /* Update the top-of-stack */ 457 458 Gbl_InputFileList = Fnode->Next; 459 460 /* Reset global line counter and filename */ 461 462 Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename; 463 Gbl_Files[ASL_FILE_INPUT].Handle = Fnode->File; 464 Gbl_CurrentLineNumber = Fnode->CurrentLineNumber; 465 466 /* Emit a new #line directive after the include file */ 467 468 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 469 Gbl_CurrentLineNumber, Fnode->Filename); 470 471 /* All done with this node */ 472 473 ACPI_FREE (Fnode); 474 return (TRUE); 475 } 476