diff options
-rw-r--r-- | src/core/base16.c | 9 | ||||
-rw-r--r-- | src/core/misc.c | 62 | ||||
-rw-r--r-- | src/core/string.c | 129 | ||||
-rw-r--r-- | src/core/strtoull.c | 60 | ||||
-rw-r--r-- | src/include/ipxe/string.h | 14 | ||||
-rw-r--r-- | src/include/stdlib.h | 28 | ||||
-rw-r--r-- | src/tests/string_test.c | 48 |
7 files changed, 199 insertions, 151 deletions
diff --git a/src/core/base16.c b/src/core/base16.c index bf9cc21..d2977bd 100644 --- a/src/core/base16.c +++ b/src/core/base16.c @@ -20,9 +20,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> -#include <stdlib.h> #include <stdio.h> #include <errno.h> +#include <assert.h> +#include <ipxe/string.h> #include <ipxe/base16.h> /** @file @@ -87,13 +88,13 @@ int hex_decode ( const char *encoded, char separator, void *data, size_t len ) { /* Extract digits. Note that either digit may be NUL, * which would be interpreted as an invalid value by - * strtoul_charval(); there is therefore no need for an + * digit_value(); there is therefore no need for an * explicit end-of-string check. */ - sixteens = strtoul_charval ( *(encoded++) ); + sixteens = digit_value ( *(encoded++) ); if ( sixteens >= 16 ) return -EINVAL; - units = strtoul_charval ( *(encoded++) ); + units = digit_value ( *(encoded++) ); if ( units >= 16 ) return -EINVAL; diff --git a/src/core/misc.c b/src/core/misc.c deleted file mode 100644 index 84cfcd8..0000000 --- a/src/core/misc.c +++ /dev/null @@ -1,62 +0,0 @@ -/************************************************************************** -MISC Support Routines -**************************************************************************/ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdlib.h> -#include <ctype.h> -#include <byteswap.h> -#include <ipxe/in.h> -#include <ipxe/timer.h> - -unsigned int strtoul_charval ( unsigned int charval ) { - - if ( charval >= 'a' ) { - charval = ( charval - 'a' + 10 ); - } else if ( charval >= 'A' ) { - charval = ( charval - 'A' + 10 ); - } else if ( charval <= '9' ) { - charval = ( charval - '0' ); - } - - return charval; -} - -unsigned long strtoul ( const char *p, char **endp, int base ) { - unsigned long ret = 0; - int negative = 0; - unsigned int charval; - - while ( isspace ( *p ) ) - p++; - - if ( *p == '-' ) { - negative = 1; - p++; - } - - base = strtoul_base ( &p, base ); - - while ( 1 ) { - charval = strtoul_charval ( *p ); - if ( charval >= ( unsigned int ) base ) - break; - ret = ( ( ret * base ) + charval ); - p++; - } - - if ( negative ) - ret = -ret; - - if ( endp ) - *endp = ( char * ) p; - - return ( ret ); -} - -/* - * Local variables: - * c-basic-offset: 8 - * End: - */ diff --git a/src/core/string.c b/src/core/string.c index db80d61..8000efc 100644 --- a/src/core/string.c +++ b/src/core/string.c @@ -366,3 +366,132 @@ char * strndup ( const char *src, size_t max ) { } return dup; } + +/** + * Calculate digit value + * + * @v character Digit character + * @ret digit Digit value + * + * Invalid digits will be returned as a value greater than or equal to + * the numeric base. + */ +unsigned int digit_value ( unsigned int character ) { + + if ( character >= 'a' ) + return ( character - ( 'a' - 10 ) ); + if ( character >= 'A' ) + return ( character - ( 'A' - 10 ) ); + if ( character <= '9' ) + return ( character - '0' ); + return character; +} + +/** + * Preprocess string for strtoul() or strtoull() + * + * @v string String + * @v negate Final value should be negated + * @v base Numeric base + * @ret string Remaining string + */ +static const char * strtoul_pre ( const char *string, int *negate, int *base ) { + + /* Skip any leading whitespace */ + while ( isspace ( *string ) ) + string++; + + /* Process arithmetic sign, if present */ + *negate = 0; + if ( *string == '-' ) { + string++; + *negate = 1; + } else if ( *string == '+' ) { + string++; + } + + /* Process base, if present */ + if ( *base == 0 ) { + *base = 10; + if ( *string == '0' ) { + string++; + *base = 8; + if ( ( *string & ~0x20 ) == 'X' ) { + string++; + *base = 16; + } + } + } + + return string; +} + +/** + * Convert string to numeric value + * + * @v string String + * @v endp End pointer (or NULL) + * @v base Numeric base (or zero to autodetect) + * @ret value Numeric value + */ +unsigned long strtoul ( const char *string, char **endp, int base ) { + unsigned long value = 0; + unsigned int digit; + int negate; + + /* Preprocess string */ + string = strtoul_pre ( string, &negate, &base ); + + /* Process digits */ + for ( ; ; string++ ) { + digit = digit_value ( *string ); + if ( digit >= ( unsigned int ) base ) + break; + value = ( ( value * base ) + digit ); + } + + /* Negate value if, applicable */ + if ( negate ) + value = -value; + + /* Fill in end pointer, if applicable */ + if ( endp ) + *endp = ( ( char * ) string ); + + return value; +} + +/** + * Convert string to numeric value + * + * @v string String + * @v endp End pointer (or NULL) + * @v base Numeric base (or zero to autodetect) + * @ret value Numeric value + */ +unsigned long long strtoull ( const char *string, char **endp, int base ) { + unsigned long long value = 0; + unsigned int digit; + int negate; + + /* Preprocess string */ + string = strtoul_pre ( string, &negate, &base ); + + /* Process digits */ + for ( ; ; string++ ) { + digit = digit_value ( *string ); + if ( digit >= ( unsigned int ) base ) + break; + value = ( ( value * base ) + digit ); + } + + /* Negate value if, applicable */ + if ( negate ) + value = -value; + + /* Fill in end pointer, if applicable */ + if ( endp ) + *endp = ( ( char * ) string ); + + return value; +} diff --git a/src/core/strtoull.c b/src/core/strtoull.c deleted file mode 100644 index 00986ee..0000000 --- a/src/core/strtoull.c +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk> - * Copyright (C) 2010 Piotr JaroszyĆski <p.jaroszynski@gmail.com> - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of the - * License, or any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -FILE_LICENCE ( GPL2_OR_LATER ); - -#include <stdlib.h> -#include <ctype.h> - -/* - * Despite being exactly the same as strtoul() except the long long instead of - * long it ends up being much bigger so provide a separate implementation in a - * separate object so that it won't be linked in if not used. - */ -unsigned long long strtoull ( const char *p, char **endp, int base ) { - unsigned long long ret = 0; - int negative = 0; - unsigned int charval; - - while ( isspace ( *p ) ) - p++; - - if ( *p == '-' ) { - negative = 1; - p++; - } - - base = strtoul_base ( &p, base ); - - while ( 1 ) { - charval = strtoul_charval ( *p ); - if ( charval >= ( unsigned int ) base ) - break; - ret = ( ( ret * base ) + charval ); - p++; - } - - if ( negative ) - ret = -ret; - - if ( endp ) - *endp = ( char * ) p; - - return ( ret ); -} diff --git a/src/include/ipxe/string.h b/src/include/ipxe/string.h new file mode 100644 index 0000000..954c7f1 --- /dev/null +++ b/src/include/ipxe/string.h @@ -0,0 +1,14 @@ +#ifndef _IPXE_STRING_H +#define _IPXE_STRING_H + +/** @file + * + * String functions + * + */ + +FILE_LICENCE ( GPL2_OR_LATER ); + +extern unsigned int digit_value ( unsigned int digit ); + +#endif /* _IPXE_STRING_H */ diff --git a/src/include/stdlib.h b/src/include/stdlib.h index 2951522..819b87b 100644 --- a/src/include/stdlib.h +++ b/src/include/stdlib.h @@ -13,31 +13,9 @@ FILE_LICENCE ( GPL2_OR_LATER ); **************************************************************************** */ -static inline int strtoul_base ( const char **pp, int base ) -{ - const char *p = *pp; - - if ( base == 0 ) { - base = 10; - if ( *p == '0' ) { - p++; - base = 8; - if ( ( *p | 0x20 ) == 'x' ) { - p++; - base = 16; - } - } - } - - *pp = p; - - return base; -} - -extern unsigned int strtoul_charval ( unsigned int charval ); -extern unsigned long strtoul ( const char *p, char **endp, int base ); -extern unsigned long long strtoull ( const char *p, char **endp, int base ); - +extern unsigned long strtoul ( const char *string, char **endp, int base ); +extern unsigned long long strtoull ( const char *string, char **endp, + int base ); /***************************************************************************** * diff --git a/src/tests/string_test.c b/src/tests/string_test.c index e5669f4..541b7e7 100644 --- a/src/tests/string_test.c +++ b/src/tests/string_test.c @@ -31,8 +31,10 @@ FILE_LICENCE ( GPL2_OR_LATER ); #include <stdint.h> #include <stdlib.h> +#include <stdio.h> #include <string.h> #include <strings.h> +#include <ipxe/string.h> #include <ipxe/test.h> /** @@ -242,6 +244,52 @@ static void string_test_exec ( void ) { ok ( dest == buf ); ok ( strcmp ( buf, "append this" ) == 0 ); } + + /* Test digit_value() */ + { + unsigned int i; + char buf[2]; + for ( i = 0 ; i < 16 ; i++ ) { + snprintf ( buf, sizeof ( buf ), "%x", i ); + ok ( digit_value ( buf[0] ) == i ); + snprintf ( buf, sizeof ( buf ), "%X", i ); + ok ( digit_value ( buf[0] ) == i ); + } + ok ( digit_value ( 0 ) >= 16 ); + ok ( digit_value ( 9 ) >= 16 ); + ok ( digit_value ( '0' - 1 ) >= 16 ); + ok ( digit_value ( '9' + 1 ) >= 16 ); + ok ( digit_value ( 'A' - 1 ) >= 16 ); + ok ( digit_value ( 'F' + 1 ) >= 16 ); + ok ( digit_value ( 'a' - 1 ) >= 16 ); + ok ( digit_value ( 'f' + 1 ) >= 16 ); + } + + /* Test strtoul() */ + ok ( strtoul ( "12345", NULL, 0 ) == 12345UL ); + ok ( strtoul ( " 741", NULL, 10 ) == 741UL ); + ok ( strtoul ( " 555a", NULL, 0 ) == 555UL ); + ok ( strtoul ( " 555a", NULL, 16 ) == 0x555aUL ); + ok ( strtoul ( "-12", NULL, 0 ) == -12UL ); + ok ( strtoul ( "+3", NULL, 0 ) == 3UL ); + ok ( strtoul ( "721", NULL, 0 ) == 721UL ); + ok ( strtoul ( "721", NULL, 8 ) == 0721UL ); + ok ( strtoul ( "0721", NULL, 0 ) == 0721UL ); + ok ( strtoul ( "", NULL, 0 ) == 0UL ); + ok ( strtoul ( "\t0xcAfe", NULL, 0 ) == 0xcafeUL ); + ok ( strtoul ( "0xffffffff", NULL, 0 ) == 0xffffffffUL ); + { + static const char string[] = "123aHa.world"; + char *endp; + ok ( strtoul ( string, &endp, 0 ) == 123UL ); + ok ( endp == &string[3] ); + ok ( strtoul ( string, &endp, 16 ) == 0x123aUL ); + ok ( endp == &string[4] ); + ok ( strtoul ( string, &endp, 26 ) == + ( ( ( ( ( 1 * 26 + 2 ) * 26 + 3 ) * 26 + 10 ) * 26 + + 17 ) * 26 + 10 ) ); + ok ( endp == &string[6] ); + } } /** String self-test */ |