_strtol.h revision 330897
1/* $FreeBSD: stable/11/lib/libc/iconv/_strtol.h 330897 2018-03-14 03:19:51Z eadler $ */
2/* $NetBSD: _strtol.h,v 1.2 2009/05/20 22:03:29 christos Exp $ */
3
4/*-
5 * SPDX-License-Identifier: BSD-3-Clause
6 *
7 * Copyright (c) 1990, 1993
8 *	The Regents of the University of California.  All rights reserved.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 *    may be used to endorse or promote products derived from this software
20 *    without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * Original version ID:
35 * NetBSD: src/lib/libc/locale/_wcstol.h,v 1.2 2003/08/07 16:43:03 agc Exp
36 */
37
38/*
39 * function template for strtol, strtoll and strtoimax.
40 *
41 * parameters:
42 *	_FUNCNAME : function name
43 *      __INT     : return type
44 *      __INT_MIN : lower limit of the return type
45 *      __INT_MAX : upper limit of the return type
46 */
47
48__INT
49_FUNCNAME(const char *nptr, char **endptr, int base)
50{
51	const char *s;
52	__INT acc, cutoff;
53	unsigned char c;
54	int any, cutlim, i, neg;
55
56	/* check base value */
57	if (base && (base < 2 || base > 36)) {
58#if !defined(_KERNEL) && !defined(_STANDALONE)
59		errno = EINVAL;
60		if (endptr != NULL)
61			/* LINTED interface specification */
62			*endptr = __DECONST(void *, nptr);
63		return (0);
64#else
65		panic("%s: invalid base %d", __func__, base);
66#endif
67	}
68
69	/*
70	 * Skip white space and pick up leading +/- sign if any.
71	 * If base is 0, allow 0x for hex and 0 for octal, else
72	 * assume decimal; if base is already 16, allow 0x.
73	 */
74	s = nptr;
75	do {
76		c = *s++;
77	} while (isspace(c));
78	if (c == '-') {
79		neg = 1;
80		c = *s++;
81	} else {
82		neg = 0;
83		if (c == '+')
84			c = *s++;
85	}
86	if ((base == 0 || base == 16) &&
87	    c == '0' && (*s == 'x' || *s == 'X')) {
88		c = s[1];
89		s += 2;
90		base = 16;
91	}
92	if (base == 0)
93		base = (c == '0' ? 8 : 10);
94
95	/*
96	 * Compute the cutoff value between legal numbers and illegal
97	 * numbers.  That is the largest legal value, divided by the
98	 * base.  An input number that is greater than this value, if
99	 * followed by a legal input character, is too big.  One that
100	 * is equal to this value may be valid or not; the limit
101	 * between valid and invalid numbers is then based on the last
102	 * digit.  For instance, if the range for longs is
103	 * [-2147483648..2147483647] and the input base is 10,
104	 * cutoff will be set to 214748364 and cutlim to either
105	 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated
106	 * a value > 214748364, or equal but the next digit is > 7 (or 8),
107	 * the number is too big, and we will return a range error.
108	 *
109	 * Set any if any `digits' consumed; make it negative to indicate
110	 * overflow.
111	 */
112	cutoff = (neg ? __INT_MIN : __INT_MAX);
113	cutlim = (int)(cutoff % base);
114	cutoff /= base;
115	if (neg) {
116		if (cutlim > 0) {
117			cutlim -= base;
118			cutoff += 1;
119		}
120		cutlim = -cutlim;
121	}
122	for (acc = 0, any = 0;; c = *s++) {
123		if (isdigit(c))
124			i = c - '0';
125		else if (isalpha(c))
126			i = c - (isupper(c) ? 'A' - 10 : 'a' - 10);
127		else
128			break;
129		if (i >= base)
130			break;
131		if (any < 0)
132			continue;
133		if (neg) {
134			if (acc < cutoff || (acc == cutoff && i > cutlim)) {
135				acc = __INT_MIN;
136#if !defined(_KERNEL) && !defined(_STANDALONE)
137				any = -1;
138				errno = ERANGE;
139#else
140				any = 0;
141				break;
142#endif
143			} else {
144				any = 1;
145				acc *= base;
146				acc -= i;
147			}
148		} else {
149			if (acc > cutoff || (acc == cutoff && i > cutlim)) {
150				acc = __INT_MAX;
151#if !defined(_KERNEL) && !defined(_STANDALONE)
152				any = -1;
153				errno = ERANGE;
154#else
155				any = 0;
156				break;
157#endif
158			} else {
159				any = 1;
160				acc *= base;
161				acc += i;
162			}
163		}
164	}
165	if (endptr != NULL)
166		/* LINTED interface specification */
167		*endptr = __DECONST(void *, any ? s - 1 : nptr);
168	return(acc);
169}
170