1*65394Sbostic /**************************************************************** 2*65394Sbostic Copyright (C) AT&T 1993 3*65394Sbostic All Rights Reserved 4*65394Sbostic 5*65394Sbostic Permission to use, copy, modify, and distribute this software and 6*65394Sbostic its documentation for any purpose and without fee is hereby 7*65394Sbostic granted, provided that the above copyright notice appear in all 8*65394Sbostic copies and that both that the copyright notice and this 9*65394Sbostic permission notice and warranty disclaimer appear in supporting 10*65394Sbostic documentation, and that the name of AT&T or any of its entities 11*65394Sbostic not be used in advertising or publicity pertaining to 12*65394Sbostic distribution of the software without specific, written prior 13*65394Sbostic permission. 14*65394Sbostic 15*65394Sbostic AT&T DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 16*65394Sbostic INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 17*65394Sbostic IN NO EVENT SHALL AT&T OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 18*65394Sbostic SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 19*65394Sbostic WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 20*65394Sbostic IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 21*65394Sbostic ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 22*65394Sbostic THIS SOFTWARE. 23*65394Sbostic ****************************************************************/ 24*65394Sbostic 25*65394Sbostic #define DEBUG 26*65394Sbostic #include <stdio.h> 27*65394Sbostic #include <math.h> 28*65394Sbostic #include <ctype.h> 29*65394Sbostic #include <string.h> 30*65394Sbostic #include <stdlib.h> 31*65394Sbostic #include "awk.h" 32*65394Sbostic #include "y.tab.h" 33*65394Sbostic 34*65394Sbostic #define FULLTAB 2 /* rehash when table gets this x full */ 35*65394Sbostic #define GROWTAB 4 /* grow table by this factor */ 36*65394Sbostic 37*65394Sbostic Array *symtab; /* main symbol table */ 38*65394Sbostic 39*65394Sbostic uchar **FS; /* initial field sep */ 40*65394Sbostic uchar **RS; /* initial record sep */ 41*65394Sbostic uchar **OFS; /* output field sep */ 42*65394Sbostic uchar **ORS; /* output record sep */ 43*65394Sbostic uchar **OFMT; /* output format for numbers */ 44*65394Sbostic uchar **CONVFMT; /* format for conversions in getsval */ 45*65394Sbostic Awkfloat *NF; /* number of fields in current record */ 46*65394Sbostic Awkfloat *NR; /* number of current record */ 47*65394Sbostic Awkfloat *FNR; /* number of current record in current file */ 48*65394Sbostic uchar **FILENAME; /* current filename argument */ 49*65394Sbostic Awkfloat *ARGC; /* number of arguments from command line */ 50*65394Sbostic uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 51*65394Sbostic Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 52*65394Sbostic Awkfloat *RLENGTH; /* length of same */ 53*65394Sbostic 54*65394Sbostic Cell *recloc; /* location of record */ 55*65394Sbostic Cell *nrloc; /* NR */ 56*65394Sbostic Cell *nfloc; /* NF */ 57*65394Sbostic Cell *fnrloc; /* FNR */ 58*65394Sbostic Array *ARGVtab; /* symbol table containing ARGV[...] */ 59*65394Sbostic Array *ENVtab; /* symbol table containing ENVIRON[...] */ 60*65394Sbostic Cell *rstartloc; /* RSTART */ 61*65394Sbostic Cell *rlengthloc; /* RLENGTH */ 62*65394Sbostic Cell *symtabloc; /* SYMTAB */ 63*65394Sbostic 64*65394Sbostic Cell *nullloc; /* a guaranteed empty cell */ 65*65394Sbostic Node *nullnode; /* zero&null, converted into a node for comparisons */ 66*65394Sbostic 67*65394Sbostic extern Cell *fldtab; 68*65394Sbostic 69*65394Sbostic void syminit(void) /* initialize symbol table with builtin vars */ 70*65394Sbostic { 71*65394Sbostic setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 72*65394Sbostic /* this is used for if(x)... tests: */ 73*65394Sbostic nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 74*65394Sbostic nullnode = valtonode(nullloc, CCON); 75*65394Sbostic 76*65394Sbostic /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */ 77*65394Sbostic /* has been done elsewhere */ 78*65394Sbostic recloc = &fldtab[0]; 79*65394Sbostic FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; 80*65394Sbostic RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 81*65394Sbostic OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 82*65394Sbostic ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 83*65394Sbostic OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 84*65394Sbostic CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 85*65394Sbostic FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 86*65394Sbostic nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 87*65394Sbostic NF = &nfloc->fval; 88*65394Sbostic nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 89*65394Sbostic NR = &nrloc->fval; 90*65394Sbostic fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 91*65394Sbostic FNR = &fnrloc->fval; 92*65394Sbostic SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 93*65394Sbostic rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 94*65394Sbostic RSTART = &rstartloc->fval; 95*65394Sbostic rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 96*65394Sbostic RLENGTH = &rlengthloc->fval; 97*65394Sbostic symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 98*65394Sbostic symtabloc->sval = (uchar *) symtab; 99*65394Sbostic } 100*65394Sbostic 101*65394Sbostic void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */ 102*65394Sbostic { 103*65394Sbostic Cell *cp; 104*65394Sbostic int i; 105*65394Sbostic uchar temp[5]; 106*65394Sbostic 107*65394Sbostic ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 108*65394Sbostic cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 109*65394Sbostic ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 110*65394Sbostic cp->sval = (uchar *) ARGVtab; 111*65394Sbostic for (i = 0; i < ac; i++) { 112*65394Sbostic sprintf((char *)temp, "%d", i); 113*65394Sbostic if (isnumber(*av)) 114*65394Sbostic setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 115*65394Sbostic else 116*65394Sbostic setsymtab(temp, *av, 0.0, STR, ARGVtab); 117*65394Sbostic av++; 118*65394Sbostic } 119*65394Sbostic } 120*65394Sbostic 121*65394Sbostic void envinit(uchar **envp) /* set up ENVIRON variable */ 122*65394Sbostic { 123*65394Sbostic Cell *cp; 124*65394Sbostic uchar *p; 125*65394Sbostic 126*65394Sbostic cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 127*65394Sbostic ENVtab = makesymtab(NSYMTAB); 128*65394Sbostic cp->sval = (uchar *) ENVtab; 129*65394Sbostic for ( ; *envp; envp++) { 130*65394Sbostic if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL) 131*65394Sbostic continue; 132*65394Sbostic *p++ = 0; /* split into two strings at = */ 133*65394Sbostic if (isnumber(p)) 134*65394Sbostic setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 135*65394Sbostic else 136*65394Sbostic setsymtab(*envp, p, 0.0, STR, ENVtab); 137*65394Sbostic p[-1] = '='; /* restore in case env is passed down to a shell */ 138*65394Sbostic } 139*65394Sbostic } 140*65394Sbostic 141*65394Sbostic Array *makesymtab(int n) /* make a new symbol table */ 142*65394Sbostic { 143*65394Sbostic Array *ap; 144*65394Sbostic Cell **tp; 145*65394Sbostic 146*65394Sbostic ap = (Array *) malloc(sizeof(Array)); 147*65394Sbostic tp = (Cell **) calloc(n, sizeof(Cell *)); 148*65394Sbostic if (ap == NULL || tp == NULL) 149*65394Sbostic ERROR "out of space in makesymtab" FATAL; 150*65394Sbostic ap->nelem = 0; 151*65394Sbostic ap->size = n; 152*65394Sbostic ap->tab = tp; 153*65394Sbostic return(ap); 154*65394Sbostic } 155*65394Sbostic 156*65394Sbostic void freesymtab(Cell *ap) /* free a symbol table */ 157*65394Sbostic { 158*65394Sbostic Cell *cp, *temp; 159*65394Sbostic Array *tp; 160*65394Sbostic int i; 161*65394Sbostic 162*65394Sbostic if (!isarr(ap)) 163*65394Sbostic return; 164*65394Sbostic tp = (Array *) ap->sval; 165*65394Sbostic if (tp == NULL) 166*65394Sbostic return; 167*65394Sbostic for (i = 0; i < tp->size; i++) { 168*65394Sbostic for (cp = tp->tab[i]; cp != NULL; cp = temp) { 169*65394Sbostic xfree(cp->nval); 170*65394Sbostic if (freeable(cp)) 171*65394Sbostic xfree(cp->sval); 172*65394Sbostic temp = cp->cnext; /* avoids freeing then using */ 173*65394Sbostic free((char *) cp); 174*65394Sbostic } 175*65394Sbostic } 176*65394Sbostic free((char *) (tp->tab)); 177*65394Sbostic free((char *) tp); 178*65394Sbostic } 179*65394Sbostic 180*65394Sbostic void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */ 181*65394Sbostic { 182*65394Sbostic Array *tp; 183*65394Sbostic Cell *p, *prev = NULL; 184*65394Sbostic int h; 185*65394Sbostic 186*65394Sbostic tp = (Array *) ap->sval; 187*65394Sbostic h = hash(s, tp->size); 188*65394Sbostic for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 189*65394Sbostic if (strcmp((char *) s, (char *) p->nval) == 0) { 190*65394Sbostic if (prev == NULL) /* 1st one */ 191*65394Sbostic tp->tab[h] = p->cnext; 192*65394Sbostic else /* middle somewhere */ 193*65394Sbostic prev->cnext = p->cnext; 194*65394Sbostic if (freeable(p)) 195*65394Sbostic xfree(p->sval); 196*65394Sbostic free(p->nval); 197*65394Sbostic free((char *) p); 198*65394Sbostic tp->nelem--; 199*65394Sbostic return; 200*65394Sbostic } 201*65394Sbostic } 202*65394Sbostic 203*65394Sbostic Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp) 204*65394Sbostic { 205*65394Sbostic register int h; 206*65394Sbostic register Cell *p; 207*65394Sbostic 208*65394Sbostic if (n != NULL && (p = lookup(n, tp)) != NULL) { 209*65394Sbostic dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n", 210*65394Sbostic p, p->nval, p->sval, p->fval, p->tval) ); 211*65394Sbostic return(p); 212*65394Sbostic } 213*65394Sbostic p = (Cell *) malloc(sizeof(Cell)); 214*65394Sbostic if (p == NULL) 215*65394Sbostic ERROR "out of space for symbol table at %s", n FATAL; 216*65394Sbostic p->nval = tostring(n); 217*65394Sbostic p->sval = s ? tostring(s) : tostring(""); 218*65394Sbostic p->fval = f; 219*65394Sbostic p->tval = t; 220*65394Sbostic tp->nelem++; 221*65394Sbostic if (tp->nelem > FULLTAB * tp->size) 222*65394Sbostic rehash(tp); 223*65394Sbostic h = hash(n, tp->size); 224*65394Sbostic p->cnext = tp->tab[h]; 225*65394Sbostic tp->tab[h] = p; 226*65394Sbostic dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n", 227*65394Sbostic p, p->nval, p->sval, p->fval, p->tval) ); 228*65394Sbostic return(p); 229*65394Sbostic } 230*65394Sbostic 231*65394Sbostic hash(uchar *s, int n) /* form hash value for string s */ 232*65394Sbostic { 233*65394Sbostic register unsigned hashval; 234*65394Sbostic 235*65394Sbostic for (hashval = 0; *s != '\0'; s++) 236*65394Sbostic hashval = (*s + 31 * hashval); 237*65394Sbostic return hashval % n; 238*65394Sbostic } 239*65394Sbostic 240*65394Sbostic void rehash(Array *tp) /* rehash items in small table into big one */ 241*65394Sbostic { 242*65394Sbostic int i, nh, nsz; 243*65394Sbostic Cell *cp, *op, **np; 244*65394Sbostic 245*65394Sbostic nsz = GROWTAB * tp->size; 246*65394Sbostic np = (Cell **) calloc(nsz, sizeof(Cell *)); 247*65394Sbostic if (np == NULL) /* can't do it, but can keep running. */ 248*65394Sbostic return; /* someone else will run out later. */ 249*65394Sbostic for (i = 0; i < tp->size; i++) { 250*65394Sbostic for (cp = tp->tab[i]; cp; cp = op) { 251*65394Sbostic op = cp->cnext; 252*65394Sbostic nh = hash(cp->nval, nsz); 253*65394Sbostic cp->cnext = np[nh]; 254*65394Sbostic np[nh] = cp; 255*65394Sbostic } 256*65394Sbostic } 257*65394Sbostic free((char *) (tp->tab)); 258*65394Sbostic tp->tab = np; 259*65394Sbostic tp->size = nsz; 260*65394Sbostic } 261*65394Sbostic 262*65394Sbostic Cell *lookup(uchar *s, Array *tp) /* look for s in tp */ 263*65394Sbostic { 264*65394Sbostic register Cell *p, *prev = NULL; 265*65394Sbostic int h; 266*65394Sbostic 267*65394Sbostic h = hash(s, tp->size); 268*65394Sbostic for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 269*65394Sbostic if (strcmp((char *) s, (char *) p->nval) == 0) 270*65394Sbostic return(p); /* found it */ 271*65394Sbostic return(NULL); /* not found */ 272*65394Sbostic } 273*65394Sbostic 274*65394Sbostic Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 275*65394Sbostic { 276*65394Sbostic if ((vp->tval & (NUM | STR)) == 0) 277*65394Sbostic funnyvar(vp, "assign to"); 278*65394Sbostic if (vp->tval & FLD) { 279*65394Sbostic donerec = 0; /* mark $0 invalid */ 280*65394Sbostic if (vp-fldtab > *NF) 281*65394Sbostic newfld(vp-fldtab); 282*65394Sbostic dprintf( ("setting field %d to %g\n", vp-fldtab, f) ); 283*65394Sbostic } else if (vp->tval & REC) { 284*65394Sbostic donefld = 0; /* mark $1... invalid */ 285*65394Sbostic donerec = 1; 286*65394Sbostic } 287*65394Sbostic vp->tval &= ~STR; /* mark string invalid */ 288*65394Sbostic vp->tval |= NUM; /* mark number ok */ 289*65394Sbostic dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); 290*65394Sbostic return vp->fval = f; 291*65394Sbostic } 292*65394Sbostic 293*65394Sbostic void funnyvar(Cell *vp, char *rw) 294*65394Sbostic { 295*65394Sbostic if (vp->tval & ARR) 296*65394Sbostic ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; 297*65394Sbostic if (vp->tval & FCN) 298*65394Sbostic ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; 299*65394Sbostic ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o", 300*65394Sbostic vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING; 301*65394Sbostic } 302*65394Sbostic 303*65394Sbostic uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */ 304*65394Sbostic { 305*65394Sbostic if ((vp->tval & (NUM | STR)) == 0) 306*65394Sbostic funnyvar(vp, "assign to"); 307*65394Sbostic if (vp->tval & FLD) { 308*65394Sbostic donerec = 0; /* mark $0 invalid */ 309*65394Sbostic if (vp-fldtab > *NF) 310*65394Sbostic newfld(vp-fldtab); 311*65394Sbostic dprintf( ("setting field %d to %s\n", vp-fldtab, s) ); 312*65394Sbostic } else if (vp->tval & REC) { 313*65394Sbostic donefld = 0; /* mark $1... invalid */ 314*65394Sbostic donerec = 1; 315*65394Sbostic } 316*65394Sbostic vp->tval &= ~NUM; 317*65394Sbostic vp->tval |= STR; 318*65394Sbostic if (freeable(vp)) 319*65394Sbostic xfree(vp->sval); 320*65394Sbostic vp->tval &= ~DONTFREE; 321*65394Sbostic dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) ); 322*65394Sbostic return(vp->sval = tostring(s)); 323*65394Sbostic } 324*65394Sbostic 325*65394Sbostic Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */ 326*65394Sbostic { 327*65394Sbostic if ((vp->tval & (NUM | STR)) == 0) 328*65394Sbostic funnyvar(vp, "read value of"); 329*65394Sbostic if ((vp->tval & FLD) && donefld == 0) 330*65394Sbostic fldbld(); 331*65394Sbostic else if ((vp->tval & REC) && donerec == 0) 332*65394Sbostic recbld(); 333*65394Sbostic if (!isnum(vp)) { /* not a number */ 334*65394Sbostic vp->fval = atof(vp->sval); /* best guess */ 335*65394Sbostic if (isnumber(vp->sval) && !(vp->tval&CON)) 336*65394Sbostic vp->tval |= NUM; /* make NUM only sparingly */ 337*65394Sbostic } 338*65394Sbostic dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); 339*65394Sbostic return(vp->fval); 340*65394Sbostic } 341*65394Sbostic 342*65394Sbostic uchar *r_getsval(Cell *vp) /* get string val of a Cell */ 343*65394Sbostic { 344*65394Sbostic uchar s[100]; 345*65394Sbostic double dtemp; 346*65394Sbostic 347*65394Sbostic if ((vp->tval & (NUM | STR)) == 0) 348*65394Sbostic funnyvar(vp, "read value of"); 349*65394Sbostic if ((vp->tval & FLD) && donefld == 0) 350*65394Sbostic fldbld(); 351*65394Sbostic else if ((vp->tval & REC) && donerec == 0) 352*65394Sbostic recbld(); 353*65394Sbostic if ((vp->tval & STR) == 0) { 354*65394Sbostic if (!(vp->tval&DONTFREE)) 355*65394Sbostic xfree(vp->sval); 356*65394Sbostic if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 357*65394Sbostic sprintf((char *)s, "%.20g", vp->fval); 358*65394Sbostic else 359*65394Sbostic sprintf((char *)s, (char *)*CONVFMT, vp->fval); 360*65394Sbostic vp->sval = tostring(s); 361*65394Sbostic vp->tval &= ~DONTFREE; 362*65394Sbostic vp->tval |= STR; 363*65394Sbostic } 364*65394Sbostic dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) ); 365*65394Sbostic return(vp->sval); 366*65394Sbostic } 367*65394Sbostic 368*65394Sbostic uchar *tostring(uchar *s) /* make a copy of string s */ 369*65394Sbostic { 370*65394Sbostic register uchar *p; 371*65394Sbostic 372*65394Sbostic p = (uchar *) malloc(strlen((char *) s)+1); 373*65394Sbostic if (p == NULL) 374*65394Sbostic ERROR "out of space in tostring on %s", s FATAL; 375*65394Sbostic strcpy((char *) p, (char *) s); 376*65394Sbostic return(p); 377*65394Sbostic } 378*65394Sbostic 379*65394Sbostic uchar *qstring(uchar *s, int delim) /* collect string up to next delim */ 380*65394Sbostic { 381*65394Sbostic uchar *q; 382*65394Sbostic int c, n; 383*65394Sbostic 384*65394Sbostic for (q = cbuf; (c = *s) != delim; s++) { 385*65394Sbostic if (q >= cbuf + CBUFLEN - 1) 386*65394Sbostic ERROR "string %.10s... too long", cbuf SYNTAX; 387*65394Sbostic else if (c == '\n') 388*65394Sbostic ERROR "newline in string %.10s...", cbuf SYNTAX; 389*65394Sbostic else if (c != '\\') 390*65394Sbostic *q++ = c; 391*65394Sbostic else /* \something */ 392*65394Sbostic switch (c = *++s) { 393*65394Sbostic case '\\': *q++ = '\\'; break; 394*65394Sbostic case 'n': *q++ = '\n'; break; 395*65394Sbostic case 't': *q++ = '\t'; break; 396*65394Sbostic case 'b': *q++ = '\b'; break; 397*65394Sbostic case 'f': *q++ = '\f'; break; 398*65394Sbostic case 'r': *q++ = '\r'; break; 399*65394Sbostic default: 400*65394Sbostic if (!isdigit(c)) { 401*65394Sbostic *q++ = c; 402*65394Sbostic break; 403*65394Sbostic } 404*65394Sbostic n = c - '0'; 405*65394Sbostic if (isdigit(s[1])) { 406*65394Sbostic n = 8 * n + *++s - '0'; 407*65394Sbostic if (isdigit(s[1])) 408*65394Sbostic n = 8 * n + *++s - '0'; 409*65394Sbostic } 410*65394Sbostic *q++ = n; 411*65394Sbostic break; 412*65394Sbostic } 413*65394Sbostic } 414*65394Sbostic *q = '\0'; 415*65394Sbostic return cbuf; 416*65394Sbostic } 417