xref: /netbsd-src/common/lib/libc/stdlib/strtoull.c (revision 82fd1ebbaa73c78a77261c6ef74724a6aaaf221f)
1*82fd1ebbSthorpej /*	$NetBSD: strtoull.c,v 1.1 2006/10/08 03:14:55 thorpej Exp $	*/
2*82fd1ebbSthorpej 
3*82fd1ebbSthorpej /*
4*82fd1ebbSthorpej  * Copyright (c) 1990, 1993
5*82fd1ebbSthorpej  *	The Regents of the University of California.  All rights reserved.
6*82fd1ebbSthorpej  *
7*82fd1ebbSthorpej  * Redistribution and use in source and binary forms, with or without
8*82fd1ebbSthorpej  * modification, are permitted provided that the following conditions
9*82fd1ebbSthorpej  * are met:
10*82fd1ebbSthorpej  * 1. Redistributions of source code must retain the above copyright
11*82fd1ebbSthorpej  *    notice, this list of conditions and the following disclaimer.
12*82fd1ebbSthorpej  * 2. Redistributions in binary form must reproduce the above copyright
13*82fd1ebbSthorpej  *    notice, this list of conditions and the following disclaimer in the
14*82fd1ebbSthorpej  *    documentation and/or other materials provided with the distribution.
15*82fd1ebbSthorpej  * 3. Neither the name of the University nor the names of its contributors
16*82fd1ebbSthorpej  *    may be used to endorse or promote products derived from this software
17*82fd1ebbSthorpej  *    without specific prior written permission.
18*82fd1ebbSthorpej  *
19*82fd1ebbSthorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20*82fd1ebbSthorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21*82fd1ebbSthorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22*82fd1ebbSthorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23*82fd1ebbSthorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24*82fd1ebbSthorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25*82fd1ebbSthorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26*82fd1ebbSthorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27*82fd1ebbSthorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28*82fd1ebbSthorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29*82fd1ebbSthorpej  * SUCH DAMAGE.
30*82fd1ebbSthorpej  */
31*82fd1ebbSthorpej 
32*82fd1ebbSthorpej #if !defined(_KERNEL) && !defined(_STANDALONE)
33*82fd1ebbSthorpej #include <sys/cdefs.h>
34*82fd1ebbSthorpej #if defined(LIBC_SCCS) && !defined(lint)
35*82fd1ebbSthorpej #if 0
36*82fd1ebbSthorpej static char sccsid[] = "from: @(#)strtoul.c	8.1 (Berkeley) 6/4/93";
37*82fd1ebbSthorpej #else
38*82fd1ebbSthorpej __RCSID("$NetBSD: strtoull.c,v 1.1 2006/10/08 03:14:55 thorpej Exp $");
39*82fd1ebbSthorpej #endif
40*82fd1ebbSthorpej #endif /* LIBC_SCCS and not lint */
41*82fd1ebbSthorpej 
42*82fd1ebbSthorpej #include "namespace.h"
43*82fd1ebbSthorpej #include <assert.h>
44*82fd1ebbSthorpej #include <ctype.h>
45*82fd1ebbSthorpej #include <errno.h>
46*82fd1ebbSthorpej #include <limits.h>
47*82fd1ebbSthorpej #include <stdlib.h>
48*82fd1ebbSthorpej 
49*82fd1ebbSthorpej #ifdef __weak_alias
50*82fd1ebbSthorpej __weak_alias(strtoull, _strtoull)
51*82fd1ebbSthorpej #endif
52*82fd1ebbSthorpej 
53*82fd1ebbSthorpej #else /* !_KERNEL && !_STANDALONE */
54*82fd1ebbSthorpej #include <sys/param.h>
55*82fd1ebbSthorpej #include <lib/libkern/libkern.h>
56*82fd1ebbSthorpej #define	isspace(x) ((x) == ' ' || (x) == '\t' || (x) == '\n' || (x) == '\r')
57*82fd1ebbSthorpej #define	isdigit(x) ((x) >= '0' && (x) <= '9')
58*82fd1ebbSthorpej #define	isalpha(x) (((x) >= 'a' && (x) <= 'z') || ((x) >= 'A' && (x) <= 'Z'))
59*82fd1ebbSthorpej #define	toupper(x) ((x) & ~0x20)
60*82fd1ebbSthorpej #endif
61*82fd1ebbSthorpej 
62*82fd1ebbSthorpej /*
63*82fd1ebbSthorpej  * Convert a string to an unsigned long long integer.
64*82fd1ebbSthorpej  *
65*82fd1ebbSthorpej  * Ignores `locale' stuff.  Assumes that the upper and lower case
66*82fd1ebbSthorpej  * alphabets and digits are each contiguous.
67*82fd1ebbSthorpej  */
68*82fd1ebbSthorpej /* LONGLONG */
69*82fd1ebbSthorpej unsigned long long int
70*82fd1ebbSthorpej strtoull(nptr, endptr, base)
71*82fd1ebbSthorpej 	const char *nptr;
72*82fd1ebbSthorpej 	char **endptr;
73*82fd1ebbSthorpej 	int base;
74*82fd1ebbSthorpej {
75*82fd1ebbSthorpej 	const char *s;
76*82fd1ebbSthorpej 	/* LONGLONG */
77*82fd1ebbSthorpej 	unsigned long long int acc, cutoff;
78*82fd1ebbSthorpej 	int c;
79*82fd1ebbSthorpej 	int neg, any, cutlim;
80*82fd1ebbSthorpej 
81*82fd1ebbSthorpej 	_DIAGASSERT(nptr != NULL);
82*82fd1ebbSthorpej 	/* endptr may be NULL */
83*82fd1ebbSthorpej 
84*82fd1ebbSthorpej 	/*
85*82fd1ebbSthorpej 	 * See strtol for comments as to the logic used.
86*82fd1ebbSthorpej 	 */
87*82fd1ebbSthorpej 	s = nptr;
88*82fd1ebbSthorpej 	do {
89*82fd1ebbSthorpej 		c = (unsigned char) *s++;
90*82fd1ebbSthorpej 	} while (isspace(c));
91*82fd1ebbSthorpej 	if (c == '-') {
92*82fd1ebbSthorpej 		neg = 1;
93*82fd1ebbSthorpej 		c = *s++;
94*82fd1ebbSthorpej 	} else {
95*82fd1ebbSthorpej 		neg = 0;
96*82fd1ebbSthorpej 		if (c == '+')
97*82fd1ebbSthorpej 			c = *s++;
98*82fd1ebbSthorpej 	}
99*82fd1ebbSthorpej 	if ((base == 0 || base == 16) &&
100*82fd1ebbSthorpej 	    c == '0' && (*s == 'x' || *s == 'X')) {
101*82fd1ebbSthorpej 		c = s[1];
102*82fd1ebbSthorpej 		s += 2;
103*82fd1ebbSthorpej 		base = 16;
104*82fd1ebbSthorpej 	}
105*82fd1ebbSthorpej 	if (base == 0)
106*82fd1ebbSthorpej 		base = c == '0' ? 8 : 10;
107*82fd1ebbSthorpej 
108*82fd1ebbSthorpej 	/* LONGLONG */
109*82fd1ebbSthorpej 	cutoff = ULLONG_MAX / (unsigned long long int)base;
110*82fd1ebbSthorpej 	/* LONGLONG */
111*82fd1ebbSthorpej 	cutlim = (int)(ULLONG_MAX % (unsigned long long int)base);
112*82fd1ebbSthorpej 	for (acc = 0, any = 0;; c = (unsigned char) *s++) {
113*82fd1ebbSthorpej 		if (isdigit(c))
114*82fd1ebbSthorpej 			c -= '0';
115*82fd1ebbSthorpej 		else if (isalpha(c)) {
116*82fd1ebbSthorpej #if defined(_KERNEL) || defined(_STANDALONE)
117*82fd1ebbSthorpej 			c = toupper(c) - 'A' + 10;
118*82fd1ebbSthorpej #else
119*82fd1ebbSthorpej 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
120*82fd1ebbSthorpej #endif
121*82fd1ebbSthorpej 		} else
122*82fd1ebbSthorpej 			break;
123*82fd1ebbSthorpej 		if (c >= base)
124*82fd1ebbSthorpej 			break;
125*82fd1ebbSthorpej 		if (any < 0)
126*82fd1ebbSthorpej 			continue;
127*82fd1ebbSthorpej 		if (acc > cutoff || (acc == cutoff && c > cutlim)) {
128*82fd1ebbSthorpej #if defined(_KERNEL) || defined(_STANDALONE)
129*82fd1ebbSthorpej 			if (endptr)
130*82fd1ebbSthorpej 				*endptr = __UNCONST(nptr);
131*82fd1ebbSthorpej 			return (ULLONG_MAX);
132*82fd1ebbSthorpej #else
133*82fd1ebbSthorpej 			any = -1;
134*82fd1ebbSthorpej 			acc = ULLONG_MAX;
135*82fd1ebbSthorpej 			errno = ERANGE;
136*82fd1ebbSthorpej #endif
137*82fd1ebbSthorpej 		} else {
138*82fd1ebbSthorpej 			any = 1;
139*82fd1ebbSthorpej 			/* LONGLONG */
140*82fd1ebbSthorpej 			acc *= (unsigned long long int)base;
141*82fd1ebbSthorpej 			acc += c;
142*82fd1ebbSthorpej 		}
143*82fd1ebbSthorpej 	}
144*82fd1ebbSthorpej 	if (neg && any > 0)
145*82fd1ebbSthorpej 		acc = -acc;
146*82fd1ebbSthorpej 	if (endptr != 0)
147*82fd1ebbSthorpej 		*endptr = __UNCONST(any ? s - 1 : nptr);
148*82fd1ebbSthorpej 	return (acc);
149*82fd1ebbSthorpej }
150