1133936Sobrien/*	$NetBSD: strsuftoll.c,v 1.5 2004/01/17 23:02:51 dbj Exp $	*/
2108760Sobrien/*-
3133936Sobrien * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
4108760Sobrien * All rights reserved.
5108760Sobrien *
6108760Sobrien * This code is derived from software contributed to The NetBSD Foundation
7108760Sobrien * by Luke Mewburn.
8108760Sobrien *
9108760Sobrien * Redistribution and use in source and binary forms, with or without
10108760Sobrien * modification, are permitted provided that the following conditions
11108760Sobrien * are met:
12108760Sobrien * 1. Redistributions of source code must retain the above copyright
13108760Sobrien *    notice, this list of conditions and the following disclaimer.
14108760Sobrien * 2. Redistributions in binary form must reproduce the above copyright
15108760Sobrien *    notice, this list of conditions and the following disclaimer in the
16108760Sobrien *    documentation and/or other materials provided with the distribution.
17108760Sobrien * 3. All advertising materials mentioning features or use of this software
18108760Sobrien *    must display the following acknowledgement:
19108760Sobrien *        This product includes software developed by the NetBSD
20108760Sobrien *        Foundation, Inc. and its contributors.
21108760Sobrien * 4. Neither the name of The NetBSD Foundation nor the names of its
22108760Sobrien *    contributors may be used to endorse or promote products derived
23108760Sobrien *    from this software without specific prior written permission.
24108760Sobrien *
25108760Sobrien * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
26108760Sobrien * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27108760Sobrien * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28108760Sobrien * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
29108760Sobrien * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30108760Sobrien * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31108760Sobrien * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32108760Sobrien * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33108760Sobrien * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34108760Sobrien * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35108760Sobrien * POSSIBILITY OF SUCH DAMAGE.
36108760Sobrien */
37108760Sobrien/*-
38108760Sobrien * Copyright (c) 1991, 1993, 1994
39108760Sobrien *	The Regents of the University of California.  All rights reserved.
40108760Sobrien *
41108760Sobrien * This code is derived from software contributed to Berkeley by
42108760Sobrien * Keith Muller of the University of California, San Diego and Lance
43108760Sobrien * Visser of Convex Computer Corporation.
44108760Sobrien *
45108760Sobrien * Redistribution and use in source and binary forms, with or without
46108760Sobrien * modification, are permitted provided that the following conditions
47108760Sobrien * are met:
48108760Sobrien * 1. Redistributions of source code must retain the above copyright
49108760Sobrien *    notice, this list of conditions and the following disclaimer.
50108760Sobrien * 2. Redistributions in binary form must reproduce the above copyright
51108760Sobrien *    notice, this list of conditions and the following disclaimer in the
52108760Sobrien *    documentation and/or other materials provided with the distribution.
53133936Sobrien * 3. Neither the name of the University nor the names of its contributors
54108760Sobrien *    may be used to endorse or promote products derived from this software
55108760Sobrien *    without specific prior written permission.
56108760Sobrien *
57108760Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58108760Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59108760Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60108760Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61108760Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62108760Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63108760Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64108760Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65108760Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66108760Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67108760Sobrien * SUCH DAMAGE.
68108760Sobrien */
69108760Sobrien
70133936Sobrien#if HAVE_NBTOOL_CONFIG_H
71133936Sobrien#include "nbtool_config.h"
72133936Sobrien#endif
73133936Sobrien
74108760Sobrien#include <sys/cdefs.h>
75108760Sobrien
76108760Sobrien#if defined(LIBC_SCCS) && !defined(lint)
77133936Sobrien__RCSID("$NetBSD: strsuftoll.c,v 1.5 2004/01/17 23:02:51 dbj Exp $");
78108760Sobrien#endif /* LIBC_SCCS and not lint */
79108760Sobrien
80108760Sobrien#ifdef _LIBC
81108760Sobrien#include "namespace.h"
82108760Sobrien#endif
83108760Sobrien
84108760Sobrien#if !HAVE_STRSUFTOLL
85108760Sobrien
86108760Sobrien#include <sys/types.h>
87108760Sobrien#include <sys/time.h>
88108760Sobrien
89108760Sobrien#include <assert.h>
90108760Sobrien#include <ctype.h>
91108760Sobrien#include <err.h>
92108760Sobrien#include <errno.h>
93108760Sobrien#include <limits.h>
94108760Sobrien#include <stdio.h>
95108760Sobrien#include <stdlib.h>
96108760Sobrien#include <string.h>
97108760Sobrien
98108760Sobrien#ifdef _LIBC
99108760Sobrien# ifdef __weak_alias
100108760Sobrien__weak_alias(strsuftoll, _strsuftoll)
101108760Sobrien__weak_alias(strsuftollx, _strsuftollx)
102108760Sobrien# endif
103133936Sobrien#endif /* LIBC */
104108760Sobrien
105108760Sobrien/*
106108760Sobrien * Convert an expression of the following forms to a (u)int64_t.
107108760Sobrien * 	1) A positive decimal number.
108108760Sobrien *	2) A positive decimal number followed by a b (mult by 512).
109108760Sobrien *	3) A positive decimal number followed by a k (mult by 1024).
110108760Sobrien *	4) A positive decimal number followed by a m (mult by 1048576).
111133936Sobrien *	5) A positive decimal number followed by a g (mult by 1073741824).
112133936Sobrien *	6) A positive decimal number followed by a t (mult by 1099511627776).
113133936Sobrien *	7) A positive decimal number followed by a w (mult by sizeof int)
114133936Sobrien *	8) Two or more positive decimal numbers (with/without k,b or w).
115108760Sobrien *	   separated by x (also * for backwards compatibility), specifying
116108760Sobrien *	   the product of the indicated values.
117108760Sobrien * Returns the result upon successful conversion, or exits with an
118108760Sobrien * appropriate error.
119108760Sobrien *
120108760Sobrien */
121108760Sobrien/* LONGLONG */
122108760Sobrienlong long
123133936Sobrienstrsuftoll(const char *desc, const char *val,
124108760Sobrien    long long min, long long max)
125108760Sobrien{
126108760Sobrien	long long result;
127108760Sobrien	char	errbuf[100];
128108760Sobrien
129108760Sobrien	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
130108760Sobrien	if (*errbuf != '\0')
131108760Sobrien		errx(1, "%s", errbuf);
132108760Sobrien	return (result);
133108760Sobrien}
134108760Sobrien
135108760Sobrien/*
136108760Sobrien * As strsuftoll(), but returns the error message into the provided buffer
137108760Sobrien * rather than exiting with it.
138108760Sobrien */
139108760Sobrien/* LONGLONG */
140108760Sobrienlong long
141133936Sobrienstrsuftollx(const char *desc, const char *val,
142108760Sobrien    long long min, long long max, char *ebuf, size_t ebuflen)
143108760Sobrien{
144108760Sobrien	long long num, t;
145108760Sobrien	char	*expr;
146108760Sobrien
147108760Sobrien	_DIAGASSERT(desc != NULL);
148108760Sobrien	_DIAGASSERT(val != NULL);
149108760Sobrien	_DIAGASSERT(ebuf != NULL);
150108760Sobrien
151108760Sobrien	errno = 0;
152108760Sobrien	ebuf[0] = '\0';
153108760Sobrien
154108760Sobrien	while (isspace((unsigned char)*val))	/* Skip leading space */
155108760Sobrien		val++;
156108760Sobrien
157133936Sobrien	num = strtoll(val, &expr, 10);
158108760Sobrien	if (errno == ERANGE)
159108760Sobrien		goto erange;			/* Overflow */
160108760Sobrien
161108760Sobrien	if (expr == val)			/* No digits */
162108760Sobrien		goto badnum;
163108760Sobrien
164108760Sobrien	switch (*expr) {
165108760Sobrien	case 'b':
166108760Sobrien		t = num;
167108760Sobrien		num *= 512;			/* 1 block */
168108760Sobrien		if (t > num)
169108760Sobrien			goto erange;
170108760Sobrien		++expr;
171108760Sobrien		break;
172108760Sobrien	case 'k':
173108760Sobrien		t = num;
174108760Sobrien		num *= 1024;			/* 1 kilobyte */
175108760Sobrien		if (t > num)
176108760Sobrien			goto erange;
177108760Sobrien		++expr;
178108760Sobrien		break;
179108760Sobrien	case 'm':
180108760Sobrien		t = num;
181108760Sobrien		num *= 1048576;			/* 1 megabyte */
182108760Sobrien		if (t > num)
183108760Sobrien			goto erange;
184108760Sobrien		++expr;
185108760Sobrien		break;
186108760Sobrien	case 'g':
187108760Sobrien		t = num;
188108760Sobrien		num *= 1073741824;		/* 1 gigabyte */
189108760Sobrien		if (t > num)
190108760Sobrien			goto erange;
191108760Sobrien		++expr;
192108760Sobrien		break;
193108760Sobrien	case 't':
194108760Sobrien		t = num;
195108760Sobrien		num *= 1099511627776LL;		/* 1 terabyte */
196108760Sobrien		if (t > num)
197108760Sobrien			goto erange;
198108760Sobrien		++expr;
199108760Sobrien		break;
200108760Sobrien	case 'w':
201108760Sobrien		t = num;
202108760Sobrien		num *= sizeof(int);		/* 1 word */
203108760Sobrien		if (t > num)
204108760Sobrien			goto erange;
205108760Sobrien		++expr;
206108760Sobrien		break;
207108760Sobrien	}
208108760Sobrien
209108760Sobrien	switch (*expr) {
210108760Sobrien	case '\0':
211108760Sobrien		break;
212108760Sobrien	case '*':				/* Backward compatible */
213108760Sobrien	case 'x':
214108760Sobrien		t = num;
215108760Sobrien		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
216108760Sobrien		if (*ebuf != '\0')
217108760Sobrien			return (0);
218108760Sobrien		if (t > num) {
219108760Sobrien erange:
220108760Sobrien			snprintf(ebuf, ebuflen,
221108760Sobrien			    "%s: %s", desc, strerror(ERANGE));
222108760Sobrien			return (0);
223108760Sobrien		}
224108760Sobrien		break;
225108760Sobrien	default:
226108760Sobrien badnum:	snprintf(ebuf, ebuflen,
227108760Sobrien		    "%s `%s': illegal number", desc, val);
228108760Sobrien		return (0);
229108760Sobrien	}
230108760Sobrien	if (num < min) {
231108760Sobrien			/* LONGLONG */
232108760Sobrien		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
233108760Sobrien		    desc, (long long)num, (long long)min);
234108760Sobrien		return (0);
235108760Sobrien	}
236108760Sobrien	if (num > max) {
237108760Sobrien			/* LONGLONG */
238108760Sobrien		snprintf(ebuf, ebuflen,
239108760Sobrien		    "%s %lld is greater than %lld.",
240133936Sobrien		    desc, (long long)num, (long long)max);
241108760Sobrien		return (0);
242108760Sobrien	}
243108760Sobrien	*ebuf = '\0';
244108760Sobrien	return (num);
245108760Sobrien}
246108760Sobrien
247108760Sobrien#endif /* !HAVE_STRSUFTOLL */
248