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