gawk

[old] Sed-like interface to the Gopher protocol
Log | Files | Refs | LICENSE

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:
MMakefile | 2+-
Mcommand.c | 28+++++++++++++++++++---------
Astrtonum.c | 65+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mutil.c | 11+++++++++++
Mutil.h | 4+++-
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 *, ...);