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