OSDN Git Service

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