xref: /freebsd/lib/libnetbsd/strsuftoll.c (revision 595e514d0df2bac5b813d35f83e32875dbf16a83)
1 /*	$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem 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 <sys/cdefs.h>
64 __FBSDID("$FreeBSD$");
65 
66 #include <sys/types.h>
67 #include <sys/time.h>
68 
69 #include <assert.h>
70 #include <ctype.h>
71 #include <err.h>
72 #include <errno.h>
73 #include <limits.h>
74 #include <stdio.h>
75 #include <stdlib.h>
76 #include <string.h>
77 
78 #ifdef _LIBC
79 # ifdef __weak_alias
80 __weak_alias(strsuftoll, _strsuftoll)
81 __weak_alias(strsuftollx, _strsuftollx)
82 # endif
83 #endif /* LIBC */
84 
85 /*
86  * Convert an expression of the following forms to a (u)int64_t.
87  * 	1) A positive decimal number.
88  *	2) A positive decimal number followed by a b (mult by 512).
89  *	3) A positive decimal number followed by a k (mult by 1024).
90  *	4) A positive decimal number followed by a m (mult by 1048576).
91  *	5) A positive decimal number followed by a g (mult by 1073741824).
92  *	6) A positive decimal number followed by a t (mult by 1099511627776).
93  *	7) A positive decimal number followed by a w (mult by sizeof int)
94  *	8) Two or more positive decimal numbers (with/without k,b or w).
95  *	   separated by x (also * for backwards compatibility), specifying
96  *	   the product of the indicated values.
97  * Returns the result upon successful conversion, or exits with an
98  * appropriate error.
99  *
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 long long
108 strsuftollx(const char *desc, const char *val,
109     long long min, long long max, char *ebuf, size_t ebuflen)
110 {
111 	long long num, t;
112 	char	*expr;
113 
114 	errno = 0;
115 	ebuf[0] = '\0';
116 
117 	while (isspace((unsigned char)*val))	/* Skip leading space */
118 		val++;
119 
120 	num = strtoll(val, &expr, 10);
121 	if (errno == ERANGE)
122 		goto erange;			/* Overflow */
123 
124 	if (expr == val)			/* No digits */
125 		goto badnum;
126 
127 	switch (*expr) {
128 	case 'b':
129 		t = num;
130 		num *= 512;			/* 1 block */
131 		if (t > num)
132 			goto erange;
133 		++expr;
134 		break;
135 	case 'k':
136 		t = num;
137 		num *= 1024;			/* 1 kilobyte */
138 		if (t > num)
139 			goto erange;
140 		++expr;
141 		break;
142 	case 'm':
143 		t = num;
144 		num *= 1048576;			/* 1 megabyte */
145 		if (t > num)
146 			goto erange;
147 		++expr;
148 		break;
149 	case 'g':
150 		t = num;
151 		num *= 1073741824;		/* 1 gigabyte */
152 		if (t > num)
153 			goto erange;
154 		++expr;
155 		break;
156 	case 't':
157 		t = num;
158 		num *= 1099511627776LL;		/* 1 terabyte */
159 		if (t > num)
160 			goto erange;
161 		++expr;
162 		break;
163 	case 'w':
164 		t = num;
165 		num *= sizeof(int);		/* 1 word */
166 		if (t > num)
167 			goto erange;
168 		++expr;
169 		break;
170 	}
171 
172 	switch (*expr) {
173 	case '\0':
174 		break;
175 	case '*':				/* Backward compatible */
176 	case 'x':
177 		t = num;
178 		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
179 		if (*ebuf != '\0')
180 			return (0);
181 		if (t > num) {
182  erange:
183 			snprintf(ebuf, ebuflen,
184 			    "%s: %s", desc, strerror(ERANGE));
185 			return (0);
186 		}
187 		break;
188 	default:
189  badnum:	snprintf(ebuf, ebuflen,
190 		    "%s `%s': illegal number", desc, val);
191 		return (0);
192 	}
193 	if (num < min) {
194 			/* LONGLONG */
195 		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
196 		    desc, (long long)num, (long long)min);
197 		return (0);
198 	}
199 	if (num > max) {
200 			/* LONGLONG */
201 		snprintf(ebuf, ebuflen,
202 		    "%s %lld is greater than %lld.",
203 		    desc, (long long)num, (long long)max);
204 		return (0);
205 	}
206 	*ebuf = '\0';
207 	return (num);
208 }
209 
210 /* LONGLONG */
211 long long
212 strsuftoll(const char *desc, const char *val,
213     long long min, long long max)
214 {
215 	long long result;
216 	char	errbuf[100];
217 
218 	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
219 	if (*errbuf != '\0')
220 		errx(1, "%s", errbuf);
221 	return (result);
222 }
223