1103793Stjr/*-
2103793Stjr * Copyright (c) 1992, 1993
3103793Stjr *	The Regents of the University of California.  All rights reserved.
4103793Stjr *
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 *
10103793Stjr * Redistribution and use in source and binary forms, with or without
11103793Stjr * modification, are permitted provided that the following conditions
12103793Stjr * are met:
13103793Stjr * 1. Redistributions of source code must retain the above copyright
14103793Stjr *    notice, this list of conditions and the following disclaimer.
15103793Stjr * 2. Redistributions in binary form must reproduce the above copyright
16103793Stjr *    notice, this list of conditions and the following disclaimer in the
17103793Stjr *    documentation and/or other materials provided with the distribution.
18103793Stjr * 4. Neither the name of the University nor the names of its contributors
19103793Stjr *    may be used to endorse or promote products derived from this software
20103793Stjr *    without specific prior written permission.
21103793Stjr *
22103793Stjr * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23103793Stjr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24103793Stjr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25103793Stjr * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26103793Stjr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27103793Stjr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28103793Stjr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29103793Stjr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30103793Stjr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31103793Stjr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32103793Stjr * SUCH DAMAGE.
33103793Stjr */
34103793Stjr
35103793Stjr#include <sys/cdefs.h>
36103793Stjr#if 0
37103793Stjr#if defined(LIBC_SCCS) && !defined(lint)
38103793Stjrstatic char sccsid[] = "@(#)strtoq.c	8.1 (Berkeley) 6/4/93";
39103793Stjr#endif /* LIBC_SCCS and not lint */
40103793Stjr__FBSDID("FreeBSD: src/lib/libc/stdlib/strtoll.c,v 1.19 2002/09/06 11:23:59 tjr Exp ");
41103793Stjr#endif
42103793Stjr__FBSDID("$FreeBSD$");
43103793Stjr
44103793Stjr#include <errno.h>
45103793Stjr#include <limits.h>
46103793Stjr#include <stdlib.h>
47103793Stjr#include <wchar.h>
48103793Stjr#include <wctype.h>
49227753Stheraven#include "xlocale_private.h"
50103793Stjr
51103793Stjr/*
52103793Stjr * Convert a wide character string to a long long integer.
53103793Stjr */
54103793Stjrlong long
55227753Stheravenwcstoll_l(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr,
56227753Stheraven		int base, locale_t locale)
57103793Stjr{
58103793Stjr	const wchar_t *s;
59103793Stjr	unsigned long long acc;
60103793Stjr	wchar_t c;
61103793Stjr	unsigned long long cutoff;
62103793Stjr	int neg, any, cutlim;
63227753Stheraven	FIX_LOCALE(locale);
64103793Stjr
65103793Stjr	/*
66103793Stjr	 * See strtoll for comments as to the logic used.
67103793Stjr	 */
68103793Stjr	s = nptr;
69103793Stjr	do {
70103793Stjr		c = *s++;
71227753Stheraven	} while (iswspace_l(c, locale));
72103793Stjr	if (c == L'-') {
73103793Stjr		neg = 1;
74103793Stjr		c = *s++;
75103793Stjr	} else {
76103793Stjr		neg = 0;
77103793Stjr		if (c == L'+')
78103793Stjr			c = *s++;
79103793Stjr	}
80103793Stjr	if ((base == 0 || base == 16) &&
81103793Stjr	    c == L'0' && (*s == L'x' || *s == L'X')) {
82103793Stjr		c = s[1];
83103793Stjr		s += 2;
84103793Stjr		base = 16;
85103793Stjr	}
86103793Stjr	if (base == 0)
87103793Stjr		base = c == L'0' ? 8 : 10;
88103793Stjr	acc = any = 0;
89103793Stjr	if (base < 2 || base > 36)
90103793Stjr		goto noconv;
91103793Stjr
92103793Stjr	cutoff = neg ? (unsigned long long)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX
93103793Stjr	    : LLONG_MAX;
94103793Stjr	cutlim = cutoff % base;
95103793Stjr	cutoff /= base;
96103793Stjr	for ( ; ; c = *s++) {
97103793Stjr#ifdef notyet
98227753Stheraven		if (iswdigit_l(c, locale))
99227753Stheraven			c = digittoint_l(c, locale);
100103793Stjr		else
101103793Stjr#endif
102103793Stjr		if (c >= L'0' && c <= L'9')
103103793Stjr			c -= L'0';
104103793Stjr		else if (c >= L'A' && c <= L'Z')
105103793Stjr			c -= L'A' - 10;
106103793Stjr		else if (c >= L'a' && c <= L'z')
107103793Stjr			c -= L'a' - 10;
108103793Stjr		else
109103793Stjr			break;
110103793Stjr		if (c >= base)
111103793Stjr			break;
112103793Stjr		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
113103793Stjr			any = -1;
114103793Stjr		else {
115103793Stjr			any = 1;
116103793Stjr			acc *= base;
117103793Stjr			acc += c;
118103793Stjr		}
119103793Stjr	}
120103793Stjr	if (any < 0) {
121103793Stjr		acc = neg ? LLONG_MIN : LLONG_MAX;
122103793Stjr		errno = ERANGE;
123103793Stjr	} else if (!any) {
124103793Stjrnoconv:
125103793Stjr		errno = EINVAL;
126103793Stjr	} else if (neg)
127103793Stjr		acc = -acc;
128103793Stjr	if (endptr != NULL)
129103793Stjr		*endptr = (wchar_t *)(any ? s - 1 : nptr);
130103793Stjr	return (acc);
131103793Stjr}
132227753Stheravenlong long
133227753Stheravenwcstoll(const wchar_t * __restrict nptr, wchar_t ** __restrict endptr, int base)
134227753Stheraven{
135227753Stheraven	return wcstoll_l(nptr, endptr, base, __get_locale());
136227753Stheraven}
137