1 /******************************************************************************
2 *
3 * Module Name: prutils - Preprocessor utilities
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 #include "aslcompiler.h"
45
46 #define _COMPONENT ASL_PREPROCESSOR
47 ACPI_MODULE_NAME ("prutils")
48
49
50 /******************************************************************************
51 *
52 * FUNCTION: PrGetNextToken
53 *
54 * PARAMETERS: Buffer - Current line buffer
55 * MatchString - String with valid token delimiters
56 * Next - Set to next possible token in buffer
57 *
58 * RETURN: Next token (null-terminated). Modifies the input line.
59 * Remainder of line is stored in *Next.
60 *
61 * DESCRIPTION: Local implementation of strtok() with local storage for the
62 * next pointer. Not only thread-safe, but allows multiple
63 * parsing of substrings such as expressions.
64 *
65 *****************************************************************************/
66
67 char *
PrGetNextToken(char * Buffer,char * MatchString,char ** Next)68 PrGetNextToken (
69 char *Buffer,
70 char *MatchString,
71 char **Next)
72 {
73 char *TokenStart;
74
75
76 if (!Buffer)
77 {
78 /* Use Next if it is valid */
79
80 Buffer = *Next;
81 if (!(*Next))
82 {
83 return (NULL);
84 }
85 }
86
87 /* Skip any leading delimiters */
88
89 while (*Buffer)
90 {
91 if (strchr (MatchString, *Buffer))
92 {
93 Buffer++;
94 }
95 else
96 {
97 break;
98 }
99 }
100
101 /* Anything left on the line? */
102
103 if (!(*Buffer))
104 {
105 *Next = NULL;
106 return (NULL);
107 }
108
109 TokenStart = Buffer;
110
111 /* Find the end of this token */
112
113 while (*Buffer)
114 {
115 if (strchr (MatchString, *Buffer))
116 {
117 *Buffer = 0;
118 *Next = Buffer+1;
119 if (!**Next)
120 {
121 *Next = NULL;
122 }
123
124 return (TokenStart);
125 }
126
127 Buffer++;
128 }
129
130 *Next = NULL;
131 return (TokenStart);
132 }
133
134
135 /*******************************************************************************
136 *
137 * FUNCTION: PrError
138 *
139 * PARAMETERS: Level - Seriousness (Warning/error, etc.)
140 * MessageId - Index into global message buffer
141 * Column - Column in current line
142 *
143 * RETURN: None
144 *
145 * DESCRIPTION: Preprocessor error reporting. Front end to AslCommonError2
146 *
147 ******************************************************************************/
148
149 void
PrError(UINT8 Level,UINT16 MessageId,UINT32 Column)150 PrError (
151 UINT8 Level,
152 UINT16 MessageId,
153 UINT32 Column)
154 {
155 #if 0
156 AcpiOsPrintf ("%s (%u) : %s", AslGbl_Files[ASL_FILE_INPUT].Filename,
157 AslGbl_CurrentLineNumber, AslGbl_CurrentLineBuffer);
158 #endif
159
160
161 if (Column > 120)
162 {
163 Column = 0;
164 }
165
166 /* TBD: Need Logical line number? */
167
168 AslCommonError2 (Level, MessageId,
169 AslGbl_CurrentLineNumber, Column,
170 AslGbl_CurrentLineBuffer,
171 AslGbl_Files[ASL_FILE_INPUT].Filename, "Preprocessor");
172
173 AslGbl_PreprocessorError = TRUE;
174 }
175
176
177 /*******************************************************************************
178 *
179 * FUNCTION: PrReplaceData
180 *
181 * PARAMETERS: Buffer - Original(target) buffer pointer
182 * LengthToRemove - Length to be removed from target buffer
183 * BufferToAdd - Data to be inserted into target buffer
184 * LengthToAdd - Length of BufferToAdd
185 *
186 * RETURN: None
187 *
188 * DESCRIPTION: Generic buffer data replacement.
189 *
190 ******************************************************************************/
191
192 void
PrReplaceData(char * Buffer,UINT32 LengthToRemove,char * BufferToAdd,UINT32 LengthToAdd)193 PrReplaceData (
194 char *Buffer,
195 UINT32 LengthToRemove,
196 char *BufferToAdd,
197 UINT32 LengthToAdd)
198 {
199 UINT32 BufferLength;
200
201
202 /* Buffer is a string, so the length must include the terminating zero */
203
204 BufferLength = strlen (Buffer) + 1;
205
206 if (LengthToRemove != LengthToAdd)
207 {
208 /*
209 * Move some of the existing data
210 * 1) If adding more bytes than removing, make room for the new data
211 * 2) if removing more bytes than adding, delete the extra space
212 */
213 if (LengthToRemove > 0)
214 {
215 memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove),
216 (BufferLength - LengthToRemove));
217 }
218 }
219
220 /* Now we can move in the new data */
221
222 if (LengthToAdd > 0)
223 {
224 memmove (Buffer, BufferToAdd, LengthToAdd);
225 }
226 }
227
228
229 /*******************************************************************************
230 *
231 * FUNCTION: PrOpenIncludeFile
232 *
233 * PARAMETERS: Filename - Filename or pathname for include file
234 *
235 * RETURN: None.
236 *
237 * DESCRIPTION: Open an include file and push it on the input file stack.
238 *
239 ******************************************************************************/
240
241 FILE *
PrOpenIncludeFile(char * Filename,char * OpenMode,char ** FullPathname)242 PrOpenIncludeFile (
243 char *Filename,
244 char *OpenMode,
245 char **FullPathname)
246 {
247 FILE *IncludeFile;
248 ASL_INCLUDE_DIR *NextDir;
249
250
251 /* Start the actual include file on the next line */
252
253 AslGbl_CurrentLineOffset++;
254
255 /* Attempt to open the include file */
256 /* If the file specifies an absolute path, just open it */
257
258 if ((Filename[0] == '/') ||
259 (Filename[0] == '\\') ||
260 (Filename[1] == ':'))
261 {
262 IncludeFile = PrOpenIncludeWithPrefix (
263 "", Filename, OpenMode, FullPathname);
264 if (!IncludeFile)
265 {
266 goto ErrorExit;
267 }
268 return (IncludeFile);
269 }
270
271 /*
272 * The include filename is not an absolute path.
273 *
274 * First, search for the file within the "local" directory -- meaning
275 * the same directory that contains the source file.
276 *
277 * Construct the file pathname from the global directory name.
278 */
279 IncludeFile = PrOpenIncludeWithPrefix (
280 AslGbl_DirectoryPath, Filename, OpenMode, FullPathname);
281 if (IncludeFile)
282 {
283 return (IncludeFile);
284 }
285
286 /*
287 * Second, search for the file within the (possibly multiple)
288 * directories specified by the -I option on the command line.
289 */
290 NextDir = AslGbl_IncludeDirList;
291 while (NextDir)
292 {
293 IncludeFile = PrOpenIncludeWithPrefix (
294 NextDir->Dir, Filename, OpenMode, FullPathname);
295 if (IncludeFile)
296 {
297 return (IncludeFile);
298 }
299
300 NextDir = NextDir->Next;
301 }
302
303 /* We could not open the include file after trying very hard */
304
305 ErrorExit:
306 snprintf (AslGbl_MainTokenBuffer, ASL_DEFAULT_LINE_BUFFER_SIZE, "%s, %s",
307 Filename, strerror (errno));
308 PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0);
309 return (NULL);
310 }
311
312
313 /*******************************************************************************
314 *
315 * FUNCTION: FlOpenIncludeWithPrefix
316 *
317 * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero
318 * length string.
319 * Filename - The include filename from the source ASL.
320 *
321 * RETURN: Valid file descriptor if successful. Null otherwise.
322 *
323 * DESCRIPTION: Open an include file and push it on the input file stack.
324 *
325 ******************************************************************************/
326
327 FILE *
PrOpenIncludeWithPrefix(char * PrefixDir,char * Filename,char * OpenMode,char ** FullPathname)328 PrOpenIncludeWithPrefix (
329 char *PrefixDir,
330 char *Filename,
331 char *OpenMode,
332 char **FullPathname)
333 {
334 FILE *IncludeFile;
335 char *Pathname;
336
337
338 /* Build the full pathname to the file */
339
340 Pathname = FlMergePathnames (PrefixDir, Filename);
341
342 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
343 "Include: Opening file - \"%s\"\n",
344 AslGbl_CurrentLineNumber, Pathname);
345
346 /* Attempt to open the file, push if successful */
347
348 IncludeFile = fopen (Pathname, OpenMode);
349 if (!IncludeFile)
350 {
351 return (NULL);
352 }
353
354 /* Push the include file on the open input file stack */
355
356 PrPushInputFileStack (IncludeFile, Pathname);
357 *FullPathname = Pathname;
358 return (IncludeFile);
359 }
360
361
362 /*******************************************************************************
363 *
364 * FUNCTION: AslPushInputFileStack
365 *
366 * PARAMETERS: InputFile - Open file pointer
367 * Filename - Name of the file
368 *
369 * RETURN: None
370 *
371 * DESCRIPTION: Push the InputFile onto the file stack, and point the parser
372 * to this file. Called when an include file is successfully
373 * opened.
374 *
375 ******************************************************************************/
376
377 void
PrPushInputFileStack(FILE * InputFile,char * Filename)378 PrPushInputFileStack (
379 FILE *InputFile,
380 char *Filename)
381 {
382 PR_FILE_NODE *Fnode;
383
384
385 AslGbl_HasIncludeFiles = TRUE;
386
387 /* Save the current state in an Fnode */
388
389 Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE));
390
391 Fnode->File = AslGbl_Files[ASL_FILE_INPUT].Handle;
392 Fnode->Next = AslGbl_InputFileList;
393 Fnode->Filename = AslGbl_Files[ASL_FILE_INPUT].Filename;
394 Fnode->CurrentLineNumber = AslGbl_CurrentLineNumber;
395
396 /* Push it on the stack */
397
398 AslGbl_InputFileList = Fnode;
399
400 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
401 "Push InputFile Stack: handle %p\n\n",
402 AslGbl_CurrentLineNumber, InputFile);
403
404 /* Reset the global line count and filename */
405
406 AslGbl_Files[ASL_FILE_INPUT].Filename =
407 UtLocalCacheCalloc (strlen (Filename) + 1);
408 strcpy (AslGbl_Files[ASL_FILE_INPUT].Filename, Filename);
409
410 AslGbl_Files[ASL_FILE_INPUT].Handle = InputFile;
411 AslGbl_CurrentLineNumber = 1;
412
413 /* Emit a new #line directive for the include file */
414
415 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 1, Filename);
416 }
417
418
419 /*******************************************************************************
420 *
421 * FUNCTION: AslPopInputFileStack
422 *
423 * PARAMETERS: None
424 *
425 * RETURN: 0 if a node was popped, -1 otherwise
426 *
427 * DESCRIPTION: Pop the top of the input file stack and point the parser to
428 * the saved parse buffer contained in the fnode. Also, set the
429 * global line counters to the saved values. This function is
430 * called when an include file reaches EOF.
431 *
432 ******************************************************************************/
433
434 BOOLEAN
PrPopInputFileStack(void)435 PrPopInputFileStack (
436 void)
437 {
438 PR_FILE_NODE *Fnode;
439
440
441 Fnode = AslGbl_InputFileList;
442 DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID
443 "Pop InputFile Stack, Fnode %p\n\n",
444 AslGbl_CurrentLineNumber, Fnode);
445
446 if (!Fnode)
447 {
448 return (FALSE);
449 }
450
451 /* Close the current include file */
452
453 fclose (AslGbl_Files[ASL_FILE_INPUT].Handle);
454
455 /* Update the top-of-stack */
456
457 AslGbl_InputFileList = Fnode->Next;
458
459 /* Reset global line counter and filename */
460
461 AslGbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename;
462 AslGbl_Files[ASL_FILE_INPUT].Handle = Fnode->File;
463 AslGbl_CurrentLineNumber = Fnode->CurrentLineNumber;
464
465 /* Emit a new #line directive after the include file */
466
467 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
468 AslGbl_CurrentLineNumber, Fnode->Filename);
469
470 /* All done with this node */
471
472 ACPI_FREE (Fnode);
473 return (TRUE);
474 }
475