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