1
2/******************************************************************************
3 *
4 * Module Name: aslutils -- compiler utilities
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2011, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions, and the following disclaimer,
17 *    without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 *    substantially similar to the "NO WARRANTY" disclaimer below
20 *    ("Disclaimer") and any redistribution must be conditioned upon
21 *    including a substantially similar Disclaimer requirement for further
22 *    binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 *    of any contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45
46#include "aslcompiler.h"
47#include "aslcompiler.y.h"
48#include "acdisasm.h"
49#include "acnamesp.h"
50#include "amlcode.h"
51#include <acapps.h>
52
53#define _COMPONENT          ACPI_COMPILER
54        ACPI_MODULE_NAME    ("aslutils")
55
56char                        AslHexLookup[] =
57{
58    '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'
59};
60
61
62/* Local prototypes */
63
64static void
65UtPadNameWithUnderscores (
66    char                    *NameSeg,
67    char                    *PaddedNameSeg);
68
69static void
70UtAttachNameseg (
71    ACPI_PARSE_OBJECT       *Op,
72    char                    *Name);
73
74
75/*******************************************************************************
76 *
77 * FUNCTION:    UtDisplaySupportedTables
78 *
79 * PARAMETERS:  None
80 *
81 * RETURN:      None
82 *
83 * DESCRIPTION: Print all supported ACPI table names.
84 *
85 ******************************************************************************/
86
87void
88UtDisplaySupportedTables (
89    void)
90{
91    ACPI_DMTABLE_DATA       *TableData;
92    UINT32                  i = 6;
93
94
95    printf ("\nACPI tables supported by iASL subsystems in "
96        "version %8.8X:\n"
97        "  ASL and Data Table compilers\n"
98        "  AML and Data Table disassemblers\n"
99        "  ACPI table template generator\n\n", ACPI_CA_VERSION);
100
101    /* Special tables */
102
103    printf ("%8u) %s    %s\n", 1, ACPI_SIG_DSDT, "Differentiated System Description Table");
104    printf ("%8u) %s    %s\n", 2, ACPI_SIG_SSDT, "Secondary System Description Table");
105    printf ("%8u) %s    %s\n", 3, ACPI_SIG_FADT, "Fixed ACPI Description Table (FADT)");
106    printf ("%8u) %s    %s\n", 4, ACPI_SIG_FACS, "Firmware ACPI Control Structure");
107    printf ("%8u) %s    %s\n", 5, ACPI_RSDP_NAME, "Root System Description Pointer");
108
109    /* All data tables with common table header */
110
111    for (TableData = AcpiDmTableData; TableData->Signature; TableData++)
112    {
113        printf ("%8u) %s    %s\n", i, TableData->Signature, TableData->Name);
114        i++;
115    }
116}
117
118
119/*******************************************************************************
120 *
121 * FUNCTION:    AcpiPsDisplayConstantOpcodes
122 *
123 * PARAMETERS:  None
124 *
125 * RETURN:      None
126 *
127 * DESCRIPTION: Print AML opcodes that can be used in constant expressions.
128 *
129 ******************************************************************************/
130
131void
132UtDisplayConstantOpcodes (
133    void)
134{
135    UINT32                  i;
136
137
138    printf ("Constant expression opcode information\n\n");
139
140    for (i = 0; i < sizeof (AcpiGbl_AmlOpInfo) / sizeof (ACPI_OPCODE_INFO); i++)
141    {
142        if (AcpiGbl_AmlOpInfo[i].Flags & AML_CONSTANT)
143        {
144            printf ("%s\n", AcpiGbl_AmlOpInfo[i].Name);
145        }
146    }
147}
148
149
150/*******************************************************************************
151 *
152 * FUNCTION:    UtLocalCalloc
153 *
154 * PARAMETERS:  Size        - Bytes to be allocated
155 *
156 * RETURN:      Pointer to the allocated memory.  Guaranteed to be valid.
157 *
158 * DESCRIPTION: Allocate zero-initialized memory.  Aborts the compile on an
159 *              allocation failure, on the assumption that nothing more can be
160 *              accomplished.
161 *
162 ******************************************************************************/
163
164void *
165UtLocalCalloc (
166    UINT32                  Size)
167{
168    void                    *Allocated;
169
170
171    Allocated = ACPI_ALLOCATE_ZEROED (Size);
172    if (!Allocated)
173    {
174        AslCommonError (ASL_ERROR, ASL_MSG_MEMORY_ALLOCATION,
175            Gbl_CurrentLineNumber, Gbl_LogicalLineNumber,
176            Gbl_InputByteCount, Gbl_CurrentColumn,
177            Gbl_Files[ASL_FILE_INPUT].Filename, NULL);
178
179        CmCleanupAndExit ();
180        exit (1);
181    }
182
183    TotalAllocations++;
184    TotalAllocated += Size;
185    return (Allocated);
186}
187
188
189/*******************************************************************************
190 *
191 * FUNCTION:    UtBeginEvent
192 *
193 * PARAMETERS:  Name        - Ascii name of this event
194 *
195 * RETURN:      Event       - Event number (integer index)
196 *
197 * DESCRIPTION: Saves the current time with this event
198 *
199 ******************************************************************************/
200
201UINT8
202UtBeginEvent (
203    char                    *Name)
204{
205
206    if (AslGbl_NextEvent >= ASL_NUM_EVENTS)
207    {
208        AcpiOsPrintf ("Ran out of compiler event structs!\n");
209        return (AslGbl_NextEvent);
210    }
211
212    /* Init event with current (start) time */
213
214    AslGbl_Events[AslGbl_NextEvent].StartTime = AcpiOsGetTimer ();
215    AslGbl_Events[AslGbl_NextEvent].EventName = Name;
216    AslGbl_Events[AslGbl_NextEvent].Valid = TRUE;
217
218    return (AslGbl_NextEvent++);
219}
220
221
222/*******************************************************************************
223 *
224 * FUNCTION:    UtEndEvent
225 *
226 * PARAMETERS:  Event       - Event number (integer index)
227 *
228 * RETURN:      None
229 *
230 * DESCRIPTION: Saves the current time (end time) with this event
231 *
232 ******************************************************************************/
233
234void
235UtEndEvent (
236    UINT8                  Event)
237{
238
239    if (Event >= ASL_NUM_EVENTS)
240    {
241        return;
242    }
243
244    /* Insert end time for event */
245
246    AslGbl_Events[Event].EndTime = AcpiOsGetTimer ();
247}
248
249
250/*******************************************************************************
251 *
252 * FUNCTION:    UtHexCharToValue
253 *
254 * PARAMETERS:  HexChar         - Hex character in Ascii
255 *
256 * RETURN:      The binary value of the hex character
257 *
258 * DESCRIPTION: Perform ascii-to-hex translation
259 *
260 ******************************************************************************/
261
262UINT8
263UtHexCharToValue (
264    int                     HexChar)
265{
266
267    if (HexChar <= 0x39)
268    {
269        return ((UINT8) (HexChar - 0x30));
270    }
271
272    if (HexChar <= 0x46)
273    {
274        return ((UINT8) (HexChar - 0x37));
275    }
276
277    return ((UINT8) (HexChar - 0x57));
278}
279
280
281/*******************************************************************************
282 *
283 * FUNCTION:    UtConvertByteToHex
284 *
285 * PARAMETERS:  RawByte         - Binary data
286 *              Buffer          - Pointer to where the hex bytes will be stored
287 *
288 * RETURN:      Ascii hex byte is stored in Buffer.
289 *
290 * DESCRIPTION: Perform hex-to-ascii translation.  The return data is prefixed
291 *              with "0x"
292 *
293 ******************************************************************************/
294
295void
296UtConvertByteToHex (
297    UINT8                   RawByte,
298    UINT8                   *Buffer)
299{
300
301    Buffer[0] = '0';
302    Buffer[1] = 'x';
303
304    Buffer[2] = (UINT8) AslHexLookup[(RawByte >> 4) & 0xF];
305    Buffer[3] = (UINT8) AslHexLookup[RawByte & 0xF];
306}
307
308
309/*******************************************************************************
310 *
311 * FUNCTION:    UtConvertByteToAsmHex
312 *
313 * PARAMETERS:  RawByte         - Binary data
314 *              Buffer          - Pointer to where the hex bytes will be stored
315 *
316 * RETURN:      Ascii hex byte is stored in Buffer.
317 *
318 * DESCRIPTION: Perform hex-to-ascii translation.  The return data is prefixed
319 *              with "0x"
320 *
321 ******************************************************************************/
322
323void
324UtConvertByteToAsmHex (
325    UINT8                   RawByte,
326    UINT8                   *Buffer)
327{
328
329    Buffer[0] = '0';
330    Buffer[1] = (UINT8) AslHexLookup[(RawByte >> 4) & 0xF];
331    Buffer[2] = (UINT8) AslHexLookup[RawByte & 0xF];
332    Buffer[3] = 'h';
333}
334
335
336/*******************************************************************************
337 *
338 * FUNCTION:    DbgPrint
339 *
340 * PARAMETERS:  Type            - Type of output
341 *              Fmt             - Printf format string
342 *              ...             - variable printf list
343 *
344 * RETURN:      None
345 *
346 * DESCRIPTION: Conditional print statement.  Prints to stderr only if the
347 *              debug flag is set.
348 *
349 ******************************************************************************/
350
351void
352DbgPrint (
353    UINT32                  Type,
354    char                    *Fmt,
355    ...)
356{
357    va_list                 Args;
358
359
360    va_start (Args, Fmt);
361
362    if (!Gbl_DebugFlag)
363    {
364        return;
365    }
366
367    if ((Type == ASL_PARSE_OUTPUT) &&
368        (!(AslCompilerdebug)))
369    {
370        return;
371    }
372
373    (void) vfprintf (stderr, Fmt, Args);
374    va_end (Args);
375    return;
376}
377
378
379/*******************************************************************************
380 *
381 * FUNCTION:    UtPrintFormattedName
382 *
383 * PARAMETERS:  ParseOpcode         - Parser keyword ID
384 *              Level               - Indentation level
385 *
386 * RETURN:      None
387 *
388 * DESCRIPTION: Print the ascii name of the parse opcode.
389 *
390 ******************************************************************************/
391
392#define TEXT_OFFSET 10
393
394void
395UtPrintFormattedName (
396    UINT16                  ParseOpcode,
397    UINT32                  Level)
398{
399
400    if (Level)
401    {
402        DbgPrint (ASL_TREE_OUTPUT,
403            "%*s", (3 * Level), " ");
404    }
405    DbgPrint (ASL_TREE_OUTPUT,
406        " %-20.20s", UtGetOpName (ParseOpcode));
407
408    if (Level < TEXT_OFFSET)
409    {
410        DbgPrint (ASL_TREE_OUTPUT,
411            "%*s", (TEXT_OFFSET - Level) * 3, " ");
412    }
413}
414
415
416/*******************************************************************************
417 *
418 * FUNCTION:    UtSetParseOpName
419 *
420 * PARAMETERS:  Op
421 *
422 * RETURN:      None
423 *
424 * DESCRIPTION: Insert the ascii name of the parse opcode
425 *
426 ******************************************************************************/
427
428void
429UtSetParseOpName (
430    ACPI_PARSE_OBJECT       *Op)
431{
432
433    strncpy (Op->Asl.ParseOpName, UtGetOpName (Op->Asl.ParseOpcode),
434        ACPI_MAX_PARSEOP_NAME);
435}
436
437
438/*******************************************************************************
439 *
440 * FUNCTION:    UtDisplaySummary
441 *
442 * PARAMETERS:  FileID          - ID of outpout file
443 *
444 * RETURN:      None
445 *
446 * DESCRIPTION: Display compilation statistics
447 *
448 ******************************************************************************/
449
450void
451UtDisplaySummary (
452    UINT32                  FileId)
453{
454
455    if (FileId != ASL_FILE_STDOUT)
456    {
457        /* Compiler name and version number */
458
459        FlPrintFile (FileId, "%s version %X%s\n",
460            ASL_COMPILER_NAME, (UINT32) ACPI_CA_VERSION, ACPI_WIDTH);
461    }
462
463    if (Gbl_FileType == ASL_INPUT_TYPE_ASCII_DATA)
464    {
465        FlPrintFile (FileId,
466            "Table Input:   %s - %u lines, %u bytes, %u fields\n",
467            Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_CurrentLineNumber,
468            Gbl_InputByteCount, Gbl_InputFieldCount);
469
470        if ((Gbl_ExceptionCount[ASL_ERROR] == 0) || (Gbl_IgnoreErrors))
471        {
472            FlPrintFile (FileId,
473                "Binary Output: %s - %u bytes\n\n",
474                Gbl_Files[ASL_FILE_AML_OUTPUT].Filename, Gbl_TableLength);
475        }
476    }
477    else
478    {
479        /* Input/Output summary */
480
481        FlPrintFile (FileId,
482            "ASL Input:  %s - %u lines, %u bytes, %u keywords\n",
483            Gbl_Files[ASL_FILE_INPUT].Filename, Gbl_CurrentLineNumber,
484            Gbl_InputByteCount, TotalKeywords);
485
486        /* AML summary */
487
488        if ((Gbl_ExceptionCount[ASL_ERROR] == 0) || (Gbl_IgnoreErrors))
489        {
490            FlPrintFile (FileId,
491                "AML Output: %s - %u bytes, %u named objects, %u executable opcodes\n\n",
492                Gbl_Files[ASL_FILE_AML_OUTPUT].Filename, Gbl_TableLength,
493                TotalNamedObjects, TotalExecutableOpcodes);
494        }
495    }
496
497    /* Error summary */
498
499    FlPrintFile (FileId,
500        "Compilation complete. %u Errors, %u Warnings, %u Remarks",
501        Gbl_ExceptionCount[ASL_ERROR],
502        Gbl_ExceptionCount[ASL_WARNING] +
503            Gbl_ExceptionCount[ASL_WARNING2] +
504            Gbl_ExceptionCount[ASL_WARNING3],
505        Gbl_ExceptionCount[ASL_REMARK]);
506
507    if (Gbl_FileType != ASL_INPUT_TYPE_ASCII_DATA)
508    {
509        FlPrintFile (FileId,
510            ", %u Optimizations", Gbl_ExceptionCount[ASL_OPTIMIZATION]);
511    }
512
513    FlPrintFile (FileId, "\n");
514}
515
516
517/*******************************************************************************
518 *
519 * FUNCTION:    UtDisplaySummary
520 *
521 * PARAMETERS:  Op              - Integer parse node
522 *              LowValue        - Smallest allowed value
523 *              HighValue       - Largest allowed value
524 *
525 * RETURN:      Op if OK, otherwise NULL
526 *
527 * DESCRIPTION: Check integer for an allowable range
528 *
529 ******************************************************************************/
530
531ACPI_PARSE_OBJECT *
532UtCheckIntegerRange (
533    ACPI_PARSE_OBJECT       *Op,
534    UINT32                  LowValue,
535    UINT32                  HighValue)
536{
537    char                    *ParseError = NULL;
538    char                    Buffer[64];
539
540
541    if (!Op)
542    {
543        return NULL;
544    }
545
546    if (Op->Asl.Value.Integer < LowValue)
547    {
548        ParseError = "Value below valid range";
549        Op->Asl.Value.Integer = LowValue;
550    }
551
552    if (Op->Asl.Value.Integer > HighValue)
553    {
554        ParseError = "Value above valid range";
555        Op->Asl.Value.Integer = HighValue;
556    }
557
558    if (ParseError)
559    {
560        sprintf (Buffer, "%s 0x%X-0x%X", ParseError, LowValue, HighValue);
561        AslCompilererror (Buffer);
562
563        return NULL;
564    }
565
566    return Op;
567}
568
569
570/*******************************************************************************
571 *
572 * FUNCTION:    UtGetStringBuffer
573 *
574 * PARAMETERS:  Length          - Size of buffer requested
575 *
576 * RETURN:      Pointer to the buffer.  Aborts on allocation failure
577 *
578 * DESCRIPTION: Allocate a string buffer.  Bypass the local
579 *              dynamic memory manager for performance reasons (This has a
580 *              major impact on the speed of the compiler.)
581 *
582 ******************************************************************************/
583
584char *
585UtGetStringBuffer (
586    UINT32                  Length)
587{
588    char                    *Buffer;
589
590
591    if ((Gbl_StringCacheNext + Length) >= Gbl_StringCacheLast)
592    {
593        Gbl_StringCacheNext = UtLocalCalloc (ASL_STRING_CACHE_SIZE + Length);
594        Gbl_StringCacheLast = Gbl_StringCacheNext + ASL_STRING_CACHE_SIZE +
595                                Length;
596    }
597
598    Buffer = Gbl_StringCacheNext;
599    Gbl_StringCacheNext += Length;
600
601    return (Buffer);
602}
603
604
605/*******************************************************************************
606 *
607 * FUNCTION:    UtInternalizeName
608 *
609 * PARAMETERS:  ExternalName            - Name to convert
610 *              ConvertedName           - Where the converted name is returned
611 *
612 * RETURN:      Status
613 *
614 * DESCRIPTION: Convert an external (ASL) name to an internal (AML) name
615 *
616 ******************************************************************************/
617
618ACPI_STATUS
619UtInternalizeName (
620    char                    *ExternalName,
621    char                    **ConvertedName)
622{
623    ACPI_NAMESTRING_INFO    Info;
624    ACPI_STATUS             Status;
625
626
627    if (!ExternalName)
628    {
629        return (AE_OK);
630    }
631
632    /* Get the length of the new internal name */
633
634    Info.ExternalName = ExternalName;
635    AcpiNsGetInternalNameLength (&Info);
636
637    /* We need a segment to store the internal  name */
638
639    Info.InternalName = UtGetStringBuffer (Info.Length);
640    if (!Info.InternalName)
641    {
642        return (AE_NO_MEMORY);
643    }
644
645    /* Build the name */
646
647    Status = AcpiNsBuildInternalName (&Info);
648    if (ACPI_FAILURE (Status))
649    {
650        return (Status);
651    }
652
653    *ConvertedName = Info.InternalName;
654    return (AE_OK);
655}
656
657
658/*******************************************************************************
659 *
660 * FUNCTION:    UtPadNameWithUnderscores
661 *
662 * PARAMETERS:  NameSeg         - Input nameseg
663 *              PaddedNameSeg   - Output padded nameseg
664 *
665 * RETURN:      Padded nameseg.
666 *
667 * DESCRIPTION: Pads a NameSeg with underscores if necessary to form a full
668 *              ACPI_NAME.
669 *
670 ******************************************************************************/
671
672static void
673UtPadNameWithUnderscores (
674    char                    *NameSeg,
675    char                    *PaddedNameSeg)
676{
677    UINT32                  i;
678
679
680    for (i = 0; (i < ACPI_NAME_SIZE); i++)
681    {
682        if (*NameSeg)
683        {
684            *PaddedNameSeg = *NameSeg;
685            NameSeg++;
686        }
687        else
688        {
689            *PaddedNameSeg = '_';
690        }
691        PaddedNameSeg++;
692    }
693}
694
695
696/*******************************************************************************
697 *
698 * FUNCTION:    UtAttachNameseg
699 *
700 * PARAMETERS:  Op              - Parent parse node
701 *              Name            - Full ExternalName
702 *
703 * RETURN:      None; Sets the NameSeg field in parent node
704 *
705 * DESCRIPTION: Extract the last nameseg of the ExternalName and store it
706 *              in the NameSeg field of the Op.
707 *
708 ******************************************************************************/
709
710static void
711UtAttachNameseg (
712    ACPI_PARSE_OBJECT       *Op,
713    char                    *Name)
714{
715    char                    *NameSeg;
716    char                    PaddedNameSeg[4];
717
718
719    if (!Name)
720    {
721        return;
722    }
723
724    /* Look for the last dot in the namepath */
725
726    NameSeg = strrchr (Name, '.');
727    if (NameSeg)
728    {
729        /* Found last dot, we have also found the final nameseg */
730
731        NameSeg++;
732        UtPadNameWithUnderscores (NameSeg, PaddedNameSeg);
733    }
734    else
735    {
736        /* No dots in the namepath, there is only a single nameseg. */
737        /* Handle prefixes */
738
739        while ((*Name == '\\') || (*Name == '^'))
740        {
741            Name++;
742        }
743
744        /* Remaing string should be one single nameseg */
745
746        UtPadNameWithUnderscores (Name, PaddedNameSeg);
747    }
748
749    strncpy (Op->Asl.NameSeg, PaddedNameSeg, 4);
750}
751
752
753/*******************************************************************************
754 *
755 * FUNCTION:    UtAttachNamepathToOwner
756 *
757 * PARAMETERS:  Op            - Parent parse node
758 *              NameOp        - Node that contains the name
759 *
760 * RETURN:      Sets the ExternalName and Namepath in the parent node
761 *
762 * DESCRIPTION: Store the name in two forms in the parent node:  The original
763 *              (external) name, and the internalized name that is used within
764 *              the ACPI namespace manager.
765 *
766 ******************************************************************************/
767
768void
769UtAttachNamepathToOwner (
770    ACPI_PARSE_OBJECT       *Op,
771    ACPI_PARSE_OBJECT       *NameOp)
772{
773    ACPI_STATUS             Status;
774
775
776    /* Full external path */
777
778    Op->Asl.ExternalName = NameOp->Asl.Value.String;
779
780    /* Save the NameOp for possible error reporting later */
781
782    Op->Asl.ParentMethod = (void *) NameOp;
783
784    /* Last nameseg of the path */
785
786    UtAttachNameseg (Op, Op->Asl.ExternalName);
787
788    /* Create internalized path */
789
790    Status = UtInternalizeName (NameOp->Asl.Value.String, &Op->Asl.Namepath);
791    if (ACPI_FAILURE (Status))
792    {
793        /* TBD: abort on no memory */
794    }
795}
796
797
798/*******************************************************************************
799 *
800 * FUNCTION:    UtDoConstant
801 *
802 * PARAMETERS:  String      - Hex, Octal, or Decimal string
803 *
804 * RETURN:      Converted Integer
805 *
806 * DESCRIPTION: Convert a string to an integer.  With error checking.
807 *
808 ******************************************************************************/
809
810UINT64
811UtDoConstant (
812    char                    *String)
813{
814    ACPI_STATUS             Status;
815    UINT64                  Converted;
816    char                    ErrBuf[64];
817
818
819    Status = UtStrtoul64 (String, 0, &Converted);
820    if (ACPI_FAILURE (Status))
821    {
822        sprintf (ErrBuf, "%s %s\n", "Conversion error:",
823            AcpiFormatException (Status));
824        AslCompilererror (ErrBuf);
825    }
826
827    return (Converted);
828}
829
830
831/* TBD: use version in ACPI CA main code base? */
832
833/*******************************************************************************
834 *
835 * FUNCTION:    UtStrtoul64
836 *
837 * PARAMETERS:  String          - Null terminated string
838 *              Terminater      - Where a pointer to the terminating byte is
839 *                                returned
840 *              Base            - Radix of the string
841 *
842 * RETURN:      Converted value
843 *
844 * DESCRIPTION: Convert a string into an unsigned value.
845 *
846 ******************************************************************************/
847
848ACPI_STATUS
849UtStrtoul64 (
850    char                    *String,
851    UINT32                  Base,
852    UINT64                  *RetInteger)
853{
854    UINT32                  Index;
855    UINT32                  Sign;
856    UINT64                  ReturnValue = 0;
857    ACPI_STATUS             Status = AE_OK;
858
859
860    *RetInteger = 0;
861
862    switch (Base)
863    {
864    case 0:
865    case 8:
866    case 10:
867    case 16:
868        break;
869
870    default:
871        /*
872         * The specified Base parameter is not in the domain of
873         * this function:
874         */
875        return (AE_BAD_PARAMETER);
876    }
877
878    /* Skip over any white space in the buffer: */
879
880    while (isspace ((int) *String) || *String == '\t')
881    {
882        ++String;
883    }
884
885    /*
886     * The buffer may contain an optional plus or minus sign.
887     * If it does, then skip over it but remember what is was:
888     */
889    if (*String == '-')
890    {
891        Sign = NEGATIVE;
892        ++String;
893    }
894    else if (*String == '+')
895    {
896        ++String;
897        Sign = POSITIVE;
898    }
899    else
900    {
901        Sign = POSITIVE;
902    }
903
904    /*
905     * If the input parameter Base is zero, then we need to
906     * determine if it is octal, decimal, or hexadecimal:
907     */
908    if (Base == 0)
909    {
910        if (*String == '0')
911        {
912            if (tolower ((int) *(++String)) == 'x')
913            {
914                Base = 16;
915                ++String;
916            }
917            else
918            {
919                Base = 8;
920            }
921        }
922        else
923        {
924            Base = 10;
925        }
926    }
927
928    /*
929     * For octal and hexadecimal bases, skip over the leading
930     * 0 or 0x, if they are present.
931     */
932    if (Base == 8 && *String == '0')
933    {
934        String++;
935    }
936
937    if (Base == 16 &&
938        *String == '0' &&
939        tolower ((int) *(++String)) == 'x')
940    {
941        String++;
942    }
943
944    /* Main loop: convert the string to an unsigned long */
945
946    while (*String)
947    {
948        if (isdigit ((int) *String))
949        {
950            Index = ((UINT8) *String) - '0';
951        }
952        else
953        {
954            Index = (UINT8) toupper ((int) *String);
955            if (isupper ((int) Index))
956            {
957                Index = Index - 'A' + 10;
958            }
959            else
960            {
961                goto ErrorExit;
962            }
963        }
964
965        if (Index >= Base)
966        {
967            goto ErrorExit;
968        }
969
970        /* Check to see if value is out of range: */
971
972        if (ReturnValue > ((ACPI_UINT64_MAX - (UINT64) Index) /
973                            (UINT64) Base))
974        {
975            goto ErrorExit;
976        }
977        else
978        {
979            ReturnValue *= Base;
980            ReturnValue += Index;
981        }
982
983        ++String;
984    }
985
986
987    /* If a minus sign was present, then "the conversion is negated": */
988
989    if (Sign == NEGATIVE)
990    {
991        ReturnValue = (ACPI_UINT32_MAX - ReturnValue) + 1;
992    }
993
994    *RetInteger = ReturnValue;
995    return (Status);
996
997
998ErrorExit:
999    switch (Base)
1000    {
1001    case 8:
1002        Status = AE_BAD_OCTAL_CONSTANT;
1003        break;
1004
1005    case 10:
1006        Status = AE_BAD_DECIMAL_CONSTANT;
1007        break;
1008
1009    case 16:
1010        Status = AE_BAD_HEX_CONSTANT;
1011        break;
1012
1013    default:
1014        /* Base validated above */
1015        break;
1016    }
1017
1018    return (Status);
1019}
1020
1021
1022