xref: /openbsd-src/lib/libc/stdlib/strtoumax.c (revision 6022c2c21c00ed222314d1a82f05f5778bfe1e32)
1*6022c2c2Smillert /*	$OpenBSD: strtoumax.c,v 1.4 2017/07/06 16:23:11 millert Exp $	*/
2b252b5f6Sschwarze /*
3aa522acbSmillert  * Copyright (c) 1992 The Regents of the University of California.
4aa522acbSmillert  * All rights reserved.
5aa522acbSmillert  *
6aa522acbSmillert  * Redistribution and use in source and binary forms, with or without
7aa522acbSmillert  * modification, are permitted provided that the following conditions
8aa522acbSmillert  * are met:
9aa522acbSmillert  * 1. Redistributions of source code must retain the above copyright
10aa522acbSmillert  *    notice, this list of conditions and the following disclaimer.
11aa522acbSmillert  * 2. Redistributions in binary form must reproduce the above copyright
12aa522acbSmillert  *    notice, this list of conditions and the following disclaimer in the
13aa522acbSmillert  *    documentation and/or other materials provided with the distribution.
14aa522acbSmillert  * 3. Neither the name of the University nor the names of its contributors
15aa522acbSmillert  *    may be used to endorse or promote products derived from this software
16aa522acbSmillert  *    without specific prior written permission.
17aa522acbSmillert  *
18aa522acbSmillert  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
19aa522acbSmillert  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20aa522acbSmillert  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21aa522acbSmillert  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
22aa522acbSmillert  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23aa522acbSmillert  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24aa522acbSmillert  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25aa522acbSmillert  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26aa522acbSmillert  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27aa522acbSmillert  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28aa522acbSmillert  * SUCH DAMAGE.
29aa522acbSmillert  */
30aa522acbSmillert 
31aa522acbSmillert #include <ctype.h>
32aa522acbSmillert #include <errno.h>
33aa522acbSmillert #include <inttypes.h>
34aa522acbSmillert 
35aa522acbSmillert /*
36aa522acbSmillert  * Convert a string to a uintmax_t.
37aa522acbSmillert  *
38aa522acbSmillert  * Ignores `locale' stuff.  Assumes that the upper and lower case
39aa522acbSmillert  * alphabets and digits are each contiguous.
40aa522acbSmillert  */
41aa522acbSmillert uintmax_t
strtoumax(const char * nptr,char ** endptr,int base)42aa522acbSmillert strtoumax(const char *nptr, char **endptr, int base)
43aa522acbSmillert {
44aa522acbSmillert 	const char *s;
45aa522acbSmillert 	uintmax_t acc, cutoff;
46aa522acbSmillert 	int c;
47aa522acbSmillert 	int neg, any, cutlim;
48aa522acbSmillert 
49aa522acbSmillert 	/*
50b252b5f6Sschwarze 	 * See strtoimax for comments as to the logic used.
51aa522acbSmillert 	 */
52b252b5f6Sschwarze 	if (base < 0 || base == 1 || base > 36) {
53b252b5f6Sschwarze 		if (endptr != 0)
54b252b5f6Sschwarze 			*endptr = (char *)nptr;
55b252b5f6Sschwarze 		errno = EINVAL;
56b252b5f6Sschwarze 		return 0;
57b252b5f6Sschwarze 	}
58b252b5f6Sschwarze 
59aa522acbSmillert 	s = nptr;
60aa522acbSmillert 	do {
61aa522acbSmillert 		c = (unsigned char) *s++;
62aa522acbSmillert 	} while (isspace(c));
63aa522acbSmillert 	if (c == '-') {
64aa522acbSmillert 		neg = 1;
65aa522acbSmillert 		c = *s++;
66aa522acbSmillert 	} else {
67aa522acbSmillert 		neg = 0;
68aa522acbSmillert 		if (c == '+')
69aa522acbSmillert 			c = *s++;
70aa522acbSmillert 	}
71*6022c2c2Smillert 	if ((base == 0 || base == 16) && c == '0' &&
72*6022c2c2Smillert 	    (*s == 'x' || *s == 'X') && isxdigit((unsigned char)s[1])) {
73aa522acbSmillert 		c = s[1];
74aa522acbSmillert 		s += 2;
75aa522acbSmillert 		base = 16;
76aa522acbSmillert 	}
77aa522acbSmillert 	if (base == 0)
78aa522acbSmillert 		base = c == '0' ? 8 : 10;
79aa522acbSmillert 
80aa522acbSmillert 	cutoff = UINTMAX_MAX / (uintmax_t)base;
81aa522acbSmillert 	cutlim = UINTMAX_MAX % (uintmax_t)base;
82aa522acbSmillert 	for (acc = 0, any = 0;; c = (unsigned char) *s++) {
83aa522acbSmillert 		if (isdigit(c))
84aa522acbSmillert 			c -= '0';
85aa522acbSmillert 		else if (isalpha(c))
86aa522acbSmillert 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
87aa522acbSmillert 		else
88aa522acbSmillert 			break;
89aa522acbSmillert 		if (c >= base)
90aa522acbSmillert 			break;
91aa522acbSmillert 		if (any < 0)
92aa522acbSmillert 			continue;
93aa522acbSmillert 		if (acc > cutoff || (acc == cutoff && c > cutlim)) {
94aa522acbSmillert 			any = -1;
95aa522acbSmillert 			acc = UINTMAX_MAX;
96aa522acbSmillert 			errno = ERANGE;
97aa522acbSmillert 		} else {
98aa522acbSmillert 			any = 1;
99aa522acbSmillert 			acc *= (uintmax_t)base;
100aa522acbSmillert 			acc += c;
101aa522acbSmillert 		}
102aa522acbSmillert 	}
103aa522acbSmillert 	if (neg && any > 0)
104aa522acbSmillert 		acc = -acc;
105aa522acbSmillert 	if (endptr != 0)
106aa522acbSmillert 		*endptr = (char *) (any ? s - 1 : nptr);
107aa522acbSmillert 	return (acc);
108aa522acbSmillert }
10938a75b98Sguenther DEF_STRONG(strtoumax);
110