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