strtoull.c revision 73152
183098Smp/*-
259243Sobrien * Copyright (c) 1992, 1993
359243Sobrien *	The Regents of the University of California.  All rights reserved.
459243Sobrien *
559243Sobrien * Redistribution and use in source and binary forms, with or without
659243Sobrien * modification, are permitted provided that the following conditions
759243Sobrien * are met:
859243Sobrien * 1. Redistributions of source code must retain the above copyright
959243Sobrien *    notice, this list of conditions and the following disclaimer.
1059243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1159243Sobrien *    notice, this list of conditions and the following disclaimer in the
1259243Sobrien *    documentation and/or other materials provided with the distribution.
1359243Sobrien * 3. All advertising materials mentioning features or use of this software
1459243Sobrien *    must display the following acknowledgement:
1559243Sobrien *	This product includes software developed by the University of
1659243Sobrien *	California, Berkeley and its contributors.
1759243Sobrien * 4. Neither the name of the University nor the names of its contributors
1859243Sobrien *    may be used to endorse or promote products derived from this software
1959243Sobrien *    without specific prior written permission.
2059243Sobrien *
2159243Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2259243Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2359243Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2459243Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2559243Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2659243Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2759243Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2859243Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2959243Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3059243Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3159243Sobrien * SUCH DAMAGE.
3259243Sobrien */
3359243Sobrien
3459243Sobrien#if defined(LIBC_SCCS) && !defined(lint)
3559243Sobrienstatic char sccsid[] = "@(#)strtouq.c	8.1 (Berkeley) 6/4/93";
3659243Sobrien#endif /* LIBC_SCCS and not lint */
3759243Sobrien
3859243Sobrien#ifndef lint
3959243Sobrienstatic const char rcsid[] =
4059243Sobrien  "$FreeBSD: head/lib/libc/stdlib/strtoull.c 73152 2001-02-27 13:33:07Z obrien $";
4159243Sobrien#endif
4259243Sobrien
4359243Sobrien#include <sys/types.h>
4459243Sobrien
4559243Sobrien#include <limits.h>
4659243Sobrien#include <errno.h>
4759243Sobrien#include <ctype.h>
4859243Sobrien#include <stdlib.h>
4959243Sobrien
5059243Sobrien/*
5159243Sobrien * Convert a string to an unsigned long long integer.
5259243Sobrien *
5359243Sobrien * Ignores `locale' stuff.  Assumes that the upper and lower case
5459243Sobrien * alphabets and digits are each contiguous.
5559243Sobrien */
5659243Sobrienunsigned long long
5759243Sobrienstrtoull(nptr, endptr, base)
5859243Sobrien	const char *nptr;
5959243Sobrien	char **endptr;
6059243Sobrien	register int base;
6159243Sobrien{
6259243Sobrien	register const char *s = nptr;
6359243Sobrien	register unsigned long long acc;
6459243Sobrien	register unsigned char c;
6559243Sobrien	register unsigned long long qbase, cutoff;
6659243Sobrien	register int neg, any, cutlim;
6759243Sobrien
6859243Sobrien	/*
6959243Sobrien	 * See strtoq for comments as to the logic used.
7059243Sobrien	 */
7159243Sobrien	s = nptr;
7259243Sobrien	do {
7359243Sobrien		c = *s++;
7459243Sobrien	} while (isspace(c));
7559243Sobrien	if (c == '-') {
7659243Sobrien		neg = 1;
7759243Sobrien		c = *s++;
7859243Sobrien	} else {
7959243Sobrien		neg = 0;
8059243Sobrien		if (c == '+')
8159243Sobrien			c = *s++;
8259243Sobrien	}
8359243Sobrien	if ((base == 0 || base == 16) &&
8459243Sobrien	    c == '0' && (*s == 'x' || *s == 'X')) {
8559243Sobrien		c = s[1];
8659243Sobrien		s += 2;
8759243Sobrien		base = 16;
8859243Sobrien	}
8959243Sobrien	if (base == 0)
9059243Sobrien		base = c == '0' ? 8 : 10;
9159243Sobrien	qbase = (unsigned)base;
9259243Sobrien	cutoff = (unsigned long long)ULLONG_MAX / qbase;
9359243Sobrien	cutlim = (unsigned long long)ULLONG_MAX % qbase;
9459243Sobrien	for (acc = 0, any = 0;; c = *s++) {
9559243Sobrien		if (!isascii(c))
9659243Sobrien			break;
9759243Sobrien		if (isdigit(c))
9859243Sobrien			c -= '0';
9959243Sobrien		else if (isalpha(c))
10059243Sobrien			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
10159243Sobrien		else
10259243Sobrien			break;
10359243Sobrien		if (c >= base)
10459243Sobrien			break;
10559243Sobrien		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
10659243Sobrien			any = -1;
10759243Sobrien		else {
10859243Sobrien			any = 1;
10959243Sobrien			acc *= qbase;
11059243Sobrien			acc += c;
11159243Sobrien		}
11259243Sobrien	}
11359243Sobrien	if (any < 0) {
11459243Sobrien		acc = ULLONG_MAX;
11559243Sobrien		errno = ERANGE;
11659243Sobrien	} else if (neg)
11759243Sobrien		acc = -acc;
11883098Smp	if (endptr != 0)
11983098Smp		*endptr = (char *)(any ? s - 1 : nptr);
12083098Smp	return (acc);
12183098Smp}
12283098Smp