1/******************************************************************************
2 *
3 * Module Name: asllistsup - Listing file support utilities
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2013, 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 "aslcompiler.y.h"
46
47
48#define _COMPONENT          ACPI_COMPILER
49        ACPI_MODULE_NAME    ("aslistsup")
50
51
52/*******************************************************************************
53 *
54 * FUNCTION:    LsDumpAscii
55 *
56 * PARAMETERS:  FileId          - ID of current listing file
57 *              Count           - Number of bytes to convert
58 *              Buffer          - Buffer of bytes to convert
59 *
60 * RETURN:      None
61 *
62 * DESCRIPTION: Convert hex bytes to ascii
63 *
64 ******************************************************************************/
65
66void
67LsDumpAscii (
68    UINT32                  FileId,
69    UINT32                  Count,
70    UINT8                   *Buffer)
71{
72    UINT8                   BufChar;
73    UINT32                  i;
74
75
76    FlPrintFile (FileId, "    \"");
77    for (i = 0; i < Count; i++)
78    {
79        BufChar = Buffer[i];
80        if (isprint (BufChar))
81        {
82            FlPrintFile (FileId, "%c", BufChar);
83        }
84        else
85        {
86            /* Not a printable character, just put out a dot */
87
88            FlPrintFile (FileId, ".");
89        }
90    }
91    FlPrintFile (FileId, "\"");
92}
93
94
95/*******************************************************************************
96 *
97 * FUNCTION:    LsDumpAsciiInComment
98 *
99 * PARAMETERS:  FileId          - ID of current listing file
100 *              Count           - Number of bytes to convert
101 *              Buffer          - Buffer of bytes to convert
102 *
103 * RETURN:      None
104 *
105 * DESCRIPTION: Convert hex bytes to ascii
106 *
107 ******************************************************************************/
108
109void
110LsDumpAsciiInComment (
111    UINT32                  FileId,
112    UINT32                  Count,
113    UINT8                   *Buffer)
114{
115    UINT8                   BufChar = 0;
116    UINT8                   LastChar;
117    UINT32                  i;
118
119
120    FlPrintFile (FileId, "    \"");
121    for (i = 0; i < Count; i++)
122    {
123        LastChar = BufChar;
124        BufChar = Buffer[i];
125
126        if (isprint (BufChar))
127        {
128            /* Handle embedded C comment sequences */
129
130            if (((LastChar == '*') && (BufChar == '/')) ||
131                ((LastChar == '/') && (BufChar == '*')))
132            {
133                /* Insert a space to break the sequence */
134
135                FlPrintFile (FileId, ".", BufChar);
136            }
137
138            FlPrintFile (FileId, "%c", BufChar);
139        }
140        else
141        {
142            /* Not a printable character, just put out a dot */
143
144            FlPrintFile (FileId, ".");
145        }
146    }
147
148    FlPrintFile (FileId, "\"");
149}
150
151
152/*******************************************************************************
153 *
154 * FUNCTION:    LsCheckException
155 *
156 * PARAMETERS:  LineNumber          - Current logical (cumulative) line #
157 *              FileId              - ID of output listing file
158 *
159 * RETURN:      None
160 *
161 * DESCRIPTION: Check if there is an exception for this line, and if there is,
162 *              put it in the listing immediately. Handles multiple errors
163 *              per line. Gbl_NextError points to the next error in the
164 *              sorted (by line #) list of compile errors/warnings.
165 *
166 ******************************************************************************/
167
168void
169LsCheckException (
170    UINT32                  LineNumber,
171    UINT32                  FileId)
172{
173
174    if ((!Gbl_NextError) ||
175        (LineNumber < Gbl_NextError->LogicalLineNumber ))
176    {
177        return;
178    }
179
180    /* Handle multiple errors per line */
181
182    if (FileId == ASL_FILE_LISTING_OUTPUT)
183    {
184        while (Gbl_NextError &&
185              (LineNumber >= Gbl_NextError->LogicalLineNumber))
186        {
187            AePrintException (FileId, Gbl_NextError, "\n[****iasl****]\n");
188
189            Gbl_NextError = Gbl_NextError->Next;
190        }
191
192        FlPrintFile (FileId, "\n");
193    }
194}
195
196
197/*******************************************************************************
198 *
199 * FUNCTION:    LsWriteListingHexBytes
200 *
201 * PARAMETERS:  Buffer          - AML code buffer
202 *              Length          - Number of AML bytes to write
203 *              FileId          - ID of current listing file.
204 *
205 * RETURN:      None
206 *
207 * DESCRIPTION: Write the contents of the AML buffer to the listing file via
208 *              the listing buffer. The listing buffer is flushed every 16
209 *              AML bytes.
210 *
211 ******************************************************************************/
212
213void
214LsWriteListingHexBytes (
215    UINT8                   *Buffer,
216    UINT32                  Length,
217    UINT32                  FileId)
218{
219    UINT32                  i;
220
221
222    /* Transfer all requested bytes */
223
224    for (i = 0; i < Length; i++)
225    {
226        /* Print line header when buffer is empty */
227
228        if (Gbl_CurrentHexColumn == 0)
229        {
230            if (Gbl_HasIncludeFiles)
231            {
232                FlPrintFile (FileId, "%*s", 10, " ");
233            }
234
235            switch (FileId)
236            {
237            case ASL_FILE_LISTING_OUTPUT:
238
239                FlPrintFile (FileId, "%8.8X%s", Gbl_CurrentAmlOffset,
240                    ASL_LISTING_LINE_PREFIX);
241                break;
242
243            case ASL_FILE_ASM_SOURCE_OUTPUT:
244
245                FlPrintFile (FileId, "    db ");
246                break;
247
248            case ASL_FILE_C_SOURCE_OUTPUT:
249
250                FlPrintFile (FileId, "        ");
251                break;
252
253            default:
254
255                /* No other types supported */
256
257                return;
258            }
259        }
260
261        /* Transfer AML byte and update counts */
262
263        Gbl_AmlBuffer[Gbl_CurrentHexColumn] = Buffer[i];
264
265        Gbl_CurrentHexColumn++;
266        Gbl_CurrentAmlOffset++;
267
268        /* Flush buffer when it is full */
269
270        if (Gbl_CurrentHexColumn >= HEX_LISTING_LINE_SIZE)
271        {
272            LsFlushListingBuffer (FileId);
273        }
274    }
275}
276
277
278/*******************************************************************************
279 *
280 * FUNCTION:    LsWriteSourceLines
281 *
282 * PARAMETERS:  ToLineNumber            -
283 *              ToLogicalLineNumber     - Write up to this source line number
284 *              FileId                  - ID of current listing file
285 *
286 * RETURN:      None
287 *
288 * DESCRIPTION: Read then write source lines to the listing file until we have
289 *              reached the specified logical (cumulative) line number. This
290 *              automatically echos out comment blocks and other non-AML
291 *              generating text until we get to the actual AML-generating line
292 *              of ASL code specified by the logical line number.
293 *
294 ******************************************************************************/
295
296void
297LsWriteSourceLines (
298    UINT32                  ToLineNumber,
299    UINT32                  ToLogicalLineNumber,
300    UINT32                  FileId)
301{
302
303    /* Nothing to do for these file types */
304
305    if ((FileId == ASL_FILE_ASM_INCLUDE_OUTPUT) ||
306        (FileId == ASL_FILE_C_INCLUDE_OUTPUT))
307    {
308        return;
309    }
310
311    Gbl_CurrentLine = ToLogicalLineNumber;
312
313    /* Flush any hex bytes remaining from the last opcode */
314
315    LsFlushListingBuffer (FileId);
316
317    /* Read lines and write them as long as we are not caught up */
318
319    if (Gbl_SourceLine < Gbl_CurrentLine)
320    {
321        /*
322         * If we just completed writing some AML hex bytes, output a linefeed
323         * to add some whitespace for readability.
324         */
325        if (Gbl_HexBytesWereWritten)
326        {
327            FlPrintFile (FileId, "\n");
328            Gbl_HexBytesWereWritten = FALSE;
329        }
330
331        if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
332        {
333            FlPrintFile (FileId, "    /*\n");
334        }
335
336        /* Write one line at a time until we have reached the target line # */
337
338        while ((Gbl_SourceLine < Gbl_CurrentLine) &&
339                LsWriteOneSourceLine (FileId))
340        { ; }
341
342        if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
343        {
344            FlPrintFile (FileId, "     */");
345        }
346
347        FlPrintFile (FileId, "\n");
348    }
349}
350
351
352/*******************************************************************************
353 *
354 * FUNCTION:    LsWriteOneSourceLine
355 *
356 * PARAMETERS:  FileId          - ID of current listing file
357 *
358 * RETURN:      FALSE on EOF (input source file), TRUE otherwise
359 *
360 * DESCRIPTION: Read one line from the input source file and echo it to the
361 *              listing file, prefixed with the line number, and if the source
362 *              file contains include files, prefixed with the current filename
363 *
364 ******************************************************************************/
365
366UINT32
367LsWriteOneSourceLine (
368    UINT32                  FileId)
369{
370    UINT8                   FileByte;
371    UINT32                  Column = 0;
372    UINT32                  Index = 16;
373    BOOLEAN                 StartOfLine = FALSE;
374    BOOLEAN                 ProcessLongLine = FALSE;
375
376
377    Gbl_SourceLine++;
378    Gbl_ListingNode->LineNumber++;
379
380    /* Ignore lines that are completely blank (but count the line above) */
381
382    if (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) != AE_OK)
383    {
384        return (0);
385    }
386    if (FileByte == '\n')
387    {
388        return (1);
389    }
390
391    /*
392     * This is a non-empty line, we will print the entire line with
393     * the line number and possibly other prefixes and transforms.
394     */
395
396    /* Line prefixes for special files, C and ASM output */
397
398    if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
399    {
400        FlPrintFile (FileId, "     *");
401    }
402    if (FileId == ASL_FILE_ASM_SOURCE_OUTPUT)
403    {
404        FlPrintFile (FileId, "; ");
405    }
406
407    if (Gbl_HasIncludeFiles)
408    {
409        /*
410         * This file contains "include" statements, print the current
411         * filename and line number within the current file
412         */
413        FlPrintFile (FileId, "%12s %5d%s",
414            Gbl_ListingNode->Filename, Gbl_ListingNode->LineNumber,
415            ASL_LISTING_LINE_PREFIX);
416    }
417    else
418    {
419        /* No include files, just print the line number */
420
421        FlPrintFile (FileId, "%8u%s", Gbl_SourceLine,
422            ASL_LISTING_LINE_PREFIX);
423    }
424
425    /* Read the rest of this line (up to a newline or EOF) */
426
427    do
428    {
429        if (FileId == ASL_FILE_C_SOURCE_OUTPUT)
430        {
431            if (FileByte == '/')
432            {
433                FileByte = '*';
434            }
435        }
436
437        /* Split long input lines for readability in the listing */
438
439        Column++;
440        if (Column >= 128)
441        {
442            if (!ProcessLongLine)
443            {
444                if ((FileByte != '}') &&
445                    (FileByte != '{'))
446                {
447                    goto WriteByte;
448                }
449
450                ProcessLongLine = TRUE;
451            }
452
453            if (FileByte == '{')
454            {
455                FlPrintFile (FileId, "\n%*s{\n", Index, " ");
456                StartOfLine = TRUE;
457                Index += 4;
458                continue;
459            }
460
461            else if (FileByte == '}')
462            {
463                if (!StartOfLine)
464                {
465                    FlPrintFile (FileId, "\n");
466                }
467
468                StartOfLine = TRUE;
469                Index -= 4;
470                FlPrintFile (FileId, "%*s}\n", Index, " ");
471                continue;
472            }
473
474            /* Ignore spaces/tabs at the start of line */
475
476            else if ((FileByte == ' ') && StartOfLine)
477            {
478                continue;
479            }
480
481            else if (StartOfLine)
482            {
483                StartOfLine = FALSE;
484                FlPrintFile (FileId, "%*s", Index, " ");
485            }
486
487WriteByte:
488            FlWriteFile (FileId, &FileByte, 1);
489            if (FileByte == '\n')
490            {
491                /*
492                 * This line has been completed.
493                 * Check if an error occurred on this source line during the compile.
494                 * If so, we print the error message after the source line.
495                 */
496                LsCheckException (Gbl_SourceLine, FileId);
497                return (1);
498            }
499        }
500        else
501        {
502            FlWriteFile (FileId, &FileByte, 1);
503            if (FileByte == '\n')
504            {
505                /*
506                 * This line has been completed.
507                 * Check if an error occurred on this source line during the compile.
508                 * If so, we print the error message after the source line.
509                 */
510                LsCheckException (Gbl_SourceLine, FileId);
511                return (1);
512            }
513        }
514
515    } while (FlReadFile (ASL_FILE_SOURCE_OUTPUT, &FileByte, 1) == AE_OK);
516
517    /* EOF on the input file was reached */
518
519    return (0);
520}
521
522
523/*******************************************************************************
524 *
525 * FUNCTION:    LsFlushListingBuffer
526 *
527 * PARAMETERS:  FileId          - ID of the listing file
528 *
529 * RETURN:      None
530 *
531 * DESCRIPTION: Flush out the current contents of the 16-byte hex AML code
532 *              buffer. Usually called at the termination of a single line
533 *              of source code or when the buffer is full.
534 *
535 ******************************************************************************/
536
537void
538LsFlushListingBuffer (
539    UINT32                  FileId)
540{
541    UINT32                  i;
542
543
544    if (Gbl_CurrentHexColumn == 0)
545    {
546        return;
547    }
548
549    /* Write the hex bytes */
550
551    switch (FileId)
552    {
553    case ASL_FILE_LISTING_OUTPUT:
554
555        for (i = 0; i < Gbl_CurrentHexColumn; i++)
556        {
557            FlPrintFile (FileId, "%2.2X ", Gbl_AmlBuffer[i]);
558        }
559
560        for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 3); i++)
561        {
562            FlWriteFile (FileId, ".", 1);
563        }
564
565        /* Write the ASCII character associated with each of the bytes */
566
567        LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
568        break;
569
570
571    case ASL_FILE_ASM_SOURCE_OUTPUT:
572
573        for (i = 0; i < Gbl_CurrentHexColumn; i++)
574        {
575            if (i > 0)
576            {
577                FlPrintFile (FileId, ",");
578            }
579            FlPrintFile (FileId, "0%2.2Xh", Gbl_AmlBuffer[i]);
580        }
581
582        for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
583        {
584            FlWriteFile (FileId, " ", 1);
585        }
586
587        FlPrintFile (FileId, "  ;%8.8X",
588            Gbl_CurrentAmlOffset - HEX_LISTING_LINE_SIZE);
589
590        /* Write the ASCII character associated with each of the bytes */
591
592        LsDumpAscii (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
593        break;
594
595
596    case ASL_FILE_C_SOURCE_OUTPUT:
597
598        for (i = 0; i < Gbl_CurrentHexColumn; i++)
599        {
600            FlPrintFile (FileId, "0x%2.2X,", Gbl_AmlBuffer[i]);
601        }
602
603        /* Pad hex output with spaces if line is shorter than max line size */
604
605        for (i = 0; i < ((HEX_LISTING_LINE_SIZE - Gbl_CurrentHexColumn) * 5); i++)
606        {
607            FlWriteFile (FileId, " ", 1);
608        }
609
610        /* AML offset for the start of the line */
611
612        FlPrintFile (FileId, "    /* %8.8X",
613            Gbl_CurrentAmlOffset - Gbl_CurrentHexColumn);
614
615        /* Write the ASCII character associated with each of the bytes */
616
617        LsDumpAsciiInComment (FileId, Gbl_CurrentHexColumn, Gbl_AmlBuffer);
618        FlPrintFile (FileId, " */");
619        break;
620
621    default:
622
623        /* No other types supported */
624
625        return;
626    }
627
628    FlPrintFile (FileId, "\n");
629
630    Gbl_CurrentHexColumn = 0;
631    Gbl_HexBytesWereWritten = TRUE;
632}
633
634
635/*******************************************************************************
636 *
637 * FUNCTION:    LsPushNode
638 *
639 * PARAMETERS:  Filename        - Pointer to the include filename
640 *
641 * RETURN:      None
642 *
643 * DESCRIPTION: Push a listing node on the listing/include file stack. This
644 *              stack enables tracking of include files (infinitely nested)
645 *              and resumption of the listing of the parent file when the
646 *              include file is finished.
647 *
648 ******************************************************************************/
649
650void
651LsPushNode (
652    char                    *Filename)
653{
654    ASL_LISTING_NODE        *Lnode;
655
656
657    /* Create a new node */
658
659    Lnode = UtLocalCalloc (sizeof (ASL_LISTING_NODE));
660
661    /* Initialize */
662
663    Lnode->Filename = Filename;
664    Lnode->LineNumber = 0;
665
666    /* Link (push) */
667
668    Lnode->Next = Gbl_ListingNode;
669    Gbl_ListingNode = Lnode;
670}
671
672
673/*******************************************************************************
674 *
675 * FUNCTION:    LsPopNode
676 *
677 * PARAMETERS:  None
678 *
679 * RETURN:      List head after current head is popped off
680 *
681 * DESCRIPTION: Pop the current head of the list, free it, and return the
682 *              next node on the stack (the new current node).
683 *
684 ******************************************************************************/
685
686ASL_LISTING_NODE *
687LsPopNode (
688    void)
689{
690    ASL_LISTING_NODE        *Lnode;
691
692
693    /* Just grab the node at the head of the list */
694
695    Lnode = Gbl_ListingNode;
696    if ((!Lnode) ||
697        (!Lnode->Next))
698    {
699        AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, NULL,
700            "Could not pop empty listing stack");
701        return (Gbl_ListingNode);
702    }
703
704    Gbl_ListingNode = Lnode->Next;
705    ACPI_FREE (Lnode);
706
707    /* New "Current" node is the new head */
708
709    return (Gbl_ListingNode);
710}
711