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