prutils.c revision 233237
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 "aslcompiler.h"
45#include "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
71void
72PrSetLineNumber (
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
118UINT32
119PrGetLineNumber (
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
163char *
164PrGetNextToken (
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
243void
244PrError (
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
286void
287PrReplaceData (
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
335void
336PrOpenIncludeFile (
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
396ErrorExit:
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
416FILE *
417PrOpenIncludeWithPrefix (
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
467void
468PrPushInputFileStack (
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
515BOOLEAN
516PrPopInputFileStack (
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