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