Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /*******************************************************************************
0003  *
0004  * Module Name: utstrsuppt - Support functions for string-to-integer conversion
0005  *
0006  ******************************************************************************/
0007 
0008 #include <acpi/acpi.h>
0009 #include "accommon.h"
0010 
0011 #define _COMPONENT          ACPI_UTILITIES
0012 ACPI_MODULE_NAME("utstrsuppt")
0013 
0014 /* Local prototypes */
0015 static acpi_status
0016 acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit);
0017 
0018 static acpi_status
0019 acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product);
0020 
0021 static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum);
0022 
0023 /*******************************************************************************
0024  *
0025  * FUNCTION:    acpi_ut_convert_octal_string
0026  *
0027  * PARAMETERS:  string                  - Null terminated input string
0028  *              return_value_ptr        - Where the converted value is returned
0029  *
0030  * RETURN:      Status and 64-bit converted integer
0031  *
0032  * DESCRIPTION: Performs a base 8 conversion of the input string to an
0033  *              integer value, either 32 or 64 bits.
0034  *
0035  * NOTE:        Maximum 64-bit unsigned octal value is 01777777777777777777777
0036  *              Maximum 32-bit unsigned octal value is 037777777777
0037  *
0038  ******************************************************************************/
0039 
0040 acpi_status acpi_ut_convert_octal_string(char *string, u64 *return_value_ptr)
0041 {
0042     u64 accumulated_value = 0;
0043     acpi_status status = AE_OK;
0044 
0045     /* Convert each ASCII byte in the input string */
0046 
0047     while (*string) {
0048         /*
0049          * Character must be ASCII 0-7, otherwise:
0050          * 1) Runtime: terminate with no error, per the ACPI spec
0051          * 2) Compiler: return an error
0052          */
0053         if (!(ACPI_IS_OCTAL_DIGIT(*string))) {
0054 #ifdef ACPI_ASL_COMPILER
0055             status = AE_BAD_OCTAL_CONSTANT;
0056 #endif
0057             break;
0058         }
0059 
0060         /* Convert and insert this octal digit into the accumulator */
0061 
0062         status = acpi_ut_insert_digit(&accumulated_value, 8, *string);
0063         if (ACPI_FAILURE(status)) {
0064             status = AE_OCTAL_OVERFLOW;
0065             break;
0066         }
0067 
0068         string++;
0069     }
0070 
0071     /* Always return the value that has been accumulated */
0072 
0073     *return_value_ptr = accumulated_value;
0074     return (status);
0075 }
0076 
0077 /*******************************************************************************
0078  *
0079  * FUNCTION:    acpi_ut_convert_decimal_string
0080  *
0081  * PARAMETERS:  string                  - Null terminated input string
0082  *              return_value_ptr        - Where the converted value is returned
0083  *
0084  * RETURN:      Status and 64-bit converted integer
0085  *
0086  * DESCRIPTION: Performs a base 10 conversion of the input string to an
0087  *              integer value, either 32 or 64 bits.
0088  *
0089  * NOTE:        Maximum 64-bit unsigned decimal value is 18446744073709551615
0090  *              Maximum 32-bit unsigned decimal value is 4294967295
0091  *
0092  ******************************************************************************/
0093 
0094 acpi_status acpi_ut_convert_decimal_string(char *string, u64 *return_value_ptr)
0095 {
0096     u64 accumulated_value = 0;
0097     acpi_status status = AE_OK;
0098 
0099     /* Convert each ASCII byte in the input string */
0100 
0101     while (*string) {
0102         /*
0103          * Character must be ASCII 0-9, otherwise:
0104          * 1) Runtime: terminate with no error, per the ACPI spec
0105          * 2) Compiler: return an error
0106          */
0107         if (!isdigit((int)*string)) {
0108 #ifdef ACPI_ASL_COMPILER
0109             status = AE_BAD_DECIMAL_CONSTANT;
0110 #endif
0111             break;
0112         }
0113 
0114         /* Convert and insert this decimal digit into the accumulator */
0115 
0116         status = acpi_ut_insert_digit(&accumulated_value, 10, *string);
0117         if (ACPI_FAILURE(status)) {
0118             status = AE_DECIMAL_OVERFLOW;
0119             break;
0120         }
0121 
0122         string++;
0123     }
0124 
0125     /* Always return the value that has been accumulated */
0126 
0127     *return_value_ptr = accumulated_value;
0128     return (status);
0129 }
0130 
0131 /*******************************************************************************
0132  *
0133  * FUNCTION:    acpi_ut_convert_hex_string
0134  *
0135  * PARAMETERS:  string                  - Null terminated input string
0136  *              return_value_ptr        - Where the converted value is returned
0137  *
0138  * RETURN:      Status and 64-bit converted integer
0139  *
0140  * DESCRIPTION: Performs a base 16 conversion of the input string to an
0141  *              integer value, either 32 or 64 bits.
0142  *
0143  * NOTE:        Maximum 64-bit unsigned hex value is 0xFFFFFFFFFFFFFFFF
0144  *              Maximum 32-bit unsigned hex value is 0xFFFFFFFF
0145  *
0146  ******************************************************************************/
0147 
0148 acpi_status acpi_ut_convert_hex_string(char *string, u64 *return_value_ptr)
0149 {
0150     u64 accumulated_value = 0;
0151     acpi_status status = AE_OK;
0152 
0153     /* Convert each ASCII byte in the input string */
0154 
0155     while (*string) {
0156         /*
0157          * Character must be ASCII A-F, a-f, or 0-9, otherwise:
0158          * 1) Runtime: terminate with no error, per the ACPI spec
0159          * 2) Compiler: return an error
0160          */
0161         if (!isxdigit((int)*string)) {
0162 #ifdef ACPI_ASL_COMPILER
0163             status = AE_BAD_HEX_CONSTANT;
0164 #endif
0165             break;
0166         }
0167 
0168         /* Convert and insert this hex digit into the accumulator */
0169 
0170         status = acpi_ut_insert_digit(&accumulated_value, 16, *string);
0171         if (ACPI_FAILURE(status)) {
0172             status = AE_HEX_OVERFLOW;
0173             break;
0174         }
0175 
0176         string++;
0177     }
0178 
0179     /* Always return the value that has been accumulated */
0180 
0181     *return_value_ptr = accumulated_value;
0182     return (status);
0183 }
0184 
0185 /*******************************************************************************
0186  *
0187  * FUNCTION:    acpi_ut_remove_leading_zeros
0188  *
0189  * PARAMETERS:  string                  - Pointer to input ASCII string
0190  *
0191  * RETURN:      Next character after any leading zeros. This character may be
0192  *              used by the caller to detect end-of-string.
0193  *
0194  * DESCRIPTION: Remove any leading zeros in the input string. Return the
0195  *              next character after the final ASCII zero to enable the caller
0196  *              to check for the end of the string (NULL terminator).
0197  *
0198  ******************************************************************************/
0199 
0200 char acpi_ut_remove_leading_zeros(char **string)
0201 {
0202 
0203     while (**string == ACPI_ASCII_ZERO) {
0204         *string += 1;
0205     }
0206 
0207     return (**string);
0208 }
0209 
0210 /*******************************************************************************
0211  *
0212  * FUNCTION:    acpi_ut_remove_whitespace
0213  *
0214  * PARAMETERS:  string                  - Pointer to input ASCII string
0215  *
0216  * RETURN:      Next character after any whitespace. This character may be
0217  *              used by the caller to detect end-of-string.
0218  *
0219  * DESCRIPTION: Remove any leading whitespace in the input string. Return the
0220  *              next character after the final ASCII zero to enable the caller
0221  *              to check for the end of the string (NULL terminator).
0222  *
0223  ******************************************************************************/
0224 
0225 char acpi_ut_remove_whitespace(char **string)
0226 {
0227 
0228     while (isspace((u8)**string)) {
0229         *string += 1;
0230     }
0231 
0232     return (**string);
0233 }
0234 
0235 /*******************************************************************************
0236  *
0237  * FUNCTION:    acpi_ut_detect_hex_prefix
0238  *
0239  * PARAMETERS:  string                  - Pointer to input ASCII string
0240  *
0241  * RETURN:      TRUE if a "0x" prefix was found at the start of the string
0242  *
0243  * DESCRIPTION: Detect and remove a hex "0x" prefix
0244  *
0245  ******************************************************************************/
0246 
0247 u8 acpi_ut_detect_hex_prefix(char **string)
0248 {
0249     char *initial_position = *string;
0250 
0251     acpi_ut_remove_hex_prefix(string);
0252     if (*string != initial_position) {
0253         return (TRUE);  /* String is past leading 0x */
0254     }
0255 
0256     return (FALSE);     /* Not a hex string */
0257 }
0258 
0259 /*******************************************************************************
0260  *
0261  * FUNCTION:    acpi_ut_remove_hex_prefix
0262  *
0263  * PARAMETERS:  string                  - Pointer to input ASCII string
0264  *
0265  * RETURN:      none
0266  *
0267  * DESCRIPTION: Remove a hex "0x" prefix
0268  *
0269  ******************************************************************************/
0270 
0271 void acpi_ut_remove_hex_prefix(char **string)
0272 {
0273     if ((**string == ACPI_ASCII_ZERO) &&
0274         (tolower((int)*(*string + 1)) == 'x')) {
0275         *string += 2;   /* Go past the leading 0x */
0276     }
0277 }
0278 
0279 /*******************************************************************************
0280  *
0281  * FUNCTION:    acpi_ut_detect_octal_prefix
0282  *
0283  * PARAMETERS:  string                  - Pointer to input ASCII string
0284  *
0285  * RETURN:      True if an octal "0" prefix was found at the start of the
0286  *              string
0287  *
0288  * DESCRIPTION: Detect and remove an octal prefix (zero)
0289  *
0290  ******************************************************************************/
0291 
0292 u8 acpi_ut_detect_octal_prefix(char **string)
0293 {
0294 
0295     if (**string == ACPI_ASCII_ZERO) {
0296         *string += 1;   /* Go past the leading 0 */
0297         return (TRUE);
0298     }
0299 
0300     return (FALSE);     /* Not an octal string */
0301 }
0302 
0303 /*******************************************************************************
0304  *
0305  * FUNCTION:    acpi_ut_insert_digit
0306  *
0307  * PARAMETERS:  accumulated_value       - Current value of the integer value
0308  *                                        accumulator. The new value is
0309  *                                        returned here.
0310  *              base                    - Radix, either 8/10/16
0311  *              ascii_digit             - ASCII single digit to be inserted
0312  *
0313  * RETURN:      Status and result of the convert/insert operation. The only
0314  *              possible returned exception code is numeric overflow of
0315  *              either the multiply or add conversion operations.
0316  *
0317  * DESCRIPTION: Generic conversion and insertion function for all bases:
0318  *
0319  *              1) Multiply the current accumulated/converted value by the
0320  *              base in order to make room for the new character.
0321  *
0322  *              2) Convert the new character to binary and add it to the
0323  *              current accumulated value.
0324  *
0325  *              Note: The only possible exception indicates an integer
0326  *              overflow (AE_NUMERIC_OVERFLOW)
0327  *
0328  ******************************************************************************/
0329 
0330 static acpi_status
0331 acpi_ut_insert_digit(u64 *accumulated_value, u32 base, int ascii_digit)
0332 {
0333     acpi_status status;
0334     u64 product;
0335 
0336     /* Make room in the accumulated value for the incoming digit */
0337 
0338     status = acpi_ut_strtoul_multiply64(*accumulated_value, base, &product);
0339     if (ACPI_FAILURE(status)) {
0340         return (status);
0341     }
0342 
0343     /* Add in the new digit, and store the sum to the accumulated value */
0344 
0345     status =
0346         acpi_ut_strtoul_add64(product,
0347                   acpi_ut_ascii_char_to_hex(ascii_digit),
0348                   accumulated_value);
0349 
0350     return (status);
0351 }
0352 
0353 /*******************************************************************************
0354  *
0355  * FUNCTION:    acpi_ut_strtoul_multiply64
0356  *
0357  * PARAMETERS:  multiplicand            - Current accumulated converted integer
0358  *              base                    - Base/Radix
0359  *              out_product             - Where the product is returned
0360  *
0361  * RETURN:      Status and 64-bit product
0362  *
0363  * DESCRIPTION: Multiply two 64-bit values, with checking for 64-bit overflow as
0364  *              well as 32-bit overflow if necessary (if the current global
0365  *              integer width is 32).
0366  *
0367  ******************************************************************************/
0368 
0369 static acpi_status
0370 acpi_ut_strtoul_multiply64(u64 multiplicand, u32 base, u64 *out_product)
0371 {
0372     u64 product;
0373     u64 quotient;
0374 
0375     /* Exit if either operand is zero */
0376 
0377     *out_product = 0;
0378     if (!multiplicand || !base) {
0379         return (AE_OK);
0380     }
0381 
0382     /*
0383      * Check for 64-bit overflow before the actual multiplication.
0384      *
0385      * Notes: 64-bit division is often not supported on 32-bit platforms
0386      * (it requires a library function), Therefore ACPICA has a local
0387      * 64-bit divide function. Also, Multiplier is currently only used
0388      * as the radix (8/10/16), to the 64/32 divide will always work.
0389      */
0390     acpi_ut_short_divide(ACPI_UINT64_MAX, base, &quotient, NULL);
0391     if (multiplicand > quotient) {
0392         return (AE_NUMERIC_OVERFLOW);
0393     }
0394 
0395     product = multiplicand * base;
0396 
0397     /* Check for 32-bit overflow if necessary */
0398 
0399     if ((acpi_gbl_integer_bit_width == 32) && (product > ACPI_UINT32_MAX)) {
0400         return (AE_NUMERIC_OVERFLOW);
0401     }
0402 
0403     *out_product = product;
0404     return (AE_OK);
0405 }
0406 
0407 /*******************************************************************************
0408  *
0409  * FUNCTION:    acpi_ut_strtoul_add64
0410  *
0411  * PARAMETERS:  addend1                 - Current accumulated converted integer
0412  *              digit                   - New hex value/char
0413  *              out_sum                 - Where sum is returned (Accumulator)
0414  *
0415  * RETURN:      Status and 64-bit sum
0416  *
0417  * DESCRIPTION: Add two 64-bit values, with checking for 64-bit overflow as
0418  *              well as 32-bit overflow if necessary (if the current global
0419  *              integer width is 32).
0420  *
0421  ******************************************************************************/
0422 
0423 static acpi_status acpi_ut_strtoul_add64(u64 addend1, u32 digit, u64 *out_sum)
0424 {
0425     u64 sum;
0426 
0427     /* Check for 64-bit overflow before the actual addition */
0428 
0429     if ((addend1 > 0) && (digit > (ACPI_UINT64_MAX - addend1))) {
0430         return (AE_NUMERIC_OVERFLOW);
0431     }
0432 
0433     sum = addend1 + digit;
0434 
0435     /* Check for 32-bit overflow if necessary */
0436 
0437     if ((acpi_gbl_integer_bit_width == 32) && (sum > ACPI_UINT32_MAX)) {
0438         return (AE_NUMERIC_OVERFLOW);
0439     }
0440 
0441     *out_sum = sum;
0442     return (AE_OK);
0443 }