113 lines
2.7 KiB
C
113 lines
2.7 KiB
C
/*
|
|
This source code was extracted from the Q8 package created and
|
|
placed in the PUBLIC DOMAIN by Doug Gwyn <gwyn@arl.mil>
|
|
last edit: 1999/11/05 gwyn@arl.mil
|
|
|
|
Implements subclause 7.8.2 of ISO/IEC 9899:1999 (E).
|
|
|
|
This particular implementation requires the matching <inttypes.h>.
|
|
It also assumes that character codes for A..Z and a..z are in
|
|
contiguous ascending order; this is true for ASCII but not EBCDIC.
|
|
*/
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <ctype.h>
|
|
#include <inttypes.h>
|
|
|
|
/* Helper macros */
|
|
|
|
/* convert digit character to number, in any base */
|
|
#define ToNumber(c) (isdigit(c) ? (c) - '0' : \
|
|
isupper(c) ? (c) - 'A' + 10 : \
|
|
islower(c) ? (c) - 'a' + 10 : \
|
|
-1 /* "invalid" flag */ \
|
|
)
|
|
/* validate converted digit character for specific base */
|
|
#define valid(n, b) ((n) >= 0 && (n) < (b))
|
|
|
|
intmax_t
|
|
strtoimax(nptr, endptr, base)
|
|
register const char * __restrict__ nptr;
|
|
char ** __restrict__ endptr;
|
|
register int base;
|
|
{
|
|
register uintmax_t accum; /* accumulates converted value */
|
|
register int n; /* numeral from digit character */
|
|
int minus; /* set iff minus sign seen */
|
|
int toobig; /* set iff value overflows */
|
|
|
|
if ( endptr != NULL )
|
|
*endptr = (char *)nptr; /* in case no conversion's performed */
|
|
|
|
if ( base < 0 || base == 1 || base > 36 )
|
|
{
|
|
errno = EDOM;
|
|
return 0; /* unspecified behavior */
|
|
}
|
|
|
|
/* skip initial, possibly empty sequence of white-space characters */
|
|
|
|
while ( isspace(*nptr) )
|
|
++nptr;
|
|
|
|
/* process subject sequence: */
|
|
|
|
/* optional sign */
|
|
if ( (minus = *nptr == '-') || *nptr == '+' )
|
|
++nptr;
|
|
|
|
if ( base == 0 ) {
|
|
if ( *nptr == '0' ) {
|
|
if ( nptr[1] == 'X' || nptr[1] == 'x' )
|
|
base = 16;
|
|
else
|
|
base = 8;
|
|
}
|
|
else
|
|
base = 10;
|
|
}
|
|
/* optional "0x" or "0X" for base 16 */
|
|
|
|
if ( base == 16 && *nptr == '0' && (nptr[1] == 'X' || nptr[1] == 'x') )
|
|
nptr += 2; /* skip past this prefix */
|
|
|
|
/* check whether there is at least one valid digit */
|
|
|
|
n = ToNumber(*nptr);
|
|
++nptr;
|
|
|
|
if ( !valid(n, base) )
|
|
return 0; /* subject seq. not of expected form */
|
|
|
|
accum = n;
|
|
|
|
for ( toobig = 0; n = ToNumber(*nptr), valid(n, base); ++nptr )
|
|
if ( accum > (uintmax_t)(INTMAX_MAX / base + 2) ) /* major wrap-around */
|
|
toobig = 1; /* but keep scanning */
|
|
else
|
|
accum = base * accum + n;
|
|
|
|
if ( endptr != NULL )
|
|
*endptr = (char *)nptr; /* points to first not-valid-digit */
|
|
|
|
if ( minus )
|
|
{
|
|
if ( accum > (uintmax_t)INTMAX_MAX + 1 )
|
|
toobig = 1;
|
|
}
|
|
else
|
|
if ( accum > (uintmax_t)INTMAX_MAX )
|
|
toobig = 1;
|
|
|
|
if ( toobig )
|
|
{
|
|
errno = ERANGE;
|
|
return minus ? INTMAX_MIN : INTMAX_MAX;
|
|
}
|
|
else
|
|
return (intmax_t)(minus ? -accum : accum);
|
|
}
|
|
|
|
long long __attribute__ ((alias ("strtoimax")))
|
|
strtoll (const char* __restrict__ nptr, char ** __restrict__ endptr, int base);
|