xref: /netbsd-src/lib/libc/stdlib/strsuftoll.c (revision 3dc3dea471c2715aca53e89a9ca1776c8028b44a)
1*3dc3dea4Smrg /*	$NetBSD: strsuftoll.c,v 1.10 2024/06/09 18:55:00 mrg Exp $	*/
26ca5b5bbSlukem /*-
3a19008b1Slukem  * 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  *
186ca5b5bbSlukem  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
196ca5b5bbSlukem  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
206ca5b5bbSlukem  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
216ca5b5bbSlukem  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
226ca5b5bbSlukem  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
236ca5b5bbSlukem  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
246ca5b5bbSlukem  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
256ca5b5bbSlukem  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
266ca5b5bbSlukem  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
276ca5b5bbSlukem  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
286ca5b5bbSlukem  * POSSIBILITY OF SUCH DAMAGE.
296ca5b5bbSlukem  */
306ca5b5bbSlukem /*-
316ca5b5bbSlukem  * Copyright (c) 1991, 1993, 1994
326ca5b5bbSlukem  *	The Regents of the University of California.  All rights reserved.
336ca5b5bbSlukem  *
346ca5b5bbSlukem  * This code is derived from software contributed to Berkeley by
356ca5b5bbSlukem  * Keith Muller of the University of California, San Diego and Lance
366ca5b5bbSlukem  * Visser of Convex Computer Corporation.
376ca5b5bbSlukem  *
386ca5b5bbSlukem  * Redistribution and use in source and binary forms, with or without
396ca5b5bbSlukem  * modification, are permitted provided that the following conditions
406ca5b5bbSlukem  * are met:
416ca5b5bbSlukem  * 1. Redistributions of source code must retain the above copyright
426ca5b5bbSlukem  *    notice, this list of conditions and the following disclaimer.
436ca5b5bbSlukem  * 2. Redistributions in binary form must reproduce the above copyright
446ca5b5bbSlukem  *    notice, this list of conditions and the following disclaimer in the
456ca5b5bbSlukem  *    documentation and/or other materials provided with the distribution.
46eb7c1594Sagc  * 3. Neither the name of the University nor the names of its contributors
476ca5b5bbSlukem  *    may be used to endorse or promote products derived from this software
486ca5b5bbSlukem  *    without specific prior written permission.
496ca5b5bbSlukem  *
506ca5b5bbSlukem  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
516ca5b5bbSlukem  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
526ca5b5bbSlukem  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
536ca5b5bbSlukem  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
546ca5b5bbSlukem  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
556ca5b5bbSlukem  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
566ca5b5bbSlukem  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
576ca5b5bbSlukem  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
586ca5b5bbSlukem  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
596ca5b5bbSlukem  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
606ca5b5bbSlukem  * SUCH DAMAGE.
616ca5b5bbSlukem  */
626ca5b5bbSlukem 
63171d6532Slukem #if HAVE_NBTOOL_CONFIG_H
64171d6532Slukem #include "nbtool_config.h"
65171d6532Slukem #endif
66171d6532Slukem 
676ca5b5bbSlukem #include <sys/cdefs.h>
686ca5b5bbSlukem 
696ca5b5bbSlukem #if defined(LIBC_SCCS) && !defined(lint)
70*3dc3dea4Smrg __RCSID("$NetBSD: strsuftoll.c,v 1.10 2024/06/09 18:55:00 mrg Exp $");
716ca5b5bbSlukem #endif /* LIBC_SCCS and not lint */
726ca5b5bbSlukem 
736ca5b5bbSlukem #ifdef _LIBC
746ca5b5bbSlukem #include "namespace.h"
756ca5b5bbSlukem #endif
766ca5b5bbSlukem 
776ca5b5bbSlukem #if !HAVE_STRSUFTOLL
786ca5b5bbSlukem 
796ca5b5bbSlukem #include <sys/types.h>
806ca5b5bbSlukem #include <sys/time.h>
816ca5b5bbSlukem 
826ca5b5bbSlukem #include <assert.h>
836ca5b5bbSlukem #include <ctype.h>
846ca5b5bbSlukem #include <err.h>
856ca5b5bbSlukem #include <errno.h>
866ca5b5bbSlukem #include <limits.h>
876ca5b5bbSlukem #include <stdio.h>
886ca5b5bbSlukem #include <stdlib.h>
896ca5b5bbSlukem #include <string.h>
906ca5b5bbSlukem 
916ca5b5bbSlukem #ifdef _LIBC
926ca5b5bbSlukem # ifdef __weak_alias
__weak_alias(strsuftoll,_strsuftoll)936ca5b5bbSlukem __weak_alias(strsuftoll, _strsuftoll)
946ca5b5bbSlukem __weak_alias(strsuftollx, _strsuftollx)
956ca5b5bbSlukem # endif
96ca348cd6Sitohy #endif /* LIBC */
976ca5b5bbSlukem 
986ca5b5bbSlukem /*
996ca5b5bbSlukem  * Convert an expression of the following forms to a (u)int64_t.
1006ca5b5bbSlukem  * 	1) A positive decimal number.
1016ca5b5bbSlukem  *	2) A positive decimal number followed by a b (mult by 512).
1026ca5b5bbSlukem  *	3) A positive decimal number followed by a k (mult by 1024).
1036ca5b5bbSlukem  *	4) A positive decimal number followed by a m (mult by 1048576).
104a19008b1Slukem  *	5) A positive decimal number followed by a g (mult by 1073741824).
105a19008b1Slukem  *	6) A positive decimal number followed by a t (mult by 1099511627776).
106a19008b1Slukem  *	7) A positive decimal number followed by a w (mult by sizeof int)
107a19008b1Slukem  *	8) Two or more positive decimal numbers (with/without k,b or w).
1086ca5b5bbSlukem  *	   separated by x (also * for backwards compatibility), specifying
1096ca5b5bbSlukem  *	   the product of the indicated values.
1106ca5b5bbSlukem  * Returns the result upon successful conversion, or exits with an
1116ca5b5bbSlukem  * appropriate error.
1126ca5b5bbSlukem  *
1136ca5b5bbSlukem  */
114*3dc3dea4Smrg #ifdef __m68k__	/* See doc/HACKS. */
115*3dc3dea4Smrg __attribute((__optimize__("-fno-stack-protector")))
116*3dc3dea4Smrg #endif
1176ca5b5bbSlukem /* LONGLONG */
1186ca5b5bbSlukem long long
119ca348cd6Sitohy strsuftoll(const char *desc, const char *val,
1206ca5b5bbSlukem     long long min, long long max)
1216ca5b5bbSlukem {
1226ca5b5bbSlukem 	long long result;
1236ca5b5bbSlukem 	char	errbuf[100];
1246ca5b5bbSlukem 
1256ca5b5bbSlukem 	result = strsuftollx(desc, val, min, max, errbuf, sizeof(errbuf));
1266ca5b5bbSlukem 	if (*errbuf != '\0')
12766744c94Schristos 		errx(EXIT_FAILURE, "%s", errbuf);
12866744c94Schristos 	return result;
1296ca5b5bbSlukem }
1306ca5b5bbSlukem 
1316ca5b5bbSlukem /*
1326ca5b5bbSlukem  * As strsuftoll(), but returns the error message into the provided buffer
1336ca5b5bbSlukem  * rather than exiting with it.
1346ca5b5bbSlukem  */
1356ca5b5bbSlukem /* LONGLONG */
13666744c94Schristos static long long
__strsuftollx(const char * desc,const char * val,long long min,long long max,char * ebuf,size_t ebuflen,size_t depth)13766744c94Schristos __strsuftollx(const char *desc, const char *val,
13866744c94Schristos     long long min, long long max, char *ebuf, size_t ebuflen, size_t depth)
1396ca5b5bbSlukem {
1406ca5b5bbSlukem 	long long num, t;
1416ca5b5bbSlukem 	char	*expr;
1426ca5b5bbSlukem 
1436ca5b5bbSlukem 	_DIAGASSERT(desc != NULL);
1446ca5b5bbSlukem 	_DIAGASSERT(val != NULL);
1456ca5b5bbSlukem 	_DIAGASSERT(ebuf != NULL);
1466ca5b5bbSlukem 
14766744c94Schristos 	if (depth > 16) {
14866744c94Schristos 		snprintf(ebuf, ebuflen, "%s: Recursion limit exceeded", desc);
14966744c94Schristos 		return 0;
15066744c94Schristos 	}
1516ca5b5bbSlukem 
1526ca5b5bbSlukem 	while (isspace((unsigned char)*val))	/* Skip leading space */
1536ca5b5bbSlukem 		val++;
1546ca5b5bbSlukem 
15566744c94Schristos 	errno = 0;
156a19008b1Slukem 	num = strtoll(val, &expr, 10);
1576ca5b5bbSlukem 	if (errno == ERANGE)
1586ca5b5bbSlukem 		goto erange;			/* Overflow */
1596ca5b5bbSlukem 
1606ca5b5bbSlukem 	if (expr == val)			/* No digits */
1616ca5b5bbSlukem 		goto badnum;
1626ca5b5bbSlukem 
1636ca5b5bbSlukem 	switch (*expr) {
1646ca5b5bbSlukem 	case 'b':
1656ca5b5bbSlukem 		t = num;
1666ca5b5bbSlukem 		num *= 512;			/* 1 block */
1676ca5b5bbSlukem 		if (t > num)
1686ca5b5bbSlukem 			goto erange;
1696ca5b5bbSlukem 		++expr;
1706ca5b5bbSlukem 		break;
1716ca5b5bbSlukem 	case 'k':
1726ca5b5bbSlukem 		t = num;
1732d50a590Slukem 		num *= 1024;			/* 1 kibibyte */
1746ca5b5bbSlukem 		if (t > num)
1756ca5b5bbSlukem 			goto erange;
1766ca5b5bbSlukem 		++expr;
1776ca5b5bbSlukem 		break;
1786ca5b5bbSlukem 	case 'm':
1796ca5b5bbSlukem 		t = num;
1802d50a590Slukem 		num *= 1048576;			/* 1 mebibyte */
1816ca5b5bbSlukem 		if (t > num)
1826ca5b5bbSlukem 			goto erange;
1836ca5b5bbSlukem 		++expr;
1846ca5b5bbSlukem 		break;
1856ca5b5bbSlukem 	case 'g':
1866ca5b5bbSlukem 		t = num;
1872d50a590Slukem 		num *= 1073741824;		/* 1 gibibyte */
1886ca5b5bbSlukem 		if (t > num)
1896ca5b5bbSlukem 			goto erange;
1906ca5b5bbSlukem 		++expr;
1916ca5b5bbSlukem 		break;
1926ca5b5bbSlukem 	case 't':
1936ca5b5bbSlukem 		t = num;
1942d50a590Slukem 		num *= 1099511627776LL;		/* 1 tebibyte */
1956ca5b5bbSlukem 		if (t > num)
1966ca5b5bbSlukem 			goto erange;
1976ca5b5bbSlukem 		++expr;
1986ca5b5bbSlukem 		break;
1996ca5b5bbSlukem 	case 'w':
2006ca5b5bbSlukem 		t = num;
2016ca5b5bbSlukem 		num *= sizeof(int);		/* 1 word */
2026ca5b5bbSlukem 		if (t > num)
2036ca5b5bbSlukem 			goto erange;
2046ca5b5bbSlukem 		++expr;
2056ca5b5bbSlukem 		break;
2066ca5b5bbSlukem 	}
2076ca5b5bbSlukem 
2086ca5b5bbSlukem 	switch (*expr) {
2096ca5b5bbSlukem 	case '\0':
2106ca5b5bbSlukem 		break;
2116ca5b5bbSlukem 	case '*':				/* Backward compatible */
2126ca5b5bbSlukem 	case 'x':
2136ca5b5bbSlukem 		t = num;
21466744c94Schristos 		num *= __strsuftollx(desc, expr + 1, min, max, ebuf, ebuflen,
21566744c94Schristos 			depth + 1);
2166ca5b5bbSlukem 		if (*ebuf != '\0')
21766744c94Schristos 			return 0;
2186ca5b5bbSlukem 		if (t > num) {
2196ca5b5bbSlukem  erange:
22066744c94Schristos 			errno = ERANGE;
22166744c94Schristos 			snprintf(ebuf, ebuflen, "%s: %s", desc, strerror(errno));
22266744c94Schristos 			return 0;
2236ca5b5bbSlukem 		}
2246ca5b5bbSlukem 		break;
2256ca5b5bbSlukem 	default:
22666744c94Schristos  badnum:
22766744c94Schristos 		snprintf(ebuf, ebuflen, "%s `%s': illegal number", desc, val);
22866744c94Schristos 		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);
23466744c94Schristos 		return 0;
2356ca5b5bbSlukem 	}
2366ca5b5bbSlukem 	if (num > max) {
2376ca5b5bbSlukem 		/* LONGLONG */
23866744c94Schristos 		snprintf(ebuf, ebuflen, "%s %lld is greater than %lld.",
2391d817633Sdbj 		    desc, (long long)num, (long long)max);
24066744c94Schristos 		return 0;
2416ca5b5bbSlukem 	}
2426ca5b5bbSlukem 	*ebuf = '\0';
24366744c94Schristos 	return num;
2446ca5b5bbSlukem }
2456ca5b5bbSlukem 
24666744c94Schristos long long
strsuftollx(const char * desc,const char * val,long long min,long long max,char * ebuf,size_t ebuflen)24766744c94Schristos strsuftollx(const char *desc, const char *val,
24866744c94Schristos     long long min, long long max, char *ebuf, size_t ebuflen)
24966744c94Schristos {
25066744c94Schristos 	return __strsuftollx(desc, val, min, max, ebuf, ebuflen, 0);
25166744c94Schristos }
2526ca5b5bbSlukem #endif /* !HAVE_STRSUFTOLL */
253