dtio.c revision 1.1.1.2 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 "aslcompiler.h"
47 #include "dtcompiler.h"
48
49 #define _COMPONENT DT_COMPILER
50 ACPI_MODULE_NAME ("dtio")
51
52
53 /* Local prototypes */
54
55 static char *
56 DtTrim (
57 char *String);
58
59 static void
60 DtLinkField (
61 DT_FIELD *Field);
62
63 static ACPI_STATUS
64 DtParseLine (
65 char *LineBuffer,
66 UINT32 Line,
67 UINT32 Offset);
68
69 UINT32
70 DtGetNextLine (
71 FILE *Handle);
72
73 static void
74 DtWriteBinary (
75 DT_SUBTABLE *Subtable,
76 void *Context,
77 void *ReturnValue);
78
79 static void
80 DtDumpBuffer (
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
96 static 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
111 static char *
112 DtTrim (
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
196 static void
197 DtLinkField (
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
237 static ACPI_STATUS
238 DtParseLine (
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
397 UINT32
398 DtGetNextLine (
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
585 DT_FIELD *
586 DtScanFile (
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
638 static void
639 DtWriteBinary (
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
661 void
662 DtOutputBinary (
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
699 static void
700 DtDumpBuffer (
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
783 void
784 DtWriteFieldToListing (
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
835 void
836 DtWriteTableToListing (
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