prutils.c revision 1.1.1.14 1 /******************************************************************************
2 *
3 * Module Name: prutils - Preprocessor utilities
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, 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 *
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
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: PrReplaceResizeSubstring
180 *
181 * PARAMETERS: Args - Struct containing name, offset & usecount
182 * Diff1 - Difference in lengths when new < old
183 * Diff2 - Difference in lengths when new > old
184 * i - The curr. no. of iteration of replacement
185 * Token - Substring that replaces Args->Name
186 *
187 * RETURN: None
188 *
189 * DESCRIPTION: Advanced substring replacement in a string using resized buffer.
190 *
191 ******************************************************************************/
192
193 void
194 PrReplaceResizeSubstring(
195 PR_MACRO_ARG *Args,
196 UINT32 Diff1,
197 UINT32 Diff2,
198 UINT32 i,
199 char *Token)
200 {
201 UINT32 b, PrevOffset;
202 char *temp;
203 char macro_sep[64];
204
205
206 AslGbl_MacroTokenReplaceBuffer = (char *) realloc (AslGbl_MacroTokenReplaceBuffer,
207 (2 * (strlen (AslGbl_MacroTokenBuffer))));
208
209 strcpy (macro_sep, "~,() {}!*/%+-<>=&^|\"\t\n");
210
211 /*
212 * When the replacement argument (during invocation) length
213 * < replaced parameter (in the macro function definition
214 * and its expansion) length
215 */
216 if (Diff1 != 0)
217 {
218 /*
219 * We save the offset value to reset it after replacing each
220 * instance of each arg and setting the offset value to
221 * the start of the arg to be replaced since it changes
222 * with each iteration when arg length != token length
223 */
224 PrevOffset = Args->Offset[i];
225 temp = strstr (AslGbl_MacroTokenBuffer, Args->Name);
226
227 ResetHere1:
228 temp = strstr (temp, Args->Name);
229 Args->Offset[i] = strlen (AslGbl_MacroTokenBuffer) -
230 strlen (temp);
231 if (Args->Offset[i] == 0)
232 {
233 goto JumpHere1;
234 }
235 if ((strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] - 1)])) &&
236 (strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] + strlen (Args->Name))])))
237 {
238 Args->Offset[i] += 0;
239 }
240 else
241 {
242 temp += strlen (Args->Name);
243 goto ResetHere1;
244 }
245
246 /*
247 * For now, we simply set the extra char positions (generated
248 * due to longer name replaced by shorter name) to whitespace
249 * chars so it will be ignored during compilation
250 */
251 JumpHere1:
252 b = strlen (Token) + Args->Offset[i];
253 memset (&AslGbl_MacroTokenBuffer[b], ' ', Diff1);
254
255 # if 0
256
257 /* Work in progress as of 03/08/2023 - experimental 'if' block
258 * to test code for removing extra whitespaces from the macro
259 * replacement when replacement arg < replaced param
260 */
261 char Buff[8192];
262 /* char* Replace; */
263 /* Replace = Buff; */
264
265 for (j = 0; j < strlen (AslGbl_MacroTokenBuffer); j++)
266 {
267 Buff[j] = AslGbl_MacroTokenBuffer[j];
268 }
269 Buff[strlen (AslGbl_MacroTokenBuffer)] = '\0';
270 //fprintf (stderr, "Buff: %s\n", Buff);
271
272 UINT32 len = strlen (Buff);
273
274 for (j = 0; j < len; j++)
275 {
276 if (Buff[0] == ' ')
277 {
278 for (j = 0; j < (len - 1); j++)
279 {
280 Buff[j] = Buff[j + 1];
281 }
282 Buff[j] = '\0';
283 len--;
284 j = -1;
285 continue;
286 }
287
288 if (Buff[j] == ' ' && Buff[j + 1] == ' ')
289 {
290 for (k = 0; k < (len - 1); k++)
291 {
292 Buff[j] = Buff[j + 1];
293 }
294 Buff[j] = '\0';
295 len--;
296 j--;
297 }
298 }
299 //fprintf(stderr, "Buff: %s\n", Buff);
300
301 for (k = 0; k < strlen (Buff); k++)
302 {
303 AslGbl_MacroTokenBuffer[k] = Buff[k];
304 }
305 #endif
306
307 PrReplaceData (
308 &AslGbl_MacroTokenBuffer[Args->Offset[i]],
309 strlen (Token), Token, strlen (Token));
310
311 temp = NULL;
312 Args->Offset[i] = PrevOffset;
313 }
314
315 /*
316 * When the replacement argument (during invocation) length
317 * > replaced parameter (in the macro function definition
318 * and its expansion) length
319 */
320 else if (Diff2 != 0)
321 {
322 /* Doing the same thing with offset value as for prev case */
323
324 PrevOffset = Args->Offset[i];
325 temp = strstr (AslGbl_MacroTokenBuffer, Args->Name);
326
327 ResetHere2:
328 temp = strstr (temp, Args->Name);
329 Args->Offset[i] = strlen (AslGbl_MacroTokenBuffer) -
330 strlen (temp);
331 if (Args->Offset[i] == 0)
332 {
333 goto JumpHere2;
334 }
335 if ((strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] - 1)])) &&
336 (strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] + strlen (Args->Name))])))
337 {
338 Args->Offset[i] += 0;
339 }
340 else
341 {
342 temp+= strlen (Args->Name);
343 goto ResetHere2;
344 }
345
346 /*
347 * We will need to allocate some extra space in our buffer to
348 * accommodate the increase in the replacement string length
349 * over the shorter outgoing arg string and do the replacement
350 * at the correct offset value which is resetted every iteration
351 */
352 JumpHere2:
353 strncpy (AslGbl_MacroTokenReplaceBuffer, AslGbl_MacroTokenBuffer, Args->Offset[i]);
354 strcat (AslGbl_MacroTokenReplaceBuffer, Token);
355 strcat (AslGbl_MacroTokenReplaceBuffer, (AslGbl_MacroTokenBuffer +
356 (Args->Offset[i] + strlen (Args->Name))));
357
358 strcpy (AslGbl_MacroTokenBuffer, AslGbl_MacroTokenReplaceBuffer);
359
360 temp = NULL;
361 Args->Offset[i] = PrevOffset;
362 }
363
364 /*
365 * When the replacement argument (during invocation) length =
366 * replaced parameter (in the macro function definition and
367 * its expansion) length
368 */
369 else
370 {
371
372 /*
373 * We still need to reset the offset for each iteration even when
374 * arg and param lengths are same since any macro func invocation
375 * could use various cases for each separate arg-param pair
376 */
377 PrevOffset = Args->Offset[i];
378 temp = strstr (AslGbl_MacroTokenBuffer, Args->Name);
379
380 ResetHere3:
381 temp = strstr (temp, Args->Name);
382 Args->Offset[i] = strlen (AslGbl_MacroTokenBuffer) -
383 strlen (temp);
384 if (Args->Offset[i] == 0)
385 {
386 goto JumpHere3;
387 }
388 if ((strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] - 1)])) &&
389 (strchr (macro_sep, AslGbl_MacroTokenBuffer[(Args->Offset[i] + strlen (Args->Name))])))
390 {
391 Args->Offset[i] += 0;
392 }
393 else
394 {
395 temp += strlen (Args->Name);
396 goto ResetHere3;
397 }
398
399 JumpHere3:
400 PrReplaceData (
401 &AslGbl_MacroTokenBuffer[Args->Offset[i]],
402 strlen (Args->Name), Token, strlen (Token));
403 temp = NULL;
404 Args->Offset[i] = PrevOffset;
405 }
406 }
407
408
409 /*******************************************************************************
410 *
411 * FUNCTION: PrReplaceData
412 *
413 * PARAMETERS: Buffer - Original(target) buffer pointer
414 * LengthToRemove - Length to be removed from target buffer
415 * BufferToAdd - Data to be inserted into target buffer
416 * LengthToAdd - Length of BufferToAdd
417 *
418 * RETURN: Pointer to where the buffer is replaced with data
419 *
420 * DESCRIPTION: Generic buffer data replacement.
421 *
422 ******************************************************************************/
423
424 char *
425 PrReplaceData (
426 char *Buffer,
427 UINT32 LengthToRemove,
428 char *BufferToAdd,
429 UINT32 LengthToAdd)
430 {
431 UINT32 BufferLength;
432
433
434 /* Buffer is a string, so the length must include the terminating zero */
435
436 BufferLength = strlen (Buffer) + 1;
437
438 if (LengthToRemove != LengthToAdd)
439 {
440 /*
441 * Move some of the existing data
442 * 1) If adding more bytes than removing, make room for the new data
443 * 2) if removing more bytes than adding, delete the extra space
444 */
445 if (LengthToRemove > 0)
446 {
447 memmove ((Buffer + LengthToAdd), (Buffer + LengthToRemove),
448 (BufferLength - LengthToRemove));
449 }
450 }
451
452
453 /* Now we can move in the new data */
454
455 if (LengthToAdd > 0)
456 {
457 memmove (Buffer, BufferToAdd, LengthToAdd);
458 }
459 return (Buffer + LengthToAdd);
460 }
461
462
463 /*******************************************************************************
464 *
465 * FUNCTION: PrOpenIncludeFile
466 *
467 * PARAMETERS: Filename - Filename or pathname for include file
468 *
469 * RETURN: None.
470 *
471 * DESCRIPTION: Open an include file and push it on the input file stack.
472 *
473 ******************************************************************************/
474
475 FILE *
476 PrOpenIncludeFile (
477 char *Filename,
478 char *OpenMode,
479 char **FullPathname)
480 {
481 FILE *IncludeFile;
482 ASL_INCLUDE_DIR *NextDir;
483
484
485 /* Start the actual include file on the next line */
486
487 AslGbl_CurrentLineOffset++;
488
489 /* Attempt to open the include file */
490 /* If the file specifies an absolute path, just open it */
491
492 if ((Filename[0] == '/') ||
493 (Filename[0] == '\\') ||
494 (Filename[1] == ':'))
495 {
496 IncludeFile = PrOpenIncludeWithPrefix (
497 "", Filename, OpenMode, FullPathname);
498 if (!IncludeFile)
499 {
500 goto ErrorExit;
501 }
502 return (IncludeFile);
503 }
504
505 /*
506 * The include filename is not an absolute path.
507 *
508 * First, search for the file within the "local" directory -- meaning
509 * the same directory that contains the source file.
510 *
511 * Construct the file pathname from the global directory name.
512 */
513 IncludeFile = PrOpenIncludeWithPrefix (
514 AslGbl_DirectoryPath, Filename, OpenMode, FullPathname);
515 if (IncludeFile)
516 {
517 return (IncludeFile);
518 }
519
520 /*
521 * Second, search for the file within the (possibly multiple)
522 * directories specified by the -I option on the command line.
523 */
524 NextDir = AslGbl_IncludeDirList;
525 while (NextDir)
526 {
527 IncludeFile = PrOpenIncludeWithPrefix (
528 NextDir->Dir, Filename, OpenMode, FullPathname);
529 if (IncludeFile)
530 {
531 return (IncludeFile);
532 }
533
534 NextDir = NextDir->Next;
535 }
536
537 /* We could not open the include file after trying very hard */
538
539 ErrorExit:
540 sprintf (AslGbl_MainTokenBuffer, "%s, %s", Filename, strerror (errno));
541 PrError (ASL_ERROR, ASL_MSG_INCLUDE_FILE_OPEN, 0);
542 return (NULL);
543 }
544
545
546 /*******************************************************************************
547 *
548 * FUNCTION: FlOpenIncludeWithPrefix
549 *
550 * PARAMETERS: PrefixDir - Prefix directory pathname. Can be a zero
551 * length string.
552 * Filename - The include filename from the source ASL.
553 *
554 * RETURN: Valid file descriptor if successful. Null otherwise.
555 *
556 * DESCRIPTION: Open an include file and push it on the input file stack.
557 *
558 ******************************************************************************/
559
560 FILE *
561 PrOpenIncludeWithPrefix (
562 char *PrefixDir,
563 char *Filename,
564 char *OpenMode,
565 char **FullPathname)
566 {
567 FILE *IncludeFile;
568 char *Pathname;
569
570
571 /* Build the full pathname to the file */
572
573 Pathname = FlMergePathnames (PrefixDir, Filename);
574
575 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
576 "Include: Opening file - \"%s\"\n",
577 AslGbl_CurrentLineNumber, Pathname);
578
579 /* Attempt to open the file, push if successful */
580
581 IncludeFile = fopen (Pathname, OpenMode);
582 if (!IncludeFile)
583 {
584 return (NULL);
585 }
586
587 /* Push the include file on the open input file stack */
588
589 PrPushInputFileStack (IncludeFile, Pathname);
590 *FullPathname = Pathname;
591 return (IncludeFile);
592 }
593
594
595 /*******************************************************************************
596 *
597 * FUNCTION: AslPushInputFileStack
598 *
599 * PARAMETERS: InputFile - Open file pointer
600 * Filename - Name of the file
601 *
602 * RETURN: None
603 *
604 * DESCRIPTION: Push the InputFile onto the file stack, and point the parser
605 * to this file. Called when an include file is successfully
606 * opened.
607 *
608 ******************************************************************************/
609
610 void
611 PrPushInputFileStack (
612 FILE *InputFile,
613 char *Filename)
614 {
615 PR_FILE_NODE *Fnode;
616
617
618 AslGbl_HasIncludeFiles = TRUE;
619
620 /* Save the current state in an Fnode */
621
622 Fnode = UtLocalCalloc (sizeof (PR_FILE_NODE));
623
624 Fnode->File = AslGbl_Files[ASL_FILE_INPUT].Handle;
625 Fnode->Next = AslGbl_InputFileList;
626 Fnode->Filename = AslGbl_Files[ASL_FILE_INPUT].Filename;
627 Fnode->CurrentLineNumber = AslGbl_CurrentLineNumber;
628
629 /* Push it on the stack */
630
631 AslGbl_InputFileList = Fnode;
632
633 DbgPrint (ASL_PARSE_OUTPUT, PR_PREFIX_ID
634 "Push InputFile Stack: handle %p\n\n",
635 AslGbl_CurrentLineNumber, InputFile);
636
637 /* Reset the global line count and filename */
638
639 AslGbl_Files[ASL_FILE_INPUT].Filename =
640 UtLocalCacheCalloc (strlen (Filename) + 1);
641 strcpy (AslGbl_Files[ASL_FILE_INPUT].Filename, Filename);
642
643 AslGbl_Files[ASL_FILE_INPUT].Handle = InputFile;
644 AslGbl_CurrentLineNumber = 1;
645
646 /* Emit a new #line directive for the include file */
647
648 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n", 1, Filename);
649 }
650
651
652 /*******************************************************************************
653 *
654 * FUNCTION: AslPopInputFileStack
655 *
656 * PARAMETERS: None
657 *
658 * RETURN: 0 if a node was popped, -1 otherwise
659 *
660 * DESCRIPTION: Pop the top of the input file stack and point the parser to
661 * the saved parse buffer contained in the fnode. Also, set the
662 * global line counters to the saved values. This function is
663 * called when an include file reaches EOF.
664 *
665 ******************************************************************************/
666
667 BOOLEAN
668 PrPopInputFileStack (
669 void)
670 {
671 PR_FILE_NODE *Fnode;
672
673
674 Fnode = AslGbl_InputFileList;
675 DbgPrint (ASL_PARSE_OUTPUT, "\n" PR_PREFIX_ID
676 "Pop InputFile Stack, Fnode %p\n\n",
677 AslGbl_CurrentLineNumber, Fnode);
678
679 if (!Fnode)
680 {
681 return (FALSE);
682 }
683
684 /* Close the current include file */
685
686 fclose (AslGbl_Files[ASL_FILE_INPUT].Handle);
687
688 /* Update the top-of-stack */
689
690 AslGbl_InputFileList = Fnode->Next;
691
692 /* Reset global line counter and filename */
693
694 AslGbl_Files[ASL_FILE_INPUT].Filename = Fnode->Filename;
695 AslGbl_Files[ASL_FILE_INPUT].Handle = Fnode->File;
696 AslGbl_CurrentLineNumber = Fnode->CurrentLineNumber;
697
698 /* Emit a new #line directive after the include file */
699
700 FlPrintFile (ASL_FILE_PREPROCESSOR, "#line %u \"%s\"\n",
701 AslGbl_CurrentLineNumber, Fnode->Filename);
702
703 /* All done with this node */
704
705 ACPI_FREE (Fnode);
706 return (TRUE);
707 }
708