1244557Sbrooks/*	$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $	*/
2244557Sbrooks/*-
3244557Sbrooks * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
4244557Sbrooks * All rights reserved.
5244557Sbrooks *
6244557Sbrooks * This code is derived from software contributed to The NetBSD Foundation
7244557Sbrooks * by Luke Mewburn.
8244557Sbrooks *
9244557Sbrooks * Redistribution and use in source and binary forms, with or without
10244557Sbrooks * modification, are permitted provided that the following conditions
11244557Sbrooks * are met:
12244557Sbrooks * 1. Redistributions of source code must retain the above copyright
13244557Sbrooks *    notice, this list of conditions and the following disclaimer.
14244557Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
15244557Sbrooks *    notice, this list of conditions and the following disclaimer in the
16244557Sbrooks *    documentation and/or other materials provided with the distribution.
17244557Sbrooks *
18244557Sbrooks * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
19244557Sbrooks * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
20244557Sbrooks * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21244557Sbrooks * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
22244557Sbrooks * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23244557Sbrooks * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24244557Sbrooks * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25244557Sbrooks * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26244557Sbrooks * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27244557Sbrooks * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28244557Sbrooks * POSSIBILITY OF SUCH DAMAGE.
29244557Sbrooks */
30244557Sbrooks/*-
31244557Sbrooks * Copyright (c) 1991, 1993, 1994
32244557Sbrooks *	The Regents of the University of California.  All rights reserved.
33244557Sbrooks *
34244557Sbrooks * This code is derived from software contributed to Berkeley by
35244557Sbrooks * Keith Muller of the University of California, San Diego and Lance
36244557Sbrooks * Visser of Convex Computer Corporation.
37244557Sbrooks *
38244557Sbrooks * Redistribution and use in source and binary forms, with or without
39244557Sbrooks * modification, are permitted provided that the following conditions
40244557Sbrooks * are met:
41244557Sbrooks * 1. Redistributions of source code must retain the above copyright
42244557Sbrooks *    notice, this list of conditions and the following disclaimer.
43244557Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
44244557Sbrooks *    notice, this list of conditions and the following disclaimer in the
45244557Sbrooks *    documentation and/or other materials provided with the distribution.
46244557Sbrooks * 3. Neither the name of the University nor the names of its contributors
47244557Sbrooks *    may be used to endorse or promote products derived from this software
48244557Sbrooks *    without specific prior written permission.
49244557Sbrooks *
50244557Sbrooks * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51244557Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52244557Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53244557Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54244557Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55244557Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56244557Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57244557Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58244557Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59244557Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60244557Sbrooks * SUCH DAMAGE.
61244557Sbrooks */
62244557Sbrooks
63244557Sbrooks#include <sys/cdefs.h>
64244557Sbrooks__FBSDID("$FreeBSD$");
65244557Sbrooks
66244557Sbrooks#include <sys/types.h>
67244557Sbrooks#include <sys/time.h>
68244557Sbrooks
69244557Sbrooks#include <assert.h>
70244557Sbrooks#include <ctype.h>
71244557Sbrooks#include <err.h>
72244557Sbrooks#include <errno.h>
73244557Sbrooks#include <limits.h>
74244557Sbrooks#include <stdio.h>
75244557Sbrooks#include <stdlib.h>
76244557Sbrooks#include <string.h>
77244557Sbrooks
78244557Sbrooks#ifdef _LIBC
79244557Sbrooks# ifdef __weak_alias
80244557Sbrooks__weak_alias(strsuftoll, _strsuftoll)
81244557Sbrooks__weak_alias(strsuftollx, _strsuftollx)
82244557Sbrooks# endif
83244557Sbrooks#endif /* LIBC */
84244557Sbrooks
85244557Sbrooks/*
86244557Sbrooks * Convert an expression of the following forms to a (u)int64_t.
87244557Sbrooks * 	1) A positive decimal number.
88244557Sbrooks *	2) A positive decimal number followed by a b (mult by 512).
89244557Sbrooks *	3) A positive decimal number followed by a k (mult by 1024).
90244557Sbrooks *	4) A positive decimal number followed by a m (mult by 1048576).
91244557Sbrooks *	5) A positive decimal number followed by a g (mult by 1073741824).
92244557Sbrooks *	6) A positive decimal number followed by a t (mult by 1099511627776).
93244557Sbrooks *	7) A positive decimal number followed by a w (mult by sizeof int)
94244557Sbrooks *	8) Two or more positive decimal numbers (with/without k,b or w).
95244557Sbrooks *	   separated by x (also * for backwards compatibility), specifying
96244557Sbrooks *	   the product of the indicated values.
97244557Sbrooks * Returns the result upon successful conversion, or exits with an
98244557Sbrooks * appropriate error.
99244557Sbrooks *
100244557Sbrooks */
101244557Sbrooks
102244557Sbrooks/*
103244557Sbrooks * As strsuftoll(), but returns the error message into the provided buffer
104244557Sbrooks * rather than exiting with it.
105244557Sbrooks */
106244557Sbrooks/* LONGLONG */
107244557Sbrookslong long
108244557Sbrooksstrsuftollx(const char *desc, const char *val,
109244557Sbrooks    long long min, long long max, char *ebuf, size_t ebuflen)
110244557Sbrooks{
111244557Sbrooks	long long num, t;
112244557Sbrooks	char	*expr;
113244557Sbrooks
114244557Sbrooks	errno = 0;
115244557Sbrooks	ebuf[0] = '\0';
116244557Sbrooks
117244557Sbrooks	while (isspace((unsigned char)*val))	/* Skip leading space */
118244557Sbrooks		val++;
119244557Sbrooks
120244557Sbrooks	num = strtoll(val, &expr, 10);
121244557Sbrooks	if (errno == ERANGE)
122244557Sbrooks		goto erange;			/* Overflow */
123244557Sbrooks
124244557Sbrooks	if (expr == val)			/* No digits */
125244557Sbrooks		goto badnum;
126244557Sbrooks
127244557Sbrooks	switch (*expr) {
128244557Sbrooks	case 'b':
129244557Sbrooks		t = num;
130244557Sbrooks		num *= 512;			/* 1 block */
131244557Sbrooks		if (t > num)
132244557Sbrooks			goto erange;
133244557Sbrooks		++expr;
134244557Sbrooks		break;
135244557Sbrooks	case 'k':
136244557Sbrooks		t = num;
137244557Sbrooks		num *= 1024;			/* 1 kilobyte */
138244557Sbrooks		if (t > num)
139244557Sbrooks			goto erange;
140244557Sbrooks		++expr;
141244557Sbrooks		break;
142244557Sbrooks	case 'm':
143244557Sbrooks		t = num;
144244557Sbrooks		num *= 1048576;			/* 1 megabyte */
145244557Sbrooks		if (t > num)
146244557Sbrooks			goto erange;
147244557Sbrooks		++expr;
148244557Sbrooks		break;
149244557Sbrooks	case 'g':
150244557Sbrooks		t = num;
151244557Sbrooks		num *= 1073741824;		/* 1 gigabyte */
152244557Sbrooks		if (t > num)
153244557Sbrooks			goto erange;
154244557Sbrooks		++expr;
155244557Sbrooks		break;
156244557Sbrooks	case 't':
157244557Sbrooks		t = num;
158244557Sbrooks		num *= 1099511627776LL;		/* 1 terabyte */
159244557Sbrooks		if (t > num)
160244557Sbrooks			goto erange;
161244557Sbrooks		++expr;
162244557Sbrooks		break;
163244557Sbrooks	case 'w':
164244557Sbrooks		t = num;
165244557Sbrooks		num *= sizeof(int);		/* 1 word */
166244557Sbrooks		if (t > num)
167244557Sbrooks			goto erange;
168244557Sbrooks		++expr;
169244557Sbrooks		break;
170244557Sbrooks	}
171244557Sbrooks
172244557Sbrooks	switch (*expr) {
173244557Sbrooks	case '\0':
174244557Sbrooks		break;
175244557Sbrooks	case '*':				/* Backward compatible */
176244557Sbrooks	case 'x':
177244557Sbrooks		t = num;
178244557Sbrooks		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
179244557Sbrooks		if (*ebuf != '\0')
180244557Sbrooks			return (0);
181244557Sbrooks		if (t > num) {
182244557Sbrooks erange:
183244557Sbrooks			snprintf(ebuf, ebuflen,
184244557Sbrooks			    "%s: %s", desc, strerror(ERANGE));
185244557Sbrooks			return (0);
186244557Sbrooks		}
187244557Sbrooks		break;
188244557Sbrooks	default:
189244557Sbrooks badnum:	snprintf(ebuf, ebuflen,
190244557Sbrooks		    "%s `%s': illegal number", desc, val);
191244557Sbrooks		return (0);
192244557Sbrooks	}
193244557Sbrooks	if (num < min) {
194244557Sbrooks			/* LONGLONG */
195244557Sbrooks		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
196244557Sbrooks		    desc, (long long)num, (long long)min);
197244557Sbrooks		return (0);
198244557Sbrooks	}
199244557Sbrooks	if (num > max) {
200244557Sbrooks			/* LONGLONG */
201244557Sbrooks		snprintf(ebuf, ebuflen,
202244557Sbrooks		    "%s %lld is greater than %lld.",
203244557Sbrooks		    desc, (long long)num, (long long)max);
204244557Sbrooks		return (0);
205244557Sbrooks	}
206244557Sbrooks	*ebuf = '\0';
207244557Sbrooks	return (num);
208244557Sbrooks}
209244557Sbrooks
210244557Sbrooks/* LONGLONG */
211244557Sbrookslong long
212244557Sbrooksstrsuftoll(const char *desc, const char *val,
213244557Sbrooks    long long min, long long max)
214244557Sbrooks{
215244557Sbrooks	long long result;
216244557Sbrooks	char	errbuf[100];
217244557Sbrooks
218244557Sbrooks	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
219244557Sbrooks	if (*errbuf != '\0')
220244557Sbrooks		errx(1, "%s", errbuf);
221244557Sbrooks	return (result);
222244557Sbrooks}
223