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