1103097Stjr/*-
2103097Stjr * Copyright (c) 1990, 1993
3103097Stjr *	The Regents of the University of California.  All rights reserved.
4103097Stjr *
5227753Stheraven * Copyright (c) 2011 The FreeBSD Foundation
6227753Stheraven * All rights reserved.
7227753Stheraven * Portions of this software were developed by David Chisnall
8227753Stheraven * under sponsorship from the FreeBSD Foundation.
9227753Stheraven *
10103097Stjr * Redistribution and use in source and binary forms, with or without
11103097Stjr * modification, are permitted provided that the following conditions
12103097Stjr * are met:
13103097Stjr * 1. Redistributions of source code must retain the above copyright
14103097Stjr *    notice, this list of conditions and the following disclaimer.
15103097Stjr * 2. Redistributions in binary form must reproduce the above copyright
16103097Stjr *    notice, this list of conditions and the following disclaimer in the
17103097Stjr *    documentation and/or other materials provided with the distribution.
18103097Stjr * 4. Neither the name of the University nor the names of its contributors
19103097Stjr *    may be used to endorse or promote products derived from this software
20103097Stjr *    without specific prior written permission.
21103097Stjr *
22103097Stjr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23103097Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24103097Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25103097Stjr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26103097Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27103097Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28103097Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29103097Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30103097Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31103097Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32103097Stjr * SUCH DAMAGE.
33103097Stjr */
34103097Stjr
35103097Stjr#include <sys/cdefs.h>
36103097Stjr__FBSDID("$FreeBSD$");
37103097Stjr
38103097Stjr#include <ctype.h>
39103097Stjr#include <errno.h>
40103097Stjr#include <limits.h>
41103097Stjr#include <wchar.h>
42103097Stjr#include <wctype.h>
43227753Stheraven#include "xlocale_private.h"
44103097Stjr
45103097Stjr/*
46103097Stjr * Convert a string to a long integer.
47103097Stjr */
48103097Stjrlong
49227753Stheravenwcstol_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int
50227753Stheraven		base, locale_t locale)
51103097Stjr{
52103097Stjr	const wchar_t *s;
53103097Stjr	unsigned long acc;
54103097Stjr	wchar_t c;
55103097Stjr	unsigned long cutoff;
56103097Stjr	int neg, any, cutlim;
57227753Stheraven	FIX_LOCALE(locale);
58103097Stjr
59103097Stjr	/*
60103097Stjr	 * See strtol for comments as to the logic used.
61103097Stjr	 */
62103097Stjr	s = nptr;
63103097Stjr	do {
64103097Stjr		c = *s++;
65227753Stheraven	} while (iswspace_l(c, locale));
66103097Stjr	if (c == '-') {
67103097Stjr		neg = 1;
68103097Stjr		c = *s++;
69103097Stjr	} else {
70103097Stjr		neg = 0;
71103097Stjr		if (c == L'+')
72103097Stjr			c = *s++;
73103097Stjr	}
74103097Stjr	if ((base == 0 || base == 16) &&
75103097Stjr	    c == L'0' && (*s == L'x' || *s == L'X')) {
76103097Stjr		c = s[1];
77103097Stjr		s += 2;
78103097Stjr		base = 16;
79103097Stjr	}
80103097Stjr	if (base == 0)
81103097Stjr		base = c == L'0' ? 8 : 10;
82103097Stjr	acc = any = 0;
83103097Stjr	if (base < 2 || base > 36)
84103097Stjr		goto noconv;
85103097Stjr
86103097Stjr	cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
87103097Stjr	    : LONG_MAX;
88103097Stjr	cutlim = cutoff % base;
89103097Stjr	cutoff /= base;
90103097Stjr	for ( ; ; c = *s++) {
91103097Stjr#ifdef notyet
92227753Stheraven		if (iswdigit_l(c, locale))
93227753Stheraven			c = digittoint_l(c, locale);
94103097Stjr		else
95103097Stjr#endif
96103097Stjr		if (c >= L'0' && c <= L'9')
97103097Stjr			c -= L'0';
98103097Stjr		else if (c >= L'A' && c <= L'Z')
99103097Stjr			c -= L'A' - 10;
100103097Stjr		else if (c >= L'a' && c <= L'z')
101103097Stjr			c -= L'a' - 10;
102103097Stjr		else
103103097Stjr			break;
104103097Stjr		if (c >= base)
105103097Stjr			break;
106103097Stjr		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
107103097Stjr			any = -1;
108103097Stjr		else {
109103097Stjr			any = 1;
110103097Stjr			acc *= base;
111103097Stjr			acc += c;
112103097Stjr		}
113103097Stjr	}
114103097Stjr	if (any < 0) {
115103097Stjr		acc = neg ? LONG_MIN : LONG_MAX;
116103097Stjr		errno = ERANGE;
117103097Stjr	} else if (!any) {
118103097Stjrnoconv:
119103097Stjr		errno = EINVAL;
120103097Stjr	} else if (neg)
121103097Stjr		acc = -acc;
122103097Stjr	if (endptr != NULL)
123103097Stjr		*endptr = (wchar_t *)(any ? s - 1 : nptr);
124103097Stjr	return (acc);
125103097Stjr}
126227753Stheravenlong
127227753Stheravenwcstol(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
128227753Stheraven{
129227753Stheraven	return wcstol_l(nptr, endptr, base, __get_locale());
130227753Stheraven}
131