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