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