xref: /dflybsd-src/lib/libc/stdlib/strsuftoll.c (revision e6975a4e86dfb50945f8cfe20663da81051aa306)
1*e6975a4eSSascha Wildner /*	$NetBSD: strsuftoll.c,v 1.9 2011/10/22 22:08:47 christos Exp $	*/
2*e6975a4eSSascha Wildner /*-
3*e6975a4eSSascha Wildner  * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
4*e6975a4eSSascha Wildner  * All rights reserved.
5*e6975a4eSSascha Wildner  *
6*e6975a4eSSascha Wildner  * This code is derived from software contributed to The NetBSD Foundation
7*e6975a4eSSascha Wildner  * by Luke Mewburn.
8*e6975a4eSSascha Wildner  *
9*e6975a4eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
10*e6975a4eSSascha Wildner  * modification, are permitted provided that the following conditions
11*e6975a4eSSascha Wildner  * are met:
12*e6975a4eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
13*e6975a4eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
14*e6975a4eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
15*e6975a4eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
16*e6975a4eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
17*e6975a4eSSascha Wildner  *
18*e6975a4eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19*e6975a4eSSascha Wildner  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20*e6975a4eSSascha Wildner  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21*e6975a4eSSascha Wildner  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22*e6975a4eSSascha Wildner  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23*e6975a4eSSascha Wildner  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24*e6975a4eSSascha Wildner  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25*e6975a4eSSascha Wildner  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26*e6975a4eSSascha Wildner  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27*e6975a4eSSascha Wildner  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28*e6975a4eSSascha Wildner  * POSSIBILITY OF SUCH DAMAGE.
29*e6975a4eSSascha Wildner  */
30*e6975a4eSSascha Wildner /*-
31*e6975a4eSSascha Wildner  * Copyright (c) 1991, 1993, 1994
32*e6975a4eSSascha Wildner  *	The Regents of the University of California.  All rights reserved.
33*e6975a4eSSascha Wildner  *
34*e6975a4eSSascha Wildner  * This code is derived from software contributed to Berkeley by
35*e6975a4eSSascha Wildner  * Keith Muller of the University of California, San Diego and Lance
36*e6975a4eSSascha Wildner  * Visser of Convex Computer Corporation.
37*e6975a4eSSascha Wildner  *
38*e6975a4eSSascha Wildner  * Redistribution and use in source and binary forms, with or without
39*e6975a4eSSascha Wildner  * modification, are permitted provided that the following conditions
40*e6975a4eSSascha Wildner  * are met:
41*e6975a4eSSascha Wildner  * 1. Redistributions of source code must retain the above copyright
42*e6975a4eSSascha Wildner  *    notice, this list of conditions and the following disclaimer.
43*e6975a4eSSascha Wildner  * 2. Redistributions in binary form must reproduce the above copyright
44*e6975a4eSSascha Wildner  *    notice, this list of conditions and the following disclaimer in the
45*e6975a4eSSascha Wildner  *    documentation and/or other materials provided with the distribution.
46*e6975a4eSSascha Wildner  * 3. Neither the name of the University nor the names of its contributors
47*e6975a4eSSascha Wildner  *    may be used to endorse or promote products derived from this software
48*e6975a4eSSascha Wildner  *    without specific prior written permission.
49*e6975a4eSSascha Wildner  *
50*e6975a4eSSascha Wildner  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51*e6975a4eSSascha Wildner  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52*e6975a4eSSascha Wildner  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53*e6975a4eSSascha Wildner  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54*e6975a4eSSascha Wildner  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55*e6975a4eSSascha Wildner  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56*e6975a4eSSascha Wildner  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57*e6975a4eSSascha Wildner  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58*e6975a4eSSascha Wildner  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59*e6975a4eSSascha Wildner  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60*e6975a4eSSascha Wildner  * SUCH DAMAGE.
61*e6975a4eSSascha Wildner  */
62*e6975a4eSSascha Wildner 
63*e6975a4eSSascha Wildner #include <assert.h>
64*e6975a4eSSascha Wildner #include <ctype.h>
65*e6975a4eSSascha Wildner #include <err.h>
66*e6975a4eSSascha Wildner #include <errno.h>
67*e6975a4eSSascha Wildner #include <libutil.h>
68*e6975a4eSSascha Wildner #include <stdio.h>
69*e6975a4eSSascha Wildner #include <stdlib.h>
70*e6975a4eSSascha Wildner #include <string.h>
71*e6975a4eSSascha Wildner 
72*e6975a4eSSascha Wildner /*
73*e6975a4eSSascha Wildner  * Convert an expression of the following forms to a (u)int64_t.
74*e6975a4eSSascha Wildner  * 	1) A positive decimal number.
75*e6975a4eSSascha Wildner  *	2) A positive decimal number followed by a b (mult by 512).
76*e6975a4eSSascha Wildner  *	3) A positive decimal number followed by a k (mult by 1024).
77*e6975a4eSSascha Wildner  *	4) A positive decimal number followed by a m (mult by 1048576).
78*e6975a4eSSascha Wildner  *	5) A positive decimal number followed by a g (mult by 1073741824).
79*e6975a4eSSascha Wildner  *	6) A positive decimal number followed by a t (mult by 1099511627776).
80*e6975a4eSSascha Wildner  *	7) A positive decimal number followed by a w (mult by sizeof int)
81*e6975a4eSSascha Wildner  *	8) Two or more positive decimal numbers (with/without k,b or w).
82*e6975a4eSSascha Wildner  *	   separated by x (also * for backwards compatibility), specifying
83*e6975a4eSSascha Wildner  *	   the product of the indicated values.
84*e6975a4eSSascha Wildner  * Returns the result upon successful conversion, or exits with an
85*e6975a4eSSascha Wildner  * appropriate error.
86*e6975a4eSSascha Wildner  *
87*e6975a4eSSascha Wildner  */
88*e6975a4eSSascha Wildner /* LONGLONG */
89*e6975a4eSSascha Wildner long long
strsuftoll(const char * desc,const char * val,long long min,long long max)90*e6975a4eSSascha Wildner strsuftoll(const char *desc, const char *val,
91*e6975a4eSSascha Wildner     long long min, long long max)
92*e6975a4eSSascha Wildner {
93*e6975a4eSSascha Wildner 	long long result;
94*e6975a4eSSascha Wildner 	char	errbuf[100];
95*e6975a4eSSascha Wildner 
96*e6975a4eSSascha Wildner 	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
97*e6975a4eSSascha Wildner 	if (*errbuf != '\0')
98*e6975a4eSSascha Wildner 		errx(EXIT_FAILURE, "%s", errbuf);
99*e6975a4eSSascha Wildner 	return result;
100*e6975a4eSSascha Wildner }
101*e6975a4eSSascha Wildner 
102*e6975a4eSSascha Wildner /*
103*e6975a4eSSascha Wildner  * As strsuftoll(), but returns the error message into the provided buffer
104*e6975a4eSSascha Wildner  * rather than exiting with it.
105*e6975a4eSSascha Wildner  */
106*e6975a4eSSascha Wildner /* LONGLONG */
107*e6975a4eSSascha Wildner static long long
__strsuftollx(const char * desc,const char * val,long long min,long long max,char * ebuf,size_t ebuflen,size_t depth)108*e6975a4eSSascha Wildner __strsuftollx(const char *desc, const char *val,
109*e6975a4eSSascha Wildner     long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
110*e6975a4eSSascha Wildner {
111*e6975a4eSSascha Wildner 	long long num, t;
112*e6975a4eSSascha Wildner 	char	*expr;
113*e6975a4eSSascha Wildner 
114*e6975a4eSSascha Wildner 	_DIAGASSERT(desc != NULL);
115*e6975a4eSSascha Wildner 	_DIAGASSERT(val != NULL);
116*e6975a4eSSascha Wildner 	_DIAGASSERT(ebuf != NULL);
117*e6975a4eSSascha Wildner 
118*e6975a4eSSascha Wildner 	if (depth > 16) {
119*e6975a4eSSascha Wildner 		snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
120*e6975a4eSSascha Wildner 		return 0;
121*e6975a4eSSascha Wildner 	}
122*e6975a4eSSascha Wildner 
123*e6975a4eSSascha Wildner 	while (isspace((unsigned char)*val))	/* Skip leading space */
124*e6975a4eSSascha Wildner 		val++;
125*e6975a4eSSascha Wildner 
126*e6975a4eSSascha Wildner 	errno = 0;
127*e6975a4eSSascha Wildner 	num = strtoll(val, &expr, 10);
128*e6975a4eSSascha Wildner 	if (errno == ERANGE)
129*e6975a4eSSascha Wildner 		goto erange;			/* Overflow */
130*e6975a4eSSascha Wildner 
131*e6975a4eSSascha Wildner 	if (expr == val)			/* No digits */
132*e6975a4eSSascha Wildner 		goto badnum;
133*e6975a4eSSascha Wildner 
134*e6975a4eSSascha Wildner 	switch (*expr) {
135*e6975a4eSSascha Wildner 	case 'b':
136*e6975a4eSSascha Wildner 		t = num;
137*e6975a4eSSascha Wildner 		num *= 512;			/* 1 block */
138*e6975a4eSSascha Wildner 		if (t > num)
139*e6975a4eSSascha Wildner 			goto erange;
140*e6975a4eSSascha Wildner 		++expr;
141*e6975a4eSSascha Wildner 		break;
142*e6975a4eSSascha Wildner 	case 'k':
143*e6975a4eSSascha Wildner 		t = num;
144*e6975a4eSSascha Wildner 		num *= 1024;			/* 1 kibibyte */
145*e6975a4eSSascha Wildner 		if (t > num)
146*e6975a4eSSascha Wildner 			goto erange;
147*e6975a4eSSascha Wildner 		++expr;
148*e6975a4eSSascha Wildner 		break;
149*e6975a4eSSascha Wildner 	case 'm':
150*e6975a4eSSascha Wildner 		t = num;
151*e6975a4eSSascha Wildner 		num *= 1048576;			/* 1 mebibyte */
152*e6975a4eSSascha Wildner 		if (t > num)
153*e6975a4eSSascha Wildner 			goto erange;
154*e6975a4eSSascha Wildner 		++expr;
155*e6975a4eSSascha Wildner 		break;
156*e6975a4eSSascha Wildner 	case 'g':
157*e6975a4eSSascha Wildner 		t = num;
158*e6975a4eSSascha Wildner 		num *= 1073741824;		/* 1 gibibyte */
159*e6975a4eSSascha Wildner 		if (t > num)
160*e6975a4eSSascha Wildner 			goto erange;
161*e6975a4eSSascha Wildner 		++expr;
162*e6975a4eSSascha Wildner 		break;
163*e6975a4eSSascha Wildner 	case 't':
164*e6975a4eSSascha Wildner 		t = num;
165*e6975a4eSSascha Wildner 		num *= 1099511627776LL;		/* 1 tebibyte */
166*e6975a4eSSascha Wildner 		if (t > num)
167*e6975a4eSSascha Wildner 			goto erange;
168*e6975a4eSSascha Wildner 		++expr;
169*e6975a4eSSascha Wildner 		break;
170*e6975a4eSSascha Wildner 	case 'w':
171*e6975a4eSSascha Wildner 		t = num;
172*e6975a4eSSascha Wildner 		num *= sizeof(int);		/* 1 word */
173*e6975a4eSSascha Wildner 		if (t > num)
174*e6975a4eSSascha Wildner 			goto erange;
175*e6975a4eSSascha Wildner 		++expr;
176*e6975a4eSSascha Wildner 		break;
177*e6975a4eSSascha Wildner 	}
178*e6975a4eSSascha Wildner 
179*e6975a4eSSascha Wildner 	switch (*expr) {
180*e6975a4eSSascha Wildner 	case '\0':
181*e6975a4eSSascha Wildner 		break;
182*e6975a4eSSascha Wildner 	case '*':				/* Backward compatible */
183*e6975a4eSSascha Wildner 	case 'x':
184*e6975a4eSSascha Wildner 		t = num;
185*e6975a4eSSascha Wildner 		num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
186*e6975a4eSSascha Wildner 			depth + 1);
187*e6975a4eSSascha Wildner 		if (*ebuf != '\0')
188*e6975a4eSSascha Wildner 			return 0;
189*e6975a4eSSascha Wildner 		if (t > num) {
190*e6975a4eSSascha Wildner  erange:
191*e6975a4eSSascha Wildner 			errno = ERANGE;
192*e6975a4eSSascha Wildner 			snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
193*e6975a4eSSascha Wildner 			return 0;
194*e6975a4eSSascha Wildner 		}
195*e6975a4eSSascha Wildner 		break;
196*e6975a4eSSascha Wildner 	default:
197*e6975a4eSSascha Wildner  badnum:
198*e6975a4eSSascha Wildner 		snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
199*e6975a4eSSascha Wildner 		return 0;
200*e6975a4eSSascha Wildner 	}
201*e6975a4eSSascha Wildner 	if (num < min) {
202*e6975a4eSSascha Wildner 		/* LONGLONG */
203*e6975a4eSSascha Wildner 		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
204*e6975a4eSSascha Wildner 		    desc, (long long)num, (long long)min);
205*e6975a4eSSascha Wildner 		return 0;
206*e6975a4eSSascha Wildner 	}
207*e6975a4eSSascha Wildner 	if (num > max) {
208*e6975a4eSSascha Wildner 		/* LONGLONG */
209*e6975a4eSSascha Wildner 		snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
210*e6975a4eSSascha Wildner 		    desc, (long long)num, (long long)max);
211*e6975a4eSSascha Wildner 		return 0;
212*e6975a4eSSascha Wildner 	}
213*e6975a4eSSascha Wildner 	*ebuf = '\0';
214*e6975a4eSSascha Wildner 	return num;
215*e6975a4eSSascha Wildner }
216*e6975a4eSSascha Wildner 
217*e6975a4eSSascha Wildner long long
strsuftollx(const char * desc,const char * val,long long min,long long max,char * ebuf,size_t ebuflen)218*e6975a4eSSascha Wildner strsuftollx(const char *desc, const char *val,
219*e6975a4eSSascha Wildner     long long min, long long max, char *ebuf, size_t ebuflen)
220*e6975a4eSSascha Wildner {
221*e6975a4eSSascha Wildner 	return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
222*e6975a4eSSascha Wildner }
223