blob: a1e28bb136f38e5fafbd4560ca167212d844e561 [file] [log] [blame]
Kai Tietz47222642008-01-05 14:10:17 +00001/**
2 * This file has no copyright assigned and is placed in the Public Domain.
3 * This file is part of the w64 mingw-runtime package.
Kai Tietzfa0cfe32010-01-15 20:02:21 +00004 * No warranty is given; refer to the file DISCLAIMER.PD within this package.
Kai Tietz47222642008-01-05 14:10:17 +00005 */
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
36wcstoimax(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 int n; /* numeral from digit character */
43 int minus; /* set iff minus sign seen */
44 int toobig; /* set iff value overflows */
45
46 if ( endptr != NULL )
47 *endptr = (wchar_t *)nptr; /* in case no conv performed */
48
49 if ( base < 0 || base == 1 || base > 36 )
50 {
51 errno = EDOM;
52 return 0; /* unspecified behavior */
53 }
54
55 /* skip initial, possibly empty sequence of white-space w.characters */
56
57 while ( iswspace(*nptr) )
58 ++nptr;
59
60 /* process subject sequence: */
61
62 /* optional sign */
63
64 if ( (minus = *nptr == L'-') || *nptr == L'+' )
65 ++nptr;
66
67 if ( base == 0 )
68 {
69 if ( *nptr == L'0' )
70 {
71 if ( nptr[1] == L'X' || nptr[1] == L'x' )
72 base = 16;
73 else
74 base = 8;
75 }
76 else
77 base = 10;
78 }
79 /* optional "0x" or "0X" for base 16 */
80
81 if ( base == 16 && *nptr == L'0'
82 && (nptr[1] == L'X' || nptr[1] == L'x')
83 )
84 nptr += 2; /* skip past this prefix */
85
86 /* check whether there is at least one valid digit */
87
88 n = ToWNumber(*nptr);
89 ++nptr;
90
91 if ( !valid(n, base) )
92 return 0; /* subject seq. not of expected form */
93
94 accum = n;
95
96 for ( toobig = 0; n = ToWNumber(*nptr), valid(n, base); ++nptr )
97 if ( accum > (uintmax_t)(INTMAX_MAX / base + 2) ) /* major wrap-around */
98 toobig = 1; /* but keep scanning */
99 else
100 accum = base * accum + n;
101
102 if ( endptr != NULL )
103 *endptr = (wchar_t *)nptr; /* -> first not-valid-digit */
104
105 if ( minus )
106 {
107 if ( accum > (uintmax_t)INTMAX_MAX + 1 )
108 toobig = 1;
109 }
110 else
111 if ( accum > (uintmax_t)INTMAX_MAX )
112 toobig = 1;
113
114 if ( toobig )
115 {
116 errno = ERANGE;
117 return minus ? INTMAX_MIN : INTMAX_MAX;
118 }
119 else
120 return (intmax_t)(minus ? -accum : accum);
121 }
122
123long long __attribute__ ((alias ("wcstoimax")))
124wcstoll (const wchar_t* __restrict__ nptr, wchar_t ** __restrict__ endptr, int base);