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