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