1*4a5d661aSToomas Soome /*- 2*4a5d661aSToomas Soome * Copyright (c) 1990, 1993 3*4a5d661aSToomas Soome * The Regents of the University of California. All rights reserved. 4*4a5d661aSToomas Soome * 5*4a5d661aSToomas Soome * Redistribution and use in source and binary forms, with or without 6*4a5d661aSToomas Soome * modification, are permitted provided that the following conditions 7*4a5d661aSToomas Soome * are met: 8*4a5d661aSToomas Soome * 1. Redistributions of source code must retain the above copyright 9*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer. 10*4a5d661aSToomas Soome * 2. Redistributions in binary form must reproduce the above copyright 11*4a5d661aSToomas Soome * notice, this list of conditions and the following disclaimer in the 12*4a5d661aSToomas Soome * documentation and/or other materials provided with the distribution. 13*4a5d661aSToomas Soome * 4. Neither the name of the University nor the names of its contributors 14*4a5d661aSToomas Soome * may be used to endorse or promote products derived from this software 15*4a5d661aSToomas Soome * without specific prior written permission. 16*4a5d661aSToomas Soome * 17*4a5d661aSToomas Soome * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18*4a5d661aSToomas Soome * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*4a5d661aSToomas Soome * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*4a5d661aSToomas Soome * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21*4a5d661aSToomas Soome * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*4a5d661aSToomas Soome * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*4a5d661aSToomas Soome * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*4a5d661aSToomas Soome * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*4a5d661aSToomas Soome * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*4a5d661aSToomas Soome * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*4a5d661aSToomas Soome * SUCH DAMAGE. 28*4a5d661aSToomas Soome */ 29*4a5d661aSToomas Soome 30*4a5d661aSToomas Soome #include <sys/cdefs.h> 31*4a5d661aSToomas Soome __FBSDID("$FreeBSD$"); 32*4a5d661aSToomas Soome 33*4a5d661aSToomas Soome #if defined(LIBC_SCCS) && !defined(lint) 34*4a5d661aSToomas Soome static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 35*4a5d661aSToomas Soome #endif /* LIBC_SCCS and not lint */ 36*4a5d661aSToomas Soome 37*4a5d661aSToomas Soome #include "stand.h" 38*4a5d661aSToomas Soome #include <limits.h> 39*4a5d661aSToomas Soome 40*4a5d661aSToomas Soome /* 41*4a5d661aSToomas Soome * Convert a string to a long integer. 42*4a5d661aSToomas Soome * 43*4a5d661aSToomas Soome * Ignores `locale' stuff. Assumes that the upper and lower case 44*4a5d661aSToomas Soome * alphabets and digits are each contiguous. 45*4a5d661aSToomas Soome */ 46*4a5d661aSToomas Soome long 47*4a5d661aSToomas Soome strtol(nptr, endptr, base) 48*4a5d661aSToomas Soome const char *nptr; 49*4a5d661aSToomas Soome char **endptr; 50*4a5d661aSToomas Soome int base; 51*4a5d661aSToomas Soome { 52*4a5d661aSToomas Soome const char *s; 53*4a5d661aSToomas Soome unsigned long acc; 54*4a5d661aSToomas Soome unsigned char c; 55*4a5d661aSToomas Soome unsigned long cutoff; 56*4a5d661aSToomas Soome int neg = 0, any, cutlim; 57*4a5d661aSToomas Soome 58*4a5d661aSToomas Soome /* Be sensible about NULL strings */ 59*4a5d661aSToomas Soome if (nptr == NULL) 60*4a5d661aSToomas Soome nptr = ""; 61*4a5d661aSToomas Soome s = nptr; 62*4a5d661aSToomas Soome 63*4a5d661aSToomas Soome /* 64*4a5d661aSToomas Soome * Skip white space and pick up leading +/- sign if any. 65*4a5d661aSToomas Soome * If base is 0, allow 0x for hex and 0 for octal, else 66*4a5d661aSToomas Soome * assume decimal; if base is already 16, allow 0x. 67*4a5d661aSToomas Soome */ 68*4a5d661aSToomas Soome do { 69*4a5d661aSToomas Soome c = *s++; 70*4a5d661aSToomas Soome } while (isspace(c)); 71*4a5d661aSToomas Soome if (c == '-') { 72*4a5d661aSToomas Soome neg = 1; 73*4a5d661aSToomas Soome c = *s++; 74*4a5d661aSToomas Soome } else if (c == '+') 75*4a5d661aSToomas Soome c = *s++; 76*4a5d661aSToomas Soome if ((base == 0 || base == 16) && 77*4a5d661aSToomas Soome c == '0' && (*s == 'x' || *s == 'X')) { 78*4a5d661aSToomas Soome c = s[1]; 79*4a5d661aSToomas Soome s += 2; 80*4a5d661aSToomas Soome base = 16; 81*4a5d661aSToomas Soome } 82*4a5d661aSToomas Soome if (base == 0) 83*4a5d661aSToomas Soome base = c == '0' ? 8 : 10; 84*4a5d661aSToomas Soome 85*4a5d661aSToomas Soome /* 86*4a5d661aSToomas Soome * Compute the cutoff value between legal numbers and illegal 87*4a5d661aSToomas Soome * numbers. That is the largest legal value, divided by the 88*4a5d661aSToomas Soome * base. An input number that is greater than this value, if 89*4a5d661aSToomas Soome * followed by a legal input character, is too big. One that 90*4a5d661aSToomas Soome * is equal to this value may be valid or not; the limit 91*4a5d661aSToomas Soome * between valid and invalid numbers is then based on the last 92*4a5d661aSToomas Soome * digit. For instance, if the range for longs is 93*4a5d661aSToomas Soome * [-2147483648..2147483647] and the input base is 10, 94*4a5d661aSToomas Soome * cutoff will be set to 214748364 and cutlim to either 95*4a5d661aSToomas Soome * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 96*4a5d661aSToomas Soome * a value > 214748364, or equal but the next digit is > 7 (or 8), 97*4a5d661aSToomas Soome * the number is too big, and we will return a range error. 98*4a5d661aSToomas Soome * 99*4a5d661aSToomas Soome * Set any if any `digits' consumed; make it negative to indicate 100*4a5d661aSToomas Soome * overflow. 101*4a5d661aSToomas Soome */ 102*4a5d661aSToomas Soome cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 103*4a5d661aSToomas Soome cutlim = cutoff % (unsigned long)base; 104*4a5d661aSToomas Soome cutoff /= (unsigned long)base; 105*4a5d661aSToomas Soome for (acc = 0, any = 0;; c = *s++) { 106*4a5d661aSToomas Soome if (!isascii(c)) 107*4a5d661aSToomas Soome break; 108*4a5d661aSToomas Soome if (isdigit(c)) 109*4a5d661aSToomas Soome c -= '0'; 110*4a5d661aSToomas Soome else if (isalpha(c)) 111*4a5d661aSToomas Soome c -= isupper(c) ? 'A' - 10 : 'a' - 10; 112*4a5d661aSToomas Soome else 113*4a5d661aSToomas Soome break; 114*4a5d661aSToomas Soome if (c >= base) 115*4a5d661aSToomas Soome break; 116*4a5d661aSToomas Soome if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 117*4a5d661aSToomas Soome any = -1; 118*4a5d661aSToomas Soome else { 119*4a5d661aSToomas Soome any = 1; 120*4a5d661aSToomas Soome acc *= base; 121*4a5d661aSToomas Soome acc += c; 122*4a5d661aSToomas Soome } 123*4a5d661aSToomas Soome } 124*4a5d661aSToomas Soome if (any < 0) { 125*4a5d661aSToomas Soome acc = neg ? LONG_MIN : LONG_MAX; 126*4a5d661aSToomas Soome errno = ERANGE; 127*4a5d661aSToomas Soome } else if (neg) 128*4a5d661aSToomas Soome acc = -acc; 129*4a5d661aSToomas Soome if (endptr != 0) 130*4a5d661aSToomas Soome *endptr = (char *)(any ? s - 1 : nptr); 131*4a5d661aSToomas Soome return (acc); 132*4a5d661aSToomas Soome } 133