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