1/*	$NetBSD: strsuftoll.c,v 1.8 2008/04/28 20:23:00 martin 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#if HAVE_NBTOOL_CONFIG_H
64#include "nbtool_config.h"
65#endif
66
67#include <sys/cdefs.h>
68
69#if defined(LIBC_SCCS) && !defined(lint)
70__RCSID("$NetBSD: strsuftoll.c,v 1.8 2008/04/28 20:23:00 martin Exp $");
71#endif /* LIBC_SCCS and not lint */
72
73#ifdef _LIBC
74#include "namespace.h"
75#endif
76
77#if !HAVE_STRSUFTOLL
78
79#include <sys/types.h>
80#include <sys/time.h>
81
82#include <assert.h>
83#include <ctype.h>
84#include <err.h>
85#include <errno.h>
86#include <limits.h>
87#include <stdio.h>
88#include <stdlib.h>
89#include <string.h>
90
91#ifdef _LIBC
92# ifdef __weak_alias
93__weak_alias(strsuftoll, _strsuftoll)
94__weak_alias(strsuftollx, _strsuftollx)
95# endif
96#endif /* LIBC */
97
98/*
99 * Convert an expression of the following forms to a (u)int64_t.
100 * 	1) A positive decimal number.
101 *	2) A positive decimal number followed by a b (mult by 512).
102 *	3) A positive decimal number followed by a k (mult by 1024).
103 *	4) A positive decimal number followed by a m (mult by 1048576).
104 *	5) A positive decimal number followed by a g (mult by 1073741824).
105 *	6) A positive decimal number followed by a t (mult by 1099511627776).
106 *	7) A positive decimal number followed by a w (mult by sizeof int)
107 *	8) Two or more positive decimal numbers (with/without k,b or w).
108 *	   separated by x (also * for backwards compatibility), specifying
109 *	   the product of the indicated values.
110 * Returns the result upon successful conversion, or exits with an
111 * appropriate error.
112 *
113 */
114/* LONGLONG */
115long long
116strsuftoll(const char *desc, const char *val,
117    long long min, long long max)
118{
119	long long result;
120	char	errbuf[100];
121
122	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
123	if (*errbuf != '\0')
124		errx(EXIT_FAILURE, "%s", errbuf);
125	return result;
126}
127
128/*
129 * As strsuftoll(), but returns the error message into the provided buffer
130 * rather than exiting with it.
131 */
132/* LONGLONG */
133static long long
134__strsuftollx(const char *desc, const char *val,
135    long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
136{
137	long long num, t;
138	char	*expr;
139
140	_DIAGASSERT(desc != NULL);
141	_DIAGASSERT(val != NULL);
142	_DIAGASSERT(ebuf != NULL);
143
144	if (depth > 16) {
145		snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
146		return 0;
147	}
148
149	while (isspace((unsigned char)*val))	/* Skip leading space */
150		val++;
151
152	errno = 0;
153	num = strtoll(val, &expr, 10);
154	if (errno == ERANGE)
155		goto erange;			/* Overflow */
156
157	if (expr == val)			/* No digits */
158		goto badnum;
159
160	switch (*expr) {
161	case 'b':
162		t = num;
163		num *= 512;			/* 1 block */
164		if (t > num)
165			goto erange;
166		++expr;
167		break;
168	case 'k':
169		t = num;
170		num *= 1024;			/* 1 kibibyte */
171		if (t > num)
172			goto erange;
173		++expr;
174		break;
175	case 'm':
176		t = num;
177		num *= 1048576;			/* 1 mebibyte */
178		if (t > num)
179			goto erange;
180		++expr;
181		break;
182	case 'g':
183		t = num;
184		num *= 1073741824;		/* 1 gibibyte */
185		if (t > num)
186			goto erange;
187		++expr;
188		break;
189	case 't':
190		t = num;
191		num *= 1099511627776LL;		/* 1 tebibyte */
192		if (t > num)
193			goto erange;
194		++expr;
195		break;
196	case 'w':
197		t = num;
198		num *= sizeof(int);		/* 1 word */
199		if (t > num)
200			goto erange;
201		++expr;
202		break;
203	}
204
205	switch (*expr) {
206	case '\0':
207		break;
208	case '*':				/* Backward compatible */
209	case 'x':
210		t = num;
211		num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
212			depth + 1);
213		if (*ebuf != '\0')
214			return 0;
215		if (t > num) {
216 erange:
217			errno = ERANGE;
218			snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
219			return 0;
220		}
221		break;
222	default:
223 badnum:
224		snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
225		return 0;
226	}
227	if (num < min) {
228		/* LONGLONG */
229		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
230		    desc, (long long)num, (long long)min);
231		return 0;
232	}
233	if (num > max) {
234		/* LONGLONG */
235		snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
236		    desc, (long long)num, (long long)max);
237		return 0;
238	}
239	*ebuf = '\0';
240	return num;
241}
242
243long long
244strsuftollx(const char *desc, const char *val,
245    long long min, long long max, char *ebuf, size_t ebuflen)
246{
247	return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
248}
249#endif /* !HAVE_STRSUFTOLL */
250