123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166 |
- #include "stdint.h"
- #include "ctype.h"
- #include "string.h"
- #include "errno.h"
- #include "limits.h"
- #include "_digits.h"
- // All code in this file was taken from PDClib
- intmax_t _atomax( const char * s )
- {
- intmax_t rc = 0;
- char sign = '+';
- const char * x;
- /* TODO: In other than "C" locale, additional patterns may be defined */
- while ( isspace( *s ) ) ++s;
- if ( *s == '+' ) ++s;
- else if ( *s == '-' ) sign = *(s++);
- /* TODO: Earlier version was missing tolower() but was not caught by tests */
- while ( ( x = memchr( _digits, tolower(*(s++)), 10 ) ) != NULL )
- {
- rc = rc * 10 + ( x - _digits );
- }
- return ( sign == '+' ) ? rc : -rc;
- }
- int atoi( const char * s )
- {
- return (int) _atomax( s );
- }
- const char * _strtox_prelim( const char * p, char * sign, int * base )
- {
- /* skipping leading whitespace */
- while ( isspace( *p ) ) ++p;
- /* determining / skipping sign */
- if ( *p != '+' && *p != '-' ) *sign = '+';
- else *sign = *(p++);
- /* determining base */
- if ( *p == '0' )
- {
- ++p;
- if ( ( *base == 0 || *base == 16 ) && ( *p == 'x' || *p == 'X' ) )
- {
- *base = 16;
- ++p;
- /* catching a border case here: "0x" followed by a non-digit should
- be parsed as the unprefixed zero.
- We have to "rewind" the parsing; having the base set to 16 if it
- was zero previously does not hurt, as the result is zero anyway.
- */
- if ( memchr( _digits, tolower(*p), *base ) == NULL )
- {
- p -= 2;
- }
- }
- else if ( *base == 0 )
- {
- *base = 8;
- /* Rewind one character back, so that the string composed
- of just a zero is correctly parsed (and endptr is set
- appropriately). */
- --p;
- }
- else
- {
- --p;
- }
- }
- else if ( ! *base )
- {
- *base = 10;
- }
- return ( ( *base >= 2 ) && ( *base <= 36 ) ) ? p : NULL;
- }
- uintmax_t _strtox_main( const char ** p, unsigned int base, uintmax_t error, uintmax_t limval, int limdigit, char * sign )
- {
- uintmax_t rc = 0;
- int digit = -1;
- const char * x;
- while ( ( x = memchr( _digits, tolower(**p), base ) ) != NULL )
- {
- digit = x - _digits;
- if ( ( rc < limval ) || ( ( rc == limval ) && ( digit <= limdigit ) ) )
- {
- rc = rc * base + (unsigned)digit;
- ++(*p);
- }
- else
- {
- errno = ERANGE;
- /* TODO: Only if endptr != NULL - but do we really want *another* parameter? */
- /* TODO: Earlier version was missing tolower() here but was not caught by tests */
- while ( memchr( _digits, tolower(**p), base ) != NULL ) ++(*p);
- /* TODO: This is ugly, but keeps caller from negating the error value */
- *sign = '+';
- return error;
- }
- }
- if ( digit == -1 )
- {
- *p = NULL;
- return 0;
- }
- return rc;
- }
- long int strtol( const char * s, char ** endptr, int base )
- {
- long int rc;
- char sign = '+';
- const char * p = _strtox_prelim( s, &sign, &base );
- if ( base < 2 || base > 36 ) return 0;
- if ( sign == '+' )
- {
- rc = (long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MAX, (uintmax_t)( LONG_MAX / base ), (int)( LONG_MAX % base ), &sign );
- }
- else
- {
- rc = (long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LONG_MIN, (uintmax_t)( LONG_MIN / -base ), (int)( -( LONG_MIN % base ) ), &sign );
- }
- if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
- return ( sign == '+' ) ? rc : -rc;
- }
- long long int strtoll( const char * s, char ** endptr, int base )
- {
- long long int rc;
- char sign = '+';
- const char * p = _strtox_prelim( s, &sign, &base );
- if ( base < 2 || base > 36 ) return 0;
- if ( sign == '+' )
- {
- rc = (long long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MAX, (uintmax_t)( LLONG_MAX / base ), (int)( LLONG_MAX % base ), &sign );
- }
- else
- {
- rc = (long long int)_strtox_main( &p, (unsigned)base, (uintmax_t)LLONG_MIN, (uintmax_t)( LLONG_MIN / -base ), (int)( -( LLONG_MIN % base ) ), &sign );
- }
- if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
- return ( sign == '+' ) ? rc : -rc;
- }
- unsigned long int strtoul( const char * s, char ** endptr, int base )
- {
- unsigned long int rc;
- char sign = '+';
- const char * p = _strtox_prelim( s, &sign, &base );
- if ( base < 2 || base > 36 ) return 0;
- rc = (unsigned long int)_strtox_main( &p, (unsigned)base, (uintmax_t)ULONG_MAX, (uintmax_t)( ULONG_MAX / base ), (int)( ULONG_MAX % base ), &sign );
- if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
- return ( sign == '+' ) ? rc : -rc;
- }
- unsigned long long int strtoull( const char * s, char ** endptr, int base )
- {
- unsigned long long int rc;
- char sign = '+';
- const char * p = _strtox_prelim( s, &sign, &base );
- if ( base < 2 || base > 36 ) return 0;
- rc = _strtox_main( &p, (unsigned)base, (uintmax_t)ULLONG_MAX, (uintmax_t)( ULLONG_MAX / base ), (int)( ULLONG_MAX % base ), &sign );
- if ( endptr != NULL ) *endptr = ( p != NULL ) ? (char *) p : (char *) s;
- return ( sign == '+' ) ? rc : -rc;
- }
|