1195699Srwatson/* $OpenBSD: strtoll.c,v 1.6 2005/11/10 10:00:17 espie Exp $ */ 2196019Srwatson/*- 3196019Srwatson * Copyright (c) 1992 The Regents of the University of California. 4196019Srwatson * All rights reserved. 5196019Srwatson * 6196019Srwatson * Redistribution and use in source and binary forms, with or without 7196019Srwatson * modification, are permitted provided that the following conditions 8196019Srwatson * are met: 9196019Srwatson * 1. Redistributions of source code must retain the above copyright 10195699Srwatson * notice, this list of conditions and the following disclaimer. 11195699Srwatson * 2. Redistributions in binary form must reproduce the above copyright 12195699Srwatson * notice, this list of conditions and the following disclaimer in the 13195699Srwatson * documentation and/or other materials provided with the distribution. 14195699Srwatson * 3. Neither the name of the University nor the names of its contributors 15195699Srwatson * may be used to endorse or promote products derived from this software 16195699Srwatson * without specific prior written permission. 17195699Srwatson * 18195699Srwatson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19195699Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20195699Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21195699Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22195699Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23195699Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24195699Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25195699Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26195699Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27195699Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28195699Srwatson * SUCH DAMAGE. 29195699Srwatson */ 30195699Srwatson 31195699Srwatson/* OPENBSD ORIGINAL: lib/libc/stdlib/strtoll.c */ 32195699Srwatson 33195699Srwatson#include "includes.h" 34195699Srwatson#ifndef HAVE_STRTOLL 35195699Srwatson 36195699Srwatson#include <sys/types.h> 37195699Srwatson 38195699Srwatson#include <ctype.h> 39196019Srwatson#include <errno.h> 40203483Szec#include <limits.h> 41203727Sbz#include <stdlib.h> 42196019Srwatson 43195699Srwatson/* 44203483Szec * Convert a string to a long long. 45195699Srwatson * 46196019Srwatson * Ignores `locale' stuff. Assumes that the upper and lower case 47203727Sbz * alphabets and digits are each contiguous. 48195699Srwatson */ 49195699Srwatsonlong long 50205345Sbzstrtoll(const char *nptr, char **endptr, int base) 51195699Srwatson{ 52195699Srwatson const char *s; 53195699Srwatson long long acc, cutoff; 54196019Srwatson int c; 55195699Srwatson int neg, any, cutlim; 56195699Srwatson 57195699Srwatson /* 58205345Sbz * Skip white space and pick up leading +/- sign if any. 59205345Sbz * If base is 0, allow 0x for hex and 0 for octal, else 60196019Srwatson * assume decimal; if base is already 16, allow 0x. 61196019Srwatson */ 62203729Sbz s = nptr; 63196019Srwatson do { 64196019Srwatson c = (unsigned char) *s++; 65196019Srwatson } while (isspace(c)); 66196019Srwatson if (c == '-') { 67195699Srwatson neg = 1; 68195699Srwatson c = *s++; 69195699Srwatson } else { 70195972Srwatson neg = 0; 71195972Srwatson if (c == '+') 72196025Srwatson c = *s++; 73196019Srwatson } 74196025Srwatson if ((base == 0 || base == 16) && 75195972Srwatson c == '0' && (*s == 'x' || *s == 'X')) { 76195972Srwatson c = s[1]; 77195972Srwatson s += 2; 78195972Srwatson base = 16; 79195972Srwatson } 80196019Srwatson if (base == 0) 81196019Srwatson base = c == '0' ? 8 : 10; 82217203Sbz 83217203Sbz /* 84227293Sed * Compute the cutoff value between legal numbers and illegal 85196019Srwatson * numbers. That is the largest legal value, divided by the 86196019Srwatson * base. An input number that is greater than this value, if 87196019Srwatson * followed by a legal input character, is too big. One that 88196019Srwatson * is equal to this value may be valid or not; the limit 89196019Srwatson * between valid and invalid numbers is then based on the last 90196025Srwatson * digit. For instance, if the range for long longs is 91196019Srwatson * [-9223372036854775808..9223372036854775807] and the input base 92196019Srwatson * is 10, cutoff will be set to 922337203685477580 and cutlim to 93196019Srwatson * either 7 (neg==0) or 8 (neg==1), meaning that if we have 94196019Srwatson * accumulated a value > 922337203685477580, or equal but the 95196019Srwatson * next digit is > 7 (or 8), the number is too big, and we will 96196019Srwatson * return a range error. 97196019Srwatson * 98196019Srwatson * Set any if any `digits' consumed; make it negative to indicate 99196019Srwatson * overflow. 100196019Srwatson */ 101196019Srwatson cutoff = neg ? LLONG_MIN : LLONG_MAX; 102196019Srwatson cutlim = cutoff % base; 103196019Srwatson cutoff /= base; 104196019Srwatson if (neg) { 105196019Srwatson if (cutlim > 0) { 106196019Srwatson cutlim -= base; 107196019Srwatson cutoff += 1; 108196019Srwatson } 109195972Srwatson cutlim = -cutlim; 110195972Srwatson } 111195972Srwatson for (acc = 0, any = 0;; c = (unsigned char) *s++) { 112195972Srwatson if (isdigit(c)) 113195972Srwatson c -= '0'; 114195699Srwatson else if (isalpha(c)) 115195699Srwatson c -= isupper(c) ? 'A' - 10 : 'a' - 10; 116195699Srwatson else 117195699Srwatson break; 118195699Srwatson if (c >= base) 119195699Srwatson break; 120195699Srwatson if (any < 0) 121195699Srwatson continue; 122195699Srwatson if (neg) { 123195699Srwatson if (acc < cutoff || (acc == cutoff && c > cutlim)) { 124195699Srwatson any = -1; 125195699Srwatson acc = LLONG_MIN; 126195699Srwatson errno = ERANGE; 127195699Srwatson } else { 128195699Srwatson any = 1; 129195699Srwatson acc *= base; 130195699Srwatson acc -= c; 131195699Srwatson } 132195699Srwatson } else { 133195699Srwatson if (acc > cutoff || (acc == cutoff && c > cutlim)) { 134195699Srwatson any = -1; 135195699Srwatson acc = LLONG_MAX; 136195699Srwatson errno = ERANGE; 137195699Srwatson } else { 138195699Srwatson any = 1; 139195699Srwatson acc *= base; 140195699Srwatson acc += c; 141195699Srwatson } 142195699Srwatson } 143195699Srwatson } 144195699Srwatson if (endptr != 0) 145195699Srwatson *endptr = (char *) (any ? s - 1 : nptr); 146195699Srwatson return (acc); 147195699Srwatson} 148195699Srwatson#endif /* HAVE_STRTOLL */ 149195699Srwatson