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