commit 1c806cd3fa394cb79d48da95b43453ff55f695c4
parent 3e859c75d3e98a8e546ba4ae23dca8ba0156326f
Author: Jacob R. Edwards <jacobouno@protonmail.com>
Date:   Tue,  5 Jan 2021 16:42:57 -0800
Use OpenBSD strtonum() in place of strtorange()
The major improvement over the old strtorange() is that it doesn't
return the result as a pointer allowing automatic casting with no
warnings.
Note since it is not portable the function has been defined in
strtonum.c.
Diffstat:
5 files changed, 99 insertions(+), 11 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,5 @@
 TARGET = gawk
-OBJS   = main.o util.o command.o
+OBJS   = main.o util.o command.o strtonum.o
 
 # paths
 PREFIX    = /usr/local
diff --git a/command.c b/command.c
@@ -140,14 +140,16 @@ cprintv(int argc, char const **argv, int ino, char const **item)
 int
 findex(int argc, char const **argv, int ino, char const **item)
 {
+	char const *err;
 	int i;
-	unsigned int n;
+	int n;
 
 	if (warg(2, -1, argc, argv))
 		return FAIL;
 
 	for (i = 1; i < argc; ++i) {
-		if (strtorange(&n, 0, UINT_MAX, argv[i]))
+		n = wstrtonum(argv[i], 0, INT_MAX, &err);
+		if (err != NULL)
 			return FAIL;
 		if (ino == n)
 			return PASS;
@@ -158,8 +160,9 @@ findex(int argc, char const **argv, int ino, char const **item)
 int
 frange(int argc, char const **argv, int ino, char const **item)
 {
+	char const *err;
 	int i, j;
-	unsigned int range[2];
+	int range[2];
 
 	if (warg(3, -1, argc, argv))
 		return FAIL;
@@ -169,11 +172,14 @@ frange(int argc, char const **argv, int ino, char const **item)
 	}
 	
 	for (i = 1; i < argc; i += 2) {
-		for (j = 0; j < 2; ++j)
-			if (strtorange(&range[j], 0, UINT_MAX, argv[i + j]))
+		for (j = 0; j < 2; ++j) {
+			range[j] = wstrtonum(argv[i + j], 0, INT_MAX, &err);
+			if (err != NULL)
 				return FAIL;
+		}
 		if (range[0] > range[1]) {
-			warn(errno, "%s: %d greater than %d", *argv, range[0], range[1]);
+			warn(errno, "%s: %d greater than %d",
+			    *argv, range[0], range[1]);
 			return FAIL;
 		}
 		if (ino < range[0] || ino > range[1])
@@ -240,14 +246,18 @@ sgoto(int argc, char const **argv, int depth, char const **addr)
 int
 sunwind(int argc, char const **argv, int depth, char const **addr)
 {
-	unsigned int n;
+	char const *err;
+	int n;
 
 	if (warg(1, 2, argc, argv))
 		return FAIL;
 
 	if (argc == 1)
 		n = 1;
-	else if (strtorange(&n, 1, INT_MAX, argv[1]))
-		return FAIL;
+	else {
+		n = wstrtonum(argv[1], 0, INT_MAX, &err);
+		if (err != NULL)
+			return FAIL;
+	}
 	return n;
 }
diff --git a/strtonum.c b/strtonum.c
@@ -0,0 +1,65 @@
+/*	$OpenBSD: strtonum.c,v 1.8 2015/09/13 08:31:48 guenther Exp $	*/
+
+/*
+ * Copyright (c) 2004 Ted Unangst and Todd Miller
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+
+#define	INVALID		1
+#define	TOOSMALL	2
+#define	TOOLARGE	3
+
+long long
+strtonum(const char *numstr, long long minval, long long maxval,
+    const char **errstrp)
+{
+	long long ll = 0;
+	int error = 0;
+	char *ep;
+	struct errval {
+		const char *errstr;
+		int err;
+	} ev[4] = {
+		{ NULL,		0 },
+		{ "invalid",	EINVAL },
+		{ "too small",	ERANGE },
+		{ "too large",	ERANGE },
+	};
+
+	ev[0].err = errno;
+	errno = 0;
+	if (minval > maxval) {
+		error = INVALID;
+	} else {
+		ll = strtoll(numstr, &ep, 10);
+		if (numstr == ep || *ep != '\0')
+			error = INVALID;
+		else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+			error = TOOSMALL;
+		else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+			error = TOOLARGE;
+	}
+	if (errstrp != NULL)
+		*errstrp = ev[error].errstr;
+	errno = ev[error].err;
+	if (error)
+		ll = 0;
+
+	return (ll);
+}
diff --git a/util.c b/util.c
@@ -127,3 +127,14 @@ warn(int error, char const *format, ...)
 		fprintf(stderr, ": %s", strerror(error));
 	fputc('\n', stderr);
 }
+
+long long
+wstrtonum(const char *ns, long long min, long long max, const char **err)
+{
+	long long n;
+
+	n = strtonum(ns, min, max, err);
+	if (err != NULL)
+		warn(0, "number '%s': %s", ns, *err);
+	return n;
+}
diff --git a/util.h b/util.h
@@ -8,10 +8,12 @@
 
 FILE *	wfopen(char const *, char const *);
 int	exists(char const *);
-int	strtorange(unsigned int *, unsigned int, unsigned int, char const *);
 int	warg(int, int, int, char const **);
 int	wfclose(FILE *);
 int	wremove(char const *);
+#undef strtonum
+long long	strtonum(const char *, long long, long long, const char **);
+long long	wstrtonum(const char *, long long, long long, const char **);
 void	tr(char *, char const *, int, int);
 void	warn(int, char const *, ...);