/****************************************************************************** * * Module Name: dtio.c - File I/O support for data table compiler * *****************************************************************************/ /* * Copyright (C) 2000 - 2011, Intel Corp. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions, and the following disclaimer, * without modification. * 2. Redistributions in binary form must reproduce at minimum a disclaimer * substantially similar to the "NO WARRANTY" disclaimer below * ("Disclaimer") and any redistribution must be conditioned upon * including a substantially similar Disclaimer requirement for further * binary redistribution. * 3. Neither the names of the above-listed copyright holders nor the names * of any contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * Alternatively, this software may be distributed under the terms of the * GNU General Public License ("GPL") version 2 as published by the Free * Software Foundation. * * NO WARRANTY * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGES. */ #define __DTIO_C__ #include "aslcompiler.h" #include "dtcompiler.h" #define _COMPONENT DT_COMPILER ACPI_MODULE_NAME ("dtio") /* Local prototypes */ static char * DtTrim ( char *String); static void DtLinkField ( DT_FIELD *Field); static void DtMergeField ( char *Value); static ACPI_STATUS DtParseLine ( char *LineBuffer, UINT32 Line, UINT32 Offset); UINT32 DtGetNextLine ( FILE *Handle); static void DtWriteBinary ( DT_SUBTABLE *Subtable, void *Context, void *ReturnValue); static void DtDumpBuffer ( UINT32 FileId, UINT8 *Buffer, UINT32 Offset, UINT32 Length); /* States for DtGetNextLine */ #define DT_NORMAL_TEXT 0 #define DT_START_QUOTED_STRING 1 #define DT_START_COMMENT 2 #define DT_SLASH_ASTERISK_COMMENT 3 #define DT_SLASH_SLASH_COMMENT 4 #define DT_END_COMMENT 5 static UINT32 Gbl_NextLineOffset; /****************************************************************************** * * FUNCTION: DtTrim * * PARAMETERS: String - Current source code line to trim * * RETURN: Trimmed line. Must be freed by caller. * * DESCRIPTION: Trim left and right spaces * *****************************************************************************/ static char * DtTrim ( char *String) { char *Start; char *End; char *ReturnString; ACPI_SIZE Length; /* Skip lines that start with a space */ if (!ACPI_STRCMP (String, " ")) { ReturnString = UtLocalCalloc (1); return (ReturnString); } /* Setup pointers to start and end of input string */ Start = String; End = String + ACPI_STRLEN (String) - 1; /* Find first non-whitespace character */ while ((Start <= End) && ((*Start == ' ') || (*Start == '\t'))) { Start++; } /* Find last non-space character */ while (End >= Start) { if (*End == '\r' || *End == '\n') { End--; continue; } if (*End != ' ') { break; } End--; } /* Remove any quotes around the string */ if (*Start == '\"') { Start++; } if (*End == '\"') { End--; } /* Create the trimmed return string */ Length = ACPI_PTR_DIFF (End, Start) + 1; ReturnString = UtLocalCalloc (Length + 1); if (ACPI_STRLEN (Start)) { ACPI_STRNCPY (ReturnString, Start, Length); } ReturnString[Length] = 0; return (ReturnString); } /****************************************************************************** * * FUNCTION: DtLinkField * * PARAMETERS: Field - New field object to link * * RETURN: None * * DESCRIPTION: Link one field name and value to the list * *****************************************************************************/ static void DtLinkField ( DT_FIELD *Field) { DT_FIELD *Prev; DT_FIELD *Next; Prev = Next = Gbl_FieldList; while (Next) { Prev = Next; Next = Next->Next; } if (Prev) { Prev->Next = Field; } else { Gbl_FieldList = Field; } } /****************************************************************************** * * FUNCTION: DtMergeField * * PARAMETERS: Value - Merge this line into previous one * * RETURN: None * * DESCRIPTION: Merge a field value to the previous one, * probably for a multi-line buffer definition. * *****************************************************************************/ static void DtMergeField ( char *Value) { DT_FIELD *Prev; DT_FIELD *Next; char *NewValue; UINT32 PrevLength; UINT32 ThisLength; Prev = Next = Gbl_FieldList; while (Next) { Prev = Next; Next = Next->Next; } if (Prev) { PrevLength = ACPI_STRLEN (Prev->Value); ThisLength = ACPI_STRLEN (Value); /* Add two for: separator + NULL terminator */ NewValue = UtLocalCalloc (PrevLength + ThisLength + 2); ACPI_STRNCPY (NewValue, Prev->Value, PrevLength); NewValue[PrevLength] = ' '; ACPI_STRNCPY ((NewValue + PrevLength + 1), Value, ThisLength); ACPI_FREE (Prev->Value); Prev->Value = NewValue; } } /****************************************************************************** * * FUNCTION: DtParseLine * * PARAMETERS: LineBuffer - Current source code line * Line - Current line number in the source * Offset - Current byte offset of the line * * RETURN: Status * * DESCRIPTION: Parse one source line * *****************************************************************************/ static ACPI_STATUS DtParseLine ( char *LineBuffer, UINT32 Line, UINT32 Offset) { char *Start; char *End; char *TmpName; char *TmpValue; char *Name; char *Value; char *Colon; UINT32 Length; DT_FIELD *Field; UINT32 Column; UINT32 NameColumn; if (!LineBuffer) { return (AE_OK); } /* All lines after "Raw Table Data" are ingored */ if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER)) { return (AE_NOT_FOUND); } Colon = strchr (LineBuffer, ':'); if (!Colon) { return (AE_OK); } Start = LineBuffer; End = Colon; while (Start < Colon) { if (*Start == ' ') { Start++; continue; } /* Found left bracket, go to the right bracket */ if (*Start == '[') { while (Start < Colon && *Start != ']') { Start++; } if (Start == Colon) { break; } Start++; continue; } break; } /* * There are two column values. One for the field name, * and one for the field value. */ Column = ACPI_PTR_DIFF (Colon, LineBuffer) + 3; NameColumn = ACPI_PTR_DIFF (Start, LineBuffer) + 1; Length = ACPI_PTR_DIFF (End, Start); TmpName = UtLocalCalloc (Length + 1); ACPI_STRNCPY (TmpName, Start, Length); Name = DtTrim (TmpName); ACPI_FREE (TmpName); Start = End = (Colon + 1); while (*End) { /* Found left quotation, go to the right quotation and break */ if (*End == '"') { End++; while (*End && (*End != '"')) { End++; } End++; break; } /* * Special "comment" fields at line end, ignore them. * Note: normal slash-slash and slash-asterisk comments are * stripped already by the DtGetNextLine parser. * * TBD: Perhaps DtGetNextLine should parse the following type * of comments also. */ if (*End == '(' || *End == '<') { break; } End++; } Length = ACPI_PTR_DIFF (End, Start); TmpValue = UtLocalCalloc (Length + 1); ACPI_STRNCPY (TmpValue, Start, Length); Value = DtTrim (TmpValue); ACPI_FREE (TmpValue); if (ACPI_STRLEN (Name) && Value) { Field = UtLocalCalloc (sizeof (DT_FIELD)); Field->Name = Name; Field->Value = Value; Field->Line = Line; Field->ByteOffset = Offset; Field->NameColumn = NameColumn; Field->Column = Column; DtLinkField (Field); } else if (!ACPI_STRLEN (Name)) { /* Handle multi-line buffers (length > 16) */ DtMergeField (Value); } else { ACPI_FREE (Name); ACPI_FREE (Value); } return (AE_OK); } /****************************************************************************** * * FUNCTION: DtGetNextLine * * PARAMETERS: Handle - Open file handle for the source file * * RETURN: Filled line buffer and offset of start-of-line (zero on EOF) * * DESCRIPTION: Get the next valid source line. Removes all comments. * Ignores empty lines. * * Handles both slash-asterisk and slash-slash comments. * Also, quoted strings, but no escapes within. * * Line is returned in Gbl_CurrentLineBuffer. * Line number in original file is returned in Gbl_CurrentLineNumber. * *****************************************************************************/ UINT32 DtGetNextLine ( FILE *Handle) { UINT32 State = DT_NORMAL_TEXT; UINT32 CurrentLineOffset; UINT32 i; char c; for (i = 0; i < ASL_LINE_BUFFER_SIZE;) { c = (char) getc (Handle); if (c == EOF) { switch (State) { case DT_START_QUOTED_STRING: case DT_SLASH_ASTERISK_COMMENT: case DT_SLASH_SLASH_COMMENT: AcpiOsPrintf ("**** EOF within comment/string %u\n", State); break; default: break; } return (0); } switch (State) { case DT_NORMAL_TEXT: /* Normal text, insert char into line buffer */ Gbl_CurrentLineBuffer[i] = c; switch (c) { case '/': State = DT_START_COMMENT; break; case '"': State = DT_START_QUOTED_STRING; i++; break; case '\n': CurrentLineOffset = Gbl_NextLineOffset; Gbl_NextLineOffset = (UINT32) ftell (Handle); Gbl_CurrentLineNumber++; /* Exit if line is complete. Ignore blank lines */ if (i != 0) { Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate line */ return (CurrentLineOffset); } break; default: i++; break; } break; case DT_START_QUOTED_STRING: /* Insert raw chars until end of quoted string */ Gbl_CurrentLineBuffer[i] = c; i++; if (c == '"') { State = DT_NORMAL_TEXT; } break; case DT_START_COMMENT: /* Open comment if this character is an asterisk or slash */ switch (c) { case '*': State = DT_SLASH_ASTERISK_COMMENT; break; case '/': State = DT_SLASH_SLASH_COMMENT; break; default: /* Not a comment */ i++; /* Save the preceeding slash */ Gbl_CurrentLineBuffer[i] = c; i++; State = DT_NORMAL_TEXT; break; } break; case DT_SLASH_ASTERISK_COMMENT: /* Ignore chars until an asterisk-slash is found */ switch (c) { case '\n': Gbl_NextLineOffset = (UINT32) ftell (Handle); Gbl_CurrentLineNumber++; break; case '*': State = DT_END_COMMENT; break; default: break; } break; case DT_SLASH_SLASH_COMMENT: /* Ignore chars until end-of-line */ if (c == '\n') { /* We will exit via the NORMAL_TEXT path */ ungetc (c, Handle); State = DT_NORMAL_TEXT; } break; case DT_END_COMMENT: /* End comment if this char is a slash */ switch (c) { case '/': State = DT_NORMAL_TEXT; break; case '\n': CurrentLineOffset = Gbl_NextLineOffset; Gbl_NextLineOffset = (UINT32) ftell (Handle); Gbl_CurrentLineNumber++; break; case '*': /* Consume all adjacent asterisks */ break; default: State = DT_SLASH_ASTERISK_COMMENT; break; } break; default: DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state"); return (0); } } printf ("ERROR - Input line is too long (max %u)\n", ASL_LINE_BUFFER_SIZE); return (0); } /****************************************************************************** * * FUNCTION: DtScanFile * * PARAMETERS: Handle - Open file handle for the source file * * RETURN: Pointer to start of the constructed parse tree. * * DESCRIPTION: Scan source file, link all field names and values * to the global parse tree: Gbl_FieldList * *****************************************************************************/ DT_FIELD * DtScanFile ( FILE *Handle) { ACPI_STATUS Status; UINT32 Offset; ACPI_FUNCTION_NAME (DtScanFile); /* Get the file size */ Gbl_InputByteCount = DtGetFileSize (Handle); Gbl_CurrentLineNumber = 0; Gbl_CurrentLineOffset = 0; Gbl_NextLineOffset = 0; /* Scan line-by-line */ while ((Offset = DtGetNextLine (Handle))) { ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s", Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer)); Status = DtParseLine (Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber, Offset); if (Status == AE_NOT_FOUND) { break; } } return (Gbl_FieldList); } /* * Output functions */ /****************************************************************************** * * FUNCTION: DtWriteBinary * * PARAMETERS: DT_WALK_CALLBACK * * RETURN: Status * * DESCRIPTION: Write one subtable of a binary ACPI table * *****************************************************************************/ static void DtWriteBinary ( DT_SUBTABLE *Subtable, void *Context, void *ReturnValue) { FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length); } /****************************************************************************** * * FUNCTION: DtOutputBinary * * PARAMETERS: * * RETURN: Status * * DESCRIPTION: Write entire binary ACPI table (result of compilation) * *****************************************************************************/ void DtOutputBinary ( DT_SUBTABLE *RootTable) { if (!RootTable) { return; } /* Walk the entire parse tree, emitting the binary data */ DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL); Gbl_TableLength = DtGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle); } /* * Listing support */ /****************************************************************************** * * FUNCTION: DtDumpBuffer * * PARAMETERS: FileID - Where to write buffer data * Buffer - Buffer to dump * Offset - Offset in current table * Length - Buffer Length * * RETURN: None * * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately). * * TBD: merge dump buffer routines * *****************************************************************************/ static void DtDumpBuffer ( UINT32 FileId, UINT8 *Buffer, UINT32 Offset, UINT32 Length) { UINT32 i; UINT32 j; UINT8 BufChar; FlPrintFile (FileId, "Output: [%3.3Xh %4.4d% 3d] ", Offset, Offset, Length); i = 0; while (i < Length) { if (i >= 16) { FlPrintFile (FileId, "%23s", ""); } /* Print 16 hex chars */ for (j = 0; j < 16;) { if (i + j >= Length) { /* Dump fill spaces */ FlPrintFile (FileId, " "); j++; continue; } FlPrintFile (FileId, "%02X ", Buffer[i+j]); j++; } FlPrintFile (FileId, " "); for (j = 0; j < 16; j++) { if (i + j >= Length) { FlPrintFile (FileId, "\n\n"); return; } BufChar = Buffer[(ACPI_SIZE) i + j]; if (ACPI_IS_PRINT (BufChar)) { FlPrintFile (FileId, "%c", BufChar); } else { FlPrintFile (FileId, "."); } } /* Done with that line. */ FlPrintFile (FileId, "\n"); i += 16; } FlPrintFile (FileId, "\n\n"); } /****************************************************************************** * * FUNCTION: DtWriteFieldToListing * * PARAMETERS: Buffer - Contains the compiled data * Field - Field node for the input line * Length - Length of the output data * * RETURN: None * * DESCRIPTION: Write one field to the listing file (if listing is enabled). * *****************************************************************************/ void DtWriteFieldToListing ( UINT8 *Buffer, DT_FIELD *Field, UINT32 Length) { UINT8 FileByte; if (!Gbl_ListingFlag || !Field) { return; } /* Dump the original source line */ FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input: "); FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset); while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK) { FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1); if (FileByte == '\n') { break; } } /* Dump the line as parsed and represented internally */ FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %s\n", Field->Column-4, Field->Name, Field->Value); /* Dump the hex data that will be output for this field */ DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Field->TableOffset, Length); } /****************************************************************************** * * FUNCTION: DtWriteTableToListing * * PARAMETERS: None * * RETURN: None * * DESCRIPTION: Write the entire compiled table to the listing file * in hex format * *****************************************************************************/ void DtWriteTableToListing ( void) { UINT8 *Buffer; if (!Gbl_ListingFlag) { return; } /* Read the entire table from the output file */ Buffer = UtLocalCalloc (Gbl_TableLength); FlSeekFile (ASL_FILE_AML_OUTPUT, 0); FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength); /* Dump the raw table data */ AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle); AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n", ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength); AcpiUtDumpBuffer2 (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY); AcpiOsRedirectOutput (stdout); }