strtoull.c revision 140577
1231200Smm/*-
2231200Smm * Copyright (c) 1992, 1993
3231200Smm *	The Regents of the University of California.  All rights reserved.
4231200Smm *
5231200Smm * Redistribution and use in source and binary forms, with or without
6231200Smm * modification, are permitted provided that the following conditions
7231200Smm * are met:
8231200Smm * 1. Redistributions of source code must retain the above copyright
9231200Smm *    notice, this list of conditions and the following disclaimer.
10231200Smm * 2. Redistributions in binary form must reproduce the above copyright
11231200Smm *    notice, this list of conditions and the following disclaimer in the
12231200Smm *    documentation and/or other materials provided with the distribution.
13231200Smm * 3. All advertising materials mentioning features or use of this software
14231200Smm *    must display the following acknowledgement:
15231200Smm *	This product includes software developed by the University of
16231200Smm *	California, Berkeley and its contributors.
17231200Smm * 4. Neither the name of the University nor the names of its contributors
18231200Smm *    may be used to endorse or promote products derived from this software
19231200Smm *    without specific prior written permission.
20231200Smm *
21231200Smm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22231200Smm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23231200Smm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24231200Smm * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25231200Smm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26231200Smm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27231200Smm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28231200Smm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29231200Smm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30231200Smm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31231200Smm * SUCH DAMAGE.
32231200Smm */
33231200Smm
34231200Smm#if defined(LIBC_SCCS) && !defined(lint)
35231200Smmstatic char sccsid[] = "@(#)strtouq.c	8.1 (Berkeley) 6/4/93";
36231200Smm#endif /* LIBC_SCCS and not lint */
37231200Smm#include <sys/cdefs.h>
38231200Smm__FBSDID("$FreeBSD: head/lib/libc/stdlib/strtoull.c 140577 2005-01-21 13:31:02Z ache $");
39231200Smm
40231200Smm#include <limits.h>
41231200Smm#include <errno.h>
42231200Smm#include <ctype.h>
43231200Smm#include <stdlib.h>
44231200Smm
45231200Smm/*
46231200Smm * Convert a string to an unsigned long long integer.
47231200Smm *
48231200Smm * Assumes that the upper and lower case
49231200Smm * alphabets and digits are each contiguous.
50231200Smm */
51231200Smmunsigned long long
52231200Smmstrtoull(const char * __restrict nptr, char ** __restrict endptr, int base)
53231200Smm{
54231200Smm	const char *s;
55231200Smm	unsigned long long acc;
56231200Smm	char c;
57231200Smm	unsigned long long cutoff;
58231200Smm	int neg, any, cutlim;
59231200Smm
60231200Smm	/*
61231200Smm	 * See strtoq for comments as to the logic used.
62231200Smm	 */
63231200Smm	s = nptr;
64231200Smm	do {
65231200Smm		c = *s++;
66231200Smm	} while (isspace((unsigned char)c));
67231200Smm	if (c == '-') {
68231200Smm		neg = 1;
69231200Smm		c = *s++;
70231200Smm	} else {
71231200Smm		neg = 0;
72231200Smm		if (c == '+')
73231200Smm			c = *s++;
74231200Smm	}
75231200Smm	if ((base == 0 || base == 16) &&
76231200Smm	    c == '0' && (*s == 'x' || *s == 'X') &&
77231200Smm	    ((s[1] >= '0' && s[1] <= '9') ||
78231200Smm	    (s[1] >= 'A' && s[1] <= 'F') ||
79231200Smm	    (s[1] >= 'a' && s[1] <= 'f'))) {
80231200Smm		c = s[1];
81231200Smm		s += 2;
82231200Smm		base = 16;
83231200Smm	}
84231200Smm	if (base == 0)
85231200Smm		base = c == '0' ? 8 : 10;
86231200Smm	acc = any = 0;
87231200Smm	if (base < 2 || base > 36)
88231200Smm		goto noconv;
89231200Smm
90231200Smm	cutoff = ULLONG_MAX / base;
91231200Smm	cutlim = ULLONG_MAX % base;
92231200Smm	for ( ; ; c = *s++) {
93231200Smm		if (c >= '0' && c <= '9')
94231200Smm			c -= '0';
95231200Smm		else if (c >= 'A' && c <= 'Z')
96231200Smm			c -= 'A' - 10;
97231200Smm		else if (c >= 'a' && c <= 'z')
98231200Smm			c -= 'a' - 10;
99231200Smm		else
100231200Smm			break;
101231200Smm		if (c >= base)
102231200Smm			break;
103231200Smm		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
104231200Smm			any = -1;
105231200Smm		else {
106231200Smm			any = 1;
107231200Smm			acc *= base;
108231200Smm			acc += c;
109231200Smm		}
110231200Smm	}
111231200Smm	if (any < 0) {
112231200Smm		acc = ULLONG_MAX;
113231200Smm		errno = ERANGE;
114231200Smm	} else if (!any) {
115231200Smmnoconv:
116231200Smm		errno = EINVAL;
117231200Smm	} else if (neg)
118231200Smm		acc = -acc;
119231200Smm	if (endptr != NULL)
120231200Smm		*endptr = (char *)(any ? s - 1 : nptr);
121231200Smm	return (acc);
122231200Smm}
123231200Smm