shithub: kwa

Download patch

ref: c0526c8928a2b554d9421bca2fc04ba044fe06af
parent: 5086f3453d6716d6dcd782a45831c1ebb0f2b115
author: qwx <qwx@sciops.net>
date: Thu Sep 25 06:04:18 EDT 2025

lex: use to_number and don't discard the results

setsymtab in lex: STR should be set to avoid a leak, but some
work is necessary for it first. right now the string cannot be
unset without breakingt.coerce2 but adding STR breaks t.strcmp.
we have to first allow sval to be unset.

--- a/lex.c
+++ b/lex.c
@@ -79,7 +79,7 @@
 	return c;
 }
 
-int gettok(char **pbuf, int *psz)	/* get next input token */
+static int gettok(char **pbuf, int *psz, Awkfloat *fp)	/* get next input token */
 {
 	int c;
 	char *buf = *pbuf;
@@ -108,6 +108,7 @@
 				break;
 			}
 		}
+		c = 'a';
 	} else {	/* it's a number */
 		char *rem;
 		/* read input until can't be a number */
@@ -124,13 +125,14 @@
 			}
 		}
 		*bp = 0;
-		strtod(buf, &rem);	/* parse the number */
+		to_number(buf, fp, &rem);	/* parse the number */
 		unputstr(rem);		/* put rest back for later */
 		rem[0] = 0;
+		c = '0';
 	}
 	*pbuf = buf;
 	*psz = sz;
-	return buf[0];
+	return c;
 }
 
 int	word(char *);
@@ -142,6 +144,7 @@
 int yylex(void)
 {
 	int c;
+	Awkfloat f;
 	static char *buf = 0;
 	static int bufsize = 500;
 
@@ -156,14 +159,14 @@
 		return regexpr();
 	}
 	for (;;) {
-		c = gettok(&buf, &bufsize);
+		c = gettok(&buf, &bufsize, &f);
 		if (c == 0)
 			return 0;
-		if (isalpha(c) || c == '_')
+		if (c == 'a')
 			return word(buf);
-		if (isdigit(c) || c == '.') {
-			yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab);
-			/* should this also have STR set? */
+		if (c == '0') {
+			yylval.cp = setsymtab(buf, tostring(buf), f, CON|NUM, symtab);
+			/* should this also have STR set? */	/* FIXME: yes. */
 			RET(NUMBER);
 		}
 	
@@ -273,7 +276,7 @@
 	
 		case '$':
 			/* BUG: awkward, if not wrong */
-			c = gettok(&buf, &bufsize);
+			c = gettok(&buf, &bufsize, &f);
 			if (c == '(' || c == '[' || (infunc && isarg(buf) >= 0)) {
 				unputstr(buf);
 				RET(INDIRECT);
--- a/lib.c
+++ b/lib.c
@@ -121,7 +121,7 @@
 					xfree(fldtab[0]->sval);
 				fldtab[0]->sval = buf;	/* buf == record */
 				fldtab[0]->tval = REC | STR | DONTFREE;
-				if (to_number(fldtab[0]->sval, &fldtab[0]->fval))
+				if (to_number(fldtab[0]->sval, &fldtab[0]->fval, nil))
 					fldtab[0]->tval |= NUM;
 			}
 			setfval(nrloc, nrloc->fval+1);
@@ -211,7 +211,7 @@
 	p = qstring(p, '\0');
 	q = setsymtab(s, p, 0.0, STR, symtab);
 	setsval(q, p);
-	if (to_number(q->sval, &q->fval))
+	if (to_number(q->sval, &q->fval, nil))
 		q->tval |= NUM;
 	   dprint( ("command line set %s to |%s|\n", s, p) );
 }
@@ -301,7 +301,7 @@
 	donefld = 1;
 	for (j = 1; j <= lastfld; j++) {
 		p = fldtab[j];
-		if (to_number(p->sval, &p->fval))
+		if (to_number(p->sval, &p->fval, nil))
 			p->tval |= NUM;
 	}
 	setfval(nfloc, (Awkfloat) lastfld);
@@ -635,12 +635,14 @@
 	return *s == '=' && s > os && *(s+1) != '=';
 }
 
-static int is_float(char *s, Awkfloat *fp)
+static int is_float(char *s, Awkfloat *fp, char **tp)
 {
 	char c, *p, *q;
 	Awkfloat f;
 
 	f = *fp = strtod(s, &p);
+	if (tp != nil)
+		*tp = p;
 	if (p == s)
 		return 0;
 	else if (isInf(f, 1) || isInf(f, -1) || isNaN(f))
@@ -665,7 +667,7 @@
 	return 1;
 }
 
-int to_number(char *s, Awkfloat *fp)
+int to_number(char *s, Awkfloat *fp, char **tp)
 {
 	vlong v;
 	char *p, *q;
@@ -672,6 +674,8 @@
 
 	v = strtoll(s, &p, 0);
 	*fp = (Awkfloat)v;
+	if (tp != nil)
+		*tp = p;
 	switch(*p){
 	case '.':
 	case 'E':
@@ -680,7 +684,7 @@
 	case 'e':
 	case 'i':
 	case 'n':
-		if (is_float(s, fp))
+		if (is_float(s, fp, tp))
 			return NUM;
 		return 0;
 	case '\0':
--- a/proto.h
+++ b/proto.h
@@ -93,7 +93,7 @@
 extern	void	bclass(int);
 extern	double	errcheck(double, char *);
 extern	int	isclvar(char *);
-extern	int	to_number(char *, Awkfloat *);
+extern	int	to_number(char *, Awkfloat *, char **);
 
 extern	int	adjbuf(char **pb, int *sz, int min, int q, char **pbp, char *what);
 extern	void	run(Node *);
--- a/run.c
+++ b/run.c
@@ -405,7 +405,7 @@
 				tfree(x);
 		} else {			/* getline <file */
 			setsval(fldtab[0], buf);
-			if (to_number(fldtab[0]->sval, &fldtab[0]->fval))
+			if (to_number(fldtab[0]->sval, &fldtab[0]->fval, nil))
 				fldtab[0]->tval |= NUM;
 		}
 	} else {			/* bare getline; use current input */
@@ -711,7 +711,7 @@
 	x = execute(a[0]);
 	m = (int) getfval(x);
 	if (m == 0) {
-		if (!to_number(s = getsval(x), &x->fval))	/* suspicion! */
+		if (!to_number(s = getsval(x), &x->fval, nil))	/* suspicion! */
 			FATAL("illegal field $(%s), name \"%s\"", s, x->nval);
 			/* BUG: can x->nval ever be null??? */
 	}
@@ -1280,7 +1280,7 @@
 				sprint(num, "%d", n);
 				temp = *patbeg;
 				*patbeg = '\0';
-				if (to_number(t, &f))
+				if (to_number(t, &f, nil))
 					setsymtab(num, t, f, STR|NUM, (Array *) ap->sval);
 				else
 					setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
@@ -1296,7 +1296,7 @@
 		}
 		n++;
 		sprint(num, "%d", n);
-		if (to_number(t, &f))
+		if (to_number(t, &f, nil))
 			setsymtab(num, t, f, STR|NUM, (Array *) ap->sval);
 		else
 			setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
@@ -1317,7 +1317,7 @@
 			temp = *s;
 			*s = '\0';
 			sprint(num, "%d", n);
-			if (to_number(t, &f))
+			if (to_number(t, &f, nil))
 				setsymtab(num, t, f, STR|NUM, (Array *) ap->sval);
 			else
 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
@@ -1349,7 +1349,7 @@
 			temp = *s;
 			*s = '\0';
 			sprint(num, "%d", n);
-			if (to_number(t, &f))
+			if (to_number(t, &f, nil))
 				setsymtab(num, t, f, STR|NUM, (Array *) ap->sval);
 			else
 				setsymtab(num, t, 0.0, STR, (Array *) ap->sval);
--- a/tran.c
+++ b/tran.c
@@ -82,7 +82,7 @@
 	cp->sval = (char *) ARGVtab;
 	for (i = 0; i < ac; i++) {
 		sprint(temp, "%d", i);
-		if (to_number(*av, &f))
+		if (to_number(*av, &f, nil))
 			setsymtab(temp, *av, f, STR|NUM, ARGVtab);
 		else
 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
@@ -109,7 +109,7 @@
 				continue;
 			if ((v = getenv(k)) == nil)
 				continue;
-			if (to_number(v, &f))
+			if (to_number(v, &f, nil))
 				setsymtab(k, v, f, STR|NUM, ENVtab);
 			else
 				setsymtab(k, v, 0.0, STR, ENVtab);
@@ -336,7 +336,7 @@
 		recbld();
 	if (!isnum(vp)) {	/* not a number */
 		vp->fval = 0;
-		if (to_number(vp->sval, &vp->fval)) {
+		if (to_number(vp->sval, &vp->fval, nil)) {
 			if (!(vp->tval&CON))
 				vp->tval |= NUM;	/* make NUM only sparingly */
 		}
--