1 /******************************************************************************
   2  *
   3  * Module Name: prutils - Preprocessor utilities
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, 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 "aslcompiler.h"
  45 #include "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     UINT8                   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 void
 242 PrOpenIncludeFile (
 243     char                    *Filename)
 244 {
 245     FILE                    *IncludeFile;
 246     ASL_INCLUDE_DIR         *NextDir;
 247 
 248 
 249     /* Start the actual include file on the next line */
 250 
 251     Gbl_CurrentLineOffset++;
 252 
 253     /* Attempt to open the include file */
 254     /* If the file specifies an absolute path, just open it */
 255 
 256     if ((Filename[0] == '/')  ||
 257         (Filename[0] == '\\') ||
 258         (Filename[1] == ':'))
 259     {
 260         IncludeFile = PrOpenIncludeWithPrefix ("", Filename);
 261         if (!IncludeFile)
 262         {
 263             goto ErrorExit;
 264         }
 265         return;
 266     }
 267 
 268     /*
 269      * The include filename is not an absolute path.
 270      *
 271      * First, search for the file within the "local" directory -- meaning
 272      * the same directory that contains the source file.
 273      *
 274      * Construct the file pathname from the global directory name.
 275      */
 276     IncludeFile = PrOpenIncludeWithPrefix (Gbl_DirectoryPath, Filename);
 277     if (IncludeFile)
 278     {
 279         return;
 280     }
 281 
 282     /*
 283      * Second, search for the file within the (possibly multiple)
 284      * directories specified by the -I option on the command line.
 285      */
 286     NextDir = Gbl_IncludeDirList;
 287     while (NextDir)
 288     {
 289         IncludeFile = PrOpenIncludeWithPrefix (NextDir->Dir, Filename);
 290         if (IncludeFile)
 291         {
 292             return;
 293         }
 294 
 295         NextDir = NextDir->Next;
 296     }
 297 
 298     /* We could not open the include file after trying very hard */
 299 
 300 ErrorExit:
 301     sprintf (Gbl_MainTokenBuffer, "%s, %s", Filename, strerror (errno));
 302     PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0);
 303 }
 304 
 305 
 306 /*******************************************************************************
 307  *
 308  * FUNCTION:    FlOpenIncludeWithPrefix
 309  *
 310  * PARAMETERS:  PrefixDir       - Prefix directory pathname. Can be a zero
 311  *                                length string.
 312  *              Filename        - The include filename from the source ASL.
 313  *
 314  * RETURN:      Valid file descriptor if successful. Null otherwise.
 315  *
 316  * DESCRIPTION: Open an include file and push it on the input file stack.
 317  *
 318  ******************************************************************************/
 319 
 320 FILE *
 321 PrOpenIncludeWithPrefix (
 322     char                    *PrefixDir,
 323     char                    *Filename)
 324 {
 325     FILE                    *IncludeFile;
 326     char                    *Pathname;
 327 
 328 
 329     /* Build the full pathname to the file */
 330 
 331     Pathname = FlMergePathnames (PrefixDir, Filename);
 332 
 333     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
 334         "Include: Opening file - \"%s\"\n",
 335         Gbl_CurrentLineNumber, Pathname);
 336 
 337     /* Attempt to open the file, push if successful */
 338 
 339     IncludeFile = fopen (Pathname, "r");
 340     if (!IncludeFile)
 341     {
 342         fprintf (stderr, "Could not open include file %s\n", Pathname);
 343         ACPI_FREE (Pathname);
 344         return (NULL);
 345     }
 346 
 347     /* Push the include file on the open input file stack */
 348 
 349     PrPushInputFileStack (IncludeFile, Pathname);
 350     return (IncludeFile);
 351 }
 352 
 353 
 354 /*******************************************************************************
 355  *
 356  * FUNCTION:    AslPushInputFileStack
 357  *
 358  * PARAMETERS:  InputFile           - Open file pointer
 359  *              Filename            - Name of the file
 360  *
 361  * RETURN:      None
 362  *
 363  * DESCRIPTION: Push the InputFile onto the file stack, and point the parser
 364  *              to this file. Called when an include file is successfully
 365  *              opened.
 366  *
 367  ******************************************************************************/
 368 
 369 void
 370 PrPushInputFileStack (
 371     FILE                    *InputFile,
 372     char                    *Filename)
 373 {
 374     PR_FILE_NODE            *Fnode;
 375 
 376 
 377     /* Save the current state in an Fnode */
 378 
 379     Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE));
 380 
 381     Fnode->File = Gbl_Files[ASL_FILE_INPUT].Handle;
 382     Fnode->Next = Gbl_InputFileList;
 383     Fnode->Filename = Gbl_Files[ASL_FILE_INPUT].Filename;
 384     Fnode->CurrentLineNumber = Gbl_CurrentLineNumber;
 385 
 386     /* Push it on the stack */
 387 
 388     Gbl_InputFileList = Fnode;
 389 
 390     DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
 391         "Push InputFile Stack: handle %p\n\n",
 392         Gbl_CurrentLineNumber, InputFile);
 393 
 394     /* Reset the global line count and filename */
 395 
 396     Gbl_Files[ASL_FILE_INPUT].Filename = Filename;
 397     Gbl_Files[ASL_FILE_INPUT].Handle = InputFile;
 398     Gbl_PreviousLineNumber = 0;
 399     Gbl_CurrentLineNumber = 0;
 400 
 401     /* Emit a new #line directive for the include file */
 402 
 403     FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
 404         1, Filename);
 405 }
 406 
 407 
 408 /*******************************************************************************
 409  *
 410  * FUNCTION:    AslPopInputFileStack
 411  *
 412  * PARAMETERS:  None
 413  *
 414  * RETURN:      0 if a node was popped, -1 otherwise
 415  *
 416  * DESCRIPTION: Pop the top of the input file stack and point the parser to
 417  *              the saved parse buffer contained in the fnode. Also, set the
 418  *              global line counters to the saved values. This function is
 419  *              called when an include file reaches EOF.
 420  *
 421  ******************************************************************************/
 422 
 423 BOOLEAN
 424 PrPopInputFileStack (
 425     void)
 426 {
 427     PR_FILE_NODE            *Fnode;
 428 
 429 
 430     Fnode = Gbl_InputFileList;
 431     DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID
 432         "Pop InputFile Stack, Fnode %p\n\n",
 433         Gbl_CurrentLineNumber, Fnode);
 434 
 435     if (!Fnode)
 436     {
 437         return (FALSE);
 438     }
 439 
 440     /* Close the current include file */
 441 
 442     fclose (Gbl_Files[ASL_FILE_INPUT].Handle);
 443 
 444     /* Update the top-of-stack */
 445 
 446     Gbl_InputFileList = Fnode->Next;
 447 
 448     /* Reset global line counter and filename */
 449 
 450     Gbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename;
 451     Gbl_Files[ASL_FILE_INPUT].Handle = Fnode->File;
 452     Gbl_CurrentLineNumber = Fnode->CurrentLineNumber;
 453     Gbl_PreviousLineNumber = 0;
 454 
 455     /* Emit a new #line directive after the include file */
 456 
 457     FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
 458         Gbl_CurrentLineNumber + 1, Fnode->Filename);
 459 
 460     /* All done with this node */
 461 
 462     ACPI_FREE (Fnode);
 463     return (TRUE);
 464 }