summaryrefslogtreecommitdiff
path: root/usr.bin/awk
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2020-12-09 20:00:12 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2020-12-09 20:00:12 +0000
commitc1262a2f42694e18e6e9179f755a231935f2b710 (patch)
treea3903d2e6d9fd26d5dc136320254565a30833788 /usr.bin/awk
parentd748bb807f88a010d30ec3116ae990da076dc35c (diff)
Update awk to December 8, 2020 version.
Prevents strings beginning with "inf" or "nan" from being interpreted as infinity or not-a-number respectively which still parsing "inf" and "nan" (with or without a leading sign) correctly.
Diffstat (limited to 'usr.bin/awk')
-rw-r--r--usr.bin/awk/FIXES21
-rw-r--r--usr.bin/awk/README.md10
-rw-r--r--usr.bin/awk/awk.158
-rw-r--r--usr.bin/awk/b.c40
-rw-r--r--usr.bin/awk/lex.c15
-rw-r--r--usr.bin/awk/lib.c99
-rw-r--r--usr.bin/awk/main.c6
-rw-r--r--usr.bin/awk/parse.c4
-rw-r--r--usr.bin/awk/proto.h6
-rw-r--r--usr.bin/awk/run.c80
-rw-r--r--usr.bin/awk/tran.c42
11 files changed, 272 insertions, 109 deletions
diff --git a/usr.bin/awk/FIXES b/usr.bin/awk/FIXES
index 8341575f2c8..cb35981b64d 100644
--- a/usr.bin/awk/FIXES
+++ b/usr.bin/awk/FIXES
@@ -1,4 +1,4 @@
-/* $OpenBSD: FIXES,v 1.38 2020/08/11 16:57:05 millert Exp $ */
+/* $OpenBSD: FIXES,v 1.39 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -26,6 +26,25 @@ THIS SOFTWARE.
This file lists all bug fixes, changes, etc., made since the AWK book
was sent to the printers in August, 1987.
+December 8, 2020:
+ Merge PR #98: Disallow hex data. Allow only +nan, -nan,
+ +inf, -inf (case independent) to give NaN and infinity values.
+ Improve things so that string to double conversion is only
+ done once, yielding something of a speedup. This obviate
+ PR #95. Thanks to Arnold Robbins.
+
+December 3, 2020:
+ Fix to argument parsing to avoid printing spurious newlines.
+ Thanks to Todd Miller. Merges PR #97.
+
+October 13, 2020:
+ Add casts before all the calls to malloc/calloc/realloc in order
+ to get it to compile with g++. Thanks to Arnold Robbins.
+
+August 16, 2020:
+ Additional fixes for DJGPP. Thanks to Eli Zaretskii for
+ the testing.
+
August 7, 2020:
Merge PR #93, which adds casts to (void*) for debug prints
using the %p format specifier. Thanks to GitHub user YongHaoWu
diff --git a/usr.bin/awk/README.md b/usr.bin/awk/README.md
index 75e7305247c..655006e49fc 100644
--- a/usr.bin/awk/README.md
+++ b/usr.bin/awk/README.md
@@ -1,4 +1,4 @@
-$OpenBSD: README.md,v 1.3 2020/07/02 19:06:22 millert Exp $
+$OpenBSD: README.md,v 1.4 2020/12/09 20:00:11 millert Exp $
# The One True Awk
@@ -101,6 +101,9 @@ welcome.
This compiles without change on Macintosh OS X using `gcc` and
the standard developer tools.
+You can also use `make CC=g++` to build with the GNU C++ compiler,
+should you choose to do so.
+
The version of `malloc` that comes with some systems is sometimes
astonishly slow. If `awk` seems slow, you might try fixing that.
More generally, turning on optimization can significantly improve
@@ -114,8 +117,9 @@ as we can. Unfortunately, however, keeping this program going
is not at the top of our priority list.
_If_ you (yes, you!) are interested in taking over active maintenance of
-`awk`, please open an issue to indicate that fact, give a little bit of
+`awk`, please open an issue to indicate that fact, and give us a little bit of
your background and some idea of your plans and dreams. Thanks!
#### Last Updated
-Thu Jul 2 21:39:31 IDT 2020
+
+Tue Oct 13 20:00:09 IDT 2020
diff --git a/usr.bin/awk/awk.1 b/usr.bin/awk/awk.1
index 3c2dfcfcd03..9027bf80fb8 100644
--- a/usr.bin/awk/awk.1
+++ b/usr.bin/awk/awk.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: awk.1,v 1.58 2020/11/05 16:04:39 jmc Exp $
+.\" $OpenBSD: awk.1,v 1.59 2020/12/09 20:00:11 millert Exp $
.\"
.\" Copyright (C) Lucent Technologies 1997
.\" All Rights Reserved
@@ -22,7 +22,7 @@
.\" ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
.\" THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 5 2020 $
+.Dd $Mdocdate: December 9 2020 $
.Dt AWK 1
.Os
.Sh NAME
@@ -280,7 +280,7 @@ and concatenation
.Pq indicated by whitespace .
The operators
.Ic \&! ++ \-\- += \-= *= /= %= ^=
-.Ic > >= < <= == != ?:
+.Ic > >= < <= == != ?\&:
are also available in expressions.
Variables may be scalars, array elements
(denoted
@@ -919,6 +919,58 @@ Print an error message to standard error:
.Bd -literal -offset indent
{ print "error!" > "/dev/stderr" }
.Ed
+.Sh UNUSUAL FLOATING-POINT VALUES
+.Nm
+was designed before IEEE 754 arithmetic defined Not-A-Number (NaN)
+and Infinity values, which are supported by all modern floating-point
+hardware.
+.Pp
+Because
+.Nm
+uses
+.Xr strtod 3
+and
+.Xr atof 3
+to convert string values to double-precision floating-point values,
+modern C libraries also convert strings starting with
+.Dv inf
+and
+.Dv nan
+into infinity and NaN values respectively.
+This led to strange results,
+with something like this:
+.Pp
+.Li echo nancy | awk '{ print $1 + 0 }'
+.Pp
+printing
+.Dv nan
+instead of zero.
+.Pp
+.Nm
+now follows GNU
+.Nm ,
+and prefilters string values before attempting
+to convert them to numbers, as follows:
+.Bl -tag -width Ds
+.It Hexadecimal values
+Hexadecimal values (allowed since C99) convert to zero, as they did
+prior to C99.
+.It NaN values
+The two strings
+.Dq +NAN
+and
+.Dq -NAN
+(case independent) convert to NaN.
+No others do.
+(NaNs can have signs.)
+.It Infinity values
+The two strings
+.Dq +INF
+and
+.Dq -INF
+(case independent) convert to positive and negative infinity, respectively.
+No others do.
+.El
.Sh SEE ALSO
.Xr cut 1 ,
.Xr date 1 ,
diff --git a/usr.bin/awk/b.c b/usr.bin/awk/b.c
index cef1bbd29bd..1c272cd5fea 100644
--- a/usr.bin/awk/b.c
+++ b/usr.bin/awk/b.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: b.c,v 1.34 2020/07/30 17:45:44 millert Exp $ */
+/* $OpenBSD: b.c,v 1.35 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -84,7 +84,7 @@ int nfatab = 0; /* entries in fatab */
static int *
intalloc(size_t n, const char *f)
{
- void *p = calloc(n, sizeof(int));
+ int *p = (int *) calloc(n, sizeof(int));
if (p == NULL)
overflo(f);
return p;
@@ -94,8 +94,8 @@ static void
allocsetvec(const char *f)
{
maxsetvec = MAXLIN;
- setvec = reallocarray(setvec, maxsetvec, sizeof(*setvec));
- tmpset = reallocarray(tmpset, maxsetvec, sizeof(*tmpset));
+ setvec = (int *) reallocarray(setvec, maxsetvec, sizeof(*setvec));
+ tmpset = (int *) reallocarray(tmpset, maxsetvec, sizeof(*tmpset));
if (setvec == NULL || tmpset == NULL)
overflo(f);
}
@@ -103,8 +103,8 @@ allocsetvec(const char *f)
static void
resizesetvec(const char *f)
{
- setvec = reallocarray(setvec, maxsetvec, 4 * sizeof(*setvec));
- tmpset = reallocarray(tmpset, maxsetvec, 4 * sizeof(*tmpset));
+ setvec = (int *) reallocarray(setvec, maxsetvec, 4 * sizeof(*setvec));
+ tmpset = (int *) reallocarray(tmpset, maxsetvec, 4 * sizeof(*tmpset));
if (setvec == NULL || tmpset == NULL)
overflo(f);
maxsetvec *= 4;
@@ -113,7 +113,9 @@ resizesetvec(const char *f)
static void
resize_state(fa *f, int state)
{
- void *p;
+ unsigned int **p;
+ uschar *p2;
+ int **p3;
int i, new_count;
if (++state < f->state_count)
@@ -121,23 +123,23 @@ resize_state(fa *f, int state)
new_count = state + 10; /* needs to be tuned */
- p = reallocarray(f->gototab, new_count, sizeof(f->gototab[0]));
+ p = (unsigned int **) reallocarray(f->gototab, new_count, sizeof(f->gototab[0]));
if (p == NULL)
goto out;
f->gototab = p;
- p = reallocarray(f->out, new_count, sizeof(f->out[0]));
- if (p == NULL)
+ p2 = (uschar *) reallocarray(f->out, new_count, sizeof(f->out[0]));
+ if (p2 == NULL)
goto out;
- f->out = p;
+ f->out = p2;
- p = reallocarray(f->posns, new_count, sizeof(f->posns[0]));
- if (p == NULL)
+ p3 = (int **) reallocarray(f->posns, new_count, sizeof(f->posns[0]));
+ if (p3 == NULL)
goto out;
- f->posns = p;
+ f->posns = p3;
for (i = f->state_count; i < new_count; ++i) {
- f->gototab[i] = calloc(NCHARS, sizeof(**f->gototab));
+ f->gototab[i] = (unsigned int *) calloc(NCHARS, sizeof(**f->gototab));
if (f->gototab[i] == NULL)
goto out;
f->out[i] = 0;
@@ -203,7 +205,7 @@ fa *mkdfa(const char *s, bool anchor) /* does the real work of making a dfa */
poscnt = 0;
penter(p1); /* enter parent pointers and leaf indices */
- if ((f = calloc(1, sizeof(fa) + poscnt * sizeof(rrow))) == NULL)
+ if ((f = (fa *) calloc(1, sizeof(fa) + poscnt * sizeof(rrow))) == NULL)
overflo(__func__);
f->accept = poscnt-1; /* penter has computed number of positions in re */
cfoll(f, p1); /* set up follow sets */
@@ -373,7 +375,7 @@ char *cclenter(const char *argp) /* add a character class */
static int bufsz = 100;
op = p;
- if (buf == NULL && (buf = malloc(bufsz)) == NULL)
+ if (buf == NULL && (buf = (uschar *) malloc(bufsz)) == NULL)
FATAL("out of space for character class [%.10s...] 1", p);
bp = buf;
for (i = 0; (c = *p++) != 0; ) {
@@ -944,7 +946,7 @@ replace_repeat(const uschar *reptok, int reptoklen, const uschar *atom,
} else if (special_case == REPEAT_ZERO) {
size += 2; /* just a null ERE: () */
}
- if ((buf = malloc(size + 1)) == NULL)
+ if ((buf = (uschar *) malloc(size + 1)) == NULL)
FATAL("out of space in reg expr %.10s..", lastre);
memcpy(buf, basestr, prefix_length); /* copy prefix */
j = prefix_length;
@@ -1072,7 +1074,7 @@ rescan:
rlxval = c;
return CHAR;
case '[':
- if (buf == NULL && (buf = malloc(bufsz)) == NULL)
+ if (buf == NULL && (buf = (uschar *) malloc(bufsz)) == NULL)
FATAL("out of space in reg expr %.10s..", lastre);
bp = buf;
if (*prestr == '^') {
diff --git a/usr.bin/awk/lex.c b/usr.bin/awk/lex.c
index 1dc1f991fa0..42feeae9962 100644
--- a/usr.bin/awk/lex.c
+++ b/usr.bin/awk/lex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lex.c,v 1.26 2020/08/28 16:29:16 millert Exp $ */
+/* $OpenBSD: lex.c,v 1.27 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -184,7 +184,7 @@ int yylex(void)
static char *buf = NULL;
static int bufsize = 5; /* BUG: setting this small causes core dump! */
- if (buf == NULL && (buf = malloc(bufsize)) == NULL)
+ if (buf == NULL && (buf = (char *) malloc(bufsize)) == NULL)
FATAL( "out of space in yylex" );
if (sc) {
sc = false;
@@ -202,7 +202,12 @@ int yylex(void)
return word(buf);
if (isdigit(c)) {
char *cp = tostring(buf);
- yylval.cp = setsymtab(buf, cp, atof(buf), CON|NUM, symtab);
+ double result;
+
+ if (is_number(cp, & result))
+ yylval.cp = setsymtab(buf, cp, result, CON|NUM, symtab);
+ else
+ yylval.cp = setsymtab(buf, cp, 0.0, STR, symtab);
free(cp);
/* should this also have STR set? */
RET(NUMBER);
@@ -381,7 +386,7 @@ int string(void)
static char *buf = NULL;
static int bufsz = 500;
- if (buf == NULL && (buf = malloc(bufsz)) == NULL)
+ if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of space for strings");
for (bp = buf; (c = input()) != '"'; ) {
if (!adjbuf(&buf, &bufsz, bp-buf+2, 500, &bp, "string"))
@@ -530,7 +535,7 @@ int regexpr(void)
static int bufsz = 500;
char *bp, *cstart;
- if (buf == NULL && (buf = malloc(bufsz)) == NULL)
+ if (buf == NULL && (buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of space for rex expr");
bp = buf;
for ( ; ((c = input()) != '/' || openclass > 0) && c != 0; ) {
diff --git a/usr.bin/awk/lib.c b/usr.bin/awk/lib.c
index 173317a85ba..a02f7609534 100644
--- a/usr.bin/awk/lib.c
+++ b/usr.bin/awk/lib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lib.c,v 1.41 2020/07/30 17:46:54 millert Exp $ */
+/* $OpenBSD: lib.c,v 1.42 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -31,6 +31,7 @@ THIS SOFTWARE.
#include <stdlib.h>
#include <stdarg.h>
#include <limits.h>
+#include <math.h>
#include "awk.h"
char EMPTY[] = { '\0' };
@@ -61,10 +62,10 @@ static Cell dollar1 = { OCELL, CFLD, NULL, EMPTY, 0.0, FLD|STR|DONTFREE, NULL, N
void recinit(unsigned int n)
{
- if ( (record = malloc(n)) == NULL
- || (fields = malloc(n+1)) == NULL
- || (fldtab = calloc(nfields+2, sizeof(*fldtab))) == NULL
- || (fldtab[0] = malloc(sizeof(**fldtab))) == NULL)
+ if ( (record = (char *) malloc(n)) == NULL
+ || (fields = (char *) malloc(n+1)) == NULL
+ || (fldtab = (Cell **) calloc(nfields+2, sizeof(*fldtab))) == NULL
+ || (fldtab[0] = (Cell *) malloc(sizeof(**fldtab))) == NULL)
FATAL("out of space for $0 and fields");
*record = '\0';
*fldtab[0] = dollar0;
@@ -79,7 +80,7 @@ void makefields(int n1, int n2) /* create $n1..$n2 inclusive */
int i;
for (i = n1; i <= n2; i++) {
- fldtab[i] = malloc(sizeof(**fldtab));
+ fldtab[i] = (Cell *) malloc(sizeof(**fldtab));
if (fldtab[i] == NULL)
FATAL("out of space in makefields %d", i);
*fldtab[i] = dollar1;
@@ -124,7 +125,7 @@ void savefs(void)
size_t len = strlen(getsval(fsloc));
if (len >= len_inputFS) {
len_inputFS = len + 1;
- inputFS = realloc(inputFS, len_inputFS);
+ inputFS = (char *) realloc(inputFS, len_inputFS);
if (inputFS == NULL)
FATAL("field separator %.10s... is too long", *FS);
}
@@ -180,12 +181,14 @@ int getrec(char **pbuf, int *pbufsize, bool isrecord) /* get next input record *
innew = false;
if (c != 0 || buf[0] != '\0') { /* normal record */
if (isrecord) {
+ double result;
+
if (freeable(fldtab[0]))
xfree(fldtab[0]->sval);
fldtab[0]->sval = buf; /* buf == record */
fldtab[0]->tval = REC | STR | DONTFREE;
- if (is_number(fldtab[0]->sval)) {
- fldtab[0]->fval = atof(fldtab[0]->sval);
+ if (is_number(fldtab[0]->sval, & result)) {
+ fldtab[0]->fval = result;
fldtab[0]->tval |= NUM;
}
}
@@ -292,6 +295,7 @@ void setclvar(char *s) /* set var=value from s */
{
char *p;
Cell *q;
+ double result;
for (p=s; *p != '='; p++)
;
@@ -299,8 +303,8 @@ void setclvar(char *s) /* set var=value from s */
p = qstring(p, '\0');
q = setsymtab(s, p, 0.0, STR, symtab);
setsval(q, p);
- if (is_number(q->sval)) {
- q->fval = atof(q->sval);
+ if (is_number(q->sval, & result)) {
+ q->fval = result;
q->tval |= NUM;
}
DPRINTF("command line set %s to |%s|\n", s, p);
@@ -324,7 +328,7 @@ void fldbld(void) /* create fields from current record */
n = strlen(r);
if (n > fieldssize) {
xfree(fields);
- if ((fields = malloc(n+2)) == NULL) /* possibly 2 final \0s */
+ if ((fields = (char *) malloc(n+2)) == NULL) /* possibly 2 final \0s */
FATAL("out of space for fields in fldbld %d", n);
fieldssize = n;
}
@@ -401,9 +405,11 @@ void fldbld(void) /* create fields from current record */
lastfld = i;
donefld = true;
for (j = 1; j <= lastfld; j++) {
+ double result;
+
p = fldtab[j];
- if(is_number(p->sval)) {
- p->fval = atof(p->sval);
+ if(is_number(p->sval, & result)) {
+ p->fval = result;
p->tval |= NUM;
}
}
@@ -473,7 +479,7 @@ void growfldtab(int n) /* make new fields up to at least $n */
nf = n;
s = (nf+1) * (sizeof (struct Cell *)); /* freebsd: how much do we need? */
if (s / sizeof(struct Cell *) - 1 == (size_t)nf) /* didn't overflow */
- fldtab = realloc(fldtab, s);
+ fldtab = (Cell **) realloc(fldtab, s);
else /* overflow sizeof int */
xfree(fldtab); /* make it null */
if (fldtab == NULL)
@@ -493,7 +499,7 @@ int refldbld(const char *rec, const char *fs) /* build fields from reg expr in F
n = strlen(rec);
if (n > fieldssize) {
xfree(fields);
- if ((fields = malloc(n+1)) == NULL)
+ if ((fields = (char *) malloc(n+1)) == NULL)
FATAL("out of space for fields in refldbld %d", n);
fieldssize = n;
}
@@ -758,24 +764,67 @@ int isclvar(const char *s) /* is s of form var=something ? */
/* strtod is supposed to be a proper test of what's a valid number */
/* appears to be broken in gcc on linux: thinks 0x123 is a valid FP number */
/* wrong: violates 4.10.1.4 of ansi C standard */
+
/* well, not quite. As of C99, hex floating point is allowed. so this is
- * a bit of a mess.
+ * a bit of a mess. We work around the mess by checking for a hexadecimal
+ * value and disallowing it. Similarly, we now follow gawk and allow only
+ * +nan, -nan, +inf, and -inf for NaN and infinity values.
*/
-#include <math.h>
-int is_number(const char *s)
+/*
+ * This routine now has a more complicated interface, the main point
+ * being to avoid the double conversion of a string to double, and
+ * also to convey out, if requested, the information that the numeric
+ * value was a leading string or is all of the string. The latter bit
+ * is used in getfval().
+ */
+
+bool is_valid_number(const char *s, bool trailing_stuff_ok,
+ bool *no_trailing, double *result)
{
double r;
char *ep;
+ bool retval = false;
+
+ if (no_trailing)
+ *no_trailing = false;
+
+ while (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')
+ s++;
+
+ if (s[0] == '0' && tolower(s[1]) == 'x') // no hex floating point, sorry
+ return false;
+
+ // allow +nan, -nan, +inf, -inf, any other letter, no
+ if (s[0] == '+' || s[0] == '-') {
+ if (strcasecmp(s+1, "nan") == 0 || strcasecmp(s+1, "inf") == 0)
+ return true;
+ else if (! isdigit(s[1]) && s[1] != '.')
+ return false;
+ }
+ else if (! isdigit(s[0]) && s[0] != '.')
+ return false;
+
errno = 0;
r = strtod(s, &ep);
if (ep == s || r == HUGE_VAL || errno == ERANGE)
- return 0;
- /* allow \r as well. windows files aren't going to go away. */
+ return false;
+
+ if (result != NULL)
+ *result = r;
+
+ /*
+ * check for trailing stuff
+ * allow \r as well. windows files aren't going to go away.
+ */
while (*ep == ' ' || *ep == '\t' || *ep == '\n' || *ep == '\r')
ep++;
- if (*ep == '\0')
- return 1;
- else
- return 0;
+
+ if (no_trailing)
+ *no_trailing = (*ep == '\0');
+
+ // return true if found the end, or trailing stuff is allowed
+ retval = (*ep == '\0') || trailing_stuff_ok;
+
+ return retval;
}
diff --git a/usr.bin/awk/main.c b/usr.bin/awk/main.c
index 9ffbf736b65..6aac4d5fa64 100644
--- a/usr.bin/awk/main.c
+++ b/usr.bin/awk/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.45 2020/08/11 16:57:05 millert Exp $ */
+/* $OpenBSD: main.c,v 1.46 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -23,7 +23,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
****************************************************************/
-const char *version = "version 20200807";
+const char *version = "version 20201208";
#define DEBUG
#include <stdio.h>
@@ -181,7 +181,7 @@ int main(int argc, char *argv[])
fn = getarg(&argc, &argv, "no program filename");
if (npfile >= maxpfile) {
maxpfile += 20;
- pfile = realloc(pfile, maxpfile * sizeof(*pfile));
+ pfile = (char **) realloc(pfile, maxpfile * sizeof(*pfile));
if (pfile == NULL)
FATAL("error allocating space for -f options");
}
diff --git a/usr.bin/awk/parse.c b/usr.bin/awk/parse.c
index 8b14f46f4e9..abd5c4fc6fc 100644
--- a/usr.bin/awk/parse.c
+++ b/usr.bin/awk/parse.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.c,v 1.12 2020/07/30 17:45:44 millert Exp $ */
+/* $OpenBSD: parse.c,v 1.13 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -34,7 +34,7 @@ Node *nodealloc(int n)
{
Node *x;
- x = malloc(sizeof(*x) + (n-1) * sizeof(x));
+ x = (Node *) malloc(sizeof(*x) + (n-1) * sizeof(x));
if (x == NULL)
FATAL("out of space in nodealloc");
x->nnext = NULL;
diff --git a/usr.bin/awk/proto.h b/usr.bin/awk/proto.h
index de70e5896d8..0c37d53725d 100644
--- a/usr.bin/awk/proto.h
+++ b/usr.bin/awk/proto.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proto.h,v 1.19 2020/06/13 01:21:01 millert Exp $ */
+/* $OpenBSD: proto.h,v 1.20 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -149,7 +149,9 @@ extern void eprint(void);
extern void bclass(int);
extern double errcheck(double, const char *);
extern int isclvar(const char *);
-extern int is_number(const char *);
+extern bool is_valid_number(const char *s, bool trailing_stuff_ok,
+ bool *no_trailing, double *result);
+#define is_number(s, val) is_valid_number(s, false, NULL, val)
extern int adjbuf(char **pb, int *sz, int min, int q, char **pbp, const char *what);
extern void run(Node *);
diff --git a/usr.bin/awk/run.c b/usr.bin/awk/run.c
index f6b141c695c..d7570bcb31f 100644
--- a/usr.bin/awk/run.c
+++ b/usr.bin/awk/run.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: run.c,v 1.68 2020/08/28 16:29:16 millert Exp $ */
+/* $OpenBSD: run.c,v 1.69 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -119,7 +119,7 @@ int adjbuf(char **pbuf, int *psiz, int minlen, int quantum, char **pbptr,
/* round up to next multiple of quantum */
if (rminlen)
minlen += quantum - rminlen;
- tbuf = realloc(*pbuf, minlen);
+ tbuf = (char *) realloc(*pbuf, minlen);
DPRINTF("adjbuf %s: %d %d (pbuf=%p, tbuf=%p)\n", whatrtn, *psiz, minlen, (void*)*pbuf, (void*)tbuf);
if (tbuf == NULL) {
if (whatrtn)
@@ -241,7 +241,7 @@ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
if (!isfcn(fcn))
FATAL("calling undefined function %s", s);
if (frame == NULL) {
- frp = frame = calloc(nframe += 100, sizeof(*frame));
+ frp = frame = (struct Frame *) calloc(nframe += 100, sizeof(*frame));
if (frame == NULL)
FATAL("out of space for stack frames calling %s", s);
}
@@ -275,7 +275,7 @@ Cell *call(Node **a, int n) /* function call. very kludgy and fragile */
frp++; /* now ok to up frame */
if (frp >= frame + nframe) {
int dfp = frp - frame; /* old index */
- frame = reallocarray(frame, (nframe += 100), sizeof(*frame));
+ frame = (struct Frame *) reallocarray(frame, (nframe += 100), sizeof(*frame));
if (frame == NULL)
FATAL("out of space for stack frames in %s", s);
frp = frame + dfp;
@@ -408,8 +408,9 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */
int bufsize = recsize;
int mode;
bool newflag;
+ double result;
- if ((buf = malloc(bufsize)) == NULL)
+ if ((buf = (char *) malloc(bufsize)) == NULL)
FATAL("out of memory in getline");
fflush(stdout); /* in case someone is waiting for a prompt */
@@ -430,15 +431,15 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */
} else if (a[0] != NULL) { /* getline var <file */
x = execute(a[0]);
setsval(x, buf);
- if (is_number(x->sval)) {
- x->fval = atof(x->sval);
+ if (is_number(x->sval, & result)) {
+ x->fval = result;
x->tval |= NUM;
}
tempfree(x);
} else { /* getline <file */
setsval(fldtab[0], buf);
- if (is_number(fldtab[0]->sval)) {
- fldtab[0]->fval = atof(fldtab[0]->sval);
+ if (is_number(fldtab[0]->sval, & result)) {
+ fldtab[0]->fval = result;
fldtab[0]->tval |= NUM;
}
}
@@ -449,8 +450,8 @@ Cell *awkgetline(Node **a, int n) /* get next line from specific input */
n = getrec(&buf, &bufsize, false);
x = execute(a[0]);
setsval(x, buf);
- if (is_number(x->sval)) {
- x->fval = atof(x->sval);
+ if (is_number(x->sval, & result)) {
+ x->fval = result;
x->tval |= NUM;
}
tempfree(x);
@@ -475,7 +476,7 @@ makearraystring(Node *p, const char *func)
int bufsz = recsize;
size_t blen;
- if ((buf = malloc(bufsz)) == NULL) {
+ if ((buf = (char *) malloc(bufsz)) == NULL) {
FATAL("%s: out of memory", func);
}
@@ -702,7 +703,7 @@ Cell *gettemp(void) /* get a tempcell */
Cell *x;
if (!tmps) {
- tmps = calloc(100, sizeof(*tmps));
+ tmps = (Cell *) calloc(100, sizeof(*tmps));
if (!tmps)
FATAL("out of space for temporaries");
for (i = 1; i < 100; i++)
@@ -727,7 +728,7 @@ Cell *indirect(Node **a, int n) /* $( a[0] ) */
if ((Awkfloat)INT_MAX < val)
FATAL("trying to access out of range field %s", x->nval);
m = (int) val;
- if (m == 0 && !is_number(s = getsval(x))) /* suspicion! */
+ if (m == 0 && !is_number(s = getsval(x), NULL)) /* suspicion! */
FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
/* BUG: can x->nval ever be null??? */
tempfree(x);
@@ -840,7 +841,7 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co
os = s;
p = buf;
- if ((fmt = malloc(fmtsz)) == NULL)
+ if ((fmt = (char *) malloc(fmtsz)) == NULL)
FATAL("out of memory in format()");
while (*s) {
adjbuf(&buf, &bufsize, MAXNUMSIZE+1+p-buf, recsize, &p, "format1");
@@ -983,7 +984,7 @@ Cell *awksprintf(Node **a, int n) /* sprintf(a[0]) */
char *buf;
int bufsz=3*recsize;
- if ((buf = malloc(bufsz)) == NULL)
+ if ((buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of memory in awksprintf");
y = a[0]->nnext;
x = execute(a[0]);
@@ -1006,7 +1007,7 @@ Cell *awkprintf(Node **a, int n) /* printf */
int len;
int bufsz=3*recsize;
- if ((buf = malloc(bufsz)) == NULL)
+ if ((buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of memory in awkprintf");
y = a[0]->nnext;
x = execute(a[0]);
@@ -1260,6 +1261,7 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
int sep;
char temp, num[50];
int n, tempstat, arg3type;
+ double result;
y = execute(a[0]); /* source string */
origs = s = strdup(getsval(y));
@@ -1308,8 +1310,8 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
snprintf(num, sizeof(num), "%d", n);
temp = *patbeg;
setptr(patbeg, '\0');
- if (is_number(s))
- setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
+ if (is_number(s, & result))
+ setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
else
setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
setptr(patbeg, temp);
@@ -1327,8 +1329,8 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
}
n++;
snprintf(num, sizeof(num), "%d", n);
- if (is_number(s))
- setsymtab(num, s, atof(s), STR|NUM, (Array *) ap->sval);
+ if (is_number(s, & result))
+ setsymtab(num, s, result, STR|NUM, (Array *) ap->sval);
else
setsymtab(num, s, 0.0, STR, (Array *) ap->sval);
spdone:
@@ -1348,8 +1350,8 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
temp = *s;
setptr(s, '\0');
snprintf(num, sizeof(num), "%d", n);
- if (is_number(t))
- setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
+ if (is_number(t, & result))
+ setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
else
setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
setptr(s, temp);
@@ -1377,8 +1379,8 @@ Cell *split(Node **a, int nnn) /* split(a[0], a[1], a[2]); a[3] is type */
temp = *s;
setptr(s, '\0');
snprintf(num, sizeof(num), "%d", n);
- if (is_number(t))
- setsymtab(num, t, atof(t), STR|NUM, (Array *) ap->sval);
+ if (is_number(t, & result))
+ setsymtab(num, t, result, STR|NUM, (Array *) ap->sval);
else
setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
setptr(s, temp);
@@ -1573,6 +1575,24 @@ static char *nawk_convert(const char *s, int (*fun_c)(int),
}
}
+#ifdef __DJGPP__
+static wint_t towupper(wint_t wc)
+{
+ if (wc >= 0 && wc < 256)
+ return toupper(wc & 0xFF);
+
+ return wc;
+}
+
+static wint_t towlower(wint_t wc)
+{
+ if (wc >= 0 && wc < 256)
+ return tolower(wc & 0xFF);
+
+ return wc;
+}
+#endif
+
static char *nawk_toupper(const char *s)
{
return nawk_convert(s, toupper, towupper);
@@ -1794,7 +1814,7 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis
sz = 32;
buf = NULL;
do {
- if ((buf = reallocarray(buf, 2, sz)) == NULL)
+ if ((buf = (char *) reallocarray(buf, 2, sz)) == NULL)
FATAL("out of memory in strftime");
sz *= 2;
} while (strftime(buf, sz, fmt, tm) == 0 && fmt[0] != '\0');
@@ -1878,7 +1898,7 @@ size_t nfiles;
static void stdinit(void) /* in case stdin, etc., are not constants */
{
nfiles = FOPEN_MAX;
- files = calloc(nfiles, sizeof(*files));
+ files = (struct files *) calloc(nfiles, sizeof(*files));
if (files == NULL)
FATAL("can't allocate file memory for %zu files", nfiles);
files[0].fp = stdin;
@@ -1918,7 +1938,7 @@ FILE *openfile(int a, const char *us, bool *pnewflag)
if (i >= nfiles) {
struct files *nf;
size_t nnf = nfiles + FOPEN_MAX;
- nf = reallocarray(files, nnf, sizeof(*nf));
+ nf = (struct files *) reallocarray(files, nnf, sizeof(*nf));
if (nf == NULL)
FATAL("cannot grow files for %s and %zu files", s, nnf);
memset(&nf[nfiles], 0, FOPEN_MAX * sizeof(*nf));
@@ -2039,7 +2059,7 @@ Cell *sub(Node **a, int nnn) /* substitute command */
fa *pfa;
int bufsz = recsize;
- if ((buf = malloc(bufsz)) == NULL)
+ if ((buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of memory in sub");
x = execute(a[3]); /* target string */
t = getsval(x);
@@ -2101,7 +2121,7 @@ Cell *gsub(Node **a, int nnn) /* global substitute */
int mflag, tempstat, num;
int bufsz = recsize;
- if ((buf = malloc(bufsz)) == NULL)
+ if ((buf = (char *) malloc(bufsz)) == NULL)
FATAL("out of memory in gsub");
mflag = 0; /* if mflag == 0, can replace empty string */
num = 0;
diff --git a/usr.bin/awk/tran.c b/usr.bin/awk/tran.c
index ea67e6f2fc5..1ea64d240d8 100644
--- a/usr.bin/awk/tran.c
+++ b/usr.bin/awk/tran.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: tran.c,v 1.31 2020/08/11 16:57:05 millert Exp $ */
+/* $OpenBSD: tran.c,v 1.32 2020/12/09 20:00:11 millert Exp $ */
/****************************************************************
Copyright (C) Lucent Technologies 1997
All Rights Reserved
@@ -130,9 +130,11 @@ void arginit(int ac, char **av) /* set up ARGV and ARGC */
free(cp->sval);
cp->sval = (char *) ARGVtab;
for (i = 0; i < ac; i++) {
+ double result;
+
snprintf(temp, sizeof temp, "%d", i);
- if (is_number(*av))
- setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
+ if (is_number(*av, & result))
+ setsymtab(temp, *av, result, STR|NUM, ARGVtab);
else
setsymtab(temp, *av, 0.0, STR, ARGVtab);
av++;
@@ -149,13 +151,15 @@ void envinit(char **envp) /* set up ENVIRON variable */
free(cp->sval);
cp->sval = (char *) ENVtab;
for ( ; *envp; envp++) {
+ double result;
+
if ((p = strchr(*envp, '=')) == NULL)
continue;
if( p == *envp ) /* no left hand side name in env string */
continue;
*p++ = 0; /* split into two strings at = */
- if (is_number(p))
- setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
+ if (is_number(p, & result))
+ setsymtab(*envp, p, result, STR|NUM, ENVtab);
else
setsymtab(*envp, p, 0.0, STR, ENVtab);
p[-1] = '='; /* restore in case env is passed down to a shell */
@@ -167,8 +171,8 @@ Array *makesymtab(int n) /* make a new symbol table */
Array *ap;
Cell **tp;
- ap = malloc(sizeof(*ap));
- tp = calloc(n, sizeof(*tp));
+ ap = (Array *) malloc(sizeof(*ap));
+ tp = (Cell **) calloc(n, sizeof(*tp));
if (ap == NULL || tp == NULL)
FATAL("out of space in makesymtab");
ap->nelem = 0;
@@ -238,7 +242,7 @@ Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval);
return(p);
}
- p = malloc(sizeof(*p));
+ p = (Cell *) malloc(sizeof(*p));
if (p == NULL)
FATAL("out of space for symbol table at %s", n);
p->nval = tostring(n);
@@ -273,7 +277,7 @@ void rehash(Array *tp) /* rehash items in small table into big one */
Cell *cp, *op, **np;
nsz = GROWTAB * tp->size;
- np = calloc(nsz, sizeof(*np));
+ np = (Cell **) calloc(nsz, sizeof(*np));
if (np == NULL) /* can't do it, but can keep running. */
return; /* someone else will run out later. */
for (i = 0; i < tp->size; i++) {
@@ -400,9 +404,15 @@ Awkfloat getfval(Cell *vp) /* get float val of a Cell */
else if (isrec(vp) && !donerec)
recbld();
if (!isnum(vp)) { /* not a number */
- vp->fval = atof(vp->sval); /* best guess */
- if (is_number(vp->sval) && !(vp->tval&CON))
- vp->tval |= NUM; /* make NUM only sparingly */
+ double fval;
+ bool no_trailing;
+
+ if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
+ vp->fval = fval;
+ if (no_trailing && !(vp->tval&CON))
+ vp->tval |= NUM; /* make NUM only sparingly */
+ } else
+ vp->fval = 0.0;
}
DPRINTF("getfval %p: %s = %g, t=%o\n",
(void*)vp, NN(vp->nval), vp->fval, vp->tval);
@@ -521,7 +531,7 @@ char *tostringN(const char *s, size_t n) /* make a copy of string s */
{
char *p;
- p = malloc(n);
+ p = (char *) malloc(n);
if (p == NULL)
FATAL("out of space in tostringN %zu", n);
if (strlcpy(p, s, n) >= n)
@@ -536,13 +546,13 @@ Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
char *sa = getsval(a);
char *sb = getsval(b);
size_t l = strlen(sa) + strlen(sb) + 1;
- p = malloc(l);
+ p = (char *) malloc(l);
if (p == NULL)
FATAL("out of space concatenating %s and %s", sa, sb);
snprintf(p, l, "%s%s", sa, sb);
l++; // add room for ' '
- char *newbuf = malloc(l);
+ char *newbuf = (char *) malloc(l);
if (newbuf == NULL)
FATAL("out of space concatenating %s and %s", sa, sb);
// See string() in lex.c; a string "xx" is stored in the symbol
@@ -561,7 +571,7 @@ char *qstring(const char *is, int delim) /* collect string up to next delim */
const uschar *s = (const uschar *) is;
uschar *buf, *bp;
- if ((buf = malloc(strlen(is)+3)) == NULL)
+ if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
FATAL( "out of space in qstring(%s)", s);
for (bp = buf; (c = *s) != delim; s++) {
if (c == '\n')