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