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 *, ...);