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 #include "ytab.h" 334b588458SPeter Avalos 344b588458SPeter Avalos #define FULLTAB 2 /* rehash when table gets this x full */ 354b588458SPeter Avalos #define GROWTAB 4 /* grow table by this factor */ 364b588458SPeter Avalos 374b588458SPeter Avalos Array *symtab; /* main symbol table */ 384b588458SPeter Avalos 394b588458SPeter Avalos char **FS; /* initial field sep */ 404b588458SPeter Avalos char **RS; /* initial record sep */ 414b588458SPeter Avalos char **OFS; /* output field sep */ 424b588458SPeter Avalos char **ORS; /* output record sep */ 434b588458SPeter Avalos char **OFMT; /* output format for numbers */ 444b588458SPeter Avalos char **CONVFMT; /* format for conversions in getsval */ 454b588458SPeter Avalos Awkfloat *NF; /* number of fields in current record */ 464b588458SPeter Avalos Awkfloat *NR; /* number of current record */ 474b588458SPeter Avalos Awkfloat *FNR; /* number of current record in current file */ 484b588458SPeter Avalos char **FILENAME; /* current filename argument */ 494b588458SPeter Avalos Awkfloat *ARGC; /* number of arguments from command line */ 504b588458SPeter Avalos char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 514b588458SPeter Avalos Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 524b588458SPeter Avalos Awkfloat *RLENGTH; /* length of same */ 534b588458SPeter Avalos 544b588458SPeter Avalos Cell *fsloc; /* FS */ 554b588458SPeter Avalos Cell *nrloc; /* NR */ 564b588458SPeter Avalos Cell *nfloc; /* NF */ 574b588458SPeter Avalos Cell *fnrloc; /* FNR */ 58*1d48fce0SDaniel Fojt Cell *ofsloc; /* OFS */ 59*1d48fce0SDaniel Fojt Cell *orsloc; /* ORS */ 60*1d48fce0SDaniel Fojt Cell *rsloc; /* RS */ 614b588458SPeter Avalos Array *ARGVtab; /* symbol table containing ARGV[...] */ 624b588458SPeter Avalos Array *ENVtab; /* symbol table containing ENVIRON[...] */ 634b588458SPeter Avalos Cell *rstartloc; /* RSTART */ 644b588458SPeter Avalos Cell *rlengthloc; /* RLENGTH */ 65*1d48fce0SDaniel Fojt Cell *subseploc; /* SUBSEP */ 664b588458SPeter Avalos Cell *symtabloc; /* SYMTAB */ 674b588458SPeter Avalos 684b588458SPeter Avalos Cell *nullloc; /* a guaranteed empty cell */ 694b588458SPeter Avalos Node *nullnode; /* zero&null, converted into a node for comparisons */ 704b588458SPeter Avalos Cell *literal0; 714b588458SPeter Avalos 724b588458SPeter Avalos extern Cell **fldtab; 734b588458SPeter Avalos 74*1d48fce0SDaniel Fojt static void 75*1d48fce0SDaniel Fojt setfree(Cell *vp) 76*1d48fce0SDaniel Fojt { 77*1d48fce0SDaniel Fojt if (&vp->sval == FS || &vp->sval == RS || 78*1d48fce0SDaniel Fojt &vp->sval == OFS || &vp->sval == ORS || 79*1d48fce0SDaniel Fojt &vp->sval == OFMT || &vp->sval == CONVFMT || 80*1d48fce0SDaniel Fojt &vp->sval == FILENAME || &vp->sval == SUBSEP) 81*1d48fce0SDaniel Fojt vp->tval |= DONTFREE; 82*1d48fce0SDaniel Fojt else 83*1d48fce0SDaniel Fojt vp->tval &= ~DONTFREE; 84*1d48fce0SDaniel Fojt } 85*1d48fce0SDaniel Fojt 864b588458SPeter Avalos void syminit(void) /* initialize symbol table with builtin vars */ 874b588458SPeter Avalos { 884b588458SPeter Avalos literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 894b588458SPeter Avalos /* this is used for if(x)... tests: */ 904b588458SPeter Avalos nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 914b588458SPeter Avalos nullnode = celltonode(nullloc, CCON); 924b588458SPeter Avalos 934b588458SPeter Avalos fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 944b588458SPeter Avalos FS = &fsloc->sval; 95*1d48fce0SDaniel Fojt rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); 96*1d48fce0SDaniel Fojt RS = &rsloc->sval; 97*1d48fce0SDaniel Fojt ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); 98*1d48fce0SDaniel Fojt OFS = &ofsloc->sval; 99*1d48fce0SDaniel Fojt orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); 100*1d48fce0SDaniel Fojt ORS = &orsloc->sval; 1014b588458SPeter Avalos OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 1024b588458SPeter Avalos CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 1034b588458SPeter Avalos FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 1044b588458SPeter Avalos nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 1054b588458SPeter Avalos NF = &nfloc->fval; 1064b588458SPeter Avalos nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 1074b588458SPeter Avalos NR = &nrloc->fval; 1084b588458SPeter Avalos fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 1094b588458SPeter Avalos FNR = &fnrloc->fval; 110*1d48fce0SDaniel Fojt subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); 111*1d48fce0SDaniel Fojt SUBSEP = &subseploc->sval; 1124b588458SPeter Avalos rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 1134b588458SPeter Avalos RSTART = &rstartloc->fval; 1144b588458SPeter Avalos rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 1154b588458SPeter Avalos RLENGTH = &rlengthloc->fval; 1164b588458SPeter Avalos symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 117*1d48fce0SDaniel Fojt free(symtabloc->sval); 1184b588458SPeter Avalos symtabloc->sval = (char *) symtab; 1194b588458SPeter Avalos } 1204b588458SPeter Avalos 1214b588458SPeter Avalos void arginit(int ac, char **av) /* set up ARGV and ARGC */ 1224b588458SPeter Avalos { 1234b588458SPeter Avalos Cell *cp; 1244b588458SPeter Avalos int i; 1254b588458SPeter Avalos char temp[50]; 1264b588458SPeter Avalos 1274b588458SPeter Avalos ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 1284b588458SPeter Avalos cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 1294b588458SPeter Avalos ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 130*1d48fce0SDaniel Fojt free(cp->sval); 1314b588458SPeter Avalos cp->sval = (char *) ARGVtab; 1324b588458SPeter Avalos for (i = 0; i < ac; i++) { 1334b588458SPeter Avalos sprintf(temp, "%d", i); 1344b588458SPeter Avalos if (is_number(*av)) 1354b588458SPeter Avalos setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1364b588458SPeter Avalos else 1374b588458SPeter Avalos setsymtab(temp, *av, 0.0, STR, ARGVtab); 1384b588458SPeter Avalos av++; 1394b588458SPeter Avalos } 1404b588458SPeter Avalos } 1414b588458SPeter Avalos 1424b588458SPeter Avalos void envinit(char **envp) /* set up ENVIRON variable */ 1434b588458SPeter Avalos { 1444b588458SPeter Avalos Cell *cp; 1454b588458SPeter Avalos char *p; 1464b588458SPeter Avalos 1474b588458SPeter Avalos cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1484b588458SPeter Avalos ENVtab = makesymtab(NSYMTAB); 149*1d48fce0SDaniel Fojt free(cp->sval); 1504b588458SPeter Avalos cp->sval = (char *) ENVtab; 1514b588458SPeter Avalos for ( ; *envp; envp++) { 1524b588458SPeter Avalos if ((p = strchr(*envp, '=')) == NULL) 1534b588458SPeter Avalos continue; 1544b588458SPeter Avalos if( p == *envp ) /* no left hand side name in env string */ 1554b588458SPeter Avalos continue; 1564b588458SPeter Avalos *p++ = 0; /* split into two strings at = */ 1574b588458SPeter Avalos if (is_number(p)) 1584b588458SPeter Avalos setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1594b588458SPeter Avalos else 1604b588458SPeter Avalos setsymtab(*envp, p, 0.0, STR, ENVtab); 1614b588458SPeter Avalos p[-1] = '='; /* restore in case env is passed down to a shell */ 1624b588458SPeter Avalos } 1634b588458SPeter Avalos } 1644b588458SPeter Avalos 1654b588458SPeter Avalos Array *makesymtab(int n) /* make a new symbol table */ 1664b588458SPeter Avalos { 1674b588458SPeter Avalos Array *ap; 1684b588458SPeter Avalos Cell **tp; 1694b588458SPeter Avalos 170*1d48fce0SDaniel Fojt ap = malloc(sizeof(*ap)); 171*1d48fce0SDaniel Fojt tp = calloc(n, sizeof(*tp)); 1724b588458SPeter Avalos if (ap == NULL || tp == NULL) 1734b588458SPeter Avalos FATAL("out of space in makesymtab"); 1744b588458SPeter Avalos ap->nelem = 0; 1754b588458SPeter Avalos ap->size = n; 1764b588458SPeter Avalos ap->tab = tp; 1774b588458SPeter Avalos return(ap); 1784b588458SPeter Avalos } 1794b588458SPeter Avalos 1804b588458SPeter Avalos void freesymtab(Cell *ap) /* free a symbol table */ 1814b588458SPeter Avalos { 1824b588458SPeter Avalos Cell *cp, *temp; 1834b588458SPeter Avalos Array *tp; 1844b588458SPeter Avalos int i; 1854b588458SPeter Avalos 1864b588458SPeter Avalos if (!isarr(ap)) 1874b588458SPeter Avalos return; 1884b588458SPeter Avalos tp = (Array *) ap->sval; 1894b588458SPeter Avalos if (tp == NULL) 1904b588458SPeter Avalos return; 1914b588458SPeter Avalos for (i = 0; i < tp->size; i++) { 1924b588458SPeter Avalos for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1934b588458SPeter Avalos xfree(cp->nval); 1944b588458SPeter Avalos if (freeable(cp)) 1954b588458SPeter Avalos xfree(cp->sval); 1964b588458SPeter Avalos temp = cp->cnext; /* avoids freeing then using */ 1974b588458SPeter Avalos free(cp); 1984b588458SPeter Avalos tp->nelem--; 1994b588458SPeter Avalos } 200*1d48fce0SDaniel Fojt tp->tab[i] = NULL; 2014b588458SPeter Avalos } 2024b588458SPeter Avalos if (tp->nelem != 0) 2034b588458SPeter Avalos WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 2044b588458SPeter Avalos free(tp->tab); 2054b588458SPeter Avalos free(tp); 2064b588458SPeter Avalos } 2074b588458SPeter Avalos 2084b588458SPeter Avalos void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 2094b588458SPeter Avalos { 2104b588458SPeter Avalos Array *tp; 2114b588458SPeter Avalos Cell *p, *prev = NULL; 2124b588458SPeter Avalos int h; 2134b588458SPeter Avalos 2144b588458SPeter Avalos tp = (Array *) ap->sval; 2154b588458SPeter Avalos h = hash(s, tp->size); 2164b588458SPeter Avalos for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 2174b588458SPeter Avalos if (strcmp(s, p->nval) == 0) { 2184b588458SPeter Avalos if (prev == NULL) /* 1st one */ 2194b588458SPeter Avalos tp->tab[h] = p->cnext; 2204b588458SPeter Avalos else /* middle somewhere */ 2214b588458SPeter Avalos prev->cnext = p->cnext; 2224b588458SPeter Avalos if (freeable(p)) 2234b588458SPeter Avalos xfree(p->sval); 2244b588458SPeter Avalos free(p->nval); 2254b588458SPeter Avalos free(p); 2264b588458SPeter Avalos tp->nelem--; 2274b588458SPeter Avalos return; 2284b588458SPeter Avalos } 2294b588458SPeter Avalos } 2304b588458SPeter Avalos 2314b588458SPeter Avalos Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 2324b588458SPeter Avalos { 2334b588458SPeter Avalos int h; 2344b588458SPeter Avalos Cell *p; 2354b588458SPeter Avalos 2364b588458SPeter Avalos if (n != NULL && (p = lookup(n, tp)) != NULL) { 2374b588458SPeter Avalos dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 238b12bae18SSascha Wildner (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 2394b588458SPeter Avalos return(p); 2404b588458SPeter Avalos } 241*1d48fce0SDaniel Fojt p = malloc(sizeof(*p)); 2424b588458SPeter Avalos if (p == NULL) 2434b588458SPeter Avalos FATAL("out of space for symbol table at %s", n); 2444b588458SPeter Avalos p->nval = tostring(n); 2454b588458SPeter Avalos p->sval = s ? tostring(s) : tostring(""); 2464b588458SPeter Avalos p->fval = f; 2474b588458SPeter Avalos p->tval = t; 2484b588458SPeter Avalos p->csub = CUNK; 2494b588458SPeter Avalos p->ctype = OCELL; 2504b588458SPeter Avalos tp->nelem++; 2514b588458SPeter Avalos if (tp->nelem > FULLTAB * tp->size) 2524b588458SPeter Avalos rehash(tp); 2534b588458SPeter Avalos h = hash(n, tp->size); 2544b588458SPeter Avalos p->cnext = tp->tab[h]; 2554b588458SPeter Avalos tp->tab[h] = p; 2564b588458SPeter Avalos dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 257b12bae18SSascha Wildner (void*)p, p->nval, p->sval, p->fval, p->tval) ); 2584b588458SPeter Avalos return(p); 2594b588458SPeter Avalos } 2604b588458SPeter Avalos 2614b588458SPeter Avalos int hash(const char *s, int n) /* form hash value for string s */ 2624b588458SPeter Avalos { 2634b588458SPeter Avalos unsigned hashval; 2644b588458SPeter Avalos 2654b588458SPeter Avalos for (hashval = 0; *s != '\0'; s++) 2664b588458SPeter Avalos hashval = (*s + 31 * hashval); 2674b588458SPeter Avalos return hashval % n; 2684b588458SPeter Avalos } 2694b588458SPeter Avalos 2704b588458SPeter Avalos void rehash(Array *tp) /* rehash items in small table into big one */ 2714b588458SPeter Avalos { 2724b588458SPeter Avalos int i, nh, nsz; 2734b588458SPeter Avalos Cell *cp, *op, **np; 2744b588458SPeter Avalos 2754b588458SPeter Avalos nsz = GROWTAB * tp->size; 276*1d48fce0SDaniel Fojt np = calloc(nsz, sizeof(*np)); 2774b588458SPeter Avalos if (np == NULL) /* can't do it, but can keep running. */ 2784b588458SPeter Avalos return; /* someone else will run out later. */ 2794b588458SPeter Avalos for (i = 0; i < tp->size; i++) { 2804b588458SPeter Avalos for (cp = tp->tab[i]; cp; cp = op) { 2814b588458SPeter Avalos op = cp->cnext; 2824b588458SPeter Avalos nh = hash(cp->nval, nsz); 2834b588458SPeter Avalos cp->cnext = np[nh]; 2844b588458SPeter Avalos np[nh] = cp; 2854b588458SPeter Avalos } 2864b588458SPeter Avalos } 2874b588458SPeter Avalos free(tp->tab); 2884b588458SPeter Avalos tp->tab = np; 2894b588458SPeter Avalos tp->size = nsz; 2904b588458SPeter Avalos } 2914b588458SPeter Avalos 2924b588458SPeter Avalos Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 2934b588458SPeter Avalos { 2944b588458SPeter Avalos Cell *p; 2954b588458SPeter Avalos int h; 2964b588458SPeter Avalos 2974b588458SPeter Avalos h = hash(s, tp->size); 2984b588458SPeter Avalos for (p = tp->tab[h]; p != NULL; p = p->cnext) 2994b588458SPeter Avalos if (strcmp(s, p->nval) == 0) 3004b588458SPeter Avalos return(p); /* found it */ 3014b588458SPeter Avalos return(NULL); /* not found */ 3024b588458SPeter Avalos } 3034b588458SPeter Avalos 3044b588458SPeter Avalos Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 3054b588458SPeter Avalos { 3064b588458SPeter Avalos int fldno; 3074b588458SPeter Avalos 308*1d48fce0SDaniel Fojt f += 0.0; /* normalise negative zero to positive zero */ 3094b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0) 3104b588458SPeter Avalos funnyvar(vp, "assign to"); 3114b588458SPeter Avalos if (isfld(vp)) { 312*1d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */ 3134b588458SPeter Avalos fldno = atoi(vp->nval); 3144b588458SPeter Avalos if (fldno > *NF) 3154b588458SPeter Avalos newfld(fldno); 3164b588458SPeter Avalos dprintf( ("setting field %d to %g\n", fldno, f) ); 317*1d48fce0SDaniel Fojt } else if (&vp->fval == NF) { 318*1d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */ 319*1d48fce0SDaniel Fojt setlastfld(f); 320*1d48fce0SDaniel Fojt dprintf( ("setting NF to %g\n", f) ); 3214b588458SPeter Avalos } else if (isrec(vp)) { 322*1d48fce0SDaniel Fojt donefld = false; /* mark $1... invalid */ 323*1d48fce0SDaniel Fojt donerec = true; 324*1d48fce0SDaniel Fojt savefs(); 325*1d48fce0SDaniel Fojt } else if (vp == ofsloc) { 326*1d48fce0SDaniel Fojt if (!donerec) 327*1d48fce0SDaniel Fojt recbld(); 3284b588458SPeter Avalos } 3294b588458SPeter Avalos if (freeable(vp)) 3304b588458SPeter Avalos xfree(vp->sval); /* free any previous string */ 331*1d48fce0SDaniel Fojt vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ 332*1d48fce0SDaniel Fojt vp->fmt = NULL; 3334b588458SPeter Avalos vp->tval |= NUM; /* mark number ok */ 3342078c1f0SJohn Marino if (f == -0) /* who would have thought this possible? */ 3352078c1f0SJohn Marino f = 0; 336b12bae18SSascha Wildner dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); 3374b588458SPeter Avalos return vp->fval = f; 3384b588458SPeter Avalos } 3394b588458SPeter Avalos 3404b588458SPeter Avalos void funnyvar(Cell *vp, const char *rw) 3414b588458SPeter Avalos { 3424b588458SPeter Avalos if (isarr(vp)) 3434b588458SPeter Avalos FATAL("can't %s %s; it's an array name.", rw, vp->nval); 3444b588458SPeter Avalos if (vp->tval & FCN) 3454b588458SPeter Avalos FATAL("can't %s %s; it's a function.", rw, vp->nval); 3464b588458SPeter Avalos WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 347*1d48fce0SDaniel Fojt (void *)vp, vp->nval, vp->sval, vp->fval, vp->tval); 3484b588458SPeter Avalos } 3494b588458SPeter Avalos 3504b588458SPeter Avalos char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 3514b588458SPeter Avalos { 3524b588458SPeter Avalos char *t; 3534b588458SPeter Avalos int fldno; 354*1d48fce0SDaniel Fojt Awkfloat f; 3554b588458SPeter Avalos 3564b588458SPeter Avalos dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 357b12bae18SSascha Wildner (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 3584b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0) 3594b588458SPeter Avalos funnyvar(vp, "assign to"); 3604b588458SPeter Avalos if (isfld(vp)) { 361*1d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */ 3624b588458SPeter Avalos fldno = atoi(vp->nval); 3634b588458SPeter Avalos if (fldno > *NF) 3644b588458SPeter Avalos newfld(fldno); 3654b588458SPeter Avalos dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) ); 3664b588458SPeter Avalos } else if (isrec(vp)) { 367*1d48fce0SDaniel Fojt donefld = false; /* mark $1... invalid */ 368*1d48fce0SDaniel Fojt donerec = true; 369*1d48fce0SDaniel Fojt savefs(); 370*1d48fce0SDaniel Fojt } else if (vp == ofsloc) { 371*1d48fce0SDaniel Fojt if (!donerec) 372*1d48fce0SDaniel Fojt recbld(); 3734b588458SPeter Avalos } 374*1d48fce0SDaniel Fojt t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ 3754b588458SPeter Avalos if (freeable(vp)) 3764b588458SPeter Avalos xfree(vp->sval); 377*1d48fce0SDaniel Fojt vp->tval &= ~(NUM|CONVC|CONVO); 3784b588458SPeter Avalos vp->tval |= STR; 379*1d48fce0SDaniel Fojt vp->fmt = NULL; 380*1d48fce0SDaniel Fojt setfree(vp); 3814b588458SPeter Avalos dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 382b12bae18SSascha Wildner (void*)vp, NN(vp->nval), t, t, vp->tval, donerec, donefld) ); 383*1d48fce0SDaniel Fojt vp->sval = t; 384*1d48fce0SDaniel Fojt if (&vp->fval == NF) { 385*1d48fce0SDaniel Fojt donerec = false; /* mark $0 invalid */ 386*1d48fce0SDaniel Fojt f = getfval(vp); 387*1d48fce0SDaniel Fojt setlastfld(f); 388*1d48fce0SDaniel Fojt dprintf( ("setting NF to %g\n", f) ); 389*1d48fce0SDaniel Fojt } 390*1d48fce0SDaniel Fojt 391*1d48fce0SDaniel Fojt return(vp->sval); 3924b588458SPeter Avalos } 3934b588458SPeter Avalos 3944b588458SPeter Avalos Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 3954b588458SPeter Avalos { 3964b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0) 3974b588458SPeter Avalos funnyvar(vp, "read value of"); 398*1d48fce0SDaniel Fojt if (isfld(vp) && !donefld) 3994b588458SPeter Avalos fldbld(); 400*1d48fce0SDaniel Fojt else if (isrec(vp) && !donerec) 4014b588458SPeter Avalos recbld(); 4024b588458SPeter Avalos if (!isnum(vp)) { /* not a number */ 4034b588458SPeter Avalos vp->fval = atof(vp->sval); /* best guess */ 4044b588458SPeter Avalos if (is_number(vp->sval) && !(vp->tval&CON)) 4054b588458SPeter Avalos vp->tval |= NUM; /* make NUM only sparingly */ 4064b588458SPeter Avalos } 407b12bae18SSascha Wildner dprintf( ("getfval %p: %s = %g, t=%o\n", 408b12bae18SSascha Wildner (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); 4094b588458SPeter Avalos return(vp->fval); 4104b588458SPeter Avalos } 4114b588458SPeter Avalos 4124b588458SPeter Avalos static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 4134b588458SPeter Avalos { 414*1d48fce0SDaniel Fojt char s[256]; 4154b588458SPeter Avalos double dtemp; 4164b588458SPeter Avalos 4174b588458SPeter Avalos if ((vp->tval & (NUM | STR)) == 0) 4184b588458SPeter Avalos funnyvar(vp, "read value of"); 419*1d48fce0SDaniel Fojt if (isfld(vp) && ! donefld) 4204b588458SPeter Avalos fldbld(); 421*1d48fce0SDaniel Fojt else if (isrec(vp) && ! donerec) 4224b588458SPeter Avalos recbld(); 423*1d48fce0SDaniel Fojt 424*1d48fce0SDaniel Fojt /* 425*1d48fce0SDaniel Fojt * ADR: This is complicated and more fragile than is desirable. 426*1d48fce0SDaniel Fojt * Retrieving a string value for a number associates the string 427*1d48fce0SDaniel Fojt * value with the scalar. Previously, the string value was 428*1d48fce0SDaniel Fojt * sticky, meaning if converted via OFMT that became the value 429*1d48fce0SDaniel Fojt * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT 430*1d48fce0SDaniel Fojt * changed after a string value was retrieved, the original value 431*1d48fce0SDaniel Fojt * was maintained and used. Also not per POSIX. 432*1d48fce0SDaniel Fojt * 433*1d48fce0SDaniel Fojt * We work around this design by adding two additional flags, 434*1d48fce0SDaniel Fojt * CONVC and CONVO, indicating how the string value was 435*1d48fce0SDaniel Fojt * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy 436*1d48fce0SDaniel Fojt * of the pointer to the xFMT format string used for the 437*1d48fce0SDaniel Fojt * conversion. This pointer is only read, **never** dereferenced. 438*1d48fce0SDaniel Fojt * The next time we do a conversion, if it's coming from the same 439*1d48fce0SDaniel Fojt * xFMT as last time, and the pointer value is different, we 440*1d48fce0SDaniel Fojt * know that the xFMT format string changed, and we need to 441*1d48fce0SDaniel Fojt * redo the conversion. If it's the same, we don't have to. 442*1d48fce0SDaniel Fojt * 443*1d48fce0SDaniel Fojt * There are also several cases where we don't do a conversion, 444*1d48fce0SDaniel Fojt * such as for a field (see the checks below). 445*1d48fce0SDaniel Fojt */ 446*1d48fce0SDaniel Fojt 447*1d48fce0SDaniel Fojt /* Don't duplicate the code for actually updating the value */ 448*1d48fce0SDaniel Fojt #define update_str_val(vp) \ 449*1d48fce0SDaniel Fojt { \ 450*1d48fce0SDaniel Fojt if (freeable(vp)) \ 451*1d48fce0SDaniel Fojt xfree(vp->sval); \ 452*1d48fce0SDaniel Fojt if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ 453*1d48fce0SDaniel Fojt snprintf(s, sizeof (s), "%.30g", vp->fval); \ 454*1d48fce0SDaniel Fojt else \ 455*1d48fce0SDaniel Fojt snprintf(s, sizeof (s), *fmt, vp->fval); \ 456*1d48fce0SDaniel Fojt vp->sval = tostring(s); \ 457*1d48fce0SDaniel Fojt vp->tval &= ~DONTFREE; \ 458*1d48fce0SDaniel Fojt vp->tval |= STR; \ 4594b588458SPeter Avalos } 460*1d48fce0SDaniel Fojt 461*1d48fce0SDaniel Fojt if (isstr(vp) == 0) { 462*1d48fce0SDaniel Fojt update_str_val(vp); 463*1d48fce0SDaniel Fojt if (fmt == OFMT) { 464*1d48fce0SDaniel Fojt vp->tval &= ~CONVC; 465*1d48fce0SDaniel Fojt vp->tval |= CONVO; 466*1d48fce0SDaniel Fojt } else { 467*1d48fce0SDaniel Fojt /* CONVFMT */ 468*1d48fce0SDaniel Fojt vp->tval &= ~CONVO; 469*1d48fce0SDaniel Fojt vp->tval |= CONVC; 470*1d48fce0SDaniel Fojt } 471*1d48fce0SDaniel Fojt vp->fmt = *fmt; 472*1d48fce0SDaniel Fojt } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { 473*1d48fce0SDaniel Fojt goto done; 474*1d48fce0SDaniel Fojt } else if (isstr(vp)) { 475*1d48fce0SDaniel Fojt if (fmt == OFMT) { 476*1d48fce0SDaniel Fojt if ((vp->tval & CONVC) != 0 477*1d48fce0SDaniel Fojt || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { 478*1d48fce0SDaniel Fojt update_str_val(vp); 479*1d48fce0SDaniel Fojt vp->tval &= ~CONVC; 480*1d48fce0SDaniel Fojt vp->tval |= CONVO; 481*1d48fce0SDaniel Fojt vp->fmt = *fmt; 482*1d48fce0SDaniel Fojt } 483*1d48fce0SDaniel Fojt } else { 484*1d48fce0SDaniel Fojt /* CONVFMT */ 485*1d48fce0SDaniel Fojt if ((vp->tval & CONVO) != 0 486*1d48fce0SDaniel Fojt || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { 487*1d48fce0SDaniel Fojt update_str_val(vp); 488*1d48fce0SDaniel Fojt vp->tval &= ~CONVO; 489*1d48fce0SDaniel Fojt vp->tval |= CONVC; 490*1d48fce0SDaniel Fojt vp->fmt = *fmt; 491*1d48fce0SDaniel Fojt } 492*1d48fce0SDaniel Fojt } 493*1d48fce0SDaniel Fojt } 494*1d48fce0SDaniel Fojt done: 495b12bae18SSascha Wildner dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", 496b12bae18SSascha Wildner (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); 4974b588458SPeter Avalos return(vp->sval); 4984b588458SPeter Avalos } 4994b588458SPeter Avalos 5004b588458SPeter Avalos char *getsval(Cell *vp) /* get string val of a Cell */ 5014b588458SPeter Avalos { 5024b588458SPeter Avalos return get_str_val(vp, CONVFMT); 5034b588458SPeter Avalos } 5044b588458SPeter Avalos 5054b588458SPeter Avalos char *getpssval(Cell *vp) /* get string val of a Cell for print */ 5064b588458SPeter Avalos { 5074b588458SPeter Avalos return get_str_val(vp, OFMT); 5084b588458SPeter Avalos } 5094b588458SPeter Avalos 5104b588458SPeter Avalos 5114b588458SPeter Avalos char *tostring(const char *s) /* make a copy of string s */ 5124b588458SPeter Avalos { 513*1d48fce0SDaniel Fojt char *p = strdup(s); 514*1d48fce0SDaniel Fojt if (p == NULL) 515*1d48fce0SDaniel Fojt FATAL("out of space in tostring on %s", s); 516*1d48fce0SDaniel Fojt return(p); 517*1d48fce0SDaniel Fojt } 518*1d48fce0SDaniel Fojt 519*1d48fce0SDaniel Fojt char *tostringN(const char *s, size_t n) /* make a copy of string s */ 520*1d48fce0SDaniel Fojt { 5214b588458SPeter Avalos char *p; 5224b588458SPeter Avalos 523*1d48fce0SDaniel Fojt p = malloc(n); 5244b588458SPeter Avalos if (p == NULL) 5254b588458SPeter Avalos FATAL("out of space in tostring on %s", s); 5264b588458SPeter Avalos strcpy(p, s); 5274b588458SPeter Avalos return(p); 5284b588458SPeter Avalos } 5294b588458SPeter Avalos 530*1d48fce0SDaniel Fojt Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ 531*1d48fce0SDaniel Fojt { 532*1d48fce0SDaniel Fojt Cell *c; 533*1d48fce0SDaniel Fojt char *p; 534*1d48fce0SDaniel Fojt char *sa = getsval(a); 535*1d48fce0SDaniel Fojt char *sb = getsval(b); 536*1d48fce0SDaniel Fojt size_t l = strlen(sa) + strlen(sb) + 1; 537*1d48fce0SDaniel Fojt p = malloc(l); 538*1d48fce0SDaniel Fojt if (p == NULL) 539*1d48fce0SDaniel Fojt FATAL("out of space concatenating %s and %s", sa, sb); 540*1d48fce0SDaniel Fojt snprintf(p, l, "%s%s", sa, sb); 541*1d48fce0SDaniel Fojt 542*1d48fce0SDaniel Fojt l++; // add room for ' ' 543*1d48fce0SDaniel Fojt char *newbuf = malloc(l); 544*1d48fce0SDaniel Fojt if (newbuf == NULL) 545*1d48fce0SDaniel Fojt FATAL("out of space concatenating %s and %s", sa, sb); 546*1d48fce0SDaniel Fojt // See string() in lex.c; a string "xx" is stored in the symbol 547*1d48fce0SDaniel Fojt // table as "xx ". 548*1d48fce0SDaniel Fojt snprintf(newbuf, l, "%s ", p); 549*1d48fce0SDaniel Fojt c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); 550*1d48fce0SDaniel Fojt free(p); 551*1d48fce0SDaniel Fojt free(newbuf); 552*1d48fce0SDaniel Fojt return c; 553*1d48fce0SDaniel Fojt } 554*1d48fce0SDaniel Fojt 5554b588458SPeter Avalos char *qstring(const char *is, int delim) /* collect string up to next delim */ 5564b588458SPeter Avalos { 5574b588458SPeter Avalos const char *os = is; 5584b588458SPeter Avalos int c, n; 559*1d48fce0SDaniel Fojt const uschar *s = (const uschar *) is; 5604b588458SPeter Avalos uschar *buf, *bp; 5614b588458SPeter Avalos 562*1d48fce0SDaniel Fojt if ((buf = malloc(strlen(is)+3)) == NULL) 5634b588458SPeter Avalos FATAL( "out of space in qstring(%s)", s); 5644b588458SPeter Avalos for (bp = buf; (c = *s) != delim; s++) { 5654b588458SPeter Avalos if (c == '\n') 5664b588458SPeter Avalos SYNTAX( "newline in string %.20s...", os ); 5674b588458SPeter Avalos else if (c != '\\') 5684b588458SPeter Avalos *bp++ = c; 5694b588458SPeter Avalos else { /* \something */ 5704b588458SPeter Avalos c = *++s; 5714b588458SPeter Avalos if (c == 0) { /* \ at end */ 5724b588458SPeter Avalos *bp++ = '\\'; 5734b588458SPeter Avalos break; /* for loop */ 5744b588458SPeter Avalos } 5754b588458SPeter Avalos switch (c) { 5764b588458SPeter Avalos case '\\': *bp++ = '\\'; break; 5774b588458SPeter Avalos case 'n': *bp++ = '\n'; break; 5784b588458SPeter Avalos case 't': *bp++ = '\t'; break; 5794b588458SPeter Avalos case 'b': *bp++ = '\b'; break; 5804b588458SPeter Avalos case 'f': *bp++ = '\f'; break; 5814b588458SPeter Avalos case 'r': *bp++ = '\r'; break; 582*1d48fce0SDaniel Fojt case 'v': *bp++ = '\v'; break; 583*1d48fce0SDaniel Fojt case 'a': *bp++ = '\a'; break; 5844b588458SPeter Avalos default: 5854b588458SPeter Avalos if (!isdigit(c)) { 5864b588458SPeter Avalos *bp++ = c; 5874b588458SPeter Avalos break; 5884b588458SPeter Avalos } 5894b588458SPeter Avalos n = c - '0'; 5904b588458SPeter Avalos if (isdigit(s[1])) { 5914b588458SPeter Avalos n = 8 * n + *++s - '0'; 5924b588458SPeter Avalos if (isdigit(s[1])) 5934b588458SPeter Avalos n = 8 * n + *++s - '0'; 5944b588458SPeter Avalos } 5954b588458SPeter Avalos *bp++ = n; 5964b588458SPeter Avalos break; 5974b588458SPeter Avalos } 5984b588458SPeter Avalos } 5994b588458SPeter Avalos } 6004b588458SPeter Avalos *bp++ = 0; 6014b588458SPeter Avalos return (char *) buf; 6024b588458SPeter Avalos } 603*1d48fce0SDaniel Fojt 604*1d48fce0SDaniel Fojt const char *flags2str(int flags) 605*1d48fce0SDaniel Fojt { 606*1d48fce0SDaniel Fojt static const struct ftab { 607*1d48fce0SDaniel Fojt const char *name; 608*1d48fce0SDaniel Fojt int value; 609*1d48fce0SDaniel Fojt } flagtab[] = { 610*1d48fce0SDaniel Fojt { "NUM", NUM }, 611*1d48fce0SDaniel Fojt { "STR", STR }, 612*1d48fce0SDaniel Fojt { "DONTFREE", DONTFREE }, 613*1d48fce0SDaniel Fojt { "CON", CON }, 614*1d48fce0SDaniel Fojt { "ARR", ARR }, 615*1d48fce0SDaniel Fojt { "FCN", FCN }, 616*1d48fce0SDaniel Fojt { "FLD", FLD }, 617*1d48fce0SDaniel Fojt { "REC", REC }, 618*1d48fce0SDaniel Fojt { "CONVC", CONVC }, 619*1d48fce0SDaniel Fojt { "CONVO", CONVO }, 620*1d48fce0SDaniel Fojt { NULL, 0 } 621*1d48fce0SDaniel Fojt }; 622*1d48fce0SDaniel Fojt static char buf[100]; 623*1d48fce0SDaniel Fojt int i; 624*1d48fce0SDaniel Fojt char *cp = buf; 625*1d48fce0SDaniel Fojt 626*1d48fce0SDaniel Fojt for (i = 0; flagtab[i].name != NULL; i++) { 627*1d48fce0SDaniel Fojt if ((flags & flagtab[i].value) != 0) { 628*1d48fce0SDaniel Fojt if (cp > buf) 629*1d48fce0SDaniel Fojt *cp++ = '|'; 630*1d48fce0SDaniel Fojt strcpy(cp, flagtab[i].name); 631*1d48fce0SDaniel Fojt cp += strlen(cp); 632*1d48fce0SDaniel Fojt } 633*1d48fce0SDaniel Fojt } 634*1d48fce0SDaniel Fojt 635*1d48fce0SDaniel Fojt return buf; 636*1d48fce0SDaniel Fojt } 637