1 /**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the mingw-w64 runtime package.
4 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
5 */
6 /*
7 This source code was extracted from the Q8 package created and
8 placed in the PUBLIC DOMAIN by Doug Gwyn <gwyn@arl.mil>
9
10 last edit: 1999/11/05 gwyn@arl.mil
11
12 Implements subclause 7.8.2 of ISO/IEC 9899:1999 (E).
13
14 This particular implementation requires the matching <inttypes.h>.
15 It also assumes that character codes for A..Z and a..z are in
16 contiguous ascending order; this is true for ASCII but not EBCDIC.
17 */
18
19 #include <wchar.h>
20 #include <errno.h>
21 #include <ctype.h>
22 #include <inttypes.h>
23
24 /* convert digit wide character to number, in any base */
25
26 #define ToWNumber(c) (iswdigit(c) ? (c) - L'0' : \
27 iswupper(c) ? (c) - L'A' + 10 : \
28 iswlower(c) ? (c) - L'a' + 10 : \
29 -1 /* "invalid" flag */ \
30 )
31
32 /* validate converted digit character for specific base */
33 #define valid(n, b) ((n) >= 0 && (n) < (b))
34
35 uintmax_t
wcstoumax(nptr,endptr,base)36 wcstoumax(nptr, endptr, base)
37 register const wchar_t * __restrict__ nptr;
38 wchar_t ** __restrict__ endptr;
39 register int base;
40 {
41 register uintmax_t accum; /* accumulates converted value */
42 register uintmax_t next; /* for computing next value of accum */
43 register int n; /* numeral from digit character */
44 int minus; /* set iff minus sign seen (yes!) */
45 int toobig; /* set iff value overflows */
46
47 if ( endptr != NULL )
48 *endptr = (wchar_t *)nptr; /* in case no conv performed */
49
50 if ( base < 0 || base == 1 || base > 36 )
51 {
52 errno = EDOM;
53 return 0; /* unspecified behavior */
54 }
55
56 /* skip initial, possibly empty sequence of white-space w.characters */
57
58 while ( iswspace(*nptr) )
59 ++nptr;
60
61 /* process subject sequence: */
62
63 /* optional sign */
64
65 if ( (minus = *nptr == L'-') || *nptr == L'+' )
66 ++nptr;
67
68 if ( base == 0 )
69 {
70 if ( *nptr == L'0' )
71 {
72 if ( nptr[1] == L'X' || nptr[1] == L'x' )
73 base = 16;
74 else
75 base = 8;
76 }
77 else
78 base = 10;
79 }
80 /* optional "0x" or "0X" for base 16 */
81
82 if ( base == 16 && *nptr == L'0'
83 && (nptr[1] == L'X' || nptr[1] == L'x')
84 )
85 nptr += 2; /* skip past this prefix */
86
87 /* check whether there is at least one valid digit */
88
89 n = ToWNumber(*nptr);
90 ++nptr;
91
92 if ( !valid(n, base) )
93 return 0; /* subject seq. not of expected form */
94
95 accum = n;
96
97 for ( toobig = 0; n = ToWNumber(*nptr), valid(n, base); ++nptr )
98 if ( accum > UINTMAX_MAX / base + 1 /* major wrap-around */
99 || (next = base * accum + n) < accum /* minor wrap-around */
100 )
101 toobig = 1; /* but keep scanning */
102 else
103 accum = next;
104
105 if ( endptr != NULL )
106 *endptr = (wchar_t *)nptr; /* -> first not-valid-digit */
107
108 if ( toobig )
109 {
110 errno = ERANGE;
111 return UINTMAX_MAX;
112 }
113 else
114 return minus ? -accum : accum; /* (yes!) */
115 }
116
117 unsigned long long __attribute__ ((alias ("wcstoumax")))
118 wcstoull (const wchar_t* __restrict__ nptr, wchar_t ** __restrict__ endptr, int base);
119