master
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
35intmax_t
36__cdecl
37wcstoimax(const wchar_t * __restrict__ nptr, wchar_t ** __restrict__ endptr, int base)
38 {
39 register uintmax_t accum; /* accumulates converted value */
40 register int n; /* numeral from digit character */
41 int minus; /* set iff minus sign seen */
42 int toobig; /* set iff value overflows */
43
44 if ( endptr != NULL )
45 *endptr = (wchar_t *)nptr; /* in case no conv performed */
46
47 if ( base < 0 || base == 1 || base > 36 )
48 {
49 errno = EDOM;
50 return 0; /* unspecified behavior */
51 }
52
53 /* skip initial, possibly empty sequence of white-space w.characters */
54
55 while ( iswspace(*nptr) )
56 ++nptr;
57
58 /* process subject sequence: */
59
60 /* optional sign */
61
62 if ( (minus = *nptr == L'-') || *nptr == L'+' )
63 ++nptr;
64
65 if ( base == 0 )
66 {
67 if ( *nptr == L'0' )
68 {
69 if ( nptr[1] == L'X' || nptr[1] == L'x' )
70 base = 16;
71 else
72 base = 8;
73 }
74 else
75 base = 10;
76 }
77 /* optional "0x" or "0X" for base 16 */
78
79 if ( base == 16 && *nptr == L'0'
80 && (nptr[1] == L'X' || nptr[1] == L'x')
81 )
82 nptr += 2; /* skip past this prefix */
83
84 /* check whether there is at least one valid digit */
85
86 n = ToWNumber(*nptr);
87 ++nptr;
88
89 if ( !valid(n, base) )
90 return 0; /* subject seq. not of expected form */
91
92 accum = n;
93
94 for ( toobig = 0; n = ToWNumber(*nptr), valid(n, base); ++nptr )
95 if ( accum > (uintmax_t)(INTMAX_MAX / base + 2) ) /* major wrap-around */
96 toobig = 1; /* but keep scanning */
97 else
98 accum = base * accum + n;
99
100 if ( endptr != NULL )
101 *endptr = (wchar_t *)nptr; /* -> first not-valid-digit */
102
103 if ( minus )
104 {
105 if ( accum > (uintmax_t)INTMAX_MAX + 1 )
106 toobig = 1;
107 }
108 else
109 if ( accum > (uintmax_t)INTMAX_MAX )
110 toobig = 1;
111
112 if ( toobig )
113 {
114 errno = ERANGE;
115 return minus ? INTMAX_MIN : INTMAX_MAX;
116 }
117 else
118 return (intmax_t)(minus ? -accum : accum);
119 }
120intmax_t (__cdecl *__MINGW_IMP_SYMBOL(wcstoimax))(const wchar_t * __restrict__, wchar_t ** __restrict__, int) = wcstoimax;
121
122long long __attribute__ ((alias ("wcstoimax")))
123__cdecl
124wcstoll (const wchar_t* __restrict__ nptr, wchar_t ** __restrict__ endptr, int base);
125extern long long __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(wcstoimax)))))
126(__cdecl *__MINGW_IMP_SYMBOL(wcstoll))(const wchar_t * __restrict__, wchar_t ** __restrict__, int);
127
128long long __attribute__ ((alias ("wcstoimax")))
129__cdecl
130_wcstoi64 (const wchar_t* __restrict__ nptr, wchar_t ** __restrict__ endptr, int base);
131extern long long __attribute__ ((alias (__MINGW64_STRINGIFY(__MINGW_IMP_SYMBOL(wcstoimax)))))
132(__cdecl *__MINGW_IMP_SYMBOL(_wcstoi64))(const wchar_t * __restrict__, wchar_t ** __restrict__, int);