14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos
254b588458SPeter Avalos #define DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <math.h>
284b588458SPeter Avalos #include <ctype.h>
294b588458SPeter Avalos #include <string.h>
304b588458SPeter Avalos #include <stdlib.h>
314b588458SPeter Avalos #include "awk.h"
324b588458SPeter Avalos
334b588458SPeter Avalos #define FULLTAB 2 /* rehash when table gets this x full */
344b588458SPeter Avalos #define GROWTAB 4 /* grow table by this factor */
354b588458SPeter Avalos
364b588458SPeter Avalos Array *symtab; /* main symbol table */
374b588458SPeter Avalos
384b588458SPeter Avalos char **FS; /* initial field sep */
394b588458SPeter Avalos char **RS; /* initial record sep */
404b588458SPeter Avalos char **OFS; /* output field sep */
414b588458SPeter Avalos char **ORS; /* output record sep */
424b588458SPeter Avalos char **OFMT; /* output format for numbers */
434b588458SPeter Avalos char **CONVFMT; /* format for conversions in getsval */
444b588458SPeter Avalos Awkfloat *NF; /* number of fields in current record */
454b588458SPeter Avalos Awkfloat *NR; /* number of current record */
464b588458SPeter Avalos Awkfloat *FNR; /* number of current record in current file */
474b588458SPeter Avalos char **FILENAME; /* current filename argument */
484b588458SPeter Avalos Awkfloat *ARGC; /* number of arguments from command line */
494b588458SPeter Avalos char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
504b588458SPeter Avalos Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
514b588458SPeter Avalos Awkfloat *RLENGTH; /* length of same */
524b588458SPeter Avalos
534b588458SPeter Avalos Cell *fsloc; /* FS */
544b588458SPeter Avalos Cell *nrloc; /* NR */
554b588458SPeter Avalos Cell *nfloc; /* NF */
564b588458SPeter Avalos Cell *fnrloc; /* FNR */
571d48fce0SDaniel Fojt Cell *ofsloc; /* OFS */
581d48fce0SDaniel Fojt Cell *orsloc; /* ORS */
591d48fce0SDaniel Fojt Cell *rsloc; /* RS */
604b588458SPeter Avalos Array *ARGVtab; /* symbol table containing ARGV[...] */
614b588458SPeter Avalos Array *ENVtab; /* symbol table containing ENVIRON[...] */
624b588458SPeter Avalos Cell *rstartloc; /* RSTART */
634b588458SPeter Avalos Cell *rlengthloc; /* RLENGTH */
641d48fce0SDaniel Fojt Cell *subseploc; /* SUBSEP */
654b588458SPeter Avalos Cell *symtabloc; /* SYMTAB */
664b588458SPeter Avalos
674b588458SPeter Avalos Cell *nullloc; /* a guaranteed empty cell */
684b588458SPeter Avalos Node *nullnode; /* zero&null, converted into a node for comparisons */
694b588458SPeter Avalos Cell *literal0;
704b588458SPeter Avalos
714b588458SPeter Avalos extern Cell **fldtab;
724b588458SPeter Avalos
syminit(void)734b588458SPeter Avalos void syminit(void) /* initialize symbol table with builtin vars */
744b588458SPeter Avalos {
754b588458SPeter Avalos literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
764b588458SPeter Avalos /* this is used for if(x)... tests: */
774b588458SPeter Avalos nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
784b588458SPeter Avalos nullnode = celltonode(nullloc, CCON);
794b588458SPeter Avalos
804b588458SPeter Avalos fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
814b588458SPeter Avalos FS = &fsloc->sval;
821d48fce0SDaniel Fojt rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab);
831d48fce0SDaniel Fojt RS = &rsloc->sval;
841d48fce0SDaniel Fojt ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab);
851d48fce0SDaniel Fojt OFS = &ofsloc->sval;
861d48fce0SDaniel Fojt orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab);
871d48fce0SDaniel Fojt ORS = &orsloc->sval;
884b588458SPeter Avalos OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
894b588458SPeter Avalos CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
904b588458SPeter Avalos FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
914b588458SPeter Avalos nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
924b588458SPeter Avalos NF = &nfloc->fval;
934b588458SPeter Avalos nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
944b588458SPeter Avalos NR = &nrloc->fval;
954b588458SPeter Avalos fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
964b588458SPeter Avalos FNR = &fnrloc->fval;
971d48fce0SDaniel Fojt subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab);
981d48fce0SDaniel Fojt SUBSEP = &subseploc->sval;
994b588458SPeter Avalos rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
1004b588458SPeter Avalos RSTART = &rstartloc->fval;
1014b588458SPeter Avalos rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
1024b588458SPeter Avalos RLENGTH = &rlengthloc->fval;
1034b588458SPeter Avalos symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
1041d48fce0SDaniel Fojt free(symtabloc->sval);
1054b588458SPeter Avalos symtabloc->sval = (char *) symtab;
1064b588458SPeter Avalos }
1074b588458SPeter Avalos
arginit(int ac,char ** av)1084b588458SPeter Avalos void arginit(int ac, char **av) /* set up ARGV and ARGC */
1094b588458SPeter Avalos {
1104b588458SPeter Avalos Cell *cp;
1114b588458SPeter Avalos int i;
1124b588458SPeter Avalos char temp[50];
1134b588458SPeter Avalos
1144b588458SPeter Avalos ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1154b588458SPeter Avalos cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1164b588458SPeter Avalos ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
1171d48fce0SDaniel Fojt free(cp->sval);
1184b588458SPeter Avalos cp->sval = (char *) ARGVtab;
1194b588458SPeter Avalos for (i = 0; i < ac; i++) {
12048f09a05SAntonio Huete Jimenez double result;
12148f09a05SAntonio Huete Jimenez
1224b588458SPeter Avalos sprintf(temp, "%d", i);
12348f09a05SAntonio Huete Jimenez if (is_number(*av, & result))
12448f09a05SAntonio Huete Jimenez setsymtab(temp, *av, result, STR|NUM, ARGVtab);
1254b588458SPeter Avalos else
1264b588458SPeter Avalos setsymtab(temp, *av, 0.0, STR, ARGVtab);
1274b588458SPeter Avalos av++;
1284b588458SPeter Avalos }
1294b588458SPeter Avalos }
1304b588458SPeter Avalos
envinit(char ** envp)1314b588458SPeter Avalos void envinit(char **envp) /* set up ENVIRON variable */
1324b588458SPeter Avalos {
1334b588458SPeter Avalos Cell *cp;
1344b588458SPeter Avalos char *p;
1354b588458SPeter Avalos
1364b588458SPeter Avalos cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1374b588458SPeter Avalos ENVtab = makesymtab(NSYMTAB);
1381d48fce0SDaniel Fojt free(cp->sval);
1394b588458SPeter Avalos cp->sval = (char *) ENVtab;
1404b588458SPeter Avalos for ( ; *envp; envp++) {
14148f09a05SAntonio Huete Jimenez double result;
14248f09a05SAntonio Huete Jimenez
1434b588458SPeter Avalos if ((p = strchr(*envp, '=')) == NULL)
1444b588458SPeter Avalos continue;
1454b588458SPeter Avalos if( p == *envp ) /* no left hand side name in env string */
1464b588458SPeter Avalos continue;
1474b588458SPeter Avalos *p++ = 0; /* split into two strings at = */
14848f09a05SAntonio Huete Jimenez if (is_number(p, & result))
14948f09a05SAntonio Huete Jimenez setsymtab(*envp, p, result, STR|NUM, ENVtab);
1504b588458SPeter Avalos else
1514b588458SPeter Avalos setsymtab(*envp, p, 0.0, STR, ENVtab);
1524b588458SPeter Avalos p[-1] = '='; /* restore in case env is passed down to a shell */
1534b588458SPeter Avalos }
1544b588458SPeter Avalos }
1554b588458SPeter Avalos
makesymtab(int n)1564b588458SPeter Avalos Array *makesymtab(int n) /* make a new symbol table */
1574b588458SPeter Avalos {
1584b588458SPeter Avalos Array *ap;
1594b588458SPeter Avalos Cell **tp;
1604b588458SPeter Avalos
16148f09a05SAntonio Huete Jimenez ap = (Array *) malloc(sizeof(*ap));
16248f09a05SAntonio Huete Jimenez tp = (Cell **) calloc(n, sizeof(*tp));
1634b588458SPeter Avalos if (ap == NULL || tp == NULL)
1644b588458SPeter Avalos FATAL("out of space in makesymtab");
1654b588458SPeter Avalos ap->nelem = 0;
1664b588458SPeter Avalos ap->size = n;
1674b588458SPeter Avalos ap->tab = tp;
1684b588458SPeter Avalos return(ap);
1694b588458SPeter Avalos }
1704b588458SPeter Avalos
freesymtab(Cell * ap)1714b588458SPeter Avalos void freesymtab(Cell *ap) /* free a symbol table */
1724b588458SPeter Avalos {
1734b588458SPeter Avalos Cell *cp, *temp;
1744b588458SPeter Avalos Array *tp;
1754b588458SPeter Avalos int i;
1764b588458SPeter Avalos
1774b588458SPeter Avalos if (!isarr(ap))
1784b588458SPeter Avalos return;
1794b588458SPeter Avalos tp = (Array *) ap->sval;
1804b588458SPeter Avalos if (tp == NULL)
1814b588458SPeter Avalos return;
1824b588458SPeter Avalos for (i = 0; i < tp->size; i++) {
1834b588458SPeter Avalos for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1844b588458SPeter Avalos xfree(cp->nval);
1854b588458SPeter Avalos if (freeable(cp))
1864b588458SPeter Avalos xfree(cp->sval);
1874b588458SPeter Avalos temp = cp->cnext; /* avoids freeing then using */
1884b588458SPeter Avalos free(cp);
1894b588458SPeter Avalos tp->nelem--;
1904b588458SPeter Avalos }
1911d48fce0SDaniel Fojt tp->tab[i] = NULL;
1924b588458SPeter Avalos }
1934b588458SPeter Avalos if (tp->nelem != 0)
1944b588458SPeter Avalos WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1954b588458SPeter Avalos free(tp->tab);
1964b588458SPeter Avalos free(tp);
1974b588458SPeter Avalos }
1984b588458SPeter Avalos
freeelem(Cell * ap,const char * s)1994b588458SPeter Avalos void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */
2004b588458SPeter Avalos {
2014b588458SPeter Avalos Array *tp;
2024b588458SPeter Avalos Cell *p, *prev = NULL;
2034b588458SPeter Avalos int h;
2044b588458SPeter Avalos
2054b588458SPeter Avalos tp = (Array *) ap->sval;
2064b588458SPeter Avalos h = hash(s, tp->size);
2074b588458SPeter Avalos for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
2084b588458SPeter Avalos if (strcmp(s, p->nval) == 0) {
2094b588458SPeter Avalos if (prev == NULL) /* 1st one */
2104b588458SPeter Avalos tp->tab[h] = p->cnext;
2114b588458SPeter Avalos else /* middle somewhere */
2124b588458SPeter Avalos prev->cnext = p->cnext;
2134b588458SPeter Avalos if (freeable(p))
2144b588458SPeter Avalos xfree(p->sval);
2154b588458SPeter Avalos free(p->nval);
2164b588458SPeter Avalos free(p);
2174b588458SPeter Avalos tp->nelem--;
2184b588458SPeter Avalos return;
2194b588458SPeter Avalos }
2204b588458SPeter Avalos }
2214b588458SPeter Avalos
setsymtab(const char * n,const char * s,Awkfloat f,unsigned t,Array * tp)2224b588458SPeter Avalos Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2234b588458SPeter Avalos {
2244b588458SPeter Avalos int h;
2254b588458SPeter Avalos Cell *p;
2264b588458SPeter Avalos
2274b588458SPeter Avalos if (n != NULL && (p = lookup(n, tp)) != NULL) {
228e5e686a0SDaniel Fojt DPRINTF("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
229e5e686a0SDaniel Fojt (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval);
2304b588458SPeter Avalos return(p);
2314b588458SPeter Avalos }
23248f09a05SAntonio Huete Jimenez p = (Cell *) malloc(sizeof(*p));
2334b588458SPeter Avalos if (p == NULL)
2344b588458SPeter Avalos FATAL("out of space for symbol table at %s", n);
2354b588458SPeter Avalos p->nval = tostring(n);
2364b588458SPeter Avalos p->sval = s ? tostring(s) : tostring("");
2374b588458SPeter Avalos p->fval = f;
2384b588458SPeter Avalos p->tval = t;
2394b588458SPeter Avalos p->csub = CUNK;
2404b588458SPeter Avalos p->ctype = OCELL;
2414b588458SPeter Avalos tp->nelem++;
2424b588458SPeter Avalos if (tp->nelem > FULLTAB * tp->size)
2434b588458SPeter Avalos rehash(tp);
2444b588458SPeter Avalos h = hash(n, tp->size);
2454b588458SPeter Avalos p->cnext = tp->tab[h];
2464b588458SPeter Avalos tp->tab[h] = p;
247e5e686a0SDaniel Fojt DPRINTF("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
248e5e686a0SDaniel Fojt (void*)p, p->nval, p->sval, p->fval, p->tval);
2494b588458SPeter Avalos return(p);
2504b588458SPeter Avalos }
2514b588458SPeter Avalos
hash(const char * s,int n)2524b588458SPeter Avalos int hash(const char *s, int n) /* form hash value for string s */
2534b588458SPeter Avalos {
2544b588458SPeter Avalos unsigned hashval;
2554b588458SPeter Avalos
2564b588458SPeter Avalos for (hashval = 0; *s != '\0'; s++)
2574b588458SPeter Avalos hashval = (*s + 31 * hashval);
2584b588458SPeter Avalos return hashval % n;
2594b588458SPeter Avalos }
2604b588458SPeter Avalos
rehash(Array * tp)2614b588458SPeter Avalos void rehash(Array *tp) /* rehash items in small table into big one */
2624b588458SPeter Avalos {
2634b588458SPeter Avalos int i, nh, nsz;
2644b588458SPeter Avalos Cell *cp, *op, **np;
2654b588458SPeter Avalos
2664b588458SPeter Avalos nsz = GROWTAB * tp->size;
26748f09a05SAntonio Huete Jimenez np = (Cell **) calloc(nsz, sizeof(*np));
2684b588458SPeter Avalos if (np == NULL) /* can't do it, but can keep running. */
2694b588458SPeter Avalos return; /* someone else will run out later. */
2704b588458SPeter Avalos for (i = 0; i < tp->size; i++) {
2714b588458SPeter Avalos for (cp = tp->tab[i]; cp; cp = op) {
2724b588458SPeter Avalos op = cp->cnext;
2734b588458SPeter Avalos nh = hash(cp->nval, nsz);
2744b588458SPeter Avalos cp->cnext = np[nh];
2754b588458SPeter Avalos np[nh] = cp;
2764b588458SPeter Avalos }
2774b588458SPeter Avalos }
2784b588458SPeter Avalos free(tp->tab);
2794b588458SPeter Avalos tp->tab = np;
2804b588458SPeter Avalos tp->size = nsz;
2814b588458SPeter Avalos }
2824b588458SPeter Avalos
lookup(const char * s,Array * tp)2834b588458SPeter Avalos Cell *lookup(const char *s, Array *tp) /* look for s in tp */
2844b588458SPeter Avalos {
2854b588458SPeter Avalos Cell *p;
2864b588458SPeter Avalos int h;
2874b588458SPeter Avalos
2884b588458SPeter Avalos h = hash(s, tp->size);
2894b588458SPeter Avalos for (p = tp->tab[h]; p != NULL; p = p->cnext)
2904b588458SPeter Avalos if (strcmp(s, p->nval) == 0)
2914b588458SPeter Avalos return(p); /* found it */
2924b588458SPeter Avalos return(NULL); /* not found */
2934b588458SPeter Avalos }
2944b588458SPeter Avalos
setfval(Cell * vp,Awkfloat f)2954b588458SPeter Avalos Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
2964b588458SPeter Avalos {
2974b588458SPeter Avalos int fldno;
2984b588458SPeter Avalos
2991d48fce0SDaniel Fojt f += 0.0; /* normalise negative zero to positive zero */
3004b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0)
3014b588458SPeter Avalos funnyvar(vp, "assign to");
3024b588458SPeter Avalos if (isfld(vp)) {
3031d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */
3044b588458SPeter Avalos fldno = atoi(vp->nval);
3054b588458SPeter Avalos if (fldno > *NF)
3064b588458SPeter Avalos newfld(fldno);
307e5e686a0SDaniel Fojt DPRINTF("setting field %d to %g\n", fldno, f);
3081d48fce0SDaniel Fojt } else if (&vp->fval == NF) {
3091d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */
3101d48fce0SDaniel Fojt setlastfld(f);
311*ed569bc2SAaron LI DPRINTF("setfval: setting NF to %g\n", f);
3124b588458SPeter Avalos } else if (isrec(vp)) {
3131d48fce0SDaniel Fojt donefld = false; /* mark $1... invalid */
3141d48fce0SDaniel Fojt donerec = true;
3151d48fce0SDaniel Fojt savefs();
3161d48fce0SDaniel Fojt } else if (vp == ofsloc) {
3171d48fce0SDaniel Fojt if (!donerec)
3181d48fce0SDaniel Fojt recbld();
3194b588458SPeter Avalos }
3204b588458SPeter Avalos if (freeable(vp))
3214b588458SPeter Avalos xfree(vp->sval); /* free any previous string */
3221d48fce0SDaniel Fojt vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */
3231d48fce0SDaniel Fojt vp->fmt = NULL;
3244b588458SPeter Avalos vp->tval |= NUM; /* mark number ok */
3252078c1f0SJohn Marino if (f == -0) /* who would have thought this possible? */
3262078c1f0SJohn Marino f = 0;
327e5e686a0SDaniel Fojt DPRINTF("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval);
3284b588458SPeter Avalos return vp->fval = f;
3294b588458SPeter Avalos }
3304b588458SPeter Avalos
funnyvar(Cell * vp,const char * rw)3314b588458SPeter Avalos void funnyvar(Cell *vp, const char *rw)
3324b588458SPeter Avalos {
3334b588458SPeter Avalos if (isarr(vp))
3344b588458SPeter Avalos FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3354b588458SPeter Avalos if (vp->tval & FCN)
3364b588458SPeter Avalos FATAL("can't %s %s; it's a function.", rw, vp->nval);
3374b588458SPeter Avalos WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3381d48fce0SDaniel Fojt (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval);
3394b588458SPeter Avalos }
3404b588458SPeter Avalos
setsval(Cell * vp,const char * s)3414b588458SPeter Avalos char *setsval(Cell *vp, const char *s) /* set string val of a Cell */
3424b588458SPeter Avalos {
3434b588458SPeter Avalos char *t;
3444b588458SPeter Avalos int fldno;
3451d48fce0SDaniel Fojt Awkfloat f;
3464b588458SPeter Avalos
347e5e686a0SDaniel Fojt DPRINTF("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
348e5e686a0SDaniel Fojt (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld);
3494b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0)
3504b588458SPeter Avalos funnyvar(vp, "assign to");
351*ed569bc2SAaron LI if (CSV && (vp == rsloc))
352*ed569bc2SAaron LI WARNING("danger: don't set RS when --csv is in effect");
353*ed569bc2SAaron LI if (CSV && (vp == fsloc))
354*ed569bc2SAaron LI WARNING("danger: don't set FS when --csv is in effect");
3554b588458SPeter Avalos if (isfld(vp)) {
3561d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */
3574b588458SPeter Avalos fldno = atoi(vp->nval);
3584b588458SPeter Avalos if (fldno > *NF)
3594b588458SPeter Avalos newfld(fldno);
36048f09a05SAntonio Huete Jimenez DPRINTF("setting field %d to %s (%p)\n", fldno, s, (const void*)s);
3614b588458SPeter Avalos } else if (isrec(vp)) {
3621d48fce0SDaniel Fojt donefld = false; /* mark $1... invalid */
3631d48fce0SDaniel Fojt donerec = true;
3641d48fce0SDaniel Fojt savefs();
3651d48fce0SDaniel Fojt } else if (vp == ofsloc) {
3661d48fce0SDaniel Fojt if (!donerec)
3671d48fce0SDaniel Fojt recbld();
3684b588458SPeter Avalos }
3691d48fce0SDaniel Fojt t = s ? tostring(s) : tostring(""); /* in case it's self-assign */
3704b588458SPeter Avalos if (freeable(vp))
3714b588458SPeter Avalos xfree(vp->sval);
37248f09a05SAntonio Huete Jimenez vp->tval &= ~(NUM|DONTFREE|CONVC|CONVO);
3734b588458SPeter Avalos vp->tval |= STR;
3741d48fce0SDaniel Fojt vp->fmt = NULL;
375e5e686a0SDaniel Fojt DPRINTF("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
37648f09a05SAntonio Huete Jimenez (void*)vp, NN(vp->nval), t, (void*)t, vp->tval, donerec, donefld);
3771d48fce0SDaniel Fojt vp->sval = t;
3781d48fce0SDaniel Fojt if (&vp->fval == NF) {
3791d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */
3801d48fce0SDaniel Fojt f = getfval(vp);
3811d48fce0SDaniel Fojt setlastfld(f);
382*ed569bc2SAaron LI DPRINTF("setsval: setting NF to %g\n", f);
3831d48fce0SDaniel Fojt }
3841d48fce0SDaniel Fojt
3851d48fce0SDaniel Fojt return(vp->sval);
3864b588458SPeter Avalos }
3874b588458SPeter Avalos
getfval(Cell * vp)3884b588458SPeter Avalos Awkfloat getfval(Cell *vp) /* get float val of a Cell */
3894b588458SPeter Avalos {
3904b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0)
3914b588458SPeter Avalos funnyvar(vp, "read value of");
3921d48fce0SDaniel Fojt if (isfld(vp) && !donefld)
3934b588458SPeter Avalos fldbld();
3941d48fce0SDaniel Fojt else if (isrec(vp) && !donerec)
3954b588458SPeter Avalos recbld();
3964b588458SPeter Avalos if (!isnum(vp)) { /* not a number */
39748f09a05SAntonio Huete Jimenez double fval;
39848f09a05SAntonio Huete Jimenez bool no_trailing;
39948f09a05SAntonio Huete Jimenez
40048f09a05SAntonio Huete Jimenez if (is_valid_number(vp->sval, true, & no_trailing, & fval)) {
40148f09a05SAntonio Huete Jimenez vp->fval = fval;
40248f09a05SAntonio Huete Jimenez if (no_trailing && !(vp->tval&CON))
4034b588458SPeter Avalos vp->tval |= NUM; /* make NUM only sparingly */
40448f09a05SAntonio Huete Jimenez } else
40548f09a05SAntonio Huete Jimenez vp->fval = 0.0;
4064b588458SPeter Avalos }
407e5e686a0SDaniel Fojt DPRINTF("getfval %p: %s = %g, t=%o\n",
408e5e686a0SDaniel Fojt (void*)vp, NN(vp->nval), vp->fval, vp->tval);
4094b588458SPeter Avalos return(vp->fval);
4104b588458SPeter Avalos }
4114b588458SPeter Avalos
get_inf_nan(double d)41248f09a05SAntonio Huete Jimenez static const char *get_inf_nan(double d)
41348f09a05SAntonio Huete Jimenez {
41448f09a05SAntonio Huete Jimenez if (isinf(d)) {
41548f09a05SAntonio Huete Jimenez return (d < 0 ? "-inf" : "+inf");
41648f09a05SAntonio Huete Jimenez } else if (isnan(d)) {
41748f09a05SAntonio Huete Jimenez return (signbit(d) != 0 ? "-nan" : "+nan");
41848f09a05SAntonio Huete Jimenez } else
41948f09a05SAntonio Huete Jimenez return NULL;
42048f09a05SAntonio Huete Jimenez }
42148f09a05SAntonio Huete Jimenez
get_str_val(Cell * vp,char ** fmt)4224b588458SPeter Avalos static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */
4234b588458SPeter Avalos {
4241d48fce0SDaniel Fojt char s[256];
4254b588458SPeter Avalos double dtemp;
42648f09a05SAntonio Huete Jimenez const char *p;
4274b588458SPeter Avalos
4284b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0)
4294b588458SPeter Avalos funnyvar(vp, "read value of");
4301d48fce0SDaniel Fojt if (isfld(vp) && ! donefld)
4314b588458SPeter Avalos fldbld();
4321d48fce0SDaniel Fojt else if (isrec(vp) && ! donerec)
4334b588458SPeter Avalos recbld();
4341d48fce0SDaniel Fojt
4351d48fce0SDaniel Fojt /*
4361d48fce0SDaniel Fojt * ADR: This is complicated and more fragile than is desirable.
4371d48fce0SDaniel Fojt * Retrieving a string value for a number associates the string
4381d48fce0SDaniel Fojt * value with the scalar. Previously, the string value was
4391d48fce0SDaniel Fojt * sticky, meaning if converted via OFMT that became the value
4401d48fce0SDaniel Fojt * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT
4411d48fce0SDaniel Fojt * changed after a string value was retrieved, the original value
4421d48fce0SDaniel Fojt * was maintained and used. Also not per POSIX.
4431d48fce0SDaniel Fojt *
4441d48fce0SDaniel Fojt * We work around this design by adding two additional flags,
4451d48fce0SDaniel Fojt * CONVC and CONVO, indicating how the string value was
4461d48fce0SDaniel Fojt * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy
4471d48fce0SDaniel Fojt * of the pointer to the xFMT format string used for the
4481d48fce0SDaniel Fojt * conversion. This pointer is only read, **never** dereferenced.
4491d48fce0SDaniel Fojt * The next time we do a conversion, if it's coming from the same
4501d48fce0SDaniel Fojt * xFMT as last time, and the pointer value is different, we
4511d48fce0SDaniel Fojt * know that the xFMT format string changed, and we need to
4521d48fce0SDaniel Fojt * redo the conversion. If it's the same, we don't have to.
4531d48fce0SDaniel Fojt *
4541d48fce0SDaniel Fojt * There are also several cases where we don't do a conversion,
4551d48fce0SDaniel Fojt * such as for a field (see the checks below).
4561d48fce0SDaniel Fojt */
4571d48fce0SDaniel Fojt
4581d48fce0SDaniel Fojt /* Don't duplicate the code for actually updating the value */
4591d48fce0SDaniel Fojt #define update_str_val(vp) \
4601d48fce0SDaniel Fojt { \
4611d48fce0SDaniel Fojt if (freeable(vp)) \
4621d48fce0SDaniel Fojt xfree(vp->sval); \
46348f09a05SAntonio Huete Jimenez if ((p = get_inf_nan(vp->fval)) != NULL) \
46448f09a05SAntonio Huete Jimenez strcpy(s, p); \
46548f09a05SAntonio Huete Jimenez else if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \
4661d48fce0SDaniel Fojt snprintf(s, sizeof (s), "%.30g", vp->fval); \
4671d48fce0SDaniel Fojt else \
4681d48fce0SDaniel Fojt snprintf(s, sizeof (s), *fmt, vp->fval); \
4691d48fce0SDaniel Fojt vp->sval = tostring(s); \
4701d48fce0SDaniel Fojt vp->tval &= ~DONTFREE; \
4711d48fce0SDaniel Fojt vp->tval |= STR; \
4724b588458SPeter Avalos }
4731d48fce0SDaniel Fojt
4741d48fce0SDaniel Fojt if (isstr(vp) == 0) {
4751d48fce0SDaniel Fojt update_str_val(vp);
4761d48fce0SDaniel Fojt if (fmt == OFMT) {
4771d48fce0SDaniel Fojt vp->tval &= ~CONVC;
4781d48fce0SDaniel Fojt vp->tval |= CONVO;
4791d48fce0SDaniel Fojt } else {
4801d48fce0SDaniel Fojt /* CONVFMT */
4811d48fce0SDaniel Fojt vp->tval &= ~CONVO;
4821d48fce0SDaniel Fojt vp->tval |= CONVC;
4831d48fce0SDaniel Fojt }
4841d48fce0SDaniel Fojt vp->fmt = *fmt;
4851d48fce0SDaniel Fojt } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) {
4861d48fce0SDaniel Fojt goto done;
4871d48fce0SDaniel Fojt } else if (isstr(vp)) {
4881d48fce0SDaniel Fojt if (fmt == OFMT) {
4891d48fce0SDaniel Fojt if ((vp->tval & CONVC) != 0
4901d48fce0SDaniel Fojt || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) {
4911d48fce0SDaniel Fojt update_str_val(vp);
4921d48fce0SDaniel Fojt vp->tval &= ~CONVC;
4931d48fce0SDaniel Fojt vp->tval |= CONVO;
4941d48fce0SDaniel Fojt vp->fmt = *fmt;
4951d48fce0SDaniel Fojt }
4961d48fce0SDaniel Fojt } else {
4971d48fce0SDaniel Fojt /* CONVFMT */
4981d48fce0SDaniel Fojt if ((vp->tval & CONVO) != 0
4991d48fce0SDaniel Fojt || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) {
5001d48fce0SDaniel Fojt update_str_val(vp);
5011d48fce0SDaniel Fojt vp->tval &= ~CONVO;
5021d48fce0SDaniel Fojt vp->tval |= CONVC;
5031d48fce0SDaniel Fojt vp->fmt = *fmt;
5041d48fce0SDaniel Fojt }
5051d48fce0SDaniel Fojt }
5061d48fce0SDaniel Fojt }
5071d48fce0SDaniel Fojt done:
508e5e686a0SDaniel Fojt DPRINTF("getsval %p: %s = \"%s (%p)\", t=%o\n",
50948f09a05SAntonio Huete Jimenez (void*)vp, NN(vp->nval), vp->sval, (void*)vp->sval, vp->tval);
5104b588458SPeter Avalos return(vp->sval);
5114b588458SPeter Avalos }
5124b588458SPeter Avalos
getsval(Cell * vp)5134b588458SPeter Avalos char *getsval(Cell *vp) /* get string val of a Cell */
5144b588458SPeter Avalos {
5154b588458SPeter Avalos return get_str_val(vp, CONVFMT);
5164b588458SPeter Avalos }
5174b588458SPeter Avalos
getpssval(Cell * vp)5184b588458SPeter Avalos char *getpssval(Cell *vp) /* get string val of a Cell for print */
5194b588458SPeter Avalos {
5204b588458SPeter Avalos return get_str_val(vp, OFMT);
5214b588458SPeter Avalos }
5224b588458SPeter Avalos
5234b588458SPeter Avalos
tostring(const char * s)5244b588458SPeter Avalos char *tostring(const char *s) /* make a copy of string s */
5254b588458SPeter Avalos {
5261d48fce0SDaniel Fojt char *p = strdup(s);
5271d48fce0SDaniel Fojt if (p == NULL)
5281d48fce0SDaniel Fojt FATAL("out of space in tostring on %s", s);
5291d48fce0SDaniel Fojt return(p);
5301d48fce0SDaniel Fojt }
5311d48fce0SDaniel Fojt
tostringN(const char * s,size_t n)5321d48fce0SDaniel Fojt char *tostringN(const char *s, size_t n) /* make a copy of string s */
5331d48fce0SDaniel Fojt {
5344b588458SPeter Avalos char *p;
5354b588458SPeter Avalos
53648f09a05SAntonio Huete Jimenez p = (char *) malloc(n);
5374b588458SPeter Avalos if (p == NULL)
5384b588458SPeter Avalos FATAL("out of space in tostring on %s", s);
5394b588458SPeter Avalos strcpy(p, s);
5404b588458SPeter Avalos return(p);
5414b588458SPeter Avalos }
5424b588458SPeter Avalos
catstr(Cell * a,Cell * b)5431d48fce0SDaniel Fojt Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */
5441d48fce0SDaniel Fojt {
5451d48fce0SDaniel Fojt Cell *c;
5461d48fce0SDaniel Fojt char *p;
5471d48fce0SDaniel Fojt char *sa = getsval(a);
5481d48fce0SDaniel Fojt char *sb = getsval(b);
5491d48fce0SDaniel Fojt size_t l = strlen(sa) + strlen(sb) + 1;
55048f09a05SAntonio Huete Jimenez p = (char *) malloc(l);
5511d48fce0SDaniel Fojt if (p == NULL)
5521d48fce0SDaniel Fojt FATAL("out of space concatenating %s and %s", sa, sb);
5531d48fce0SDaniel Fojt snprintf(p, l, "%s%s", sa, sb);
5541d48fce0SDaniel Fojt
5551d48fce0SDaniel Fojt l++; // add room for ' '
55648f09a05SAntonio Huete Jimenez char *newbuf = (char *) malloc(l);
5571d48fce0SDaniel Fojt if (newbuf == NULL)
5581d48fce0SDaniel Fojt FATAL("out of space concatenating %s and %s", sa, sb);
5591d48fce0SDaniel Fojt // See string() in lex.c; a string "xx" is stored in the symbol
5601d48fce0SDaniel Fojt // table as "xx ".
5611d48fce0SDaniel Fojt snprintf(newbuf, l, "%s ", p);
5621d48fce0SDaniel Fojt c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab);
5631d48fce0SDaniel Fojt free(p);
5641d48fce0SDaniel Fojt free(newbuf);
5651d48fce0SDaniel Fojt return c;
5661d48fce0SDaniel Fojt }
5671d48fce0SDaniel Fojt
qstring(const char * is,int delim)5684b588458SPeter Avalos char *qstring(const char *is, int delim) /* collect string up to next delim */
5694b588458SPeter Avalos {
5704b588458SPeter Avalos int c, n;
5711d48fce0SDaniel Fojt const uschar *s = (const uschar *) is;
5724b588458SPeter Avalos uschar *buf, *bp;
5734b588458SPeter Avalos
57448f09a05SAntonio Huete Jimenez if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
5754b588458SPeter Avalos FATAL( "out of space in qstring(%s)", s);
5764b588458SPeter Avalos for (bp = buf; (c = *s) != delim; s++) {
5774b588458SPeter Avalos if (c == '\n')
57848f09a05SAntonio Huete Jimenez SYNTAX( "newline in string %.20s...", is );
5794b588458SPeter Avalos else if (c != '\\')
5804b588458SPeter Avalos *bp++ = c;
5814b588458SPeter Avalos else { /* \something */
5824b588458SPeter Avalos c = *++s;
5834b588458SPeter Avalos if (c == 0) { /* \ at end */
5844b588458SPeter Avalos *bp++ = '\\';
5854b588458SPeter Avalos break; /* for loop */
5864b588458SPeter Avalos }
5874b588458SPeter Avalos switch (c) {
5884b588458SPeter Avalos case '\\': *bp++ = '\\'; break;
5894b588458SPeter Avalos case 'n': *bp++ = '\n'; break;
5904b588458SPeter Avalos case 't': *bp++ = '\t'; break;
5914b588458SPeter Avalos case 'b': *bp++ = '\b'; break;
5924b588458SPeter Avalos case 'f': *bp++ = '\f'; break;
5934b588458SPeter Avalos case 'r': *bp++ = '\r'; break;
5941d48fce0SDaniel Fojt case 'v': *bp++ = '\v'; break;
5951d48fce0SDaniel Fojt case 'a': *bp++ = '\a'; break;
5964b588458SPeter Avalos default:
5974b588458SPeter Avalos if (!isdigit(c)) {
5984b588458SPeter Avalos *bp++ = c;
5994b588458SPeter Avalos break;
6004b588458SPeter Avalos }
6014b588458SPeter Avalos n = c - '0';
6024b588458SPeter Avalos if (isdigit(s[1])) {
6034b588458SPeter Avalos n = 8 * n + *++s - '0';
6044b588458SPeter Avalos if (isdigit(s[1]))
6054b588458SPeter Avalos n = 8 * n + *++s - '0';
6064b588458SPeter Avalos }
6074b588458SPeter Avalos *bp++ = n;
6084b588458SPeter Avalos break;
6094b588458SPeter Avalos }
6104b588458SPeter Avalos }
6114b588458SPeter Avalos }
6124b588458SPeter Avalos *bp++ = 0;
6134b588458SPeter Avalos return (char *) buf;
6144b588458SPeter Avalos }
6151d48fce0SDaniel Fojt
flags2str(int flags)6161d48fce0SDaniel Fojt const char *flags2str(int flags)
6171d48fce0SDaniel Fojt {
6181d48fce0SDaniel Fojt static const struct ftab {
6191d48fce0SDaniel Fojt const char *name;
6201d48fce0SDaniel Fojt int value;
6211d48fce0SDaniel Fojt } flagtab[] = {
6221d48fce0SDaniel Fojt { "NUM", NUM },
6231d48fce0SDaniel Fojt { "STR", STR },
6241d48fce0SDaniel Fojt { "DONTFREE", DONTFREE },
6251d48fce0SDaniel Fojt { "CON", CON },
6261d48fce0SDaniel Fojt { "ARR", ARR },
6271d48fce0SDaniel Fojt { "FCN", FCN },
6281d48fce0SDaniel Fojt { "FLD", FLD },
6291d48fce0SDaniel Fojt { "REC", REC },
6301d48fce0SDaniel Fojt { "CONVC", CONVC },
6311d48fce0SDaniel Fojt { "CONVO", CONVO },
6321d48fce0SDaniel Fojt { NULL, 0 }
6331d48fce0SDaniel Fojt };
6341d48fce0SDaniel Fojt static char buf[100];
6351d48fce0SDaniel Fojt int i;
6361d48fce0SDaniel Fojt char *cp = buf;
6371d48fce0SDaniel Fojt
6381d48fce0SDaniel Fojt for (i = 0; flagtab[i].name != NULL; i++) {
6391d48fce0SDaniel Fojt if ((flags & flagtab[i].value) != 0) {
6401d48fce0SDaniel Fojt if (cp > buf)
6411d48fce0SDaniel Fojt *cp++ = '|';
6421d48fce0SDaniel Fojt strcpy(cp, flagtab[i].name);
6431d48fce0SDaniel Fojt cp += strlen(cp);
6441d48fce0SDaniel Fojt }
6451d48fce0SDaniel Fojt }
6461d48fce0SDaniel Fojt
6471d48fce0SDaniel Fojt return buf;
6481d48fce0SDaniel Fojt }
649