strtol.c revision 92986
1238438Sdteske/*-
2238438Sdteske * Copyright (c) 1990, 1993
3249746Sdteske *	The Regents of the University of California.  All rights reserved.
4238438Sdteske *
5238438Sdteske * Redistribution and use in source and binary forms, with or without
6238438Sdteske * modification, are permitted provided that the following conditions
7238438Sdteske * are met:
8238438Sdteske * 1. Redistributions of source code must retain the above copyright
9238438Sdteske *    notice, this list of conditions and the following disclaimer.
10238438Sdteske * 2. Redistributions in binary form must reproduce the above copyright
11238438Sdteske *    notice, this list of conditions and the following disclaimer in the
12238438Sdteske *    documentation and/or other materials provided with the distribution.
13238438Sdteske * 3. All advertising materials mentioning features or use of this software
14238438Sdteske *    must display the following acknowledgement:
15238438Sdteske *	This product includes software developed by the University of
16238438Sdteske *	California, Berkeley and its contributors.
17238438Sdteske * 4. Neither the name of the University nor the names of its contributors
18238438Sdteske *    may be used to endorse or promote products derived from this software
19238438Sdteske *    without specific prior written permission.
20238438Sdteske *
21238438Sdteske * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22238438Sdteske * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23238438Sdteske * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24238438Sdteske * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25238438Sdteske * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26238438Sdteske * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27238438Sdteske * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28238438Sdteske * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29238438Sdteske * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30238438Sdteske * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31240684Sdteske * SUCH DAMAGE.
32240684Sdteske */
33244675Sdteske
34240684Sdteske#if defined(LIBC_SCCS) && !defined(lint)
35240684Sdteskestatic char sccsid[] = "@(#)strtol.c	8.1 (Berkeley) 6/4/93";
36240684Sdteske#endif /* LIBC_SCCS and not lint */
37238438Sdteske#include <sys/cdefs.h>
38240684Sdteske__FBSDID("$FreeBSD: head/lib/libc/stdlib/strtol.c 92986 2002-03-22 21:53:29Z obrien $");
39238438Sdteske
40238438Sdteske#include <limits.h>
41243112Sdteske#include <ctype.h>
42238438Sdteske#include <errno.h>
43238438Sdteske#include <stdlib.h>
44238438Sdteske
45238438Sdteske
46238438Sdteske/*
47238438Sdteske * Convert a string to a long integer.
48238438Sdteske *
49238438Sdteske * Assumes that the upper and lower case
50238438Sdteske * alphabets and digits are each contiguous.
51238438Sdteske */
52238438Sdteskelong
53251264Sdteskestrtol(nptr, endptr, base)
54251390Sdteske	const char *nptr;
55251390Sdteske	char **endptr;
56251390Sdteske	int base;
57251390Sdteske{
58251390Sdteske	const char *s;
59251390Sdteske	unsigned long acc;
60251390Sdteske	char c;
61251390Sdteske	unsigned long cutoff;
62251390Sdteske	int neg, any, cutlim;
63251390Sdteske
64251390Sdteske	/*
65251390Sdteske	 * Skip white space and pick up leading +/- sign if any.
66251390Sdteske	 * If base is 0, allow 0x for hex and 0 for octal, else
67238438Sdteske	 * assume decimal; if base is already 16, allow 0x.
68238438Sdteske	 */
69251264Sdteske	s = nptr;
70251264Sdteske	do {
71238438Sdteske		c = *s++;
72251190Sdteske	} while (isspace((unsigned char)c));
73251190Sdteske	if (c == '-') {
74251190Sdteske		neg = 1;
75251190Sdteske		c = *s++;
76251190Sdteske	} else {
77251190Sdteske		neg = 0;
78251190Sdteske		if (c == '+')
79238438Sdteske			c = *s++;
80249751Sdteske	}
81251390Sdteske	if ((base == 0 || base == 16) &&
82251390Sdteske	    c == '0' && (*s == 'x' || *s == 'X')) {
83251390Sdteske		c = s[1];
84251390Sdteske		s += 2;
85251390Sdteske		base = 16;
86251390Sdteske	}
87251390Sdteske	if (base == 0)
88251390Sdteske		base = c == '0' ? 8 : 10;
89251390Sdteske	acc = any = 0;
90251390Sdteske	if (base < 2 || base > 36)
91251390Sdteske		goto noconv;
92251390Sdteske
93251390Sdteske	/*
94249751Sdteske	 * Compute the cutoff value between legal numbers and illegal
95249751Sdteske	 * numbers.  That is the largest legal value, divided by the
96251236Sdteske	 * base.  An input number that is greater than this value, if
97251236Sdteske	 * followed by a legal input character, is too big.  One that
98249751Sdteske	 * is equal to this value may be valid or not; the limit
99238438Sdteske	 * between valid and invalid numbers is then based on the last
100238438Sdteske	 * digit.  For instance, if the range for longs is
101238438Sdteske	 * [-2147483648..2147483647] and the input base is 10,
102238438Sdteske	 * cutoff will be set to 214748364 and cutlim to either
103249751Sdteske	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
104251190Sdteske	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
105251190Sdteske	 * the number is too big, and we will return a range error.
106238438Sdteske	 *
107240768Sdteske	 * Set 'any' if any `digits' consumed; make it negative to indicate
108240768Sdteske	 * overflow.
109240768Sdteske	 */
110251236Sdteske	cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX
111240768Sdteske	    : LONG_MAX;
112238438Sdteske	cutlim = cutoff % base;
113238438Sdteske	cutoff /= base;
114238438Sdteske	for ( ; ; c = *s++) {
115238438Sdteske		if (c >= '0' && c <= '9')
116238438Sdteske			c -= '0';
117238438Sdteske		else if (c >= 'A' && c <= 'Z')
118238438Sdteske			c -= 'A' - 10;
119238438Sdteske		else if (c >= 'a' && c <= 'z')
120238438Sdteske			c -= 'a' - 10;
121238438Sdteske		else
122250633Sdteske			break;
123238438Sdteske		if (c >= base)
124238438Sdteske			break;
125238438Sdteske		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
126238438Sdteske			any = -1;
127238438Sdteske		else {
128238438Sdteske			any = 1;
129238438Sdteske			acc *= base;
130238438Sdteske			acc += c;
131238438Sdteske		}
132238438Sdteske	}
133238438Sdteske	if (any < 0) {
134238438Sdteske		acc = neg ? LONG_MIN : LONG_MAX;
135238438Sdteske		errno = ERANGE;
136238438Sdteske	} else if (!any) {
137238438Sdteskenoconv:
138238438Sdteske		errno = EINVAL;
139238438Sdteske	} else if (neg)
140251236Sdteske		acc = -acc;
141251236Sdteske	if (endptr != NULL)
142238438Sdteske		*endptr = (char *)(any ? s - 1 : nptr);
143238438Sdteske	return (acc);
144251390Sdteske}
145251390Sdteske