1193323Sed/*
2193323Sed * Copyright (c) 1990, 1993
3193323Sed *	The Regents of the University of California.  All rights reserved.
4193323Sed *
5193323Sed * Copyright (c) 2011 The FreeBSD Foundation
6193323Sed * All rights reserved.
7193323Sed * Portions of this software were developed by David Chisnall
8193323Sed * under sponsorship from the FreeBSD Foundation.
9193323Sed *
10193323Sed * Redistribution and use in source and binary forms, with or without
11193323Sed * modification, are permitted provided that the following conditions
12193323Sed * are met:
13193323Sed * 1. Redistributions of source code must retain the above copyright
14193323Sed *    notice, this list of conditions and the following disclaimer.
15193323Sed * 2. Redistributions in binary form must reproduce the above copyright
16193323Sed *    notice, this list of conditions and the following disclaimer in the
17193323Sed *    documentation and/or other materials provided with the distribution.
18249423Sdim * 4. Neither the name of the University nor the names of its contributors
19249423Sdim *    may be used to endorse or promote products derived from this software
20198090Srdivacky *    without specific prior written permission.
21198090Srdivacky *
22193323Sed * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23193323Sed * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24193323Sed * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25193323Sed * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26193323Sed * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27193323Sed * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28193323Sed * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29193323Sed * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32193323Sed * SUCH DAMAGE.
33193323Sed */
34193323Sed
35193323Sed#include <sys/cdefs.h>
36193323Sed__FBSDID("$FreeBSD$");
37193323Sed
38193323Sed#include <ctype.h>
39193323Sed#include <errno.h>
40193323Sed#include <limits.h>
41193323Sed#include <wchar.h>
42193323Sed#include <wctype.h>
43193323Sed#include "xlocale_private.h"
44249423Sdim
45193323Sed/*
46249423Sdim * Convert a wide character string to an unsigned long integer.
47193323Sed */
48249423Sdimunsigned long
49193323Sedwcstoul_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
50249423Sdim		int base, locale_t locale)
51193323Sed{
52249423Sdim	const wchar_t *s;
53193323Sed	unsigned long acc;
54193323Sed	wchar_t c;
55193323Sed	unsigned long cutoff;
56193323Sed	int neg, any, cutlim;
57193323Sed	FIX_LOCALE(locale);
58193323Sed
59193323Sed	/*
60249423Sdim	 * See strtol for comments as to the logic used.
61193323Sed	 */
62193323Sed	s = nptr;
63193323Sed	do {
64249423Sdim		c = *s++;
65193323Sed	} while (iswspace_l(c, locale));
66193323Sed	if (c == L'-') {
67193323Sed		neg = 1;
68249423Sdim		c = *s++;
69193323Sed	} else {
70249423Sdim		neg = 0;
71249423Sdim		if (c == L'+')
72249423Sdim			c = *s++;
73193323Sed	}
74193323Sed	if ((base == 0 || base == 16) &&
75249423Sdim	    c == L'0' && (*s == L'x' || *s == L'X')) {
76249423Sdim		c = s[1];
77249423Sdim		s += 2;
78193323Sed		base = 16;
79193323Sed	}
80249423Sdim	if (base == 0)
81193323Sed		base = c == L'0' ? 8 : 10;
82193323Sed	acc = any = 0;
83249423Sdim	if (base < 2 || base > 36)
84249423Sdim		goto noconv;
85193323Sed
86193323Sed	cutoff = ULONG_MAX / base;
87193323Sed	cutlim = ULONG_MAX % base;
88249423Sdim	for ( ; ; c = *s++) {
89234353Sdim#ifdef notyet
90234353Sdim		if (iswdigit_l(c, locale))
91193323Sed			c = digittoint_l(c, locale);
92193323Sed		else
93193323Sed#endif
94193323Sed		if (c >= L'0' && c <= L'9')
95193323Sed			c -= L'0';
96193323Sed		else if (c >= L'A' && c <= L'Z')
97193323Sed			c -= L'A' - 10;
98193323Sed		else if (c >= L'a' && c <= L'z')
99193323Sed			c -= L'a' - 10;
100249423Sdim		else
101193323Sed			break;
102249423Sdim		if (c >= base)
103193323Sed			break;
104193323Sed		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
105249423Sdim			any = -1;
106249423Sdim		else {
107249423Sdim			any = 1;
108193323Sed			acc *= base;
109193323Sed			acc += c;
110249423Sdim		}
111193323Sed	}
112193323Sed	if (any < 0) {
113193323Sed		acc = ULONG_MAX;
114193323Sed		errno = ERANGE;
115193323Sed	} else if (!any) {
116193323Sednoconv:
117249423Sdim		errno = EINVAL;
118193323Sed	} else if (neg)
119193323Sed		acc = -acc;
120193323Sed	if (endptr != NULL)
121249423Sdim		*endptr = (wchar_t *)(any ? s - 1 : nptr);
122193323Sed	return (acc);
123193323Sed}
124193323Sedunsigned long
125193323Sedwcstoul(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
126193323Sed{
127193323Sed	return wcstoul_l(nptr, endptr, base, __get_locale());
128249423Sdim}
129193323Sed