dtio.c revision 217365
1/******************************************************************************
2 *
3 * Module Name: dtio.c - File I/O support for data table compiler
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2011, 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 MERCHANTIBILITY 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 __DTIO_C__
45
46#include <contrib/dev/acpica/compiler/aslcompiler.h>
47#include <contrib/dev/acpica/compiler/dtcompiler.h>
48
49#define _COMPONENT          DT_COMPILER
50        ACPI_MODULE_NAME    ("dtio")
51
52
53/* Local prototypes */
54
55static char *
56DtTrim (
57    char                    *String);
58
59static void
60DtLinkField (
61    DT_FIELD                *Field);
62
63static ACPI_STATUS
64DtParseLine (
65    char                    *LineBuffer,
66    UINT32                  Line,
67    UINT32                  Offset);
68
69static UINT32
70DtGetNextLine (
71    FILE                    *Handle);
72
73static void
74DtWriteBinary (
75    DT_SUBTABLE             *Subtable,
76    void                    *Context,
77    void                    *ReturnValue);
78
79static void
80DtDumpBuffer (
81    UINT32                  FileId,
82    UINT8                   *Buffer,
83    UINT32                  Length);
84
85/* States for DtGetNextLine */
86
87#define DT_NORMAL_TEXT              0
88#define DT_START_QUOTED_STRING      1
89#define DT_START_COMMENT            2
90#define DT_SLASH_ASTERISK_COMMENT   3
91#define DT_SLASH_SLASH_COMMENT      4
92#define DT_END_COMMENT              5
93
94static UINT32  Gbl_NextLineOffset;
95
96
97/******************************************************************************
98 *
99 * FUNCTION:    DtTrim
100 *
101 * PARAMETERS:  String              - Current source code line to trim
102 *
103 * RETURN:      Trimmed line. Must be freed by caller.
104 *
105 * DESCRIPTION: Trim left and right spaces
106 *
107 *****************************************************************************/
108
109static char *
110DtTrim (
111    char                    *String)
112{
113    char                    *Start;
114    char                    *End;
115    char                    *ReturnString;
116    ACPI_SIZE               Length;
117
118
119    /* Skip lines that start with a space */
120
121    if (!ACPI_STRCMP (String, " "))
122    {
123        ReturnString = UtLocalCalloc (1);
124        return (ReturnString);
125    }
126
127    /* Setup pointers to start and end of input string */
128
129    Start = String;
130    End = String + ACPI_STRLEN (String) - 1;
131
132    /* Find first non-whitespace character */
133
134    while ((Start <= End) && ((*Start == ' ') || (*Start == '\t')))
135    {
136        Start++;
137    }
138
139    /* Find last non-space character */
140
141    while (End >= Start)
142    {
143        if (*End == '\r' || *End == '\n')
144        {
145            End--;
146            continue;
147        }
148
149        if (*End != ' ')
150        {
151            break;
152        }
153
154        End--;
155    }
156
157    /* Remove any quotes around the string */
158
159    if (*Start == '\"')
160    {
161        Start++;
162    }
163    if (*End == '\"')
164    {
165        End--;
166    }
167
168    /* Create the trimmed return string */
169
170    Length = ACPI_PTR_DIFF (End, Start) + 1;
171    ReturnString = UtLocalCalloc (Length + 1);
172    if (ACPI_STRLEN (Start))
173    {
174        ACPI_STRNCPY (ReturnString, Start, Length);
175    }
176
177    ReturnString[Length] = 0;
178    return (ReturnString);
179}
180
181
182/******************************************************************************
183 *
184 * FUNCTION:    DtLinkField
185 *
186 * PARAMETERS:  Field               - New field object to link
187 *
188 * RETURN:      None
189 *
190 * DESCRIPTION: Link one field name and value to the list
191 *
192 *****************************************************************************/
193
194static void
195DtLinkField (
196    DT_FIELD                *Field)
197{
198    DT_FIELD                *Prev;
199    DT_FIELD                *Next;
200
201
202    Prev = Next = Gbl_FieldList;
203
204    while (Next)
205    {
206        Prev = Next;
207        Next = Next->Next;
208    }
209
210    if (Prev)
211    {
212        Prev->Next = Field;
213    }
214    else
215    {
216        Gbl_FieldList = Field;
217    }
218}
219
220
221/******************************************************************************
222 *
223 * FUNCTION:    DtParseLine
224 *
225 * PARAMETERS:  LineBuffer          - Current source code line
226 *              Line                - Current line number in the source
227 *              Offset              - Current byte offset of the line
228 *
229 * RETURN:      Status
230 *
231 * DESCRIPTION: Parse one source line
232 *
233 *****************************************************************************/
234
235static ACPI_STATUS
236DtParseLine (
237    char                    *LineBuffer,
238    UINT32                  Line,
239    UINT32                  Offset)
240{
241    char                    *Start;
242    char                    *End;
243    char                    *TmpName;
244    char                    *TmpValue;
245    char                    *Name;
246    char                    *Value;
247    char                    *Colon;
248    UINT32                  Length;
249    DT_FIELD                *Field;
250    UINT32                  Column;
251    UINT32                  NameColumn;
252
253
254    if (!LineBuffer)
255    {
256        return (AE_OK);
257    }
258
259    /* All lines after "Raw Table Data" are ingored */
260
261    if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER))
262    {
263        return (AE_NOT_FOUND);
264    }
265
266    Colon = strchr (LineBuffer, ':');
267    if (!Colon)
268    {
269        return (AE_OK);
270    }
271
272    Start = LineBuffer;
273    End = Colon;
274
275    while (Start < Colon)
276    {
277        if (*Start == ' ')
278        {
279            Start++;
280            continue;
281        }
282
283        /* Found left bracket, go to the right bracket */
284
285        if (*Start == '[')
286        {
287            while (Start < Colon && *Start != ']')
288            {
289                Start++;
290            }
291
292            if (Start == Colon)
293            {
294                break;
295            }
296
297            Start++;
298            continue;
299        }
300
301        break;
302    }
303
304    /*
305     * There are two column values. One for the field name,
306     * and one for the field value.
307     */
308    Column = ACPI_PTR_DIFF (Colon, LineBuffer) + 3;
309    NameColumn = ACPI_PTR_DIFF (Start, LineBuffer) + 1;
310
311    Length = ACPI_PTR_DIFF (End, Start);
312
313    TmpName = UtLocalCalloc (Length + 1);
314    ACPI_STRNCPY (TmpName, Start, Length);
315    Name = DtTrim (TmpName);
316    ACPI_FREE (TmpName);
317
318    Start = End = (Colon + 1);
319
320    while (*End)
321    {
322        /* Found left quotation, go to the right quotation and break */
323
324        if (*End == '"')
325        {
326            End++;
327            while (*End && *End != '"')
328            {
329                End++;
330            }
331
332            End++;
333            break;
334        }
335
336        if (*End == '(' ||
337            *End == '<' ||
338            *End == '/')
339        {
340            break;
341        }
342
343        End++;
344    }
345
346    Length = ACPI_PTR_DIFF (End, Start);
347    TmpValue = UtLocalCalloc (Length + 1);
348    ACPI_STRNCPY (TmpValue, Start, Length);
349    Value = DtTrim (TmpValue);
350    ACPI_FREE (TmpValue);
351
352    if (Name && Value)
353    {
354        Field = UtLocalCalloc (sizeof (DT_FIELD));
355        Field->Name = Name;
356        Field->Value = Value;
357        Field->Line = Line;
358        Field->ByteOffset = Offset;
359        Field->NameColumn = NameColumn;
360        Field->Column = Column;
361
362        DtLinkField (Field);
363    }
364
365    return (AE_OK);
366}
367
368
369/******************************************************************************
370 *
371 * FUNCTION:    DtGetNextLine
372 *
373 * PARAMETERS:  Handle              - Open file handle for the source file
374 *
375 * RETURN:      Filled line buffer and offset of start-of-line (zero on EOF)
376 *
377 * DESCRIPTION: Get the next valid source line. Removes all comments.
378 *              Ignores empty lines.
379 *
380 * Handles both slash-asterisk and slash-slash comments.
381 * Also, quoted strings, but no escapes within.
382 *
383 * Line is returned in Gbl_CurrentLineBuffer.
384 * Line number in original file is returned in Gbl_CurrentLineNumber.
385 *
386 *****************************************************************************/
387
388static UINT32
389DtGetNextLine (
390    FILE                    *Handle)
391{
392    UINT32                  State = DT_NORMAL_TEXT;
393    UINT32                  CurrentLineOffset;
394    UINT32                  i;
395    char                    c;
396
397
398    for (i = 0; i < ASL_LINE_BUFFER_SIZE;)
399    {
400        c = (char) getc (Handle);
401        if (c == EOF)
402        {
403            return (0);
404        }
405
406        switch (State)
407        {
408        case DT_NORMAL_TEXT:
409
410            /* Normal text, insert char into line buffer */
411
412            Gbl_CurrentLineBuffer[i] = c;
413            switch (c)
414            {
415            case '/':
416                State = DT_START_COMMENT;
417                break;
418
419            case '"':
420                State = DT_START_QUOTED_STRING;
421                i++;
422                break;
423
424            case '\n':
425                CurrentLineOffset = Gbl_NextLineOffset;
426                Gbl_NextLineOffset = (UINT32) ftell (Handle);
427                Gbl_CurrentLineNumber++;
428
429                /* Exit if line is complete. Ignore blank lines */
430
431                if (i != 0)
432                {
433                    Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate line */
434                    return (CurrentLineOffset);
435                }
436                break;
437
438            default:
439                i++;
440                break;
441            }
442            break;
443
444        case DT_START_QUOTED_STRING:
445
446            /* Insert raw chars until end of quoted string */
447
448            Gbl_CurrentLineBuffer[i] = c;
449            i++;
450
451            if (c == '"')
452            {
453                State = DT_NORMAL_TEXT;
454            }
455            break;
456
457        case DT_START_COMMENT:
458
459            /* Open comment if this character is an asterisk or slash */
460
461            switch (c)
462            {
463            case '*':
464                State = DT_SLASH_ASTERISK_COMMENT;
465                break;
466
467            case '/':
468                State = DT_SLASH_SLASH_COMMENT;
469                break;
470
471            default:    /* Not a comment */
472                i++;    /* Save the preceeding slash */
473                Gbl_CurrentLineBuffer[i] = c;
474                i++;
475                State = DT_NORMAL_TEXT;
476                break;
477            }
478            break;
479
480        case DT_SLASH_ASTERISK_COMMENT:
481
482            /* Ignore chars until an asterisk-slash is found */
483
484            switch (c)
485            {
486            case '\n':
487                Gbl_NextLineOffset = (UINT32) ftell (Handle);
488                Gbl_CurrentLineNumber++;
489                break;
490
491            case '*':
492                State = DT_END_COMMENT;
493                break;
494
495            default:
496                break;
497            }
498            break;
499
500        case DT_SLASH_SLASH_COMMENT:
501
502            /* Ignore chars until end-of-line */
503
504            if (c == '\n')
505            {
506                /* We will exit via the NORMAL_TEXT path */
507
508                ungetc (c, Handle);
509                State = DT_NORMAL_TEXT;
510            }
511            break;
512
513        case DT_END_COMMENT:
514
515            /* End comment if this char is a slash */
516
517            switch (c)
518            {
519            case '/':
520                State = DT_NORMAL_TEXT;
521                break;
522
523            default:
524                State = DT_SLASH_ASTERISK_COMMENT;
525                break;
526            }
527            break;
528
529        default:
530            DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state");
531            return (0);
532        }
533    }
534
535    printf ("ERROR - Input line is too long (max %u)\n", ASL_LINE_BUFFER_SIZE);
536    return (0);
537}
538
539
540/******************************************************************************
541 *
542 * FUNCTION:    DtScanFile
543 *
544 * PARAMETERS:  Handle              - Open file handle for the source file
545 *
546 * RETURN:      Pointer to start of the constructed parse tree.
547 *
548 * DESCRIPTION: Scan source file, link all field names and values
549 *              to the global parse tree: Gbl_FieldList
550 *
551 *****************************************************************************/
552
553DT_FIELD *
554DtScanFile (
555    FILE                    *Handle)
556{
557    ACPI_STATUS             Status;
558    UINT32                  Offset;
559
560
561    ACPI_FUNCTION_NAME (DtScanFile);
562
563
564    /* Get the file size */
565
566    Gbl_InputByteCount = DtGetFileSize (Handle);
567
568    Gbl_CurrentLineNumber = 0;
569    Gbl_CurrentLineOffset = 0;
570    Gbl_NextLineOffset = 0;
571
572    /* Scan line-by-line */
573
574    while ((Offset = DtGetNextLine (Handle)))
575    {
576        ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s",
577            Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer));
578
579        Status = DtParseLine (Gbl_CurrentLineBuffer, Gbl_CurrentLineNumber, Offset);
580        if (Status == AE_NOT_FOUND)
581        {
582            break;
583        }
584    }
585
586    return (Gbl_FieldList);
587}
588
589
590/*
591 * Output functions
592 */
593
594/******************************************************************************
595 *
596 * FUNCTION:    DtWriteBinary
597 *
598 * PARAMETERS:  DT_WALK_CALLBACK
599 *
600 * RETURN:      Status
601 *
602 * DESCRIPTION: Write one subtable of a binary ACPI table
603 *
604 *****************************************************************************/
605
606static void
607DtWriteBinary (
608    DT_SUBTABLE             *Subtable,
609    void                    *Context,
610    void                    *ReturnValue)
611{
612
613    FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length);
614}
615
616
617/******************************************************************************
618 *
619 * FUNCTION:    DtOutputBinary
620 *
621 * PARAMETERS:
622 *
623 * RETURN:      Status
624 *
625 * DESCRIPTION: Write entire binary ACPI table (result of compilation)
626 *
627 *****************************************************************************/
628
629void
630DtOutputBinary (
631    DT_SUBTABLE             *RootTable)
632{
633
634    if (!RootTable)
635    {
636        return;
637    }
638
639    /* Walk the entire parse tree, emitting the binary data */
640
641    DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL);
642    Gbl_TableLength = DtGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
643}
644
645
646/*
647 * Listing support
648 */
649
650/******************************************************************************
651 *
652 * FUNCTION:    DtDumpBuffer
653 *
654 * PARAMETERS:  FileID              - Where to write buffer data
655 *              Buffer              - Buffer to dump
656 *              Length              - Buffer Length
657 *
658 * RETURN:      None
659 *
660 * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately).
661 *
662 * TBD: merge dump buffer routines
663 *
664 *****************************************************************************/
665
666static void
667DtDumpBuffer (
668    UINT32                  FileId,
669    UINT8                   *Buffer,
670    UINT32                  Length)
671{
672    UINT32                  i;
673    UINT32                  j;
674    UINT8                   BufChar;
675
676
677    i = 0;
678    while (i < Length)
679    {
680        /* Print 16 hex chars */
681
682        FlPrintFile (FileId, "Output: [%.3d] ", Length);
683
684        for (j = 0; j < 16;)
685        {
686            if (i + j >= Length)
687            {
688                /* Dump fill spaces */
689
690                FlPrintFile (FileId, "   ");
691                j++;
692                continue;
693            }
694
695            FlPrintFile (FileId, "%02X ", Buffer[i+j]);
696            j++;
697        }
698
699        FlPrintFile (FileId, " ");
700        for (j = 0; j < 16; j++)
701        {
702            if (i + j >= Length)
703            {
704                FlPrintFile (FileId, "\n\n");
705                return;
706            }
707
708            BufChar = Buffer[(ACPI_SIZE) i + j];
709            if (ACPI_IS_PRINT (BufChar))
710            {
711                FlPrintFile (FileId, "%c", BufChar);
712            }
713            else
714            {
715                FlPrintFile (FileId, ".");
716            }
717        }
718
719        /* Done with that line. */
720
721        FlPrintFile (FileId, "\n");
722        i += 16;
723    }
724
725    FlPrintFile (FileId, "\n\n");
726}
727
728
729/******************************************************************************
730 *
731 * FUNCTION:    DtWriteFieldToListing
732 *
733 * PARAMETERS:  Buffer              - Contains the compiled data
734 *              Field               - Field node for the input line
735 *              Length              - Length of the output data
736 *
737 * RETURN:      None
738 *
739 * DESCRIPTION: Write one field to the listing file (if listing is enabled).
740 *
741 *****************************************************************************/
742
743void
744DtWriteFieldToListing (
745    UINT8                   *Buffer,
746    DT_FIELD                *Field,
747    UINT32                  Length)
748{
749    UINT8                   FileByte;
750
751
752    if (!Gbl_ListingFlag || !Field)
753    {
754        return;
755    }
756
757    /* Dump the original source line */
758
759    FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input:  ");
760    FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset);
761
762    while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK)
763    {
764        FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1);
765        if (FileByte == '\n')
766        {
767            break;
768        }
769    }
770
771    /* Dump the line as parsed and represented internally */
772
773    FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %s\n",
774        Field->Column-4, Field->Name, Field->Value);
775
776#if 0
777    /* TBD Dump the length and AML offset */
778
779    FlPrintFile (ASL_FILE_LISTING_OUTPUT,
780        "Output: Length %d(0x%X) Offset %d(0x%X)\n",
781        Field->Column-4, Field->Name, Field->Value);
782#endif
783
784    /* Dump the hex data that will be output for this field */
785
786    DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Length);
787}
788
789
790/******************************************************************************
791 *
792 * FUNCTION:    DtWriteTableToListing
793 *
794 * PARAMETERS:  None
795 *
796 * RETURN:      None
797 *
798 * DESCRIPTION: Write the entire compiled table to the listing file
799 *              in hex format
800 *
801 *****************************************************************************/
802
803void
804DtWriteTableToListing (
805    void)
806{
807    UINT8                   *Buffer;
808
809
810    if (!Gbl_ListingFlag)
811    {
812        return;
813    }
814
815    /* Read the entire table from the output file */
816
817    Buffer = UtLocalCalloc (Gbl_TableLength);
818    FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
819    FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength);
820
821    /* Dump the raw table data */
822
823    AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle);
824
825    AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n",
826        ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength);
827    AcpiUtDumpBuffer2 (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY);
828
829    AcpiOsRedirectOutput (stdout);
830}
831