Home | History | Annotate | Line # | Download | only in compiler
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