Mon Aug 31 23:36:58 2020 UTC ()
Don't try so hard to convert strings into numbers. Results in bogus
conversions like:

% awk 'BEGIN { print "nanotime" + 123 }'
nan
% awk 'BEGIN { print "microtime" + 123 }'
123
% awk 'BEGIN { print "inftime" + 123 }'
inf


(christos)
diff -r1.11 -r1.12 src/external/historical/nawk/dist/tran.c

cvs diff -r1.11 -r1.12 src/external/historical/nawk/dist/tran.c (switch to unified diff)

--- src/external/historical/nawk/dist/tran.c 2020/02/18 21:12:21 1.11
+++ src/external/historical/nawk/dist/tran.c 2020/08/31 23:36:58 1.12
@@ -1,640 +1,643 @@ @@ -1,640 +1,643 @@
1/**************************************************************** 1/****************************************************************
2Copyright (C) Lucent Technologies 1997 2Copyright (C) Lucent Technologies 1997
3All Rights Reserved 3All Rights Reserved
4 4
5Permission to use, copy, modify, and distribute this software and 5Permission to use, copy, modify, and distribute this software and
6its documentation for any purpose and without fee is hereby 6its documentation for any purpose and without fee is hereby
7granted, provided that the above copyright notice appear in all 7granted, provided that the above copyright notice appear in all
8copies and that both that the copyright notice and this 8copies and that both that the copyright notice and this
9permission notice and warranty disclaimer appear in supporting 9permission notice and warranty disclaimer appear in supporting
10documentation, and that the name Lucent Technologies or any of 10documentation, and that the name Lucent Technologies or any of
11its entities not be used in advertising or publicity pertaining 11its entities not be used in advertising or publicity pertaining
12to distribution of the software without specific, written prior 12to distribution of the software without specific, written prior
13permission. 13permission.
14 14
15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 16INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 17IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 20IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22THIS SOFTWARE. 22THIS SOFTWARE.
23****************************************************************/ 23****************************************************************/
24 24
25#if HAVE_NBTOOL_CONFIG_H 25#if HAVE_NBTOOL_CONFIG_H
26#include "nbtool_config.h" 26#include "nbtool_config.h"
27#endif 27#endif
28 28
29#define DEBUG 29#define DEBUG
30#include <stdio.h> 30#include <stdio.h>
31#include <math.h> 31#include <math.h>
32#include <ctype.h> 32#include <ctype.h>
33#include <string.h> 33#include <string.h>
34#include <stdlib.h> 34#include <stdlib.h>
35#include "awk.h" 35#include "awk.h"
36#include "awkgram.h" 36#include "awkgram.h"
37 37
38#define FULLTAB 2 /* rehash when table gets this x full */ 38#define FULLTAB 2 /* rehash when table gets this x full */
39#define GROWTAB 4 /* grow table by this factor */ 39#define GROWTAB 4 /* grow table by this factor */
40 40
41Array *symtab; /* main symbol table */ 41Array *symtab; /* main symbol table */
42 42
43char **FS; /* initial field sep */ 43char **FS; /* initial field sep */
44char **RS; /* initial record sep */ 44char **RS; /* initial record sep */
45char **OFS; /* output field sep */ 45char **OFS; /* output field sep */
46char **ORS; /* output record sep */ 46char **ORS; /* output record sep */
47char **OFMT; /* output format for numbers */ 47char **OFMT; /* output format for numbers */
48char **CONVFMT; /* format for conversions in getsval */ 48char **CONVFMT; /* format for conversions in getsval */
49Awkfloat *NF; /* number of fields in current record */ 49Awkfloat *NF; /* number of fields in current record */
50Awkfloat *NR; /* number of current record */ 50Awkfloat *NR; /* number of current record */
51Awkfloat *FNR; /* number of current record in current file */ 51Awkfloat *FNR; /* number of current record in current file */
52char **FILENAME; /* current filename argument */ 52char **FILENAME; /* current filename argument */
53Awkfloat *ARGC; /* number of arguments from command line */ 53Awkfloat *ARGC; /* number of arguments from command line */
54char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 54char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
55Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 55Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
56Awkfloat *RLENGTH; /* length of same */ 56Awkfloat *RLENGTH; /* length of same */
57 57
58Cell *fsloc; /* FS */ 58Cell *fsloc; /* FS */
59Cell *nrloc; /* NR */ 59Cell *nrloc; /* NR */
60Cell *nfloc; /* NF */ 60Cell *nfloc; /* NF */
61Cell *fnrloc; /* FNR */ 61Cell *fnrloc; /* FNR */
62Cell *ofsloc; /* OFS */ 62Cell *ofsloc; /* OFS */
63Cell *orsloc; /* ORS */ 63Cell *orsloc; /* ORS */
64Cell *rsloc; /* RS */ 64Cell *rsloc; /* RS */
65Array *ARGVtab; /* symbol table containing ARGV[...] */ 65Array *ARGVtab; /* symbol table containing ARGV[...] */
66Array *ENVtab; /* symbol table containing ENVIRON[...] */ 66Array *ENVtab; /* symbol table containing ENVIRON[...] */
67Cell *rstartloc; /* RSTART */ 67Cell *rstartloc; /* RSTART */
68Cell *rlengthloc; /* RLENGTH */ 68Cell *rlengthloc; /* RLENGTH */
69Cell *subseploc; /* SUBSEP */ 69Cell *subseploc; /* SUBSEP */
70Cell *symtabloc; /* SYMTAB */ 70Cell *symtabloc; /* SYMTAB */
71 71
72Cell *nullloc; /* a guaranteed empty cell */ 72Cell *nullloc; /* a guaranteed empty cell */
73Node *nullnode; /* zero&null, converted into a node for comparisons */ 73Node *nullnode; /* zero&null, converted into a node for comparisons */
74Cell *literal0; 74Cell *literal0;
75 75
76extern Cell **fldtab; 76extern Cell **fldtab;
77 77
78static void 78static void
79setfree(Cell *vp) 79setfree(Cell *vp)
80{ 80{
81 if (&vp->sval == FS || &vp->sval == RS || 81 if (&vp->sval == FS || &vp->sval == RS ||
82 &vp->sval == OFS || &vp->sval == ORS || 82 &vp->sval == OFS || &vp->sval == ORS ||
83 &vp->sval == OFMT || &vp->sval == CONVFMT || 83 &vp->sval == OFMT || &vp->sval == CONVFMT ||
84 &vp->sval == FILENAME || &vp->sval == SUBSEP) 84 &vp->sval == FILENAME || &vp->sval == SUBSEP)
85 vp->tval |= DONTFREE; 85 vp->tval |= DONTFREE;
86 else 86 else
87 vp->tval &= ~DONTFREE; 87 vp->tval &= ~DONTFREE;
88} 88}
89 89
90void syminit(void) /* initialize symbol table with builtin vars */ 90void syminit(void) /* initialize symbol table with builtin vars */
91{ 91{
92 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 92 literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
93 /* this is used for if(x)... tests: */ 93 /* this is used for if(x)... tests: */
94 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 94 nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
95 nullnode = celltonode(nullloc, CCON); 95 nullnode = celltonode(nullloc, CCON);
96 96
97 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 97 fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
98 FS = &fsloc->sval; 98 FS = &fsloc->sval;
99 rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); 99 rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
100 RS = &rsloc->sval; 100 RS = &rsloc->sval;
101 ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); 101 ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
102 OFS = &ofsloc->sval; 102 OFS = &ofsloc->sval;
103 orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); 103 orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
104 ORS = &orsloc->sval; 104 ORS = &orsloc->sval;
105 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 105 OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
106 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 106 CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
107 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 107 FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
108 nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 108 nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
109 NF = &nfloc->fval; 109 NF = &nfloc->fval;
110 nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 110 nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
111 NR = &nrloc->fval; 111 NR = &nrloc->fval;
112 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 112 fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
113 FNR = &fnrloc->fval; 113 FNR = &fnrloc->fval;
114 subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); 114 subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
115 SUBSEP = &subseploc->sval; 115 SUBSEP = &subseploc->sval;
116 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 116 rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
117 RSTART = &rstartloc->fval; 117 RSTART = &rstartloc->fval;
118 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 118 rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
119 RLENGTH = &rlengthloc->fval; 119 RLENGTH = &rlengthloc->fval;
120 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 120 symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
121 free(symtabloc->sval); 121 free(symtabloc->sval);
122 symtabloc->sval = (char *) symtab; 122 symtabloc->sval = (char *) symtab;
123} 123}
124 124
125void arginit(int ac, char **av) /* set up ARGV and ARGC */ 125void arginit(int ac, char **av) /* set up ARGV and ARGC */
126{ 126{
127 Cell *cp; 127 Cell *cp;
128 int i; 128 int i;
129 char temp[50]; 129 char temp[50];
130 130
131 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 131 ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
132 cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 132 cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
133 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 133 ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
134 free(cp->sval); 134 free(cp->sval);
135 cp->sval = (char *) ARGVtab; 135 cp->sval = (char *) ARGVtab;
136 for (i = 0; i < ac; i++) { 136 for (i = 0; i < ac; i++) {
137 sprintf(temp, "%d", i); 137 sprintf(temp, "%d", i);
138 if (is_number(*av)) 138 if (is_number(*av))
139 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 139 setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
140 else 140 else
141 setsymtab(temp, *av, 0.0, STR, ARGVtab); 141 setsymtab(temp, *av, 0.0, STR, ARGVtab);
142 av++; 142 av++;
143 } 143 }
144} 144}
145 145
146void envinit(char **envp) /* set up ENVIRON variable */ 146void envinit(char **envp) /* set up ENVIRON variable */
147{ 147{
148 Cell *cp; 148 Cell *cp;
149 char *p; 149 char *p;
150 150
151 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 151 cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
152 ENVtab = makesymtab(NSYMTAB); 152 ENVtab = makesymtab(NSYMTAB);
153 free(cp->sval); 153 free(cp->sval);
154 cp->sval = (char *) ENVtab; 154 cp->sval = (char *) ENVtab;
155 for ( ; *envp; envp++) { 155 for ( ; *envp; envp++) {
156 if ((p = strchr(*envp, '=')) == NULL) 156 if ((p = strchr(*envp, '=')) == NULL)
157 continue; 157 continue;
158 if( p == *envp ) /* no left hand side name in env string */ 158 if( p == *envp ) /* no left hand side name in env string */
159 continue; 159 continue;
160 *p++ = 0; /* split into two strings at = */ 160 *p++ = 0; /* split into two strings at = */
161 if (is_number(p)) 161 if (is_number(p))
162 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 162 setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
163 else 163 else
164 setsymtab(*envp, p, 0.0, STR, ENVtab); 164 setsymtab(*envp, p, 0.0, STR, ENVtab);
165 p[-1] = '='; /* restore in case env is passed down to a shell */ 165 p[-1] = '='; /* restore in case env is passed down to a shell */
166 } 166 }
167} 167}
168 168
169Array *makesymtab(int n) /* make a new symbol table */ 169Array *makesymtab(int n) /* make a new symbol table */
170{ 170{
171 Array *ap; 171 Array *ap;
172 Cell **tp; 172 Cell **tp;
173 173
174 ap = malloc(sizeof(*ap)); 174 ap = malloc(sizeof(*ap));
175 tp = calloc(n, sizeof(*tp)); 175 tp = calloc(n, sizeof(*tp));
176 if (ap == NULL || tp == NULL) 176 if (ap == NULL || tp == NULL)
177 FATAL("out of space in makesymtab"); 177 FATAL("out of space in makesymtab");
178 ap->nelem = 0; 178 ap->nelem = 0;
179 ap->size = n; 179 ap->size = n;
180 ap->tab = tp; 180 ap->tab = tp;
181 return(ap); 181 return(ap);
182} 182}
183 183
184void freesymtab(Cell *ap) /* free a symbol table */ 184void freesymtab(Cell *ap) /* free a symbol table */
185{ 185{
186 Cell *cp, *temp; 186 Cell *cp, *temp;
187 Array *tp; 187 Array *tp;
188 int i; 188 int i;
189 189
190 if (!isarr(ap)) 190 if (!isarr(ap))
191 return; 191 return;
192 tp = (Array *) ap->sval; 192 tp = (Array *) ap->sval;
193 if (tp == NULL) 193 if (tp == NULL)
194 return; 194 return;
195 for (i = 0; i < tp->size; i++) { 195 for (i = 0; i < tp->size; i++) {
196 for (cp = tp->tab[i]; cp != NULL; cp = temp) { 196 for (cp = tp->tab[i]; cp != NULL; cp = temp) {
197 xfree(cp->nval); 197 xfree(cp->nval);
198 if (freeable(cp)) 198 if (freeable(cp))
199 xfree(cp->sval); 199 xfree(cp->sval);
200 temp = cp->cnext; /* avoids freeing then using */ 200 temp = cp->cnext; /* avoids freeing then using */
201 free(cp); 201 free(cp);
202 tp->nelem--; 202 tp->nelem--;
203 } 203 }
204 tp->tab[i] = NULL; 204 tp->tab[i] = NULL;
205 } 205 }
206 if (tp->nelem != 0) 206 if (tp->nelem != 0)
207 WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 207 WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
208 free(tp->tab); 208 free(tp->tab);
209 free(tp); 209 free(tp);
210} 210}
211 211
212void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 212void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
213{ 213{
214 Array *tp; 214 Array *tp;
215 Cell *p, *prev = NULL; 215 Cell *p, *prev = NULL;
216 int h; 216 int h;
217 217
218 tp = (Array *) ap->sval; 218 tp = (Array *) ap->sval;
219 h = hash(s, tp->size); 219 h = hash(s, tp->size);
220 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 220 for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
221 if (strcmp(s, p->nval) == 0) { 221 if (strcmp(s, p->nval) == 0) {
222 if (prev == NULL) /* 1st one */ 222 if (prev == NULL) /* 1st one */
223 tp->tab[h] = p->cnext; 223 tp->tab[h] = p->cnext;
224 else /* middle somewhere */ 224 else /* middle somewhere */
225 prev->cnext = p->cnext; 225 prev->cnext = p->cnext;
226 if (freeable(p)) 226 if (freeable(p))
227 xfree(p->sval); 227 xfree(p->sval);
228 free(p->nval); 228 free(p->nval);
229 free(p); 229 free(p);
230 tp->nelem--; 230 tp->nelem--;
231 return; 231 return;
232 } 232 }
233} 233}
234 234
235Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 235Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
236{ 236{
237 int h; 237 int h;
238 Cell *p; 238 Cell *p;
239 239
240 if (n != NULL && (p = lookup(n, tp)) != NULL) { 240 if (n != NULL && (p = lookup(n, tp)) != NULL) {
241 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 241 dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
242 (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 242 (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
243 return(p); 243 return(p);
244 } 244 }
245 p = malloc(sizeof(*p)); 245 p = malloc(sizeof(*p));
246 if (p == NULL) 246 if (p == NULL)
247 FATAL("out of space for symbol table at %s", n); 247 FATAL("out of space for symbol table at %s", n);
248 p->nval = tostring(n); 248 p->nval = tostring(n);
249 p->sval = s ? tostring(s) : tostring(""); 249 p->sval = s ? tostring(s) : tostring("");
250 p->fval = f; 250 p->fval = f;
251 p->tval = t; 251 p->tval = t;
252 p->csub = CUNK; 252 p->csub = CUNK;
253 p->ctype = OCELL; 253 p->ctype = OCELL;
254 tp->nelem++; 254 tp->nelem++;
255 if (tp->nelem > FULLTAB * tp->size) 255 if (tp->nelem > FULLTAB * tp->size)
256 rehash(tp); 256 rehash(tp);
257 h = hash(n, tp->size); 257 h = hash(n, tp->size);
258 p->cnext = tp->tab[h]; 258 p->cnext = tp->tab[h];
259 tp->tab[h] = p; 259 tp->tab[h] = p;
260 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 260 dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
261 (void*)p, p->nval, p->sval, p->fval, p->tval) ); 261 (void*)p, p->nval, p->sval, p->fval, p->tval) );
262 return(p); 262 return(p);
263} 263}
264 264
265int hash(const char *s, int n) /* form hash value for string s */ 265int hash(const char *s, int n) /* form hash value for string s */
266{ 266{
267 unsigned hashval; 267 unsigned hashval;
268 268
269 for (hashval = 0; *s != '\0'; s++) 269 for (hashval = 0; *s != '\0'; s++)
270 hashval = (*s + 31 * hashval); 270 hashval = (*s + 31 * hashval);
271 return hashval % n; 271 return hashval % n;
272} 272}
273 273
274void rehash(Array *tp) /* rehash items in small table into big one */ 274void rehash(Array *tp) /* rehash items in small table into big one */
275{ 275{
276 int i, nh, nsz; 276 int i, nh, nsz;
277 Cell *cp, *op, **np; 277 Cell *cp, *op, **np;
278 278
279 nsz = GROWTAB * tp->size; 279 nsz = GROWTAB * tp->size;
280 np = calloc(nsz, sizeof(*np)); 280 np = calloc(nsz, sizeof(*np));
281 if (np == NULL) /* can't do it, but can keep running. */ 281 if (np == NULL) /* can't do it, but can keep running. */
282 return; /* someone else will run out later. */ 282 return; /* someone else will run out later. */
283 for (i = 0; i < tp->size; i++) { 283 for (i = 0; i < tp->size; i++) {
284 for (cp = tp->tab[i]; cp; cp = op) { 284 for (cp = tp->tab[i]; cp; cp = op) {
285 op = cp->cnext; 285 op = cp->cnext;
286 nh = hash(cp->nval, nsz); 286 nh = hash(cp->nval, nsz);
287 cp->cnext = np[nh]; 287 cp->cnext = np[nh];
288 np[nh] = cp; 288 np[nh] = cp;
289 } 289 }
290 } 290 }
291 free(tp->tab); 291 free(tp->tab);
292 tp->tab = np; 292 tp->tab = np;
293 tp->size = nsz; 293 tp->size = nsz;
294} 294}
295 295
296Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 296Cell *lookup(const char *s, Array *tp) /* look for s in tp */
297{ 297{
298 Cell *p; 298 Cell *p;
299 int h; 299 int h;
300 300
301 h = hash(s, tp->size); 301 h = hash(s, tp->size);
302 for (p = tp->tab[h]; p != NULL; p = p->cnext) 302 for (p = tp->tab[h]; p != NULL; p = p->cnext)
303 if (strcmp(s, p->nval) == 0) 303 if (strcmp(s, p->nval) == 0)
304 return(p); /* found it */ 304 return(p); /* found it */
305 return(NULL); /* not found */ 305 return(NULL); /* not found */
306} 306}
307 307
308Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 308Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
309{ 309{
310 int fldno; 310 int fldno;
311 311
312 f += 0.0; /* normalise negative zero to positive zero */ 312 f += 0.0; /* normalise negative zero to positive zero */
313 if ((vp->tval & (NUM | STR)) == 0) 313 if ((vp->tval & (NUM | STR)) == 0)
314 funnyvar(vp, "assign to"); 314 funnyvar(vp, "assign to");
315 if (isfld(vp)) { 315 if (isfld(vp)) {
316 donerec = false; /* mark $0 invalid */ 316 donerec = false; /* mark $0 invalid */
317 fldno = atoi(vp->nval); 317 fldno = atoi(vp->nval);
318 if (fldno > *NF) 318 if (fldno > *NF)
319 newfld(fldno); 319 newfld(fldno);
320 dprintf( ("setting field %d to %g\n", fldno, f) ); 320 dprintf( ("setting field %d to %g\n", fldno, f) );
321 } else if (&vp->fval == NF) { 321 } else if (&vp->fval == NF) {
322 donerec = false; /* mark $0 invalid */ 322 donerec = false; /* mark $0 invalid */
323 setlastfld(f); 323 setlastfld(f);
324 dprintf( ("setting NF to %g\n", f) ); 324 dprintf( ("setting NF to %g\n", f) );
325 } else if (isrec(vp)) { 325 } else if (isrec(vp)) {
326 donefld = false; /* mark $1... invalid */ 326 donefld = false; /* mark $1... invalid */
327 donerec = true; 327 donerec = true;
328 savefs(); 328 savefs();
329 } else if (vp == ofsloc) { 329 } else if (vp == ofsloc) {
330 if (!donerec) 330 if (!donerec)
331 recbld(); 331 recbld();
332 } 332 }
333 if (freeable(vp)) 333 if (freeable(vp))
334 xfree(vp->sval); /* free any previous string */ 334 xfree(vp->sval); /* free any previous string */
335 vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ 335 vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
336 vp->fmt = NULL; 336 vp->fmt = NULL;
337 vp->tval |= NUM; /* mark number ok */ 337 vp->tval |= NUM; /* mark number ok */
338 if (f == -0) /* who would have thought this possible? */ 338 if (f == -0) /* who would have thought this possible? */
339 f = 0; 339 f = 0;
340 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); 340 dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
341 return vp->fval = f; 341 return vp->fval = f;
342} 342}
343 343
344void funnyvar(Cell *vp, const char *rw) 344void funnyvar(Cell *vp, const char *rw)
345{ 345{
346 if (isarr(vp)) 346 if (isarr(vp))
347 FATAL("can't %s %s; it's an array name.", rw, vp->nval); 347 FATAL("can't %s %s; it's an array name.", rw, vp->nval);
348 if (vp->tval & FCN) 348 if (vp->tval & FCN)
349 FATAL("can't %s %s; it's a function.", rw, vp->nval); 349 FATAL("can't %s %s; it's a function.", rw, vp->nval);
350 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 350 WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
351 (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval); 351 (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
352} 352}
353 353
354char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 354char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
355{ 355{
356 char *t; 356 char *t;
357 int fldno; 357 int fldno;
358 Awkfloat f; 358 Awkfloat f;
359 359
360 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 360 dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
361 (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 361 (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
362 if ((vp->tval & (NUM | STR)) == 0) 362 if ((vp->tval & (NUM | STR)) == 0)
363 funnyvar(vp, "assign to"); 363 funnyvar(vp, "assign to");
364 if (isfld(vp)) { 364 if (isfld(vp)) {
365 donerec = false; /* mark $0 invalid */ 365 donerec = false; /* mark $0 invalid */
366 fldno = atoi(vp->nval); 366 fldno = atoi(vp->nval);
367 if (fldno > *NF) 367 if (fldno > *NF)
368 newfld(fldno); 368 newfld(fldno);
369 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 369 dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
370 } else if (isrec(vp)) { 370 } else if (isrec(vp)) {
371 donefld = false; /* mark $1... invalid */ 371 donefld = false; /* mark $1... invalid */
372 donerec = true; 372 donerec = true;
373 savefs(); 373 savefs();
374 } else if (vp == ofsloc) { 374 } else if (vp == ofsloc) {
375 if (!donerec) 375 if (!donerec)
376 recbld(); 376 recbld();
377 } 377 }
378 t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ 378 t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
379 if (freeable(vp)) 379 if (freeable(vp))
380 xfree(vp->sval); 380 xfree(vp->sval);
381 vp->tval &= ~(NUM|CONVC|CONVO); 381 vp->tval &= ~(NUM|CONVC|CONVO);
382 vp->tval |= STR; 382 vp->tval |= STR;
383 vp->fmt = NULL; 383 vp->fmt = NULL;
384 setfree(vp); 384 setfree(vp);
385 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 385 dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
386 (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) ); 386 (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) );
387 vp->sval = t; 387 vp->sval = t;
388 if (&vp->fval == NF) { 388 if (&vp->fval == NF) {
389 donerec = false; /* mark $0 invalid */ 389 donerec = false; /* mark $0 invalid */
390 f = getfval(vp); 390 f = getfval(vp);
391 setlastfld(f); 391 setlastfld(f);
392 dprintf( ("setting NF to %g\n", f) ); 392 dprintf( ("setting NF to %g\n", f) );
393 } 393 }
394 394
395 return(vp->sval); 395 return(vp->sval);
396} 396}
397 397
398Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 398Awkfloat getfval(Cell *vp) /* get float val of a Cell */
399{ 399{
400 if ((vp->tval & (NUM | STR)) == 0) 400 if ((vp->tval & (NUM | STR)) == 0)
401 funnyvar(vp, "read value of"); 401 funnyvar(vp, "read value of");
402 if (isfld(vp) && !donefld) 402 if (isfld(vp) && !donefld)
403 fldbld(); 403 fldbld();
404 else if (isrec(vp) && !donerec) 404 else if (isrec(vp) && !donerec)
405 recbld(); 405 recbld();
406 if (!isnum(vp)) { /* not a number */ 406 if (!isnum(vp)) { /* not a number */
407 vp->fval = atof(vp->sval); /* best guess */ 407 if (is_number(vp->sval) && !(vp->tval&CON)) {
408 if (is_number(vp->sval) && !(vp->tval&CON)) 408 vp->fval = atof(vp->sval); /* best guess */
409 vp->tval |= NUM; /* make NUM only sparingly */ 409 vp->tval |= NUM; /* make NUM only sparingly */
 410 } else {
 411 vp->fval = 0;
 412 }
410 } 413 }
411 dprintf( ("getfval %p: %s = %g, t=%o\n", 414 dprintf( ("getfval %p: %s = %g, t=%o\n",
412 (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); 415 (void*)vp, NN(vp->nval), vp->fval, vp->tval) );
413 return(vp->fval); 416 return(vp->fval);
414} 417}
415 418
416static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 419static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
417{ 420{
418 char s[256]; 421 char s[256];
419 double dtemp; 422 double dtemp;
420 423
421 if ((vp->tval & (NUM | STR)) == 0) 424 if ((vp->tval & (NUM | STR)) == 0)
422 funnyvar(vp, "read value of"); 425 funnyvar(vp, "read value of");
423 if (isfld(vp) && ! donefld) 426 if (isfld(vp) && ! donefld)
424 fldbld(); 427 fldbld();
425 else if (isrec(vp) && ! donerec) 428 else if (isrec(vp) && ! donerec)
426 recbld(); 429 recbld();
427 430
428 /* 431 /*
429 * ADR: This is complicated and more fragile than is desirable. 432 * ADR: This is complicated and more fragile than is desirable.
430 * Retrieving a string value for a number associates the string 433 * Retrieving a string value for a number associates the string
431 * value with the scalar. Previously, the string value was 434 * value with the scalar. Previously, the string value was
432 * sticky, meaning if converted via OFMT that became the value 435 * sticky, meaning if converted via OFMT that became the value
433 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT 436 * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
434 * changed after a string value was retrieved, the original value 437 * changed after a string value was retrieved, the original value
435 * was maintained and used. Also not per POSIX. 438 * was maintained and used. Also not per POSIX.
436 * 439 *
437 * We work around this design by adding two additional flags, 440 * We work around this design by adding two additional flags,
438 * CONVC and CONVO, indicating how the string value was 441 * CONVC and CONVO, indicating how the string value was
439 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy 442 * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
440 * of the pointer to the xFMT format string used for the 443 * of the pointer to the xFMT format string used for the
441 * conversion. This pointer is only read, **never** dereferenced. 444 * conversion. This pointer is only read, **never** dereferenced.
442 * The next time we do a conversion, if it's coming from the same 445 * The next time we do a conversion, if it's coming from the same
443 * xFMT as last time, and the pointer value is different, we 446 * xFMT as last time, and the pointer value is different, we
444 * know that the xFMT format string changed, and we need to 447 * know that the xFMT format string changed, and we need to
445 * redo the conversion. If it's the same, we don't have to. 448 * redo the conversion. If it's the same, we don't have to.
446 * 449 *
447 * There are also several cases where we don't do a conversion, 450 * There are also several cases where we don't do a conversion,
448 * such as for a field (see the checks below). 451 * such as for a field (see the checks below).
449 */ 452 */
450 453
451 /* Don't duplicate the code for actually updating the value */ 454 /* Don't duplicate the code for actually updating the value */
452#define update_str_val(vp) \ 455#define update_str_val(vp) \
453 { \ 456 { \
454 if (freeable(vp)) \ 457 if (freeable(vp)) \
455 xfree(vp->sval); \ 458 xfree(vp->sval); \
456 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ 459 if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
457 snprintf(s, sizeof (s), "%.30g", vp->fval); \ 460 snprintf(s, sizeof (s), "%.30g", vp->fval); \
458 else \ 461 else \
459 snprintf(s, sizeof (s), *fmt, vp->fval); \ 462 snprintf(s, sizeof (s), *fmt, vp->fval); \
460 vp->sval = tostring(s); \ 463 vp->sval = tostring(s); \
461 vp->tval &= ~DONTFREE; \ 464 vp->tval &= ~DONTFREE; \
462 vp->tval |= STR; \ 465 vp->tval |= STR; \
463 } 466 }
464 467
465 if (isstr(vp) == 0) { 468 if (isstr(vp) == 0) {
466 update_str_val(vp); 469 update_str_val(vp);
467 if (fmt == OFMT) { 470 if (fmt == OFMT) {
468 vp->tval &= ~CONVC; 471 vp->tval &= ~CONVC;
469 vp->tval |= CONVO; 472 vp->tval |= CONVO;
470 } else { 473 } else {
471 /* CONVFMT */ 474 /* CONVFMT */
472 vp->tval &= ~CONVO; 475 vp->tval &= ~CONVO;
473 vp->tval |= CONVC; 476 vp->tval |= CONVC;
474 } 477 }
475 vp->fmt = *fmt; 478 vp->fmt = *fmt;
476 } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { 479 } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
477 goto done; 480 goto done;
478 } else if (isstr(vp)) { 481 } else if (isstr(vp)) {
479 if (fmt == OFMT) { 482 if (fmt == OFMT) {
480 if ((vp->tval & CONVC) != 0 483 if ((vp->tval & CONVC) != 0
481 || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { 484 || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
482 update_str_val(vp); 485 update_str_val(vp);
483 vp->tval &= ~CONVC; 486 vp->tval &= ~CONVC;
484 vp->tval |= CONVO; 487 vp->tval |= CONVO;
485 vp->fmt = *fmt; 488 vp->fmt = *fmt;
486 } 489 }
487 } else { 490 } else {
488 /* CONVFMT */ 491 /* CONVFMT */
489 if ((vp->tval & CONVO) != 0 492 if ((vp->tval & CONVO) != 0
490 || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { 493 || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
491 update_str_val(vp); 494 update_str_val(vp);
492 vp->tval &= ~CONVO; 495 vp->tval &= ~CONVO;
493 vp->tval |= CONVC; 496 vp->tval |= CONVC;
494 vp->fmt = *fmt; 497 vp->fmt = *fmt;
495 } 498 }
496 } 499 }
497 } 500 }
498done: 501done:
499 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", 502 dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
500 (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 503 (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
501 return(vp->sval); 504 return(vp->sval);
502} 505}
503 506
504char *getsval(Cell *vp) /* get string val of a Cell */ 507char *getsval(Cell *vp) /* get string val of a Cell */
505{ 508{
506 return get_str_val(vp, CONVFMT); 509 return get_str_val(vp, CONVFMT);
507} 510}
508 511
509char *getpssval(Cell *vp) /* get string val of a Cell for print */ 512char *getpssval(Cell *vp) /* get string val of a Cell for print */
510{ 513{
511 return get_str_val(vp, OFMT); 514 return get_str_val(vp, OFMT);
512} 515}
513 516
514 517
515char *tostring(const char *s) /* make a copy of string s */ 518char *tostring(const char *s) /* make a copy of string s */
516{ 519{
517 char *p = strdup(s); 520 char *p = strdup(s);
518 if (p == NULL) 521 if (p == NULL)
519 FATAL("out of space in tostring on %s", s); 522 FATAL("out of space in tostring on %s", s);
520 return(p); 523 return(p);
521} 524}
522 525
523char *tostringN(const char *s, size_t n) /* make a copy of string s */ 526char *tostringN(const char *s, size_t n) /* make a copy of string s */
524{ 527{
525 char *p; 528 char *p;
526 529
527 p = malloc(n); 530 p = malloc(n);
528 if (p == NULL) 531 if (p == NULL)
529 FATAL("out of space in tostring on %s", s); 532 FATAL("out of space in tostring on %s", s);
530 strcpy(p, s); 533 strcpy(p, s);
531 return(p); 534 return(p);
532} 535}
533 536
534Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ 537Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
535{ 538{
536 Cell *c; 539 Cell *c;
537 char *p; 540 char *p;
538 char *sa = getsval(a); 541 char *sa = getsval(a);
539 char *sb = getsval(b); 542 char *sb = getsval(b);
540 size_t l = strlen(sa) + strlen(sb) + 1; 543 size_t l = strlen(sa) + strlen(sb) + 1;
541 p = malloc(l); 544 p = malloc(l);
542 if (p == NULL) 545 if (p == NULL)
543 FATAL("out of space concatenating %s and %s", sa, sb); 546 FATAL("out of space concatenating %s and %s", sa, sb);
544 snprintf(p, l, "%s%s", sa, sb); 547 snprintf(p, l, "%s%s", sa, sb);
545 548
546 l++; // add room for ' ' 549 l++; // add room for ' '
547 char *newbuf = malloc(l); 550 char *newbuf = malloc(l);
548 if (newbuf == NULL) 551 if (newbuf == NULL)
549 FATAL("out of space concatenating %s and %s", sa, sb); 552 FATAL("out of space concatenating %s and %s", sa, sb);
550 // See string() in lex.c; a string "xx" is stored in the symbol 553 // See string() in lex.c; a string "xx" is stored in the symbol
551 // table as "xx ". 554 // table as "xx ".
552 snprintf(newbuf, l, "%s ", p); 555 snprintf(newbuf, l, "%s ", p);
553 c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); 556 c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
554 free(p); 557 free(p);
555 free(newbuf); 558 free(newbuf);
556 return c; 559 return c;
557} 560}
558 561
559char *qstring(const char *is, int delim) /* collect string up to next delim */ 562char *qstring(const char *is, int delim) /* collect string up to next delim */
560{ 563{
561 const char *os = is; 564 const char *os = is;
562 int c, n; 565 int c, n;
563 const uschar *s = (const uschar *) is; 566 const uschar *s = (const uschar *) is;
564 uschar *buf, *bp; 567 uschar *buf, *bp;
565 568
566 if ((buf = malloc(strlen(is)+3)) == NULL) 569 if ((buf = malloc(strlen(is)+3)) == NULL)
567 FATAL( "out of space in qstring(%s)", s); 570 FATAL( "out of space in qstring(%s)", s);
568 for (bp = buf; (c = *s) != delim; s++) { 571 for (bp = buf; (c = *s) != delim; s++) {
569 if (c == '\n') 572 if (c == '\n')
570 SYNTAX( "newline in string %.20s...", os ); 573 SYNTAX( "newline in string %.20s...", os );
571 else if (c != '\\') 574 else if (c != '\\')
572 *bp++ = c; 575 *bp++ = c;
573 else { /* \something */ 576 else { /* \something */
574 c = *++s; 577 c = *++s;
575 if (c == 0) { /* \ at end */ 578 if (c == 0) { /* \ at end */
576 *bp++ = '\\'; 579 *bp++ = '\\';
577 break; /* for loop */ 580 break; /* for loop */
578 } 581 }
579 switch (c) { 582 switch (c) {
580 case '\\': *bp++ = '\\'; break; 583 case '\\': *bp++ = '\\'; break;
581 case 'n': *bp++ = '\n'; break; 584 case 'n': *bp++ = '\n'; break;
582 case 't': *bp++ = '\t'; break; 585 case 't': *bp++ = '\t'; break;
583 case 'b': *bp++ = '\b'; break; 586 case 'b': *bp++ = '\b'; break;
584 case 'f': *bp++ = '\f'; break; 587 case 'f': *bp++ = '\f'; break;
585 case 'r': *bp++ = '\r'; break; 588 case 'r': *bp++ = '\r'; break;
586 case 'v': *bp++ = '\v'; break; 589 case 'v': *bp++ = '\v'; break;
587 case 'a': *bp++ = '\a'; break; 590 case 'a': *bp++ = '\a'; break;
588 default: 591 default:
589 if (!isdigit(c)) { 592 if (!isdigit(c)) {
590 *bp++ = c; 593 *bp++ = c;
591 break; 594 break;
592 } 595 }
593 n = c - '0'; 596 n = c - '0';
594 if (isdigit(s[1])) { 597 if (isdigit(s[1])) {
595 n = 8 * n + *++s - '0'; 598 n = 8 * n + *++s - '0';
596 if (isdigit(s[1])) 599 if (isdigit(s[1]))
597 n = 8 * n + *++s - '0'; 600 n = 8 * n + *++s - '0';
598 } 601 }
599 *bp++ = n; 602 *bp++ = n;
600 break; 603 break;
601 } 604 }
602 } 605 }
603 } 606 }
604 *bp++ = 0; 607 *bp++ = 0;
605 return (char *) buf; 608 return (char *) buf;
606} 609}
607 610
608const char *flags2str(int flags) 611const char *flags2str(int flags)
609{ 612{
610 static const struct ftab { 613 static const struct ftab {
611 const char *name; 614 const char *name;
612 int value; 615 int value;
613 } flagtab[] = { 616 } flagtab[] = {
614 { "NUM", NUM }, 617 { "NUM", NUM },
615 { "STR", STR }, 618 { "STR", STR },
616 { "DONTFREE", DONTFREE }, 619 { "DONTFREE", DONTFREE },
617 { "CON", CON }, 620 { "CON", CON },
618 { "ARR", ARR }, 621 { "ARR", ARR },
619 { "FCN", FCN }, 622 { "FCN", FCN },
620 { "FLD", FLD }, 623 { "FLD", FLD },
621 { "REC", REC }, 624 { "REC", REC },
622 { "CONVC", CONVC }, 625 { "CONVC", CONVC },
623 { "CONVO", CONVO }, 626 { "CONVO", CONVO },
624 { NULL, 0 } 627 { NULL, 0 }
625 }; 628 };
626 static char buf[100]; 629 static char buf[100];
627 int i; 630 int i;
628 char *cp = buf; 631 char *cp = buf;
629 632
630 for (i = 0; flagtab[i].name != NULL; i++) { 633 for (i = 0; flagtab[i].name != NULL; i++) {
631 if ((flags & flagtab[i].value) != 0) { 634 if ((flags & flagtab[i].value) != 0) {
632 if (cp > buf) 635 if (cp > buf)
633 *cp++ = '|'; 636 *cp++ = '|';
634 strcpy(cp, flagtab[i].name); 637 strcpy(cp, flagtab[i].name);
635 cp += strlen(cp); 638 cp += strlen(cp);
636 } 639 }
637 } 640 }
638 641
639 return buf; 642 return buf;
640} 643}