xref: /freebsd/lib/libnetbsd/strsuftoll.c (revision a2f733abcff64628b7771a47089628b7327a88bd)
16bea8766SBrooks Davis /*	$NetBSD: strsuftoll.c,v 1.6 2004/03/05 05:58:29 lukem Exp $	*/
26bea8766SBrooks Davis /*-
3*b61a5730SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
45e53a4f9SPedro 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/types.h>
666bea8766SBrooks Davis #include <sys/time.h>
676bea8766SBrooks Davis 
686bea8766SBrooks Davis #include <assert.h>
696bea8766SBrooks Davis #include <ctype.h>
706bea8766SBrooks Davis #include <err.h>
716bea8766SBrooks Davis #include <errno.h>
726bea8766SBrooks Davis #include <limits.h>
736bea8766SBrooks Davis #include <stdio.h>
746bea8766SBrooks Davis #include <stdlib.h>
756bea8766SBrooks Davis #include <string.h>
766bea8766SBrooks Davis 
776bea8766SBrooks Davis #ifdef _LIBC
786bea8766SBrooks Davis # ifdef __weak_alias
__weak_alias(strsuftoll,_strsuftoll)796bea8766SBrooks Davis __weak_alias(strsuftoll, _strsuftoll)
806bea8766SBrooks Davis __weak_alias(strsuftollx, _strsuftollx)
816bea8766SBrooks Davis # endif
826bea8766SBrooks Davis #endif /* LIBC */
836bea8766SBrooks Davis 
846bea8766SBrooks Davis /*
856bea8766SBrooks Davis  * Convert an expression of the following forms to a (u)int64_t.
866bea8766SBrooks Davis  * 	1) A positive decimal number.
876bea8766SBrooks Davis  *	2) A positive decimal number followed by a b (mult by 512).
886bea8766SBrooks Davis  *	3) A positive decimal number followed by a k (mult by 1024).
896bea8766SBrooks Davis  *	4) A positive decimal number followed by a m (mult by 1048576).
906bea8766SBrooks Davis  *	5) A positive decimal number followed by a g (mult by 1073741824).
916bea8766SBrooks Davis  *	6) A positive decimal number followed by a t (mult by 1099511627776).
926bea8766SBrooks Davis  *	7) A positive decimal number followed by a w (mult by sizeof int)
936bea8766SBrooks Davis  *	8) Two or more positive decimal numbers (with/without k,b or w).
946bea8766SBrooks Davis  *	   separated by x (also * for backwards compatibility), specifying
956bea8766SBrooks Davis  *	   the product of the indicated values.
966bea8766SBrooks Davis  * Returns the result upon successful conversion, or exits with an
976bea8766SBrooks Davis  * appropriate error.
986bea8766SBrooks Davis  *
996bea8766SBrooks Davis  */
1006bea8766SBrooks Davis 
1016bea8766SBrooks Davis /*
1026bea8766SBrooks Davis  * As strsuftoll(), but returns the error message into the provided buffer
1036bea8766SBrooks Davis  * rather than exiting with it.
1046bea8766SBrooks Davis  */
1056bea8766SBrooks Davis /* LONGLONG */
1066bea8766SBrooks Davis long long
1076bea8766SBrooks Davis strsuftollx(const char *desc, const char *val,
1086bea8766SBrooks Davis     long long min, long long max, char *ebuf, size_t ebuflen)
1096bea8766SBrooks Davis {
1106bea8766SBrooks Davis 	long long num, t;
1116bea8766SBrooks Davis 	char	*expr;
1126bea8766SBrooks Davis 
1136bea8766SBrooks Davis 	errno = 0;
1146bea8766SBrooks Davis 	ebuf[0] = '\0';
1156bea8766SBrooks Davis 
1166bea8766SBrooks Davis 	while (isspace((unsigned char)*val))	/* Skip leading space */
1176bea8766SBrooks Davis 		val++;
1186bea8766SBrooks Davis 
1196bea8766SBrooks Davis 	num = strtoll(val, &expr, 10);
1206bea8766SBrooks Davis 	if (errno == ERANGE)
1216bea8766SBrooks Davis 		goto erange;			/* Overflow */
1226bea8766SBrooks Davis 
1236bea8766SBrooks Davis 	if (expr == val)			/* No digits */
1246bea8766SBrooks Davis 		goto badnum;
1256bea8766SBrooks Davis 
1266bea8766SBrooks Davis 	switch (*expr) {
1276bea8766SBrooks Davis 	case 'b':
1286bea8766SBrooks Davis 		t = num;
1296bea8766SBrooks Davis 		num *= 512;			/* 1 block */
1306bea8766SBrooks Davis 		if (t > num)
1316bea8766SBrooks Davis 			goto erange;
1326bea8766SBrooks Davis 		++expr;
1336bea8766SBrooks Davis 		break;
1346bea8766SBrooks Davis 	case 'k':
1356bea8766SBrooks Davis 		t = num;
1366bea8766SBrooks Davis 		num *= 1024;			/* 1 kilobyte */
1376bea8766SBrooks Davis 		if (t > num)
1386bea8766SBrooks Davis 			goto erange;
1396bea8766SBrooks Davis 		++expr;
1406bea8766SBrooks Davis 		break;
1416bea8766SBrooks Davis 	case 'm':
1426bea8766SBrooks Davis 		t = num;
1436bea8766SBrooks Davis 		num *= 1048576;			/* 1 megabyte */
1446bea8766SBrooks Davis 		if (t > num)
1456bea8766SBrooks Davis 			goto erange;
1466bea8766SBrooks Davis 		++expr;
1476bea8766SBrooks Davis 		break;
1486bea8766SBrooks Davis 	case 'g':
1496bea8766SBrooks Davis 		t = num;
1506bea8766SBrooks Davis 		num *= 1073741824;		/* 1 gigabyte */
1516bea8766SBrooks Davis 		if (t > num)
1526bea8766SBrooks Davis 			goto erange;
1536bea8766SBrooks Davis 		++expr;
1546bea8766SBrooks Davis 		break;
1556bea8766SBrooks Davis 	case 't':
1566bea8766SBrooks Davis 		t = num;
1576bea8766SBrooks Davis 		num *= 1099511627776LL;		/* 1 terabyte */
1586bea8766SBrooks Davis 		if (t > num)
1596bea8766SBrooks Davis 			goto erange;
1606bea8766SBrooks Davis 		++expr;
1616bea8766SBrooks Davis 		break;
1626bea8766SBrooks Davis 	case 'w':
1636bea8766SBrooks Davis 		t = num;
1646bea8766SBrooks Davis 		num *= sizeof(int);		/* 1 word */
1656bea8766SBrooks Davis 		if (t > num)
1666bea8766SBrooks Davis 			goto erange;
1676bea8766SBrooks Davis 		++expr;
1686bea8766SBrooks Davis 		break;
1696bea8766SBrooks Davis 	}
1706bea8766SBrooks Davis 
1716bea8766SBrooks Davis 	switch (*expr) {
1726bea8766SBrooks Davis 	case '\0':
1736bea8766SBrooks Davis 		break;
1746bea8766SBrooks Davis 	case '*':				/* Backward compatible */
1756bea8766SBrooks Davis 	case 'x':
1766bea8766SBrooks Davis 		t = num;
1776bea8766SBrooks Davis 		num *= strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen);
1786bea8766SBrooks Davis 		if (*ebuf != '\0')
1796bea8766SBrooks Davis 			return (0);
1806bea8766SBrooks Davis 		if (t > num) {
1816bea8766SBrooks Davis  erange:
1826bea8766SBrooks Davis 			snprintf(ebuf, ebuflen,
1836bea8766SBrooks Davis 			    "%s: %s", desc, strerror(ERANGE));
1846bea8766SBrooks Davis 			return (0);
1856bea8766SBrooks Davis 		}
1866bea8766SBrooks Davis 		break;
1876bea8766SBrooks Davis 	default:
1886bea8766SBrooks Davis  badnum:	snprintf(ebuf, ebuflen,
1896bea8766SBrooks Davis 		    "%s `%s': illegal number", desc, val);
1906bea8766SBrooks Davis 		return (0);
1916bea8766SBrooks Davis 	}
1926bea8766SBrooks Davis 	if (num < min) {
1936bea8766SBrooks Davis 			/* LONGLONG */
1946bea8766SBrooks Davis 		snprintf(ebuf, ebuflen, "%s %lld is less than %lld.",
1956bea8766SBrooks Davis 		    desc, (long long)num, (long long)min);
1966bea8766SBrooks Davis 		return (0);
1976bea8766SBrooks Davis 	}
1986bea8766SBrooks Davis 	if (num > max) {
1996bea8766SBrooks Davis 			/* LONGLONG */
2006bea8766SBrooks Davis 		snprintf(ebuf, ebuflen,
2016bea8766SBrooks Davis 		    "%s %lld is greater than %lld.",
2026bea8766SBrooks Davis 		    desc, (long long)num, (long long)max);
2036bea8766SBrooks Davis 		return (0);
2046bea8766SBrooks Davis 	}
2056bea8766SBrooks Davis 	*ebuf = '\0';
2066bea8766SBrooks Davis 	return (num);
2076bea8766SBrooks Davis }
2086bea8766SBrooks Davis 
2096bea8766SBrooks Davis /* LONGLONG */
2106bea8766SBrooks Davis long long
strsuftoll(const char * desc,const char * val,long long min,long long max)2116bea8766SBrooks Davis strsuftoll(const char *desc, const char *val,
2126bea8766SBrooks Davis     long long min, long long max)
2136bea8766SBrooks Davis {
2146bea8766SBrooks Davis 	long long result;
2156bea8766SBrooks Davis 	char	errbuf[100];
2166bea8766SBrooks Davis 
2176bea8766SBrooks Davis 	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
2186bea8766SBrooks Davis 	if (*errbuf != '\0')
2196bea8766SBrooks Davis 		errx(1, "%s", errbuf);
2206bea8766SBrooks Davis 	return (result);
2216bea8766SBrooks Davis }
222