xref: /freebsd/sys/contrib/dev/acpica/compiler/dtio.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /******************************************************************************
2  *
3  * Module Name: dtio.c - File I/O support for data table compiler
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2016, 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 #include <contrib/dev/acpica/compiler/aslcompiler.h>
45 #include <contrib/dev/acpica/compiler/dtcompiler.h>
46 #include <contrib/dev/acpica/include/acapps.h>
47 
48 #define _COMPONENT          DT_COMPILER
49         ACPI_MODULE_NAME    ("dtio")
50 
51 
52 /* Local prototypes */
53 
54 static char *
55 DtTrim (
56     char                    *String);
57 
58 static void
59 DtLinkField (
60     DT_FIELD                *Field);
61 
62 static ACPI_STATUS
63 DtParseLine (
64     char                    *LineBuffer,
65     UINT32                  Line,
66     UINT32                  Offset);
67 
68 static void
69 DtWriteBinary (
70     DT_SUBTABLE             *Subtable,
71     void                    *Context,
72     void                    *ReturnValue);
73 
74 static void
75 DtDumpBuffer (
76     UINT32                  FileId,
77     UINT8                   *Buffer,
78     UINT32                  Offset,
79     UINT32                  Length);
80 
81 static void
82 DtDumpSubtableInfo (
83     DT_SUBTABLE             *Subtable,
84     void                    *Context,
85     void                    *ReturnValue);
86 
87 static void
88 DtDumpSubtableTree (
89     DT_SUBTABLE             *Subtable,
90     void                    *Context,
91     void                    *ReturnValue);
92 
93 
94 /* States for DtGetNextLine */
95 
96 #define DT_NORMAL_TEXT              0
97 #define DT_START_QUOTED_STRING      1
98 #define DT_START_COMMENT            2
99 #define DT_SLASH_ASTERISK_COMMENT   3
100 #define DT_SLASH_SLASH_COMMENT      4
101 #define DT_END_COMMENT              5
102 #define DT_MERGE_LINES              6
103 #define DT_ESCAPE_SEQUENCE          7
104 
105 static UINT32               Gbl_NextLineOffset;
106 
107 
108 /******************************************************************************
109  *
110  * FUNCTION:    DtTrim
111  *
112  * PARAMETERS:  String              - Current source code line to trim
113  *
114  * RETURN:      Trimmed line. Must be freed by caller.
115  *
116  * DESCRIPTION: Trim left and right spaces
117  *
118  *****************************************************************************/
119 
120 static char *
121 DtTrim (
122     char                    *String)
123 {
124     char                    *Start;
125     char                    *End;
126     char                    *ReturnString;
127     ACPI_SIZE               Length;
128 
129 
130     /* Skip lines that start with a space */
131 
132     if (!strcmp (String, " "))
133     {
134         ReturnString = UtStringCacheCalloc (1);
135         return (ReturnString);
136     }
137 
138     /* Setup pointers to start and end of input string */
139 
140     Start = String;
141     End = String + strlen (String) - 1;
142 
143     /* Find first non-whitespace character */
144 
145     while ((Start <= End) && ((*Start == ' ') || (*Start == '\t')))
146     {
147         Start++;
148     }
149 
150     /* Find last non-space character */
151 
152     while (End >= Start)
153     {
154         if (*End == '\r' || *End == '\n')
155         {
156             End--;
157             continue;
158         }
159 
160         if (*End != ' ')
161         {
162             break;
163         }
164 
165         End--;
166     }
167 
168     /* Remove any quotes around the string */
169 
170     if (*Start == '\"')
171     {
172         Start++;
173     }
174     if (*End == '\"')
175     {
176         End--;
177     }
178 
179     /* Create the trimmed return string */
180 
181     Length = ACPI_PTR_DIFF (End, Start) + 1;
182     ReturnString = UtStringCacheCalloc (Length + 1);
183     if (strlen (Start))
184     {
185         strncpy (ReturnString, Start, Length);
186     }
187 
188     ReturnString[Length] = 0;
189     return (ReturnString);
190 }
191 
192 
193 /******************************************************************************
194  *
195  * FUNCTION:    DtLinkField
196  *
197  * PARAMETERS:  Field               - New field object to link
198  *
199  * RETURN:      None
200  *
201  * DESCRIPTION: Link one field name and value to the list
202  *
203  *****************************************************************************/
204 
205 static void
206 DtLinkField (
207     DT_FIELD                *Field)
208 {
209     DT_FIELD                *Prev;
210     DT_FIELD                *Next;
211 
212 
213     Prev = Next = Gbl_FieldList;
214 
215     while (Next)
216     {
217         Prev = Next;
218         Next = Next->Next;
219     }
220 
221     if (Prev)
222     {
223         Prev->Next = Field;
224     }
225     else
226     {
227         Gbl_FieldList = Field;
228     }
229 }
230 
231 
232 /******************************************************************************
233  *
234  * FUNCTION:    DtParseLine
235  *
236  * PARAMETERS:  LineBuffer          - Current source code line
237  *              Line                - Current line number in the source
238  *              Offset              - Current byte offset of the line
239  *
240  * RETURN:      Status
241  *
242  * DESCRIPTION: Parse one source line
243  *
244  *****************************************************************************/
245 
246 static ACPI_STATUS
247 DtParseLine (
248     char                    *LineBuffer,
249     UINT32                  Line,
250     UINT32                  Offset)
251 {
252     char                    *Start;
253     char                    *End;
254     char                    *TmpName;
255     char                    *TmpValue;
256     char                    *Name;
257     char                    *Value;
258     char                    *Colon;
259     UINT32                  Length;
260     DT_FIELD                *Field;
261     UINT32                  Column;
262     UINT32                  NameColumn;
263     BOOLEAN                 IsNullString = FALSE;
264 
265 
266     if (!LineBuffer)
267     {
268         return (AE_OK);
269     }
270 
271     /* All lines after "Raw Table Data" are ingored */
272 
273     if (strstr (LineBuffer, ACPI_RAW_TABLE_DATA_HEADER))
274     {
275         return (AE_NOT_FOUND);
276     }
277 
278     Colon = strchr (LineBuffer, ':');
279     if (!Colon)
280     {
281         return (AE_OK);
282     }
283 
284     Start = LineBuffer;
285     End = Colon;
286 
287     while (Start < Colon)
288     {
289         if (*Start == '[')
290         {
291             /* Found left bracket, go to the right bracket */
292 
293             while (Start < Colon && *Start != ']')
294             {
295                 Start++;
296             }
297         }
298         else if (*Start != ' ')
299         {
300             break;
301         }
302 
303         Start++;
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     strncpy (TmpName, Start, Length);
317     Name = DtTrim (TmpName);
318     ACPI_FREE (TmpName);
319 
320     Start = End = (Colon + 1);
321     while (*End)
322     {
323         /* Found left quotation, go to the right quotation and break */
324 
325         if (*End == '"')
326         {
327             End++;
328 
329             /* Check for an explicit null string */
330 
331             if (*End == '"')
332             {
333                 IsNullString = TRUE;
334             }
335             while (*End && (*End != '"'))
336             {
337                 End++;
338             }
339 
340             End++;
341             break;
342         }
343 
344         /*
345          * Special "comment" fields at line end, ignore them.
346          * Note: normal slash-slash and slash-asterisk comments are
347          * stripped already by the DtGetNextLine parser.
348          *
349          * TBD: Perhaps DtGetNextLine should parse the following type
350          * of comments also.
351          */
352         if (*End == '[')
353         {
354             End--;
355             break;
356         }
357 
358         End++;
359     }
360 
361     Length = ACPI_PTR_DIFF (End, Start);
362     TmpValue = UtLocalCalloc (Length + 1);
363 
364     strncpy (TmpValue, Start, Length);
365     Value = DtTrim (TmpValue);
366     ACPI_FREE (TmpValue);
367 
368     /* Create a new field object only if we have a valid value field */
369 
370     if ((Value && *Value) || IsNullString)
371     {
372         Field = UtFieldCacheCalloc ();
373         Field->Name = Name;
374         Field->Value = Value;
375         Field->Line = Line;
376         Field->ByteOffset = Offset;
377         Field->NameColumn = NameColumn;
378         Field->Column = Column;
379         Field->StringLength = Length;
380 
381         DtLinkField (Field);
382     }
383     /* Else -- Ignore this field, it has no valid data */
384 
385     return (AE_OK);
386 }
387 
388 
389 /******************************************************************************
390  *
391  * FUNCTION:    DtGetNextLine
392  *
393  * PARAMETERS:  Handle              - Open file handle for the source file
394  *
395  * RETURN:      Filled line buffer and offset of start-of-line (ASL_EOF on EOF)
396  *
397  * DESCRIPTION: Get the next valid source line. Removes all comments.
398  *              Ignores empty lines.
399  *
400  * Handles both slash-asterisk and slash-slash comments.
401  * Also, quoted strings, but no escapes within.
402  *
403  * Line is returned in Gbl_CurrentLineBuffer.
404  * Line number in original file is returned in Gbl_CurrentLineNumber.
405  *
406  *****************************************************************************/
407 
408 UINT32
409 DtGetNextLine (
410     FILE                    *Handle,
411     UINT32                  Flags)
412 {
413     BOOLEAN                 LineNotAllBlanks = FALSE;
414     UINT32                  State = DT_NORMAL_TEXT;
415     UINT32                  CurrentLineOffset;
416     UINT32                  i;
417     int                     c;
418 
419 
420     memset (Gbl_CurrentLineBuffer, 0, Gbl_LineBufferSize);
421     for (i = 0; ;)
422     {
423         /*
424          * If line is too long, expand the line buffers. Also increases
425          * Gbl_LineBufferSize.
426          */
427         if (i >= Gbl_LineBufferSize)
428         {
429             UtExpandLineBuffers ();
430         }
431 
432         c = getc (Handle);
433         if (c == EOF)
434         {
435             switch (State)
436             {
437             case DT_START_QUOTED_STRING:
438             case DT_SLASH_ASTERISK_COMMENT:
439 
440                 AcpiOsPrintf ("**** EOF within comment/string %u\n", State);
441                 break;
442 
443             default:
444 
445                 break;
446             }
447 
448             /* Standalone EOF is OK */
449 
450             if (i == 0)
451             {
452                 return (ASL_EOF);
453             }
454 
455             /*
456              * Received an EOF in the middle of a line. Terminate the
457              * line with a newline. The next call to this function will
458              * return a standalone EOF. Thus, the upper parsing software
459              * never has to deal with an EOF within a valid line (or
460              * the last line does not get tossed on the floor.)
461              */
462             c = '\n';
463             State = DT_NORMAL_TEXT;
464         }
465 
466         switch (State)
467         {
468         case DT_NORMAL_TEXT:
469 
470             /* Normal text, insert char into line buffer */
471 
472             Gbl_CurrentLineBuffer[i] = (char) c;
473             switch (c)
474             {
475             case '/':
476 
477                 State = DT_START_COMMENT;
478                 break;
479 
480             case '"':
481 
482                 State = DT_START_QUOTED_STRING;
483                 LineNotAllBlanks = TRUE;
484                 i++;
485                 break;
486 
487             case '\\':
488                 /*
489                  * The continuation char MUST be last char on this line.
490                  * Otherwise, it will be assumed to be a valid ASL char.
491                  */
492                 State = DT_MERGE_LINES;
493                 break;
494 
495             case '\n':
496 
497                 CurrentLineOffset = Gbl_NextLineOffset;
498                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
499                 Gbl_CurrentLineNumber++;
500 
501                 /*
502                  * Exit if line is complete. Ignore empty lines (only \n)
503                  * or lines that contain nothing but blanks.
504                  */
505                 if ((i != 0) && LineNotAllBlanks)
506                 {
507                     if ((i + 1) >= Gbl_LineBufferSize)
508                     {
509                         UtExpandLineBuffers ();
510                     }
511 
512                     Gbl_CurrentLineBuffer[i+1] = 0; /* Terminate string */
513                     return (CurrentLineOffset);
514                 }
515 
516                 /* Toss this line and start a new one */
517 
518                 i = 0;
519                 LineNotAllBlanks = FALSE;
520                 break;
521 
522             default:
523 
524                 if (c != ' ')
525                 {
526                     LineNotAllBlanks = TRUE;
527                 }
528 
529                 i++;
530                 break;
531             }
532             break;
533 
534         case DT_START_QUOTED_STRING:
535 
536             /* Insert raw chars until end of quoted string */
537 
538             Gbl_CurrentLineBuffer[i] = (char) c;
539             i++;
540 
541             switch (c)
542             {
543             case '"':
544 
545                 State = DT_NORMAL_TEXT;
546                 break;
547 
548             case '\\':
549 
550                 State = DT_ESCAPE_SEQUENCE;
551                 break;
552 
553             case '\n':
554 
555                 if (!(Flags & DT_ALLOW_MULTILINE_QUOTES))
556                 {
557                     AcpiOsPrintf (
558                         "ERROR at line %u: Unterminated quoted string\n",
559                         Gbl_CurrentLineNumber++);
560                     State = DT_NORMAL_TEXT;
561                 }
562                 break;
563 
564             default:    /* Get next character */
565 
566                 break;
567             }
568             break;
569 
570         case DT_ESCAPE_SEQUENCE:
571 
572             /* Just copy the escaped character. TBD: sufficient for table compiler? */
573 
574             Gbl_CurrentLineBuffer[i] = (char) c;
575             i++;
576             State = DT_START_QUOTED_STRING;
577             break;
578 
579         case DT_START_COMMENT:
580 
581             /* Open comment if this character is an asterisk or slash */
582 
583             switch (c)
584             {
585             case '*':
586 
587                 State = DT_SLASH_ASTERISK_COMMENT;
588                 break;
589 
590             case '/':
591 
592                 State = DT_SLASH_SLASH_COMMENT;
593                 break;
594 
595             default:    /* Not a comment */
596 
597                 i++;    /* Save the preceding slash */
598                 if (i >= Gbl_LineBufferSize)
599                 {
600                     UtExpandLineBuffers ();
601                 }
602 
603                 Gbl_CurrentLineBuffer[i] = (char) c;
604                 i++;
605                 State = DT_NORMAL_TEXT;
606                 break;
607             }
608             break;
609 
610         case DT_SLASH_ASTERISK_COMMENT:
611 
612             /* Ignore chars until an asterisk-slash is found */
613 
614             switch (c)
615             {
616             case '\n':
617 
618                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
619                 Gbl_CurrentLineNumber++;
620                 break;
621 
622             case '*':
623 
624                 State = DT_END_COMMENT;
625                 break;
626 
627             default:
628 
629                 break;
630             }
631             break;
632 
633         case DT_SLASH_SLASH_COMMENT:
634 
635             /* Ignore chars until end-of-line */
636 
637             if (c == '\n')
638             {
639                 /* We will exit via the NORMAL_TEXT path */
640 
641                 ungetc (c, Handle);
642                 State = DT_NORMAL_TEXT;
643             }
644             break;
645 
646         case DT_END_COMMENT:
647 
648             /* End comment if this char is a slash */
649 
650             switch (c)
651             {
652             case '/':
653 
654                 State = DT_NORMAL_TEXT;
655                 break;
656 
657             case '\n':
658 
659                 CurrentLineOffset = Gbl_NextLineOffset;
660                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
661                 Gbl_CurrentLineNumber++;
662                 break;
663 
664             case '*':
665 
666                 /* Consume all adjacent asterisks */
667                 break;
668 
669             default:
670 
671                 State = DT_SLASH_ASTERISK_COMMENT;
672                 break;
673             }
674             break;
675 
676         case DT_MERGE_LINES:
677 
678             if (c != '\n')
679             {
680                 /*
681                  * This is not a continuation backslash, it is a normal
682                  * normal ASL backslash - for example: Scope(\_SB_)
683                  */
684                 i++; /* Keep the backslash that is already in the buffer */
685 
686                 ungetc (c, Handle);
687                 State = DT_NORMAL_TEXT;
688             }
689             else
690             {
691                 /*
692                  * This is a continuation line -- a backlash followed
693                  * immediately by a newline. Insert a space between the
694                  * lines (overwrite the backslash)
695                  */
696                 Gbl_CurrentLineBuffer[i] = ' ';
697                 i++;
698 
699                 /* Ignore newline, this will merge the lines */
700 
701                 CurrentLineOffset = Gbl_NextLineOffset;
702                 Gbl_NextLineOffset = (UINT32) ftell (Handle);
703                 Gbl_CurrentLineNumber++;
704                 State = DT_NORMAL_TEXT;
705             }
706             break;
707 
708         default:
709 
710             DtFatal (ASL_MSG_COMPILER_INTERNAL, NULL, "Unknown input state");
711             return (ASL_EOF);
712         }
713     }
714 }
715 
716 
717 /******************************************************************************
718  *
719  * FUNCTION:    DtScanFile
720  *
721  * PARAMETERS:  Handle              - Open file handle for the source file
722  *
723  * RETURN:      Pointer to start of the constructed parse tree.
724  *
725  * DESCRIPTION: Scan source file, link all field names and values
726  *              to the global parse tree: Gbl_FieldList
727  *
728  *****************************************************************************/
729 
730 DT_FIELD *
731 DtScanFile (
732     FILE                    *Handle)
733 {
734     ACPI_STATUS             Status;
735     UINT32                  Offset;
736 
737 
738     ACPI_FUNCTION_NAME (DtScanFile);
739 
740 
741     /* Get the file size */
742 
743     Gbl_InputByteCount = CmGetFileSize (Handle);
744     if (Gbl_InputByteCount == ACPI_UINT32_MAX)
745     {
746         AslAbort ();
747     }
748 
749     Gbl_CurrentLineNumber = 0;
750     Gbl_CurrentLineOffset = 0;
751     Gbl_NextLineOffset = 0;
752 
753     /* Scan line-by-line */
754 
755     while ((Offset = DtGetNextLine (Handle, 0)) != ASL_EOF)
756     {
757         ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Line %2.2u/%4.4X - %s",
758             Gbl_CurrentLineNumber, Offset, Gbl_CurrentLineBuffer));
759 
760         Status = DtParseLine (Gbl_CurrentLineBuffer,
761             Gbl_CurrentLineNumber, Offset);
762         if (Status == AE_NOT_FOUND)
763         {
764             break;
765         }
766     }
767 
768     /* Dump the parse tree if debug enabled */
769 
770     DtDumpFieldList (Gbl_FieldList);
771     return (Gbl_FieldList);
772 }
773 
774 
775 /*
776  * Output functions
777  */
778 
779 /******************************************************************************
780  *
781  * FUNCTION:    DtWriteBinary
782  *
783  * PARAMETERS:  DT_WALK_CALLBACK
784  *
785  * RETURN:      Status
786  *
787  * DESCRIPTION: Write one subtable of a binary ACPI table
788  *
789  *****************************************************************************/
790 
791 static void
792 DtWriteBinary (
793     DT_SUBTABLE             *Subtable,
794     void                    *Context,
795     void                    *ReturnValue)
796 {
797 
798     FlWriteFile (ASL_FILE_AML_OUTPUT, Subtable->Buffer, Subtable->Length);
799 }
800 
801 
802 /******************************************************************************
803  *
804  * FUNCTION:    DtOutputBinary
805  *
806  * PARAMETERS:
807  *
808  * RETURN:      Status
809  *
810  * DESCRIPTION: Write entire binary ACPI table (result of compilation)
811  *
812  *****************************************************************************/
813 
814 void
815 DtOutputBinary (
816     DT_SUBTABLE             *RootTable)
817 {
818 
819     if (!RootTable)
820     {
821         return;
822     }
823 
824     /* Walk the entire parse tree, emitting the binary data */
825 
826     DtWalkTableTree (RootTable, DtWriteBinary, NULL, NULL);
827 
828     Gbl_TableLength = CmGetFileSize (Gbl_Files[ASL_FILE_AML_OUTPUT].Handle);
829     if (Gbl_TableLength == ACPI_UINT32_MAX)
830     {
831         AslAbort ();
832     }
833 }
834 
835 
836 /*
837  * Listing support
838  */
839 
840 /******************************************************************************
841  *
842  * FUNCTION:    DtDumpBuffer
843  *
844  * PARAMETERS:  FileID              - Where to write buffer data
845  *              Buffer              - Buffer to dump
846  *              Offset              - Offset in current table
847  *              Length              - Buffer Length
848  *
849  * RETURN:      None
850  *
851  * DESCRIPTION: Another copy of DumpBuffer routine (unfortunately).
852  *
853  * TBD: merge dump buffer routines
854  *
855  *****************************************************************************/
856 
857 static void
858 DtDumpBuffer (
859     UINT32                  FileId,
860     UINT8                   *Buffer,
861     UINT32                  Offset,
862     UINT32                  Length)
863 {
864     UINT32                  i;
865     UINT32                  j;
866     UINT8                   BufChar;
867 
868 
869     FlPrintFile (FileId, "Output: [%3.3Xh %4.4d %3d] ",
870         Offset, Offset, Length);
871 
872     i = 0;
873     while (i < Length)
874     {
875         if (i >= 16)
876         {
877             FlPrintFile (FileId, "%24s", "");
878         }
879 
880         /* Print 16 hex chars */
881 
882         for (j = 0; j < 16;)
883         {
884             if (i + j >= Length)
885             {
886                 /* Dump fill spaces */
887 
888                 FlPrintFile (FileId, "   ");
889                 j++;
890                 continue;
891             }
892 
893             FlPrintFile (FileId, "%02X ", Buffer[i+j]);
894             j++;
895         }
896 
897         FlPrintFile (FileId, " ");
898         for (j = 0; j < 16; j++)
899         {
900             if (i + j >= Length)
901             {
902                 FlPrintFile (FileId, "\n\n");
903                 return;
904             }
905 
906             BufChar = Buffer[(ACPI_SIZE) i + j];
907             if (isprint (BufChar))
908             {
909                 FlPrintFile (FileId, "%c", BufChar);
910             }
911             else
912             {
913                 FlPrintFile (FileId, ".");
914             }
915         }
916 
917         /* Done with that line. */
918 
919         FlPrintFile (FileId, "\n");
920         i += 16;
921     }
922 
923     FlPrintFile (FileId, "\n\n");
924 }
925 
926 
927 /******************************************************************************
928  *
929  * FUNCTION:    DtDumpFieldList
930  *
931  * PARAMETERS:  Field               - Root field
932  *
933  * RETURN:      None
934  *
935  * DESCRIPTION: Dump the entire field list
936  *
937  *****************************************************************************/
938 
939 void
940 DtDumpFieldList (
941     DT_FIELD                *Field)
942 {
943 
944     if (!Gbl_DebugFlag || !Field)
945     {
946         return;
947     }
948 
949     DbgPrint (ASL_DEBUG_OUTPUT,  "\nField List:\n"
950         "LineNo   ByteOff  NameCol  Column   TableOff "
951         "Flags %32s : %s\n\n", "Name", "Value");
952 
953     while (Field)
954     {
955         DbgPrint (ASL_DEBUG_OUTPUT,
956             "%.08X %.08X %.08X %.08X %.08X %2.2X    %32s : %s\n",
957             Field->Line, Field->ByteOffset, Field->NameColumn,
958             Field->Column, Field->TableOffset, Field->Flags,
959             Field->Name, Field->Value);
960 
961         Field = Field->Next;
962     }
963 
964     DbgPrint (ASL_DEBUG_OUTPUT,  "\n\n");
965 }
966 
967 
968 /******************************************************************************
969  *
970  * FUNCTION:    DtDumpSubtableInfo, DtDumpSubtableTree
971  *
972  * PARAMETERS:  DT_WALK_CALLBACK
973  *
974  * RETURN:      None
975  *
976  * DESCRIPTION: Info - dump a subtable tree entry with extra information.
977  *              Tree - dump a subtable tree formatted by depth indentation.
978  *
979  *****************************************************************************/
980 
981 static void
982 DtDumpSubtableInfo (
983     DT_SUBTABLE             *Subtable,
984     void                    *Context,
985     void                    *ReturnValue)
986 {
987 
988     DbgPrint (ASL_DEBUG_OUTPUT,
989         "[%.04X] %24s %.08X %.08X %.08X %.08X %.08X %p %p %p\n",
990         Subtable->Depth, Subtable->Name, Subtable->Length, Subtable->TotalLength,
991         Subtable->SizeOfLengthField, Subtable->Flags, Subtable,
992         Subtable->Parent, Subtable->Child, Subtable->Peer);
993 }
994 
995 static void
996 DtDumpSubtableTree (
997     DT_SUBTABLE             *Subtable,
998     void                    *Context,
999     void                    *ReturnValue)
1000 {
1001 
1002     DbgPrint (ASL_DEBUG_OUTPUT,
1003         "[%.04X] %24s %*s%08X (%.02X) - (%.02X)\n",
1004         Subtable->Depth, Subtable->Name, (4 * Subtable->Depth), " ",
1005         Subtable, Subtable->Length, Subtable->TotalLength);
1006 }
1007 
1008 
1009 /******************************************************************************
1010  *
1011  * FUNCTION:    DtDumpSubtableList
1012  *
1013  * PARAMETERS:  None
1014  *
1015  * RETURN:      None
1016  *
1017  * DESCRIPTION: Dump the raw list of subtables with information, and also
1018  *              dump the subtable list in formatted tree format. Assists with
1019  *              the development of new table code.
1020  *
1021  *****************************************************************************/
1022 
1023 void
1024 DtDumpSubtableList (
1025     void)
1026 {
1027 
1028     if (!Gbl_DebugFlag || !Gbl_RootTable)
1029     {
1030         return;
1031     }
1032 
1033     DbgPrint (ASL_DEBUG_OUTPUT,
1034         "Subtable Info:\n"
1035         "Depth                      Name Length   TotalLen LenSize  Flags    "
1036         "This     Parent   Child    Peer\n\n");
1037     DtWalkTableTree (Gbl_RootTable, DtDumpSubtableInfo, NULL, NULL);
1038 
1039     DbgPrint (ASL_DEBUG_OUTPUT,
1040         "\nSubtable Tree: (Depth, Name, Subtable, Length, TotalLength)\n\n");
1041     DtWalkTableTree (Gbl_RootTable, DtDumpSubtableTree, NULL, NULL);
1042 
1043     DbgPrint (ASL_DEBUG_OUTPUT, "\n");
1044 }
1045 
1046 
1047 /******************************************************************************
1048  *
1049  * FUNCTION:    DtWriteFieldToListing
1050  *
1051  * PARAMETERS:  Buffer              - Contains the compiled data
1052  *              Field               - Field node for the input line
1053  *              Length              - Length of the output data
1054  *
1055  * RETURN:      None
1056  *
1057  * DESCRIPTION: Write one field to the listing file (if listing is enabled).
1058  *
1059  *****************************************************************************/
1060 
1061 void
1062 DtWriteFieldToListing (
1063     UINT8                   *Buffer,
1064     DT_FIELD                *Field,
1065     UINT32                  Length)
1066 {
1067     UINT8                   FileByte;
1068 
1069 
1070     if (!Gbl_ListingFlag || !Field)
1071     {
1072         return;
1073     }
1074 
1075     /* Dump the original source line */
1076 
1077     FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Input:  ");
1078     FlSeekFile (ASL_FILE_INPUT, Field->ByteOffset);
1079 
1080     while (FlReadFile (ASL_FILE_INPUT, &FileByte, 1) == AE_OK)
1081     {
1082         FlWriteFile (ASL_FILE_LISTING_OUTPUT, &FileByte, 1);
1083         if (FileByte == '\n')
1084         {
1085             break;
1086         }
1087     }
1088 
1089     /* Dump the line as parsed and represented internally */
1090 
1091     FlPrintFile (ASL_FILE_LISTING_OUTPUT, "Parsed: %*s : %.64s",
1092         Field->Column-4, Field->Name, Field->Value);
1093 
1094     if (strlen (Field->Value) > 64)
1095     {
1096         FlPrintFile (ASL_FILE_LISTING_OUTPUT, "...Additional data, length 0x%X\n",
1097             strlen (Field->Value));
1098     }
1099 
1100     FlPrintFile (ASL_FILE_LISTING_OUTPUT, "\n");
1101 
1102     /* Dump the hex data that will be output for this field */
1103 
1104     DtDumpBuffer (ASL_FILE_LISTING_OUTPUT, Buffer, Field->TableOffset, Length);
1105 }
1106 
1107 
1108 /******************************************************************************
1109  *
1110  * FUNCTION:    DtWriteTableToListing
1111  *
1112  * PARAMETERS:  None
1113  *
1114  * RETURN:      None
1115  *
1116  * DESCRIPTION: Write the entire compiled table to the listing file
1117  *              in hex format
1118  *
1119  *****************************************************************************/
1120 
1121 void
1122 DtWriteTableToListing (
1123     void)
1124 {
1125     UINT8                   *Buffer;
1126 
1127 
1128     if (!Gbl_ListingFlag)
1129     {
1130         return;
1131     }
1132 
1133     /* Read the entire table from the output file */
1134 
1135     Buffer = UtLocalCalloc (Gbl_TableLength);
1136     FlSeekFile (ASL_FILE_AML_OUTPUT, 0);
1137     FlReadFile (ASL_FILE_AML_OUTPUT, Buffer, Gbl_TableLength);
1138 
1139     /* Dump the raw table data */
1140 
1141     AcpiOsRedirectOutput (Gbl_Files[ASL_FILE_LISTING_OUTPUT].Handle);
1142 
1143     AcpiOsPrintf ("\n%s: Length %d (0x%X)\n\n",
1144         ACPI_RAW_TABLE_DATA_HEADER, Gbl_TableLength, Gbl_TableLength);
1145     AcpiUtDumpBuffer (Buffer, Gbl_TableLength, DB_BYTE_DISPLAY, 0);
1146 
1147     AcpiOsRedirectOutput (stdout);
1148     ACPI_FREE (Buffer);
1149 }
1150