strtoull.c revision 251672
1193323Sed/*-
2193323Sed * Copyright (c) 1992, 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.
15195340Sed * 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.
18193323Sed * 3. Neither the name of the University nor the names of its contributors
19193323Sed *    may be used to endorse or promote products derived from this software
20193323Sed *    without specific prior written permission.
21193323Sed *
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)
29198090Srdivacky * 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.
33193399Sed */
34193323Sed
35193323Sed#if defined(LIBC_SCCS) && !defined(lint)
36193323Sedstatic char sccsid[] = "@(#)strtouq.c	8.1 (Berkeley) 6/4/93";
37193323Sed#endif /* LIBC_SCCS and not lint */
38193323Sed#include <sys/cdefs.h>
39193323Sed__FBSDID("$FreeBSD: head/lib/libc/stdlib/strtoull.c 251672 2013-06-13 00:19:30Z emaste $");
40193323Sed
41193323Sed#include <limits.h>
42193323Sed#include <errno.h>
43193323Sed#include <ctype.h>
44193323Sed#include <stdlib.h>
45193323Sed#include "xlocale_private.h"
46193323Sed
47193323Sed/*
48193323Sed * Convert a string to an unsigned long long integer.
49193323Sed *
50193323Sed * Assumes that the upper and lower case
51198090Srdivacky * alphabets and digits are each contiguous.
52193323Sed */
53193323Sedunsigned long long
54193323Sedstrtoull_l(const char * __restrict nptr, char ** __restrict endptr, int base,
55193323Sed		locale_t locale)
56193323Sed{
57193323Sed	const char *s;
58193323Sed	unsigned long long acc;
59198090Srdivacky	char c;
60193323Sed	unsigned long long cutoff;
61193323Sed	int neg, any, cutlim;
62193323Sed	FIX_LOCALE(locale);
63193323Sed
64193323Sed	/*
65193323Sed	 * See strtoq for comments as to the logic used.
66193323Sed	 */
67193323Sed	s = nptr;
68193323Sed	do {
69198113Srdivacky		c = *s++;
70198090Srdivacky	} while (isspace_l((unsigned char)c, locale));
71198090Srdivacky	if (c == '-') {
72193323Sed		neg = 1;
73193323Sed		c = *s++;
74193323Sed	} else {
75193323Sed		neg = 0;
76193323Sed		if (c == '+')
77193323Sed			c = *s++;
78193323Sed	}
79193323Sed	if ((base == 0 || base == 16) &&
80193323Sed	    c == '0' && (*s == 'x' || *s == 'X') &&
81193323Sed	    ((s[1] >= '0' && s[1] <= '9') ||
82193323Sed	    (s[1] >= 'A' && s[1] <= 'F') ||
83193323Sed	    (s[1] >= 'a' && s[1] <= 'f'))) {
84198090Srdivacky		c = s[1];
85198090Srdivacky		s += 2;
86193323Sed		base = 16;
87193323Sed	}
88193323Sed	if (base == 0)
89198090Srdivacky		base = c == '0' ? 8 : 10;
90198090Srdivacky	acc = any = 0;
91198090Srdivacky	if (base < 2 || base > 36)
92198090Srdivacky		goto noconv;
93198090Srdivacky
94193323Sed	cutoff = ULLONG_MAX / base;
95193323Sed	cutlim = ULLONG_MAX % base;
96193323Sed	for ( ; ; c = *s++) {
97198090Srdivacky		if (c >= '0' && c <= '9')
98198090Srdivacky			c -= '0';
99198090Srdivacky		else if (c >= 'A' && c <= 'Z')
100198090Srdivacky			c -= 'A' - 10;
101193323Sed		else if (c >= 'a' && c <= 'z')
102193323Sed			c -= 'a' - 10;
103193323Sed		else
104193323Sed			break;
105193323Sed		if (c >= base)
106193323Sed			break;
107193323Sed		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
108193323Sed			any = -1;
109193323Sed		else {
110193323Sed			any = 1;
111193323Sed			acc *= base;
112193323Sed			acc += c;
113193323Sed		}
114198090Srdivacky	}
115198090Srdivacky	if (any < 0) {
116193323Sed		acc = ULLONG_MAX;
117193323Sed		errno = ERANGE;
118193323Sed	} else if (!any) {
119193323Sednoconv:
120193323Sed		errno = EINVAL;
121193323Sed	} else if (neg)
122193323Sed		acc = -acc;
123193323Sed	if (endptr != NULL)
124193323Sed		*endptr = (char *)(any ? s - 1 : nptr);
125193323Sed	return (acc);
126193323Sed}
127193323Sedunsigned long long
128193323Sedstrtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
129193323Sed{
130198396Srdivacky	return strtoull_l(nptr, endptr, base, __get_locale());
131198396Srdivacky}
132198396Srdivacky