1/* $NetBSD: _strtol.h,v 1.1 2008/08/20 12:42:26 joerg 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 * Original version ID:
32 * NetBSD: src/lib/libc/locale/_wcstol.h,v 1.2 2003/08/07 16:43:03 agc Exp
33 */
34
35/*
36 * function template for strtol, strtoll and strtoimax.
37 *
38 * parameters:
39 *	_FUNCNAME : function name
40 *      __INT     : return type
41 *      __INT_MIN : lower limit of the return type
42 *      __INT_MAX : upper limit of the return type
43 */
44
45__INT
46_FUNCNAME(const char *nptr, char **endptr, int base)
47{
48	const char *s;
49	__INT acc, cutoff;
50	unsigned char c;
51	int i, neg, any, cutlim;
52
53	_DIAGASSERT(nptr != NULL);
54	/* endptr may be NULL */
55
56	/* check base value */
57	if (base && (base < 2 || base > 36)) {
58#if !defined(_KERNEL) && !defined(_STANDALONE)
59		errno = EINVAL;
60		if (endptr != NULL)
61			/* LINTED interface specification */
62			*endptr = __UNCONST(nptr);
63		return 0;
64#else
65		panic("%s: invalid base %d", __func__, base);
66#endif
67	}
68
69	/*
70	 * Skip white space and pick up leading +/- sign if any.
71	 * If base is 0, allow 0x for hex and 0 for octal, else
72	 * assume decimal; if base is already 16, allow 0x.
73	 */
74	s = nptr;
75	do {
76		c = *s++;
77	} while (isspace(c));
78	if (c == '-') {
79		neg = 1;
80		c = *s++;
81	} else {
82		neg = 0;
83		if (c == '+')
84			c = *s++;
85	}
86	if ((base == 0 || base == 16) &&
87	    c == '0' && (*s == 'x' || *s == 'X')) {
88		c = s[1];
89		s += 2;
90		base = 16;
91	}
92	if (base == 0)
93		base = (c == '0' ? 8 : 10);
94
95	/*
96	 * Compute the cutoff value between legal numbers and illegal
97	 * numbers.  That is the largest legal value, divided by the
98	 * base.  An input number that is greater than this value, if
99	 * followed by a legal input character, is too big.  One that
100	 * is equal to this value may be valid or not; the limit
101	 * between valid and invalid numbers is then based on the last
102	 * digit.  For instance, if the range for longs is
103	 * [-2147483648..2147483647] and the input base is 10,
104	 * cutoff will be set to 214748364 and cutlim to either
105	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
106	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
107	 * the number is too big, and we will return a range error.
108	 *
109	 * Set any if any `digits' consumed; make it negative to indicate
110	 * overflow.
111	 */
112	cutoff = (neg ? __INT_MIN : __INT_MAX);
113	cutlim = (int)(cutoff % base);
114	cutoff /= base;
115	if (neg) {
116		if (cutlim > 0) {
117			cutlim -= base;
118			cutoff += 1;
119		}
120		cutlim = -cutlim;
121	}
122	for (acc = 0, any = 0;; c = *s++) {
123		if (isdigit(c))
124			i = c - '0';
125		else if (isalpha(c))
126			i = c - (isupper(c) ? 'A' - 10 : 'a' - 10);
127		else
128			break;
129		if (i >= base)
130			break;
131		if (any < 0)
132			continue;
133		if (neg) {
134			if (acc < cutoff || (acc == cutoff && i > cutlim)) {
135				acc = __INT_MIN;
136#if !defined(_KERNEL) && !defined(_STANDALONE)
137				any = -1;
138				errno = ERANGE;
139#else
140				any = 0;
141				break;
142#endif
143			} else {
144				any = 1;
145				acc *= base;
146				acc -= i;
147			}
148		} else {
149			if (acc > cutoff || (acc == cutoff && i > cutlim)) {
150				acc = __INT_MAX;
151#if !defined(_KERNEL) && !defined(_STANDALONE)
152				any = -1;
153				errno = ERANGE;
154#else
155				any = 0;
156				break;
157#endif
158			} else {
159				any = 1;
160				acc *= base;
161				acc += i;
162			}
163		}
164	}
165	if (endptr != NULL)
166		/* LINTED interface specification */
167		*endptr = __UNCONST(any ? s - 1 : nptr);
168	return(acc);
169}
170