prscan.c revision 283092
1/******************************************************************************
2 *
3 * Module Name: prscan - Preprocessor start-up and file scan module
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#define _DECLARE_PR_GLOBALS
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include <contrib/dev/acpica/compiler/dtcompiler.h>
48
49/*
50 * TBDs:
51 *
52 * No nested macros, maybe never
53 * Implement ASL "Include" as well as "#include" here?
54 */
55#define _COMPONENT          ASL_PREPROCESSOR
56        ACPI_MODULE_NAME    ("prscan")
57
58
59/* Local prototypes */
60
61static void
62PrPreprocessInputFile (
63    void);
64
65static void
66PrDoDirective (
67    char                    *DirectiveToken,
68    char                    **Next);
69
70static int
71PrMatchDirective (
72    char                    *Directive);
73
74static void
75PrPushDirective (
76    int                     Directive,
77    char                    *Argument);
78
79static ACPI_STATUS
80PrPopDirective (
81    void);
82
83static void
84PrDbgPrint (
85    char                    *Action,
86    char                    *DirectiveName);
87
88static void
89PrDoIncludeBuffer (
90    char                    *Pathname,
91    char                    *BufferName);
92
93static void
94PrDoIncludeFile (
95    char                    *Pathname);
96
97
98/*
99 * Supported preprocessor directives
100 * Each entry is of the form "Name, ArgumentCount"
101 */
102static const PR_DIRECTIVE_INFO      Gbl_DirectiveInfo[] =
103{
104    {"define",          1},
105    {"elif",            0}, /* Converted to #else..#if internally */
106    {"else",            0},
107    {"endif",           0},
108    {"error",           1},
109    {"if",              1},
110    {"ifdef",           1},
111    {"ifndef",          1},
112    {"include",         0}, /* Argument is not standard format, so just use 0 here */
113    {"includebuffer",   0}, /* Argument is not standard format, so just use 0 here */
114    {"line",            1},
115    {"loadbuffer",      0},
116    {"pragma",          1},
117    {"undef",           1},
118    {"warning",         1},
119    {NULL,              0}
120};
121
122/* This table must match ordering of above table exactly */
123
124enum Gbl_DirectiveIndexes
125{
126    PR_DIRECTIVE_DEFINE = 0,
127    PR_DIRECTIVE_ELIF,
128    PR_DIRECTIVE_ELSE,
129    PR_DIRECTIVE_ENDIF,
130    PR_DIRECTIVE_ERROR,
131    PR_DIRECTIVE_IF,
132    PR_DIRECTIVE_IFDEF,
133    PR_DIRECTIVE_IFNDEF,
134    PR_DIRECTIVE_INCLUDE,
135    PR_DIRECTIVE_INCLUDEBUFFER,
136    PR_DIRECTIVE_LINE,
137    PR_DIRECTIVE_PRAGMA,
138    PR_DIRECTIVE_UNDEF,
139    PR_DIRECTIVE_WARNING,
140};
141
142#define ASL_DIRECTIVE_NOT_FOUND     -1
143
144
145/*******************************************************************************
146 *
147 * FUNCTION:    PrInitializePreprocessor
148 *
149 * PARAMETERS:  None
150 *
151 * RETURN:      None
152 *
153 * DESCRIPTION: Startup initialization for the Preprocessor.
154 *
155 ******************************************************************************/
156
157void
158PrInitializePreprocessor (
159    void)
160{
161    /* Init globals and the list of #defines */
162
163    PrInitializeGlobals ();
164    Gbl_DefineList = NULL;
165}
166
167
168/*******************************************************************************
169 *
170 * FUNCTION:    PrInitializeGlobals
171 *
172 * PARAMETERS:  None
173 *
174 * RETURN:      None
175 *
176 * DESCRIPTION: Initialize globals for the Preprocessor. Used for startuup
177 *              initialization and re-initialization between compiles during
178 *              a multiple source file compile.
179 *
180 ******************************************************************************/
181
182void
183PrInitializeGlobals (
184    void)
185{
186    /* Init globals */
187
188    Gbl_InputFileList = NULL;
189    Gbl_CurrentLineNumber = 0;
190    Gbl_PreprocessorLineNumber = 1;
191    Gbl_PreprocessorError = FALSE;
192
193    /* These are used to track #if/#else blocks (possibly nested) */
194
195    Gbl_IfDepth = 0;
196    Gbl_IgnoringThisCodeBlock = FALSE;
197    Gbl_DirectiveStack = NULL;
198}
199
200
201/*******************************************************************************
202 *
203 * FUNCTION:    PrTerminatePreprocessor
204 *
205 * PARAMETERS:  None
206 *
207 * RETURN:      None
208 *
209 * DESCRIPTION: Termination of the preprocessor. Delete lists. Keep any
210 *              defines that were specified on the command line, in order to
211 *              support multiple compiles with a single compiler invocation.
212 *
213 ******************************************************************************/
214
215void
216PrTerminatePreprocessor (
217    void)
218{
219    PR_DEFINE_INFO          *DefineInfo;
220
221
222    /*
223     * The persistent defines (created on the command line) are always at the
224     * end of the list. We save them.
225     */
226    while ((Gbl_DefineList) && (!Gbl_DefineList->Persist))
227    {
228        DefineInfo = Gbl_DefineList;
229        Gbl_DefineList = DefineInfo->Next;
230
231        ACPI_FREE (DefineInfo->Replacement);
232        ACPI_FREE (DefineInfo->Identifier);
233        ACPI_FREE (DefineInfo);
234    }
235}
236
237
238/*******************************************************************************
239 *
240 * FUNCTION:    PrDoPreprocess
241 *
242 * PARAMETERS:  None
243 *
244 * RETURN:      None
245 *
246 * DESCRIPTION: Main entry point for the iASL Preprocessor. Input file must
247 *              be already open. Handles multiple input files via the
248 *              #include directive.
249 *
250 ******************************************************************************/
251
252void
253PrDoPreprocess (
254    void)
255{
256    BOOLEAN                 MoreInputFiles;
257
258
259    DbgPrint (ASL_DEBUG_OUTPUT, "Starting preprocessing phase\n\n");
260
261
262    FlSeekFile (ASL_FILE_INPUT, 0);
263    PrDumpPredefinedNames ();
264
265    /* Main preprocessor loop, handles include files */
266
267    do
268    {
269        PrPreprocessInputFile ();
270        MoreInputFiles = PrPopInputFileStack ();
271
272    } while (MoreInputFiles);
273
274    /* Point compiler input to the new preprocessor output file (.i) */
275
276    FlCloseFile (ASL_FILE_INPUT);
277    Gbl_Files[ASL_FILE_INPUT].Handle = Gbl_Files[ASL_FILE_PREPROCESSOR].Handle;
278    AslCompilerin = Gbl_Files[ASL_FILE_INPUT].Handle;
279
280    /* Reset globals to allow compiler to run */
281
282    FlSeekFile (ASL_FILE_INPUT, 0);
283    Gbl_CurrentLineNumber = 1;
284
285    DbgPrint (ASL_DEBUG_OUTPUT, "Preprocessing phase complete \n\n");
286}
287
288
289/*******************************************************************************
290 *
291 * FUNCTION:    PrPreprocessInputFile
292 *
293 * PARAMETERS:  None
294 *
295 * RETURN:      None
296 *
297 * DESCRIPTION: Preprocess one entire file, line-by-line.
298 *
299 * Input:  Raw user ASL from ASL_FILE_INPUT
300 * Output: Preprocessed file written to ASL_FILE_PREPROCESSOR
301 *
302 ******************************************************************************/
303
304static void
305PrPreprocessInputFile (
306    void)
307{
308    UINT32                  Offset;
309    char                    *Token;
310    char                    *ReplaceString;
311    PR_DEFINE_INFO          *DefineInfo;
312    ACPI_SIZE               TokenOffset;
313    char                    *Next;
314    int                     OffsetAdjust;
315
316
317    /* Scan line-by-line. Comments and blank lines are skipped by this function */
318
319    while ((Offset = DtGetNextLine (Gbl_Files[ASL_FILE_INPUT].Handle)) != ASL_EOF)
320    {
321        /* Need a copy of the input line for strok() */
322
323        strcpy (Gbl_MainTokenBuffer, Gbl_CurrentLineBuffer);
324        Token = PrGetNextToken (Gbl_MainTokenBuffer, PR_TOKEN_SEPARATORS, &Next);
325        OffsetAdjust = 0;
326
327        /* All preprocessor directives must begin with '#' */
328
329        if (Token && (*Token == '#'))
330        {
331            if (strlen (Token) == 1)
332            {
333                Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
334            }
335            else
336            {
337                Token++;    /* Skip leading # */
338            }
339
340            /* Execute the directive, do not write line to output file */
341
342            PrDoDirective (Token, &Next);
343            continue;
344        }
345
346        /*
347         * If we are currently within the part of an IF/ELSE block that is
348         * FALSE, ignore the line and do not write it to the output file.
349         * This continues until an #else or #endif is encountered.
350         */
351        if (Gbl_IgnoringThisCodeBlock)
352        {
353            continue;
354        }
355
356        /* Match and replace all #defined names within this source line */
357
358        while (Token)
359        {
360            DefineInfo = PrMatchDefine (Token);
361            if (DefineInfo)
362            {
363                if (DefineInfo->Body)
364                {
365                    /* This is a macro */
366
367                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
368                        "Matched Macro: %s->%s\n",
369                        Gbl_CurrentLineNumber, DefineInfo->Identifier,
370                        DefineInfo->Replacement);
371
372                    PrDoMacroInvocation (Gbl_MainTokenBuffer, Token,
373                        DefineInfo, &Next);
374                }
375                else
376                {
377                    ReplaceString = DefineInfo->Replacement;
378
379                    /* Replace the name in the original line buffer */
380
381                    TokenOffset = Token - Gbl_MainTokenBuffer + OffsetAdjust;
382                    PrReplaceData (
383                        &Gbl_CurrentLineBuffer[TokenOffset], strlen (Token),
384                        ReplaceString, strlen (ReplaceString));
385
386                    /* Adjust for length difference between old and new name length */
387
388                    OffsetAdjust += strlen (ReplaceString) - strlen (Token);
389
390                    DbgPrint (ASL_DEBUG_OUTPUT, PR_PREFIX_ID
391                        "Matched #define: %s->%s\n",
392                        Gbl_CurrentLineNumber, Token,
393                        *ReplaceString ? ReplaceString : "(NULL STRING)");
394                }
395            }
396
397            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, &Next);
398        }
399
400        /*
401         * Emit a #line directive if necessary, to keep the line numbers in
402         * the (.i) file synchronized with the original source code file, so
403         * that the correct line number appears in any error messages
404         * generated by the actual compiler.
405         */
406        if (Gbl_CurrentLineNumber > (Gbl_PreviousLineNumber + 1))
407        {
408            FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u\n",
409                Gbl_CurrentLineNumber);
410        }
411
412        Gbl_PreviousLineNumber = Gbl_CurrentLineNumber;
413        Gbl_PreprocessorLineNumber++;
414
415        /*
416         * Now we can write the possibly modified source line to the
417         * preprocessor (.i) file
418         */
419        FlWriteFile (ASL_FILE_PREPROCESSOR, Gbl_CurrentLineBuffer,
420            strlen (Gbl_CurrentLineBuffer));
421    }
422}
423
424
425/*******************************************************************************
426 *
427 * FUNCTION:    PrDoDirective
428 *
429 * PARAMETERS:  Directive               - Pointer to directive name token
430 *              Next                    - "Next" buffer from GetNextToken
431 *
432 * RETURN:      None.
433 *
434 * DESCRIPTION: Main processing for all preprocessor directives
435 *
436 ******************************************************************************/
437
438static void
439PrDoDirective (
440    char                    *DirectiveToken,
441    char                    **Next)
442{
443    char                    *Token = Gbl_MainTokenBuffer;
444    char                    *Token2 = NULL;
445    char                    *End;
446    UINT64                  Value;
447    ACPI_SIZE               TokenOffset;
448    int                     Directive;
449    ACPI_STATUS             Status;
450
451
452    if (!DirectiveToken)
453    {
454        goto SyntaxError;
455    }
456
457    Directive = PrMatchDirective (DirectiveToken);
458    if (Directive == ASL_DIRECTIVE_NOT_FOUND)
459    {
460        PrError (ASL_ERROR, ASL_MSG_UNKNOWN_DIRECTIVE,
461            THIS_TOKEN_OFFSET (DirectiveToken));
462
463        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
464            "#%s: Unknown directive\n",
465            Gbl_CurrentLineNumber, DirectiveToken);
466        return;
467    }
468
469    /*
470     * If we are currently ignoring this block and we encounter a #else or
471     * #elif, we must ignore their blocks also if the parent block is also
472     * being ignored.
473     */
474    if (Gbl_IgnoringThisCodeBlock)
475    {
476        switch (Directive)
477        {
478        case PR_DIRECTIVE_ELSE:
479        case PR_DIRECTIVE_ELIF:
480
481            if (Gbl_DirectiveStack && Gbl_DirectiveStack->IgnoringThisCodeBlock)
482            {
483                PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
484                return;
485            }
486            break;
487
488        default:
489            break;
490        }
491    }
492
493    /*
494     * Need to always check for #else, #elif, #endif regardless of
495     * whether we are ignoring the current code block, since these
496     * are conditional code block terminators.
497     */
498    switch (Directive)
499    {
500    case PR_DIRECTIVE_ELSE:
501
502        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
503        PrDbgPrint ("Executing", "else block");
504        return;
505
506    case PR_DIRECTIVE_ELIF:
507
508        Gbl_IgnoringThisCodeBlock = !(Gbl_IgnoringThisCodeBlock);
509        Directive = PR_DIRECTIVE_IF;
510
511        if (Gbl_IgnoringThisCodeBlock == TRUE)
512        {
513            /* Not executing the ELSE part -- all done here */
514            PrDbgPrint ("Ignoring", "elif block");
515            return;
516        }
517
518        /*
519         * After this, we will execute the IF part further below.
520         * First, however, pop off the original #if directive.
521         */
522        if (ACPI_FAILURE (PrPopDirective ()))
523        {
524            PrError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
525                THIS_TOKEN_OFFSET (DirectiveToken));
526        }
527
528        PrDbgPrint ("Executing", "elif block");
529        break;
530
531    case PR_DIRECTIVE_ENDIF:
532
533        PrDbgPrint ("Executing", "endif");
534
535        /* Pop the owning #if/#ifdef/#ifndef */
536
537        if (ACPI_FAILURE (PrPopDirective ()))
538        {
539            PrError (ASL_ERROR, ASL_MSG_ENDIF_MISMATCH,
540                THIS_TOKEN_OFFSET (DirectiveToken));
541        }
542        return;
543
544    default:
545        break;
546    }
547
548    /* Most directives have at least one argument */
549
550    if (Gbl_DirectiveInfo[Directive].ArgCount >= 1)
551    {
552        Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
553        if (!Token)
554        {
555            goto SyntaxError;
556        }
557    }
558
559    if (Gbl_DirectiveInfo[Directive].ArgCount >= 2)
560    {
561        Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
562        if (!Token2)
563        {
564            goto SyntaxError;
565        }
566    }
567
568    /*
569     * At this point, if we are ignoring the current code block,
570     * do not process any more directives (i.e., ignore them also.)
571     * For "if" style directives, open/push a new block anyway. We
572     * must do this to keep track of #endif directives
573     */
574    if (Gbl_IgnoringThisCodeBlock)
575    {
576        switch (Directive)
577        {
578        case PR_DIRECTIVE_IF:
579        case PR_DIRECTIVE_IFDEF:
580        case PR_DIRECTIVE_IFNDEF:
581
582            PrPushDirective (Directive, Token);
583            PrDbgPrint ("Ignoring", Gbl_DirectiveInfo[Directive].Name);
584            break;
585
586        default:
587            break;
588        }
589
590        return;
591    }
592
593    /*
594     * Execute the directive
595     */
596    PrDbgPrint ("Begin execution", Gbl_DirectiveInfo[Directive].Name);
597
598    switch (Directive)
599    {
600    case PR_DIRECTIVE_IF:
601
602        TokenOffset = Token - Gbl_MainTokenBuffer;
603
604        /* Need to expand #define macros in the expression string first */
605
606        Status = PrResolveIntegerExpression (
607            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
608        if (ACPI_FAILURE (Status))
609        {
610            return;
611        }
612
613        PrPushDirective (Directive, Token);
614        if (!Value)
615        {
616            Gbl_IgnoringThisCodeBlock = TRUE;
617        }
618
619        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
620            "Resolved #if: %8.8X%8.8X %s\n",
621            Gbl_CurrentLineNumber, ACPI_FORMAT_UINT64 (Value),
622            Gbl_IgnoringThisCodeBlock ? "<Skipping Block>" : "<Executing Block>");
623        break;
624
625    case PR_DIRECTIVE_IFDEF:
626
627        PrPushDirective (Directive, Token);
628        if (!PrMatchDefine (Token))
629        {
630            Gbl_IgnoringThisCodeBlock = TRUE;
631        }
632
633        PrDbgPrint ("Evaluated", "ifdef");
634        break;
635
636    case PR_DIRECTIVE_IFNDEF:
637
638        PrPushDirective (Directive, Token);
639        if (PrMatchDefine (Token))
640        {
641            Gbl_IgnoringThisCodeBlock = TRUE;
642        }
643
644        PrDbgPrint ("Evaluated", "ifndef");
645        break;
646
647    case PR_DIRECTIVE_DEFINE:
648        /*
649         * By definition, if first char after the name is a paren,
650         * this is a function macro.
651         */
652        TokenOffset = Token - Gbl_MainTokenBuffer + strlen (Token);
653        if (*(&Gbl_CurrentLineBuffer[TokenOffset]) == '(')
654        {
655#ifndef MACROS_SUPPORTED
656            AcpiOsPrintf ("%s ERROR - line %u: #define macros are not supported yet\n",
657                Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber);
658            exit(1);
659#else
660            PrAddMacro (Token, Next);
661#endif
662        }
663        else
664        {
665            /* Use the remainder of the line for the #define */
666
667            Token2 = *Next;
668            if (Token2)
669            {
670                while ((*Token2 == ' ') || (*Token2 == '\t'))
671                {
672                    Token2++;
673                }
674                End = Token2;
675                while (*End != '\n')
676                {
677                    End++;
678                }
679                *End = 0;
680            }
681            else
682            {
683                Token2 = "";
684            }
685#if 0
686            Token2 = PrGetNextToken (NULL, "\n", /*PR_TOKEN_SEPARATORS,*/ Next);
687            if (!Token2)
688            {
689                Token2 = "";
690            }
691#endif
692            DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
693                "New #define: %s->%s\n",
694                Gbl_CurrentLineNumber, Token, Token2);
695
696            PrAddDefine (Token, Token2, FALSE);
697        }
698        break;
699
700    case PR_DIRECTIVE_ERROR:
701
702        /* Note: No macro expansion */
703
704        PrError (ASL_ERROR, ASL_MSG_ERROR_DIRECTIVE,
705            THIS_TOKEN_OFFSET (Token));
706
707        Gbl_SourceLine = 0;
708        Gbl_NextError = Gbl_ErrorLog;
709        CmCleanupAndExit ();
710        exit(1);
711
712    case PR_DIRECTIVE_INCLUDE:
713
714        Token = PrGetNextToken (NULL, " \"<>", Next);
715        if (!Token)
716        {
717            goto SyntaxError;
718        }
719
720        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
721            "Start #include file \"%s\"\n", Gbl_CurrentLineNumber,
722            Token, Gbl_CurrentLineNumber);
723
724        PrDoIncludeFile (Token);
725        break;
726
727    case PR_DIRECTIVE_INCLUDEBUFFER:
728
729        Token = PrGetNextToken (NULL, " \"<>", Next);
730        if (!Token)
731        {
732            goto SyntaxError;
733        }
734
735        Token2 = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
736        if (!Token2)
737        {
738            goto SyntaxError;
739        }
740
741        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
742            "Start #includebuffer input from file \"%s\", buffer name %s\n",
743            Gbl_CurrentLineNumber, Token, Token2);
744
745        PrDoIncludeBuffer (Token, Token2);
746        break;
747
748    case PR_DIRECTIVE_LINE:
749
750        TokenOffset = Token - Gbl_MainTokenBuffer;
751
752        Status = PrResolveIntegerExpression (
753            &Gbl_CurrentLineBuffer[TokenOffset-1], &Value);
754        if (ACPI_FAILURE (Status))
755        {
756            return;
757        }
758
759        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
760            "User #line invocation %s\n", Gbl_CurrentLineNumber,
761            Token);
762
763        /* Update local line numbers */
764
765        Gbl_CurrentLineNumber = (UINT32) Value;
766        Gbl_PreviousLineNumber = 0;
767
768        /* Emit #line into the preprocessor file */
769
770        FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
771            Gbl_CurrentLineNumber, Gbl_Files[ASL_FILE_INPUT].Filename);
772        break;
773
774    case PR_DIRECTIVE_PRAGMA:
775
776        if (!strcmp (Token, "disable"))
777        {
778            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
779            if (!Token)
780            {
781                goto SyntaxError;
782            }
783
784            TokenOffset = Token - Gbl_MainTokenBuffer;
785            AslDisableException (&Gbl_CurrentLineBuffer[TokenOffset]);
786        }
787        else if (!strcmp (Token, "message"))
788        {
789            Token = PrGetNextToken (NULL, PR_TOKEN_SEPARATORS, Next);
790            if (!Token)
791            {
792                goto SyntaxError;
793            }
794
795            TokenOffset = Token - Gbl_MainTokenBuffer;
796            AcpiOsPrintf ("%s\n", &Gbl_CurrentLineBuffer[TokenOffset]);
797        }
798        else
799        {
800            PrError (ASL_ERROR, ASL_MSG_UNKNOWN_PRAGMA,
801                THIS_TOKEN_OFFSET (Token));
802            return;
803        }
804
805        break;
806
807    case PR_DIRECTIVE_UNDEF:
808
809        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
810            "#undef: %s\n", Gbl_CurrentLineNumber, Token);
811
812        PrRemoveDefine (Token);
813        break;
814
815    case PR_DIRECTIVE_WARNING:
816
817        PrError (ASL_WARNING, ASL_MSG_WARNING_DIRECTIVE,
818            THIS_TOKEN_OFFSET (Token));
819        break;
820
821    default:
822
823        /* Should never get here */
824        DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
825            "Unrecognized directive: %u\n",
826            Gbl_CurrentLineNumber, Directive);
827        break;
828    }
829
830    return;
831
832SyntaxError:
833
834    PrError (ASL_ERROR, ASL_MSG_DIRECTIVE_SYNTAX,
835        THIS_TOKEN_OFFSET (DirectiveToken));
836    return;
837}
838
839
840/*******************************************************************************
841 *
842 * FUNCTION:    PrMatchDirective
843 *
844 * PARAMETERS:  Directive           - Pointer to directive name token
845 *
846 * RETURN:      Index into command array, -1 if not found
847 *
848 * DESCRIPTION: Lookup the incoming directive in the known directives table.
849 *
850 ******************************************************************************/
851
852static int
853PrMatchDirective (
854    char                    *Directive)
855{
856    int                     i;
857
858
859    if (!Directive || Directive[0] == 0)
860    {
861        return (ASL_DIRECTIVE_NOT_FOUND);
862    }
863
864    for (i = 0; Gbl_DirectiveInfo[i].Name; i++)
865    {
866        if (!strcmp (Gbl_DirectiveInfo[i].Name, Directive))
867        {
868            return (i);
869        }
870    }
871
872    return (ASL_DIRECTIVE_NOT_FOUND);    /* Command not recognized */
873}
874
875
876/*******************************************************************************
877 *
878 * FUNCTION:    PrPushDirective
879 *
880 * PARAMETERS:  Directive           - Encoded directive ID
881 *              Argument            - String containing argument to the
882 *                                    directive
883 *
884 * RETURN:      None
885 *
886 * DESCRIPTION: Push an item onto the directive stack. Used for processing
887 *              nested #if/#else type conditional compilation directives.
888 *              Specifically: Used on detection of #if/#ifdef/#ifndef to open
889 *              a block.
890 *
891 ******************************************************************************/
892
893static void
894PrPushDirective (
895    int                     Directive,
896    char                    *Argument)
897{
898    DIRECTIVE_INFO          *Info;
899
900
901    /* Allocate and populate a stack info item */
902
903    Info = ACPI_ALLOCATE (sizeof (DIRECTIVE_INFO));
904
905    Info->Next = Gbl_DirectiveStack;
906    Info->Directive = Directive;
907    Info->IgnoringThisCodeBlock = Gbl_IgnoringThisCodeBlock;
908    strncpy (Info->Argument, Argument, MAX_ARGUMENT_LENGTH);
909
910    DbgPrint (ASL_DEBUG_OUTPUT,
911        "Pr(%.4u) - [%u %s] %*s Pushed [#%s %s]: IgnoreFlag = %s\n",
912        Gbl_CurrentLineNumber, Gbl_IfDepth,
913        Gbl_IgnoringThisCodeBlock ? "I" : "E",
914        Gbl_IfDepth * 4, " ",
915        Gbl_DirectiveInfo[Directive].Name,
916        Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
917
918    /* Push new item */
919
920    Gbl_DirectiveStack = Info;
921    Gbl_IfDepth++;
922}
923
924
925/*******************************************************************************
926 *
927 * FUNCTION:    PrPopDirective
928 *
929 * PARAMETERS:  None
930 *
931 * RETURN:      Status. Error if the stack is empty.
932 *
933 * DESCRIPTION: Pop an item off the directive stack. Used for processing
934 *              nested #if/#else type conditional compilation directives.
935 *              Specifically: Used on detection of #elif and #endif to remove
936 *              the original #if/#ifdef/#ifndef from the stack and close
937 *              the block.
938 *
939 ******************************************************************************/
940
941static ACPI_STATUS
942PrPopDirective (
943    void)
944{
945    DIRECTIVE_INFO          *Info;
946
947
948    /* Check for empty stack */
949
950    Info = Gbl_DirectiveStack;
951    if (!Info)
952    {
953        return (AE_ERROR);
954    }
955
956    /* Pop one item, keep globals up-to-date */
957
958    Gbl_IfDepth--;
959    Gbl_IgnoringThisCodeBlock = Info->IgnoringThisCodeBlock;
960    Gbl_DirectiveStack = Info->Next;
961
962    DbgPrint (ASL_DEBUG_OUTPUT,
963        "Pr(%.4u) - [%u %s] %*s Popped [#%s %s]: IgnoreFlag now = %s\n",
964        Gbl_CurrentLineNumber, Gbl_IfDepth,
965        Gbl_IgnoringThisCodeBlock ? "I" : "E",
966        Gbl_IfDepth * 4, " ",
967        Gbl_DirectiveInfo[Info->Directive].Name,
968        Info->Argument, Gbl_IgnoringThisCodeBlock ? "TRUE" : "FALSE");
969
970    ACPI_FREE (Info);
971    return (AE_OK);
972}
973
974
975/*******************************************************************************
976 *
977 * FUNCTION:    PrDbgPrint
978 *
979 * PARAMETERS:  Action              - Action being performed
980 *              DirectiveName       - Directive being processed
981 *
982 * RETURN:      None
983 *
984 * DESCRIPTION: Special debug print for directive processing.
985 *
986 ******************************************************************************/
987
988static void
989PrDbgPrint (
990    char                    *Action,
991    char                    *DirectiveName)
992{
993
994    DbgPrint (ASL_DEBUG_OUTPUT, "Pr(%.4u) - [%u %s] "
995        "%*s %s #%s, IfDepth %u\n",
996        Gbl_CurrentLineNumber, Gbl_IfDepth,
997        Gbl_IgnoringThisCodeBlock ? "I" : "E",
998        Gbl_IfDepth * 4, " ",
999        Action, DirectiveName, Gbl_IfDepth);
1000}
1001
1002
1003/*******************************************************************************
1004 *
1005 * FUNCTION:    PrDoIncludeFile
1006 *
1007 * PARAMETERS:  Pathname                - Name of the input file
1008 *
1009 * RETURN:      None.
1010 *
1011 * DESCRIPTION: Open an include file, from #include.
1012 *
1013 ******************************************************************************/
1014
1015static void
1016PrDoIncludeFile (
1017    char                    *Pathname)
1018{
1019    char                    *FullPathname;
1020
1021
1022    (void) PrOpenIncludeFile (Pathname, "r", &FullPathname);
1023}
1024
1025
1026/*******************************************************************************
1027 *
1028 * FUNCTION:    PrDoIncludeBuffer
1029 *
1030 * PARAMETERS:  Pathname                - Name of the input binary file
1031 *              BufferName              - ACPI namepath of the buffer
1032 *
1033 * RETURN:      None.
1034 *
1035 * DESCRIPTION: Create an ACPI buffer object from a binary file. The contents
1036 *              of the file are emitted into the buffer object as ascii
1037 *              hex data. From #includebuffer.
1038 *
1039 ******************************************************************************/
1040
1041static void
1042PrDoIncludeBuffer (
1043    char                    *Pathname,
1044    char                    *BufferName)
1045{
1046    char                    *FullPathname;
1047    FILE                    *BinaryBufferFile;
1048    UINT32                  i = 0;
1049    UINT8                   c;
1050
1051
1052    BinaryBufferFile = PrOpenIncludeFile (Pathname, "rb", &FullPathname);
1053    if (!BinaryBufferFile)
1054    {
1055        return;
1056    }
1057
1058    /* Emit "Name (XXXX, Buffer() {" header */
1059
1060    FlPrintFile (ASL_FILE_PREPROCESSOR, "Name (%s, Buffer()\n{", BufferName);
1061
1062    /* Dump the entire file in ascii hex format */
1063
1064    while (fread (&c, 1, 1, BinaryBufferFile))
1065    {
1066        if (!(i % 8))
1067        {
1068            FlPrintFile (ASL_FILE_PREPROCESSOR, "\n   ", c);
1069        }
1070
1071        FlPrintFile (ASL_FILE_PREPROCESSOR, " 0x%2.2X,", c);
1072        i++;
1073    }
1074
1075    DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
1076        "#includebuffer: read %u bytes from %s\n",
1077        Gbl_CurrentLineNumber, i, FullPathname);
1078
1079    /* Close the Name() operator */
1080
1081    FlPrintFile (ASL_FILE_PREPROCESSOR, "\n})\n", BufferName);
1082    fclose (BinaryBufferFile);
1083}
1084