1015240d9SMadhukar Pappireddy /*- 2015240d9SMadhukar Pappireddy * SPDX-License-Identifier: BSD-3-Clause 3015240d9SMadhukar Pappireddy * 4015240d9SMadhukar Pappireddy * Copyright (c) 1990, 1993 5015240d9SMadhukar Pappireddy * The Regents of the University of California. All rights reserved. 6015240d9SMadhukar Pappireddy * 7015240d9SMadhukar Pappireddy * Copyright (c) 2011 The FreeBSD Foundation 8015240d9SMadhukar Pappireddy * All rights reserved. 9015240d9SMadhukar Pappireddy * Portions of this software were developed by David Chisnall 10015240d9SMadhukar Pappireddy * under sponsorship from the FreeBSD Foundation. 11015240d9SMadhukar Pappireddy * 12015240d9SMadhukar Pappireddy * Redistribution and use in source and binary forms, with or without 13015240d9SMadhukar Pappireddy * modification, are permitted provided that the following conditions 14015240d9SMadhukar Pappireddy * are met: 15015240d9SMadhukar Pappireddy * 1. Redistributions of source code must retain the above copyright 16015240d9SMadhukar Pappireddy * notice, this list of conditions and the following disclaimer. 17015240d9SMadhukar Pappireddy * 2. Redistributions in binary form must reproduce the above copyright 18015240d9SMadhukar Pappireddy * notice, this list of conditions and the following disclaimer in the 19015240d9SMadhukar Pappireddy * documentation and/or other materials provided with the distribution. 20015240d9SMadhukar Pappireddy * 3. Neither the name of the University nor the names of its contributors 21015240d9SMadhukar Pappireddy * may be used to endorse or promote products derived from this software 22015240d9SMadhukar Pappireddy * without specific prior written permission. 23015240d9SMadhukar Pappireddy * 24015240d9SMadhukar Pappireddy * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25015240d9SMadhukar Pappireddy * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26015240d9SMadhukar Pappireddy * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27015240d9SMadhukar Pappireddy * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28015240d9SMadhukar Pappireddy * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29015240d9SMadhukar Pappireddy * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30015240d9SMadhukar Pappireddy * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31015240d9SMadhukar Pappireddy * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32015240d9SMadhukar Pappireddy * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33015240d9SMadhukar Pappireddy * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34015240d9SMadhukar Pappireddy * SUCH DAMAGE. 35015240d9SMadhukar Pappireddy */ 36015240d9SMadhukar Pappireddy 37015240d9SMadhukar Pappireddy #include <errno.h> 38015240d9SMadhukar Pappireddy #include <limits.h> 39015240d9SMadhukar Pappireddy #include <stddef.h> 40015240d9SMadhukar Pappireddy #include <stdlib.h> 41015240d9SMadhukar Pappireddy 42015240d9SMadhukar Pappireddy /* 43015240d9SMadhukar Pappireddy * Convert a string to a long integer. 44015240d9SMadhukar Pappireddy * 45015240d9SMadhukar Pappireddy * Assumes that the upper and lower case 46015240d9SMadhukar Pappireddy * alphabets and digits are each contiguous. 47015240d9SMadhukar Pappireddy */ 48015240d9SMadhukar Pappireddy long strtol(const char *nptr, char **endptr, int base) 49015240d9SMadhukar Pappireddy { 50015240d9SMadhukar Pappireddy const char *s; 51015240d9SMadhukar Pappireddy unsigned long acc; 52015240d9SMadhukar Pappireddy char c; 53015240d9SMadhukar Pappireddy unsigned long cutoff; 54015240d9SMadhukar Pappireddy int neg, any, cutlim; 55*02dbb148SGovindraj Raja long result; 56015240d9SMadhukar Pappireddy 57015240d9SMadhukar Pappireddy /* 58015240d9SMadhukar Pappireddy * Skip white space and pick up leading +/- sign if any. 59015240d9SMadhukar Pappireddy * If base is 0, allow 0x for hex and 0 for octal, else 60015240d9SMadhukar Pappireddy * assume decimal; if base is already 16, allow 0x. 61015240d9SMadhukar Pappireddy */ 62015240d9SMadhukar Pappireddy s = nptr; 63015240d9SMadhukar Pappireddy do { 64015240d9SMadhukar Pappireddy c = *s++; 65015240d9SMadhukar Pappireddy } while (isspace((unsigned char)c)); 66015240d9SMadhukar Pappireddy if (c == '-') { 67015240d9SMadhukar Pappireddy neg = 1; 68015240d9SMadhukar Pappireddy c = *s++; 69015240d9SMadhukar Pappireddy } else { 70015240d9SMadhukar Pappireddy neg = 0; 71015240d9SMadhukar Pappireddy if (c == '+') 72015240d9SMadhukar Pappireddy c = *s++; 73015240d9SMadhukar Pappireddy } 74015240d9SMadhukar Pappireddy if ((base == 0 || base == 16) && 75015240d9SMadhukar Pappireddy c == '0' && (*s == 'x' || *s == 'X') && 76015240d9SMadhukar Pappireddy ((s[1] >= '0' && s[1] <= '9') || 77015240d9SMadhukar Pappireddy (s[1] >= 'A' && s[1] <= 'F') || 78015240d9SMadhukar Pappireddy (s[1] >= 'a' && s[1] <= 'f'))) { 79015240d9SMadhukar Pappireddy c = s[1]; 80015240d9SMadhukar Pappireddy s += 2; 81015240d9SMadhukar Pappireddy base = 16; 82015240d9SMadhukar Pappireddy } 83015240d9SMadhukar Pappireddy if (base == 0) 84015240d9SMadhukar Pappireddy base = c == '0' ? 8 : 10; 85015240d9SMadhukar Pappireddy acc = any = 0; 86015240d9SMadhukar Pappireddy 87015240d9SMadhukar Pappireddy /* 88015240d9SMadhukar Pappireddy * Compute the cutoff value between legal numbers and illegal 89015240d9SMadhukar Pappireddy * numbers. That is the largest legal value, divided by the 90015240d9SMadhukar Pappireddy * base. An input number that is greater than this value, if 91015240d9SMadhukar Pappireddy * followed by a legal input character, is too big. One that 92015240d9SMadhukar Pappireddy * is equal to this value may be valid or not; the limit 93015240d9SMadhukar Pappireddy * between valid and invalid numbers is then based on the last 94015240d9SMadhukar Pappireddy * digit. For instance, if the range for longs is 95015240d9SMadhukar Pappireddy * [-2147483648..2147483647] and the input base is 10, 96015240d9SMadhukar Pappireddy * cutoff will be set to 214748364 and cutlim to either 97015240d9SMadhukar Pappireddy * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 98015240d9SMadhukar Pappireddy * a value > 214748364, or equal but the next digit is > 7 (or 8), 99015240d9SMadhukar Pappireddy * the number is too big, and we will return a range error. 100015240d9SMadhukar Pappireddy * 101015240d9SMadhukar Pappireddy * Set 'any' if any `digits' consumed; make it negative to indicate 102015240d9SMadhukar Pappireddy * overflow. 103015240d9SMadhukar Pappireddy */ 104015240d9SMadhukar Pappireddy cutoff = neg ? (unsigned long)-(LONG_MIN + LONG_MAX) + LONG_MAX 105015240d9SMadhukar Pappireddy : LONG_MAX; 106015240d9SMadhukar Pappireddy cutlim = cutoff % base; 107015240d9SMadhukar Pappireddy cutoff /= base; 108015240d9SMadhukar Pappireddy for ( ; ; c = *s++) { 109015240d9SMadhukar Pappireddy if (c >= '0' && c <= '9') 110015240d9SMadhukar Pappireddy c -= '0'; 111015240d9SMadhukar Pappireddy else if (c >= 'A' && c <= 'Z') 112015240d9SMadhukar Pappireddy c -= 'A' - 10; 113015240d9SMadhukar Pappireddy else if (c >= 'a' && c <= 'z') 114015240d9SMadhukar Pappireddy c -= 'a' - 10; 115015240d9SMadhukar Pappireddy else 116015240d9SMadhukar Pappireddy break; 117015240d9SMadhukar Pappireddy if (c >= base) 118015240d9SMadhukar Pappireddy break; 119015240d9SMadhukar Pappireddy if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 120015240d9SMadhukar Pappireddy any = -1; 121015240d9SMadhukar Pappireddy else { 122015240d9SMadhukar Pappireddy any = 1; 123015240d9SMadhukar Pappireddy acc *= base; 124015240d9SMadhukar Pappireddy acc += c; 125015240d9SMadhukar Pappireddy } 126015240d9SMadhukar Pappireddy } 127*02dbb148SGovindraj Raja 128015240d9SMadhukar Pappireddy if (any < 0) { 129*02dbb148SGovindraj Raja result = neg ? LONG_MIN : LONG_MAX; 130*02dbb148SGovindraj Raja } else { 131*02dbb148SGovindraj Raja result = neg ? -(long)acc : (long)acc; 132*02dbb148SGovindraj Raja } 133*02dbb148SGovindraj Raja 134015240d9SMadhukar Pappireddy if (endptr != NULL) 135015240d9SMadhukar Pappireddy *endptr = (char *)(any ? s - 1 : nptr); 136*02dbb148SGovindraj Raja 137*02dbb148SGovindraj Raja return result; 138015240d9SMadhukar Pappireddy } 139