prutils.c revision 306536
1/******************************************************************************
2 *
3 * Module Name: prutils - Preprocessor utilities
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2016, 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
69char *
70PrGetNextToken (
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
151void
152PrError (
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
194void
195PrReplaceData (
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
243FILE *
244PrOpenIncludeFile (
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
307ErrorExit:
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
328FILE *
329PrOpenIncludeWithPrefix (
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
379void
380PrPushInputFileStack (
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
436BOOLEAN
437PrPopInputFileStack (
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