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