xref: /freebsd/lib/libnetbsd/strsuftoll.c (revision 5e53a4f90f82c4345f277dd87cc9292f26e04a29)
16bea8766SBrooks Davis /*	$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $	*/
26bea8766SBrooks Davis /*-
3*5e53a4f9SPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause-NetBSD
4*5e53a4f9SPedro F. Giffuni  *
56bea8766SBrooks Davis  * Copyright (c) 2001-2002,2004 The NetBSD Foundation, Inc.
66bea8766SBrooks Davis  * All rights reserved.
76bea8766SBrooks Davis  *
86bea8766SBrooks Davis  * This code is derived from software contributed to The NetBSD Foundation
96bea8766SBrooks Davis  * by Luke Mewburn.
106bea8766SBrooks Davis  *
116bea8766SBrooks Davis  * Redistribution and use in source and binary forms, with or without
126bea8766SBrooks Davis  * modification, are permitted provided that the following conditions
136bea8766SBrooks Davis  * are met:
146bea8766SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
156bea8766SBrooks Davis  *    notice, this list of conditions and the following disclaimer.
166bea8766SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
176bea8766SBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
186bea8766SBrooks Davis  *    documentation and/or other materials provided with the distribution.
196bea8766SBrooks Davis  *
206bea8766SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
216bea8766SBrooks Davis  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
226bea8766SBrooks Davis  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
236bea8766SBrooks Davis  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
246bea8766SBrooks Davis  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
256bea8766SBrooks Davis  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
266bea8766SBrooks Davis  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
276bea8766SBrooks Davis  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
286bea8766SBrooks Davis  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
296bea8766SBrooks Davis  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
306bea8766SBrooks Davis  * POSSIBILITY OF SUCH DAMAGE.
316bea8766SBrooks Davis  */
326bea8766SBrooks Davis /*-
336bea8766SBrooks Davis  * Copyright (c) 1991, 1993, 1994
346bea8766SBrooks Davis  *	The Regents of the University of California.  All rights reserved.
356bea8766SBrooks Davis  *
366bea8766SBrooks Davis  * This code is derived from software contributed to Berkeley by
376bea8766SBrooks Davis  * Keith Muller of the University of California, San Diego and Lance
386bea8766SBrooks Davis  * Visser of Convex Computer Corporation.
396bea8766SBrooks Davis  *
406bea8766SBrooks Davis  * Redistribution and use in source and binary forms, with or without
416bea8766SBrooks Davis  * modification, are permitted provided that the following conditions
426bea8766SBrooks Davis  * are met:
436bea8766SBrooks Davis  * 1. Redistributions of source code must retain the above copyright
446bea8766SBrooks Davis  *    notice, this list of conditions and the following disclaimer.
456bea8766SBrooks Davis  * 2. Redistributions in binary form must reproduce the above copyright
466bea8766SBrooks Davis  *    notice, this list of conditions and the following disclaimer in the
476bea8766SBrooks Davis  *    documentation and/or other materials provided with the distribution.
486bea8766SBrooks Davis  * 3. Neither the name of the University nor the names of its contributors
496bea8766SBrooks Davis  *    may be used to endorse or promote products derived from this software
506bea8766SBrooks Davis  *    without specific prior written permission.
516bea8766SBrooks Davis  *
526bea8766SBrooks Davis  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
536bea8766SBrooks Davis  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
546bea8766SBrooks Davis  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
556bea8766SBrooks Davis  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
566bea8766SBrooks Davis  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
576bea8766SBrooks Davis  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
586bea8766SBrooks Davis  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
596bea8766SBrooks Davis  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
606bea8766SBrooks Davis  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
616bea8766SBrooks Davis  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
626bea8766SBrooks Davis  * SUCH DAMAGE.
636bea8766SBrooks Davis  */
646bea8766SBrooks Davis 
656bea8766SBrooks Davis #include <sys/cdefs.h>
666bea8766SBrooks Davis __FBSDID("$FreeBSD$");
676bea8766SBrooks Davis 
686bea8766SBrooks Davis #include <sys/types.h>
696bea8766SBrooks Davis #include <sys/time.h>
706bea8766SBrooks Davis 
716bea8766SBrooks Davis #include <assert.h>
726bea8766SBrooks Davis #include <ctype.h>
736bea8766SBrooks Davis #include <err.h>
746bea8766SBrooks Davis #include <errno.h>
756bea8766SBrooks Davis #include <limits.h>
766bea8766SBrooks Davis #include <stdio.h>
776bea8766SBrooks Davis #include <stdlib.h>
786bea8766SBrooks Davis #include <string.h>
796bea8766SBrooks Davis 
806bea8766SBrooks Davis #ifdef _LIBC
816bea8766SBrooks Davis # ifdef __weak_alias
826bea8766SBrooks Davis __weak_alias(strsuftoll, _strsuftoll)
836bea8766SBrooks Davis __weak_alias(strsuftollx, _strsuftollx)
846bea8766SBrooks Davis # endif
856bea8766SBrooks Davis #endif /* LIBC */
866bea8766SBrooks Davis 
876bea8766SBrooks Davis /*
886bea8766SBrooks Davis  * Convert an expression of the following forms to a (u)int64_t.
896bea8766SBrooks Davis  * 	1) A positive decimal number.
906bea8766SBrooks Davis  *	2) A positive decimal number followed by a b (mult by 512).
916bea8766SBrooks Davis  *	3) A positive decimal number followed by a k (mult by 1024).
926bea8766SBrooks Davis  *	4) A positive decimal number followed by a m (mult by 1048576).
936bea8766SBrooks Davis  *	5) A positive decimal number followed by a g (mult by 1073741824).
946bea8766SBrooks Davis  *	6) A positive decimal number followed by a t (mult by 1099511627776).
956bea8766SBrooks Davis  *	7) A positive decimal number followed by a w (mult by sizeof int)
966bea8766SBrooks Davis  *	8) Two or more positive decimal numbers (with/without k,b or w).
976bea8766SBrooks Davis  *	   separated by x (also * for backwards compatibility), specifying
986bea8766SBrooks Davis  *	   the product of the indicated values.
996bea8766SBrooks Davis  * Returns the result upon successful conversion, or exits with an
1006bea8766SBrooks Davis  * appropriate error.
1016bea8766SBrooks Davis  *
1026bea8766SBrooks Davis  */
1036bea8766SBrooks Davis 
1046bea8766SBrooks Davis /*
1056bea8766SBrooks Davis  * As strsuftoll(), but returns the error message into the provided buffer
1066bea8766SBrooks Davis  * rather than exiting with it.
1076bea8766SBrooks Davis  */
1086bea8766SBrooks Davis /* LONGLONG */
1096bea8766SBrooks Davis long long
1106bea8766SBrooks Davis strsuftollx(const char *desc, const char *val,
1116bea8766SBrooks Davis     long long min, long long max, char *ebuf, size_t ebuflen)
1126bea8766SBrooks Davis {
1136bea8766SBrooks Davis 	long long num, t;
1146bea8766SBrooks Davis 	char	*expr;
1156bea8766SBrooks Davis 
1166bea8766SBrooks Davis 	errno = 0;
1176bea8766SBrooks Davis 	ebuf[0] = '\0';
1186bea8766SBrooks Davis 
1196bea8766SBrooks Davis 	while (isspace((unsigned char)*val))	/* Skip leading space */
1206bea8766SBrooks Davis 		val++;
1216bea8766SBrooks Davis 
1226bea8766SBrooks Davis 	num = strtoll(val, &expr, 10);
1236bea8766SBrooks Davis 	if (errno == ERANGE)
1246bea8766SBrooks Davis 		goto erange;			/* Overflow */
1256bea8766SBrooks Davis 
1266bea8766SBrooks Davis 	if (expr == val)			/* No digits */
1276bea8766SBrooks Davis 		goto badnum;
1286bea8766SBrooks Davis 
1296bea8766SBrooks Davis 	switch (*expr) {
1306bea8766SBrooks Davis 	case 'b':
1316bea8766SBrooks Davis 		t = num;
1326bea8766SBrooks Davis 		num *= 512;			/* 1 block */
1336bea8766SBrooks Davis 		if (t > num)
1346bea8766SBrooks Davis 			goto erange;
1356bea8766SBrooks Davis 		++expr;
1366bea8766SBrooks Davis 		break;
1376bea8766SBrooks Davis 	case 'k':
1386bea8766SBrooks Davis 		t = num;
1396bea8766SBrooks Davis 		num *= 1024;			/* 1 kilobyte */
1406bea8766SBrooks Davis 		if (t > num)
1416bea8766SBrooks Davis 			goto erange;
1426bea8766SBrooks Davis 		++expr;
1436bea8766SBrooks Davis 		break;
1446bea8766SBrooks Davis 	case 'm':
1456bea8766SBrooks Davis 		t = num;
1466bea8766SBrooks Davis 		num *= 1048576;			/* 1 megabyte */
1476bea8766SBrooks Davis 		if (t > num)
1486bea8766SBrooks Davis 			goto erange;
1496bea8766SBrooks Davis 		++expr;
1506bea8766SBrooks Davis 		break;
1516bea8766SBrooks Davis 	case 'g':
1526bea8766SBrooks Davis 		t = num;
1536bea8766SBrooks Davis 		num *= 1073741824;		/* 1 gigabyte */
1546bea8766SBrooks Davis 		if (t > num)
1556bea8766SBrooks Davis 			goto erange;
1566bea8766SBrooks Davis 		++expr;
1576bea8766SBrooks Davis 		break;
1586bea8766SBrooks Davis 	case 't':
1596bea8766SBrooks Davis 		t = num;
1606bea8766SBrooks Davis 		num *= 1099511627776LL;		/* 1 terabyte */
1616bea8766SBrooks Davis 		if (t > num)
1626bea8766SBrooks Davis 			goto erange;
1636bea8766SBrooks Davis 		++expr;
1646bea8766SBrooks Davis 		break;
1656bea8766SBrooks Davis 	case 'w':
1666bea8766SBrooks Davis 		t = num;
1676bea8766SBrooks Davis 		num *= sizeof(int);		/* 1 word */
1686bea8766SBrooks Davis 		if (t > num)
1696bea8766SBrooks Davis 			goto erange;
1706bea8766SBrooks Davis 		++expr;
1716bea8766SBrooks Davis 		break;
1726bea8766SBrooks Davis 	}
1736bea8766SBrooks Davis 
1746bea8766SBrooks Davis 	switch (*expr) {
1756bea8766SBrooks Davis 	case '\0':
1766bea8766SBrooks Davis 		break;
1776bea8766SBrooks Davis 	case '*':				/* Backward compatible */
1786bea8766SBrooks Davis 	case 'x':
1796bea8766SBrooks Davis 		t = num;
1806bea8766SBrooks Davis 		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
1816bea8766SBrooks Davis 		if (*ebuf != '\0')
1826bea8766SBrooks Davis 			return (0);
1836bea8766SBrooks Davis 		if (t > num) {
1846bea8766SBrooks Davis  erange:
1856bea8766SBrooks Davis 			snprintf(ebuf, ebuflen,
1866bea8766SBrooks Davis 			    "%s: %s", desc, strerror(ERANGE));
1876bea8766SBrooks Davis 			return (0);
1886bea8766SBrooks Davis 		}
1896bea8766SBrooks Davis 		break;
1906bea8766SBrooks Davis 	default:
1916bea8766SBrooks Davis  badnum:	snprintf(ebuf, ebuflen,
1926bea8766SBrooks Davis 		    "%s `%s': illegal number", desc, val);
1936bea8766SBrooks Davis 		return (0);
1946bea8766SBrooks Davis 	}
1956bea8766SBrooks Davis 	if (num < min) {
1966bea8766SBrooks Davis 			/* LONGLONG */
1976bea8766SBrooks Davis 		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
1986bea8766SBrooks Davis 		    desc, (long long)num, (long long)min);
1996bea8766SBrooks Davis 		return (0);
2006bea8766SBrooks Davis 	}
2016bea8766SBrooks Davis 	if (num > max) {
2026bea8766SBrooks Davis 			/* LONGLONG */
2036bea8766SBrooks Davis 		snprintf(ebuf, ebuflen,
2046bea8766SBrooks Davis 		    "%s %lld is greater than %lld.",
2056bea8766SBrooks Davis 		    desc, (long long)num, (long long)max);
2066bea8766SBrooks Davis 		return (0);
2076bea8766SBrooks Davis 	}
2086bea8766SBrooks Davis 	*ebuf = '\0';
2096bea8766SBrooks Davis 	return (num);
2106bea8766SBrooks Davis }
2116bea8766SBrooks Davis 
2126bea8766SBrooks Davis /* LONGLONG */
2136bea8766SBrooks Davis long long
2146bea8766SBrooks Davis strsuftoll(const char *desc, const char *val,
2156bea8766SBrooks Davis     long long min, long long max)
2166bea8766SBrooks Davis {
2176bea8766SBrooks Davis 	long long result;
2186bea8766SBrooks Davis 	char	errbuf[100];
2196bea8766SBrooks Davis 
2206bea8766SBrooks Davis 	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
2216bea8766SBrooks Davis 	if (*errbuf != '\0')
2226bea8766SBrooks Davis 		errx(1, "%s", errbuf);
2236bea8766SBrooks Davis 	return (result);
2246bea8766SBrooks Davis }
225