diff options
author | Danny Smith <dannysmith@users.sourceforge.net> | 2002-06-13 10:20:48 +0000 |
---|---|---|
committer | Danny Smith <dannysmith@users.sourceforge.net> | 2002-06-13 10:20:48 +0000 |
commit | dc8971488e7c174ab4084cbdb0a8f12c39b738d7 (patch) | |
tree | d679387fa379b6d5feb9756bdd7237347614453b /winsup/mingw/mingwex/wcstoumax.c | |
parent | 5f74ae83e5fba1ceb73a8d822cbe2b48c619127f (diff) | |
download | cygnal-dc8971488e7c174ab4084cbdb0a8f12c39b738d7.tar.gz cygnal-dc8971488e7c174ab4084cbdb0a8f12c39b738d7.tar.bz2 cygnal-dc8971488e7c174ab4084cbdb0a8f12c39b738d7.zip |
* include/_mingw.h: Increment version to 2.0.
* Makefile.in: Ditto.
Merge in mingwex branch.
Diffstat (limited to 'winsup/mingw/mingwex/wcstoumax.c')
-rw-r--r-- | winsup/mingw/mingwex/wcstoumax.c | 113 |
1 files changed, 113 insertions, 0 deletions
diff --git a/winsup/mingw/mingwex/wcstoumax.c b/winsup/mingw/mingwex/wcstoumax.c new file mode 100644 index 000000000..9bd6cd704 --- /dev/null +++ b/winsup/mingw/mingwex/wcstoumax.c @@ -0,0 +1,113 @@ +/* + 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 <wchar.h> +#include <errno.h> +#include <ctype.h> +#include <inttypes.h> + +/* convert digit wide character to number, in any base */ + +#define ToWNumber(c) (iswdigit(c) ? (c) - L'0' : \ + iswupper(c) ? (c) - L'A' + 10 : \ + iswlower(c) ? (c) - L'a' + 10 : \ + -1 /* "invalid" flag */ \ + ) + +/* validate converted digit character for specific base */ +#define valid(n, b) ((n) >= 0 && (n) < (b)) + +uintmax_t +wcstoumax(nptr, endptr, base) + register const wchar_t * __restrict__ nptr; + wchar_t ** __restrict__ endptr; + register int base; + { + register uintmax_t accum; /* accumulates converted value */ + register uintmax_t next; /* for computing next value of accum */ + register int n; /* numeral from digit character */ + int minus; /* set iff minus sign seen (yes!) */ + int toobig; /* set iff value overflows */ + + if ( endptr != NULL ) + *endptr = (wchar_t *)nptr; /* in case no conv performed */ + + if ( base < 0 || base == 1 || base > 36 ) + { + errno = EDOM; + return 0; /* unspecified behavior */ + } + + /* skip initial, possibly empty sequence of white-space w.characters */ + + while ( iswspace(*nptr) ) + ++nptr; + + /* process subject sequence: */ + + /* optional sign */ + + if ( (minus = *nptr == L'-') || *nptr == L'+' ) + ++nptr; + + if ( base == 0 ) + { + if ( *nptr == L'0' ) + { + if ( nptr[1] == L'X' || nptr[1] == L'x' ) + base = 16; + else + base = 8; + } + else + base = 10; + } + /* optional "0x" or "0X" for base 16 */ + + if ( base == 16 && *nptr == L'0' + && (nptr[1] == L'X' || nptr[1] == L'x') + ) + nptr += 2; /* skip past this prefix */ + + /* check whether there is at least one valid digit */ + + n = ToWNumber(*nptr); + ++nptr; + + if ( !valid(n, base) ) + return 0; /* subject seq. not of expected form */ + + accum = n; + + for ( toobig = 0; n = ToWNumber(*nptr), valid(n, base); ++nptr ) + if ( accum > UINTMAX_MAX / base + 1 /* major wrap-around */ + || (next = base * accum + n) < accum /* minor wrap-around */ + ) + toobig = 1; /* but keep scanning */ + else + accum = next; + + if ( endptr != NULL ) + *endptr = (wchar_t *)nptr; /* -> first not-valid-digit */ + + if ( toobig ) + { + errno = ERANGE; + return UINTMAX_MAX; + } + else + return minus ? -accum : accum; /* (yes!) */ + } + +unsigned long long __attribute__ ((alias ("wcstoumax"))) +wcstoull (const wchar_t* __restrict__ nptr, wchar_t ** __restrict__ endptr, int base); |