12a55deb1SDavid E. O'Brien /**************************************************************** 22a55deb1SDavid E. O'Brien Copyright (C) Lucent Technologies 1997 32a55deb1SDavid E. O'Brien All Rights Reserved 42a55deb1SDavid E. O'Brien 52a55deb1SDavid E. O'Brien Permission to use, copy, modify, and distribute this software and 62a55deb1SDavid E. O'Brien its documentation for any purpose and without fee is hereby 72a55deb1SDavid E. O'Brien granted, provided that the above copyright notice appear in all 82a55deb1SDavid E. O'Brien copies and that both that the copyright notice and this 92a55deb1SDavid E. O'Brien permission notice and warranty disclaimer appear in supporting 102a55deb1SDavid E. O'Brien documentation, and that the name Lucent Technologies or any of 112a55deb1SDavid E. O'Brien its entities not be used in advertising or publicity pertaining 122a55deb1SDavid E. O'Brien to distribution of the software without specific, written prior 132a55deb1SDavid E. O'Brien permission. 142a55deb1SDavid E. O'Brien 152a55deb1SDavid E. O'Brien LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 162a55deb1SDavid E. O'Brien INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. 172a55deb1SDavid E. O'Brien IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY 182a55deb1SDavid E. O'Brien SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 192a55deb1SDavid E. O'Brien WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER 202a55deb1SDavid E. O'Brien IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 212a55deb1SDavid E. O'Brien ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF 222a55deb1SDavid E. O'Brien THIS SOFTWARE. 232a55deb1SDavid E. O'Brien ****************************************************************/ 242a55deb1SDavid E. O'Brien 252a55deb1SDavid E. O'Brien #define DEBUG 262a55deb1SDavid E. O'Brien #include <stdio.h> 272a55deb1SDavid E. O'Brien #include <math.h> 282a55deb1SDavid E. O'Brien #include <ctype.h> 292a55deb1SDavid E. O'Brien #include <string.h> 302a55deb1SDavid E. O'Brien #include <stdlib.h> 312a55deb1SDavid E. O'Brien #include "awk.h" 322a55deb1SDavid E. O'Brien #include "ytab.h" 332a55deb1SDavid E. O'Brien 342a55deb1SDavid E. O'Brien #define FULLTAB 2 /* rehash when table gets this x full */ 352a55deb1SDavid E. O'Brien #define GROWTAB 4 /* grow table by this factor */ 362a55deb1SDavid E. O'Brien 372a55deb1SDavid E. O'Brien Array *symtab; /* main symbol table */ 382a55deb1SDavid E. O'Brien 392a55deb1SDavid E. O'Brien char **FS; /* initial field sep */ 402a55deb1SDavid E. O'Brien char **RS; /* initial record sep */ 412a55deb1SDavid E. O'Brien char **OFS; /* output field sep */ 422a55deb1SDavid E. O'Brien char **ORS; /* output record sep */ 432a55deb1SDavid E. O'Brien char **OFMT; /* output format for numbers */ 442a55deb1SDavid E. O'Brien char **CONVFMT; /* format for conversions in getsval */ 452a55deb1SDavid E. O'Brien Awkfloat *NF; /* number of fields in current record */ 462a55deb1SDavid E. O'Brien Awkfloat *NR; /* number of current record */ 472a55deb1SDavid E. O'Brien Awkfloat *FNR; /* number of current record in current file */ 482a55deb1SDavid E. O'Brien char **FILENAME; /* current filename argument */ 492a55deb1SDavid E. O'Brien Awkfloat *ARGC; /* number of arguments from command line */ 502a55deb1SDavid E. O'Brien char **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 512a55deb1SDavid E. O'Brien Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 522a55deb1SDavid E. O'Brien Awkfloat *RLENGTH; /* length of same */ 532a55deb1SDavid E. O'Brien 54c263f9bfSRuslan Ermilov Cell *fsloc; /* FS */ 552a55deb1SDavid E. O'Brien Cell *nrloc; /* NR */ 562a55deb1SDavid E. O'Brien Cell *nfloc; /* NF */ 572a55deb1SDavid E. O'Brien Cell *fnrloc; /* FNR */ 58b5253557SWarner Losh Cell *ofsloc; /* OFS */ 59b5253557SWarner Losh Cell *orsloc; /* ORS */ 60b5253557SWarner Losh Cell *rsloc; /* RS */ 612a55deb1SDavid E. O'Brien Array *ARGVtab; /* symbol table containing ARGV[...] */ 622a55deb1SDavid E. O'Brien Array *ENVtab; /* symbol table containing ENVIRON[...] */ 632a55deb1SDavid E. O'Brien Cell *rstartloc; /* RSTART */ 642a55deb1SDavid E. O'Brien Cell *rlengthloc; /* RLENGTH */ 65b5253557SWarner Losh Cell *subseploc; /* SUBSEP */ 662a55deb1SDavid E. O'Brien Cell *symtabloc; /* SYMTAB */ 672a55deb1SDavid E. O'Brien 682a55deb1SDavid E. O'Brien Cell *nullloc; /* a guaranteed empty cell */ 692a55deb1SDavid E. O'Brien Node *nullnode; /* zero&null, converted into a node for comparisons */ 702a55deb1SDavid E. O'Brien Cell *literal0; 712a55deb1SDavid E. O'Brien 722a55deb1SDavid E. O'Brien extern Cell **fldtab; 732a55deb1SDavid E. O'Brien 74b5253557SWarner Losh static void 75b5253557SWarner Losh setfree(Cell *vp) 76b5253557SWarner Losh { 77b5253557SWarner Losh if (&vp->sval == FS || &vp->sval == RS || 78b5253557SWarner Losh &vp->sval == OFS || &vp->sval == ORS || 79b5253557SWarner Losh &vp->sval == OFMT || &vp->sval == CONVFMT || 80b5253557SWarner Losh &vp->sval == FILENAME || &vp->sval == SUBSEP) 81b5253557SWarner Losh vp->tval |= DONTFREE; 82b5253557SWarner Losh else 83b5253557SWarner Losh vp->tval &= ~DONTFREE; 84b5253557SWarner Losh } 85b5253557SWarner Losh 862a55deb1SDavid E. O'Brien void syminit(void) /* initialize symbol table with builtin vars */ 872a55deb1SDavid E. O'Brien { 882a55deb1SDavid E. O'Brien literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 892a55deb1SDavid E. O'Brien /* this is used for if(x)... tests: */ 902a55deb1SDavid E. O'Brien nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 912a55deb1SDavid E. O'Brien nullnode = celltonode(nullloc, CCON); 922a55deb1SDavid E. O'Brien 93c263f9bfSRuslan Ermilov fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab); 94c263f9bfSRuslan Ermilov FS = &fsloc->sval; 95b5253557SWarner Losh rsloc = setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab); 96b5253557SWarner Losh RS = &rsloc->sval; 97b5253557SWarner Losh ofsloc = setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab); 98b5253557SWarner Losh OFS = &ofsloc->sval; 99b5253557SWarner Losh orsloc = setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab); 100b5253557SWarner Losh ORS = &orsloc->sval; 1012a55deb1SDavid E. O'Brien OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 1022a55deb1SDavid E. O'Brien CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 1032a55deb1SDavid E. O'Brien FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 1042a55deb1SDavid E. O'Brien nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 1052a55deb1SDavid E. O'Brien NF = &nfloc->fval; 1062a55deb1SDavid E. O'Brien nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 1072a55deb1SDavid E. O'Brien NR = &nrloc->fval; 1082a55deb1SDavid E. O'Brien fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 1092a55deb1SDavid E. O'Brien FNR = &fnrloc->fval; 110b5253557SWarner Losh subseploc = setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab); 111b5253557SWarner Losh SUBSEP = &subseploc->sval; 1122a55deb1SDavid E. O'Brien rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 1132a55deb1SDavid E. O'Brien RSTART = &rstartloc->fval; 1142a55deb1SDavid E. O'Brien rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 1152a55deb1SDavid E. O'Brien RLENGTH = &rlengthloc->fval; 1162a55deb1SDavid E. O'Brien symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 1172a55deb1SDavid E. O'Brien symtabloc->sval = (char *) symtab; 1182a55deb1SDavid E. O'Brien } 1192a55deb1SDavid E. O'Brien 1202a55deb1SDavid E. O'Brien void arginit(int ac, char **av) /* set up ARGV and ARGC */ 1212a55deb1SDavid E. O'Brien { 1222a55deb1SDavid E. O'Brien Cell *cp; 1232a55deb1SDavid E. O'Brien int i; 1242a55deb1SDavid E. O'Brien char temp[50]; 1252a55deb1SDavid E. O'Brien 1262a55deb1SDavid E. O'Brien ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 1272a55deb1SDavid E. O'Brien cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 1282a55deb1SDavid E. O'Brien ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 1292a55deb1SDavid E. O'Brien cp->sval = (char *) ARGVtab; 1302a55deb1SDavid E. O'Brien for (i = 0; i < ac; i++) { 1312a55deb1SDavid E. O'Brien sprintf(temp, "%d", i); 1322a55deb1SDavid E. O'Brien if (is_number(*av)) 1332a55deb1SDavid E. O'Brien setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1342a55deb1SDavid E. O'Brien else 1352a55deb1SDavid E. O'Brien setsymtab(temp, *av, 0.0, STR, ARGVtab); 1362a55deb1SDavid E. O'Brien av++; 1372a55deb1SDavid E. O'Brien } 1382a55deb1SDavid E. O'Brien } 1392a55deb1SDavid E. O'Brien 1402a55deb1SDavid E. O'Brien void envinit(char **envp) /* set up ENVIRON variable */ 1412a55deb1SDavid E. O'Brien { 1422a55deb1SDavid E. O'Brien Cell *cp; 1432a55deb1SDavid E. O'Brien char *p; 1442a55deb1SDavid E. O'Brien 1452a55deb1SDavid E. O'Brien cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1462a55deb1SDavid E. O'Brien ENVtab = makesymtab(NSYMTAB); 1472a55deb1SDavid E. O'Brien cp->sval = (char *) ENVtab; 1482a55deb1SDavid E. O'Brien for ( ; *envp; envp++) { 1492a55deb1SDavid E. O'Brien if ((p = strchr(*envp, '=')) == NULL) 1502a55deb1SDavid E. O'Brien continue; 1512a55deb1SDavid E. O'Brien if( p == *envp ) /* no left hand side name in env string */ 1522a55deb1SDavid E. O'Brien continue; 1532a55deb1SDavid E. O'Brien *p++ = 0; /* split into two strings at = */ 1542a55deb1SDavid E. O'Brien if (is_number(p)) 1552a55deb1SDavid E. O'Brien setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1562a55deb1SDavid E. O'Brien else 1572a55deb1SDavid E. O'Brien setsymtab(*envp, p, 0.0, STR, ENVtab); 1582a55deb1SDavid E. O'Brien p[-1] = '='; /* restore in case env is passed down to a shell */ 1592a55deb1SDavid E. O'Brien } 1602a55deb1SDavid E. O'Brien } 1612a55deb1SDavid E. O'Brien 1622a55deb1SDavid E. O'Brien Array *makesymtab(int n) /* make a new symbol table */ 1632a55deb1SDavid E. O'Brien { 1642a55deb1SDavid E. O'Brien Array *ap; 1652a55deb1SDavid E. O'Brien Cell **tp; 1662a55deb1SDavid E. O'Brien 1672a55deb1SDavid E. O'Brien ap = (Array *) malloc(sizeof(Array)); 1682a55deb1SDavid E. O'Brien tp = (Cell **) calloc(n, sizeof(Cell *)); 1692a55deb1SDavid E. O'Brien if (ap == NULL || tp == NULL) 1702a55deb1SDavid E. O'Brien FATAL("out of space in makesymtab"); 1712a55deb1SDavid E. O'Brien ap->nelem = 0; 1722a55deb1SDavid E. O'Brien ap->size = n; 1732a55deb1SDavid E. O'Brien ap->tab = tp; 1742a55deb1SDavid E. O'Brien return(ap); 1752a55deb1SDavid E. O'Brien } 1762a55deb1SDavid E. O'Brien 1772a55deb1SDavid E. O'Brien void freesymtab(Cell *ap) /* free a symbol table */ 1782a55deb1SDavid E. O'Brien { 1792a55deb1SDavid E. O'Brien Cell *cp, *temp; 1802a55deb1SDavid E. O'Brien Array *tp; 1812a55deb1SDavid E. O'Brien int i; 1822a55deb1SDavid E. O'Brien 1832a55deb1SDavid E. O'Brien if (!isarr(ap)) 1842a55deb1SDavid E. O'Brien return; 1852a55deb1SDavid E. O'Brien tp = (Array *) ap->sval; 1862a55deb1SDavid E. O'Brien if (tp == NULL) 1872a55deb1SDavid E. O'Brien return; 1882a55deb1SDavid E. O'Brien for (i = 0; i < tp->size; i++) { 1892a55deb1SDavid E. O'Brien for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1902a55deb1SDavid E. O'Brien xfree(cp->nval); 1912a55deb1SDavid E. O'Brien if (freeable(cp)) 1922a55deb1SDavid E. O'Brien xfree(cp->sval); 1932a55deb1SDavid E. O'Brien temp = cp->cnext; /* avoids freeing then using */ 1942a55deb1SDavid E. O'Brien free(cp); 195007c6572SDag-Erling Smørgrav tp->nelem--; 1962a55deb1SDavid E. O'Brien } 197b5253557SWarner Losh tp->tab[i] = 0; 1982a55deb1SDavid E. O'Brien } 199007c6572SDag-Erling Smørgrav if (tp->nelem != 0) 200007c6572SDag-Erling Smørgrav WARNING("can't happen: inconsistent element count freeing %s", ap->nval); 2012a55deb1SDavid E. O'Brien free(tp->tab); 2022a55deb1SDavid E. O'Brien free(tp); 2032a55deb1SDavid E. O'Brien } 2042a55deb1SDavid E. O'Brien 205813da98dSDavid E. O'Brien void freeelem(Cell *ap, const char *s) /* free elem s from ap (i.e., ap["s"] */ 2062a55deb1SDavid E. O'Brien { 2072a55deb1SDavid E. O'Brien Array *tp; 2082a55deb1SDavid E. O'Brien Cell *p, *prev = NULL; 2092a55deb1SDavid E. O'Brien int h; 2102a55deb1SDavid E. O'Brien 2112a55deb1SDavid E. O'Brien tp = (Array *) ap->sval; 2122a55deb1SDavid E. O'Brien h = hash(s, tp->size); 2132a55deb1SDavid E. O'Brien for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 2142a55deb1SDavid E. O'Brien if (strcmp(s, p->nval) == 0) { 2152a55deb1SDavid E. O'Brien if (prev == NULL) /* 1st one */ 2162a55deb1SDavid E. O'Brien tp->tab[h] = p->cnext; 2172a55deb1SDavid E. O'Brien else /* middle somewhere */ 2182a55deb1SDavid E. O'Brien prev->cnext = p->cnext; 2192a55deb1SDavid E. O'Brien if (freeable(p)) 2202a55deb1SDavid E. O'Brien xfree(p->sval); 2212a55deb1SDavid E. O'Brien free(p->nval); 2222a55deb1SDavid E. O'Brien free(p); 2232a55deb1SDavid E. O'Brien tp->nelem--; 2242a55deb1SDavid E. O'Brien return; 2252a55deb1SDavid E. O'Brien } 2262a55deb1SDavid E. O'Brien } 2272a55deb1SDavid E. O'Brien 228813da98dSDavid E. O'Brien Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp) 2292a55deb1SDavid E. O'Brien { 2302a55deb1SDavid E. O'Brien int h; 2312a55deb1SDavid E. O'Brien Cell *p; 2322a55deb1SDavid E. O'Brien 2332a55deb1SDavid E. O'Brien if (n != NULL && (p = lookup(n, tp)) != NULL) { 2342a55deb1SDavid E. O'Brien dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n", 235d86a0988SRuslan Ermilov (void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) ); 2362a55deb1SDavid E. O'Brien return(p); 2372a55deb1SDavid E. O'Brien } 2382a55deb1SDavid E. O'Brien p = (Cell *) malloc(sizeof(Cell)); 2392a55deb1SDavid E. O'Brien if (p == NULL) 2402a55deb1SDavid E. O'Brien FATAL("out of space for symbol table at %s", n); 2412a55deb1SDavid E. O'Brien p->nval = tostring(n); 2422a55deb1SDavid E. O'Brien p->sval = s ? tostring(s) : tostring(""); 2432a55deb1SDavid E. O'Brien p->fval = f; 2442a55deb1SDavid E. O'Brien p->tval = t; 2452a55deb1SDavid E. O'Brien p->csub = CUNK; 2462a55deb1SDavid E. O'Brien p->ctype = OCELL; 2472a55deb1SDavid E. O'Brien tp->nelem++; 2482a55deb1SDavid E. O'Brien if (tp->nelem > FULLTAB * tp->size) 2492a55deb1SDavid E. O'Brien rehash(tp); 2502a55deb1SDavid E. O'Brien h = hash(n, tp->size); 2512a55deb1SDavid E. O'Brien p->cnext = tp->tab[h]; 2522a55deb1SDavid E. O'Brien tp->tab[h] = p; 2532a55deb1SDavid E. O'Brien dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n", 254d86a0988SRuslan Ermilov (void*)p, p->nval, p->sval, p->fval, p->tval) ); 2552a55deb1SDavid E. O'Brien return(p); 2562a55deb1SDavid E. O'Brien } 2572a55deb1SDavid E. O'Brien 258813da98dSDavid E. O'Brien int hash(const char *s, int n) /* form hash value for string s */ 2592a55deb1SDavid E. O'Brien { 2602a55deb1SDavid E. O'Brien unsigned hashval; 2612a55deb1SDavid E. O'Brien 2622a55deb1SDavid E. O'Brien for (hashval = 0; *s != '\0'; s++) 2632a55deb1SDavid E. O'Brien hashval = (*s + 31 * hashval); 2642a55deb1SDavid E. O'Brien return hashval % n; 2652a55deb1SDavid E. O'Brien } 2662a55deb1SDavid E. O'Brien 2672a55deb1SDavid E. O'Brien void rehash(Array *tp) /* rehash items in small table into big one */ 2682a55deb1SDavid E. O'Brien { 2692a55deb1SDavid E. O'Brien int i, nh, nsz; 2702a55deb1SDavid E. O'Brien Cell *cp, *op, **np; 2712a55deb1SDavid E. O'Brien 2722a55deb1SDavid E. O'Brien nsz = GROWTAB * tp->size; 2732a55deb1SDavid E. O'Brien np = (Cell **) calloc(nsz, sizeof(Cell *)); 2742a55deb1SDavid E. O'Brien if (np == NULL) /* can't do it, but can keep running. */ 2752a55deb1SDavid E. O'Brien return; /* someone else will run out later. */ 2762a55deb1SDavid E. O'Brien for (i = 0; i < tp->size; i++) { 2772a55deb1SDavid E. O'Brien for (cp = tp->tab[i]; cp; cp = op) { 2782a55deb1SDavid E. O'Brien op = cp->cnext; 2792a55deb1SDavid E. O'Brien nh = hash(cp->nval, nsz); 2802a55deb1SDavid E. O'Brien cp->cnext = np[nh]; 2812a55deb1SDavid E. O'Brien np[nh] = cp; 2822a55deb1SDavid E. O'Brien } 2832a55deb1SDavid E. O'Brien } 2842a55deb1SDavid E. O'Brien free(tp->tab); 2852a55deb1SDavid E. O'Brien tp->tab = np; 2862a55deb1SDavid E. O'Brien tp->size = nsz; 2872a55deb1SDavid E. O'Brien } 2882a55deb1SDavid E. O'Brien 289813da98dSDavid E. O'Brien Cell *lookup(const char *s, Array *tp) /* look for s in tp */ 2902a55deb1SDavid E. O'Brien { 2912a55deb1SDavid E. O'Brien Cell *p; 2922a55deb1SDavid E. O'Brien int h; 2932a55deb1SDavid E. O'Brien 2942a55deb1SDavid E. O'Brien h = hash(s, tp->size); 2952a55deb1SDavid E. O'Brien for (p = tp->tab[h]; p != NULL; p = p->cnext) 2962a55deb1SDavid E. O'Brien if (strcmp(s, p->nval) == 0) 2972a55deb1SDavid E. O'Brien return(p); /* found it */ 2982a55deb1SDavid E. O'Brien return(NULL); /* not found */ 2992a55deb1SDavid E. O'Brien } 3002a55deb1SDavid E. O'Brien 3012a55deb1SDavid E. O'Brien Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 3022a55deb1SDavid E. O'Brien { 3032a55deb1SDavid E. O'Brien int fldno; 3042a55deb1SDavid E. O'Brien 305b5253557SWarner Losh f += 0.0; /* normalise negative zero to positive zero */ 3062a55deb1SDavid E. O'Brien if ((vp->tval & (NUM | STR)) == 0) 3072a55deb1SDavid E. O'Brien funnyvar(vp, "assign to"); 3082a55deb1SDavid E. O'Brien if (isfld(vp)) { 3092a55deb1SDavid E. O'Brien donerec = 0; /* mark $0 invalid */ 3102a55deb1SDavid E. O'Brien fldno = atoi(vp->nval); 3112a55deb1SDavid E. O'Brien if (fldno > *NF) 3122a55deb1SDavid E. O'Brien newfld(fldno); 3132a55deb1SDavid E. O'Brien dprintf( ("setting field %d to %g\n", fldno, f) ); 314b5253557SWarner Losh } else if (&vp->fval == NF) { 315b5253557SWarner Losh donerec = 0; /* mark $0 invalid */ 316b5253557SWarner Losh setlastfld(f); 317b5253557SWarner Losh dprintf( ("setting NF to %g\n", f) ); 3182a55deb1SDavid E. O'Brien } else if (isrec(vp)) { 3192a55deb1SDavid E. O'Brien donefld = 0; /* mark $1... invalid */ 3202a55deb1SDavid E. O'Brien donerec = 1; 321b5253557SWarner Losh } else if (vp == ofsloc) { 322b5253557SWarner Losh if (donerec == 0) 323b5253557SWarner Losh recbld(); 3242a55deb1SDavid E. O'Brien } 3252a55deb1SDavid E. O'Brien if (freeable(vp)) 3262a55deb1SDavid E. O'Brien xfree(vp->sval); /* free any previous string */ 327b5253557SWarner Losh vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ 328b5253557SWarner Losh vp->fmt = NULL; 3292a55deb1SDavid E. O'Brien vp->tval |= NUM; /* mark number ok */ 3300840e960SXin LI if (f == -0) /* who would have thought this possible? */ 3310840e960SXin LI f = 0; 332d86a0988SRuslan Ermilov dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) ); 3332a55deb1SDavid E. O'Brien return vp->fval = f; 3342a55deb1SDavid E. O'Brien } 3352a55deb1SDavid E. O'Brien 336813da98dSDavid E. O'Brien void funnyvar(Cell *vp, const char *rw) 3372a55deb1SDavid E. O'Brien { 3382a55deb1SDavid E. O'Brien if (isarr(vp)) 3392a55deb1SDavid E. O'Brien FATAL("can't %s %s; it's an array name.", rw, vp->nval); 3402a55deb1SDavid E. O'Brien if (vp->tval & FCN) 3412a55deb1SDavid E. O'Brien FATAL("can't %s %s; it's a function.", rw, vp->nval); 3422a55deb1SDavid E. O'Brien WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o", 3432a55deb1SDavid E. O'Brien vp, vp->nval, vp->sval, vp->fval, vp->tval); 3442a55deb1SDavid E. O'Brien } 3452a55deb1SDavid E. O'Brien 346813da98dSDavid E. O'Brien char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ 3472a55deb1SDavid E. O'Brien { 3482a55deb1SDavid E. O'Brien char *t; 3492a55deb1SDavid E. O'Brien int fldno; 350b5253557SWarner Losh Awkfloat f; 3512a55deb1SDavid E. O'Brien 352c263f9bfSRuslan Ermilov dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", 353d86a0988SRuslan Ermilov (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); 3542a55deb1SDavid E. O'Brien if ((vp->tval & (NUM | STR)) == 0) 3552a55deb1SDavid E. O'Brien funnyvar(vp, "assign to"); 3562a55deb1SDavid E. O'Brien if (isfld(vp)) { 3572a55deb1SDavid E. O'Brien donerec = 0; /* mark $0 invalid */ 3582a55deb1SDavid E. O'Brien fldno = atoi(vp->nval); 3592a55deb1SDavid E. O'Brien if (fldno > *NF) 3602a55deb1SDavid E. O'Brien newfld(fldno); 361b5253557SWarner Losh dprintf( ("setting field %d to %s (%p)\n", fldno, s, (void *) s) ); 3622a55deb1SDavid E. O'Brien } else if (isrec(vp)) { 3632a55deb1SDavid E. O'Brien donefld = 0; /* mark $1... invalid */ 3642a55deb1SDavid E. O'Brien donerec = 1; 365b5253557SWarner Losh } else if (vp == ofsloc) { 366b5253557SWarner Losh if (donerec == 0) 367b5253557SWarner Losh recbld(); 3682a55deb1SDavid E. O'Brien } 369b5253557SWarner Losh t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ 3702a55deb1SDavid E. O'Brien if (freeable(vp)) 3712a55deb1SDavid E. O'Brien xfree(vp->sval); 372b5253557SWarner Losh vp->tval &= ~(NUM|CONVC|CONVO); 373d2f6e492SDavid E. O'Brien vp->tval |= STR; 374b5253557SWarner Losh vp->fmt = NULL; 375b5253557SWarner Losh setfree(vp); 376c263f9bfSRuslan Ermilov dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", 377b5253557SWarner Losh (void*)vp, NN(vp->nval), t, (void *) t, vp->tval, donerec, donefld) ); 378b5253557SWarner Losh vp->sval = t; 379b5253557SWarner Losh if (&vp->fval == NF) { 380b5253557SWarner Losh donerec = 0; /* mark $0 invalid */ 381b5253557SWarner Losh f = getfval(vp); 382b5253557SWarner Losh setlastfld(f); 383b5253557SWarner Losh dprintf( ("setting NF to %g\n", f) ); 384b5253557SWarner Losh } 385b5253557SWarner Losh 386b5253557SWarner Losh return(vp->sval); 3872a55deb1SDavid E. O'Brien } 3882a55deb1SDavid E. O'Brien 3892a55deb1SDavid E. O'Brien Awkfloat getfval(Cell *vp) /* get float val of a Cell */ 3902a55deb1SDavid E. O'Brien { 3912a55deb1SDavid E. O'Brien if ((vp->tval & (NUM | STR)) == 0) 3922a55deb1SDavid E. O'Brien funnyvar(vp, "read value of"); 3932a55deb1SDavid E. O'Brien if (isfld(vp) && donefld == 0) 3942a55deb1SDavid E. O'Brien fldbld(); 3952a55deb1SDavid E. O'Brien else if (isrec(vp) && donerec == 0) 3962a55deb1SDavid E. O'Brien recbld(); 3972a55deb1SDavid E. O'Brien if (!isnum(vp)) { /* not a number */ 3982a55deb1SDavid E. O'Brien vp->fval = atof(vp->sval); /* best guess */ 3992a55deb1SDavid E. O'Brien if (is_number(vp->sval) && !(vp->tval&CON)) 4002a55deb1SDavid E. O'Brien vp->tval |= NUM; /* make NUM only sparingly */ 4012a55deb1SDavid E. O'Brien } 402d86a0988SRuslan Ermilov dprintf( ("getfval %p: %s = %g, t=%o\n", 403d86a0988SRuslan Ermilov (void*)vp, NN(vp->nval), vp->fval, vp->tval) ); 4042a55deb1SDavid E. O'Brien return(vp->fval); 4052a55deb1SDavid E. O'Brien } 4062a55deb1SDavid E. O'Brien 407813da98dSDavid E. O'Brien static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cell */ 4082a55deb1SDavid E. O'Brien { 409b5253557SWarner Losh char s[256]; 4102a55deb1SDavid E. O'Brien double dtemp; 4112a55deb1SDavid E. O'Brien 4122a55deb1SDavid E. O'Brien if ((vp->tval & (NUM | STR)) == 0) 4132a55deb1SDavid E. O'Brien funnyvar(vp, "read value of"); 4142a55deb1SDavid E. O'Brien if (isfld(vp) && donefld == 0) 4152a55deb1SDavid E. O'Brien fldbld(); 4162a55deb1SDavid E. O'Brien else if (isrec(vp) && donerec == 0) 4172a55deb1SDavid E. O'Brien recbld(); 418b5253557SWarner Losh 419b5253557SWarner Losh /* 420b5253557SWarner Losh * ADR: This is complicated and more fragile than is desirable. 421b5253557SWarner Losh * Retrieving a string value for a number associates the string 422b5253557SWarner Losh * value with the scalar. Previously, the string value was 423b5253557SWarner Losh * sticky, meaning if converted via OFMT that became the value 424b5253557SWarner Losh * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT 425b5253557SWarner Losh * changed after a string value was retrieved, the original value 426b5253557SWarner Losh * was maintained and used. Also not per POSIX. 427b5253557SWarner Losh * 428b5253557SWarner Losh * We work around this design by adding two additional flags, 429b5253557SWarner Losh * CONVC and CONVO, indicating how the string value was 430b5253557SWarner Losh * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy 431b5253557SWarner Losh * of the pointer to the xFMT format string used for the 432b5253557SWarner Losh * conversion. This pointer is only read, **never** dereferenced. 433b5253557SWarner Losh * The next time we do a conversion, if it's coming from the same 434b5253557SWarner Losh * xFMT as last time, and the pointer value is different, we 435b5253557SWarner Losh * know that the xFMT format string changed, and we need to 436b5253557SWarner Losh * redo the conversion. If it's the same, we don't have to. 437b5253557SWarner Losh * 438b5253557SWarner Losh * There are also several cases where we don't do a conversion, 439b5253557SWarner Losh * such as for a field (see the checks below). 440b5253557SWarner Losh */ 441b5253557SWarner Losh 442b5253557SWarner Losh /* Don't duplicate the code for actually updating the value */ 443b5253557SWarner Losh #define update_str_val(vp) \ 444b5253557SWarner Losh { \ 445b5253557SWarner Losh if (freeable(vp)) \ 446b5253557SWarner Losh xfree(vp->sval); \ 447b5253557SWarner Losh if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ 448b5253557SWarner Losh snprintf(s, sizeof (s), "%.30g", vp->fval); \ 449b5253557SWarner Losh else \ 450b5253557SWarner Losh snprintf(s, sizeof (s), *fmt, vp->fval); \ 451b5253557SWarner Losh vp->sval = tostring(s); \ 452b5253557SWarner Losh vp->tval &= ~DONTFREE; \ 453b5253557SWarner Losh vp->tval |= STR; \ 4542a55deb1SDavid E. O'Brien } 455b5253557SWarner Losh 456b5253557SWarner Losh if (isstr(vp) == 0) { 457b5253557SWarner Losh update_str_val(vp); 458b5253557SWarner Losh if (fmt == OFMT) { 459b5253557SWarner Losh vp->tval &= ~CONVC; 460b5253557SWarner Losh vp->tval |= CONVO; 461b5253557SWarner Losh } else { 462b5253557SWarner Losh /* CONVFMT */ 463b5253557SWarner Losh vp->tval &= ~CONVO; 464b5253557SWarner Losh vp->tval |= CONVC; 465b5253557SWarner Losh } 466b5253557SWarner Losh vp->fmt = *fmt; 467b5253557SWarner Losh } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { 468b5253557SWarner Losh goto done; 469b5253557SWarner Losh } else if (isstr(vp)) { 470b5253557SWarner Losh if (fmt == OFMT) { 471b5253557SWarner Losh if ((vp->tval & CONVC) != 0 472b5253557SWarner Losh || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { 473b5253557SWarner Losh update_str_val(vp); 474b5253557SWarner Losh vp->tval &= ~CONVC; 475b5253557SWarner Losh vp->tval |= CONVO; 476b5253557SWarner Losh vp->fmt = *fmt; 477b5253557SWarner Losh } 478b5253557SWarner Losh } else { 479b5253557SWarner Losh /* CONVFMT */ 480b5253557SWarner Losh if ((vp->tval & CONVO) != 0 481b5253557SWarner Losh || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { 482b5253557SWarner Losh update_str_val(vp); 483b5253557SWarner Losh vp->tval &= ~CONVO; 484b5253557SWarner Losh vp->tval |= CONVC; 485b5253557SWarner Losh vp->fmt = *fmt; 486b5253557SWarner Losh } 487b5253557SWarner Losh } 488b5253557SWarner Losh } 489b5253557SWarner Losh done: 490d86a0988SRuslan Ermilov dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", 491b5253557SWarner Losh (void*)vp, NN(vp->nval), vp->sval, (void *) vp->sval, vp->tval) ); 4922a55deb1SDavid E. O'Brien return(vp->sval); 4932a55deb1SDavid E. O'Brien } 4942a55deb1SDavid E. O'Brien 495813da98dSDavid E. O'Brien char *getsval(Cell *vp) /* get string val of a Cell */ 496813da98dSDavid E. O'Brien { 497813da98dSDavid E. O'Brien return get_str_val(vp, CONVFMT); 498813da98dSDavid E. O'Brien } 499813da98dSDavid E. O'Brien 500813da98dSDavid E. O'Brien char *getpssval(Cell *vp) /* get string val of a Cell for print */ 501813da98dSDavid E. O'Brien { 502813da98dSDavid E. O'Brien return get_str_val(vp, OFMT); 503813da98dSDavid E. O'Brien } 504813da98dSDavid E. O'Brien 505813da98dSDavid E. O'Brien 506813da98dSDavid E. O'Brien char *tostring(const char *s) /* make a copy of string s */ 5072a55deb1SDavid E. O'Brien { 5082a55deb1SDavid E. O'Brien char *p; 5092a55deb1SDavid E. O'Brien 5102a55deb1SDavid E. O'Brien p = (char *) malloc(strlen(s)+1); 5112a55deb1SDavid E. O'Brien if (p == NULL) 5122a55deb1SDavid E. O'Brien FATAL("out of space in tostring on %s", s); 5132a55deb1SDavid E. O'Brien strcpy(p, s); 5142a55deb1SDavid E. O'Brien return(p); 5152a55deb1SDavid E. O'Brien } 5162a55deb1SDavid E. O'Brien 517813da98dSDavid E. O'Brien char *qstring(const char *is, int delim) /* collect string up to next delim */ 5182a55deb1SDavid E. O'Brien { 519813da98dSDavid E. O'Brien const char *os = is; 5202a55deb1SDavid E. O'Brien int c, n; 5212a55deb1SDavid E. O'Brien uschar *s = (uschar *) is; 5222a55deb1SDavid E. O'Brien uschar *buf, *bp; 5232a55deb1SDavid E. O'Brien 524007c6572SDag-Erling Smørgrav if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL) 5252a55deb1SDavid E. O'Brien FATAL( "out of space in qstring(%s)", s); 5262a55deb1SDavid E. O'Brien for (bp = buf; (c = *s) != delim; s++) { 5272a55deb1SDavid E. O'Brien if (c == '\n') 5282a55deb1SDavid E. O'Brien SYNTAX( "newline in string %.20s...", os ); 5292a55deb1SDavid E. O'Brien else if (c != '\\') 5302a55deb1SDavid E. O'Brien *bp++ = c; 5312a55deb1SDavid E. O'Brien else { /* \something */ 5322a55deb1SDavid E. O'Brien c = *++s; 5332a55deb1SDavid E. O'Brien if (c == 0) { /* \ at end */ 5342a55deb1SDavid E. O'Brien *bp++ = '\\'; 5352a55deb1SDavid E. O'Brien break; /* for loop */ 5362a55deb1SDavid E. O'Brien } 5372a55deb1SDavid E. O'Brien switch (c) { 5382a55deb1SDavid E. O'Brien case '\\': *bp++ = '\\'; break; 5392a55deb1SDavid E. O'Brien case 'n': *bp++ = '\n'; break; 5402a55deb1SDavid E. O'Brien case 't': *bp++ = '\t'; break; 5412a55deb1SDavid E. O'Brien case 'b': *bp++ = '\b'; break; 5422a55deb1SDavid E. O'Brien case 'f': *bp++ = '\f'; break; 5432a55deb1SDavid E. O'Brien case 'r': *bp++ = '\r'; break; 5442a55deb1SDavid E. O'Brien default: 5452a55deb1SDavid E. O'Brien if (!isdigit(c)) { 5462a55deb1SDavid E. O'Brien *bp++ = c; 5472a55deb1SDavid E. O'Brien break; 5482a55deb1SDavid E. O'Brien } 5492a55deb1SDavid E. O'Brien n = c - '0'; 5502a55deb1SDavid E. O'Brien if (isdigit(s[1])) { 5512a55deb1SDavid E. O'Brien n = 8 * n + *++s - '0'; 5522a55deb1SDavid E. O'Brien if (isdigit(s[1])) 5532a55deb1SDavid E. O'Brien n = 8 * n + *++s - '0'; 5542a55deb1SDavid E. O'Brien } 5552a55deb1SDavid E. O'Brien *bp++ = n; 5562a55deb1SDavid E. O'Brien break; 5572a55deb1SDavid E. O'Brien } 5582a55deb1SDavid E. O'Brien } 5592a55deb1SDavid E. O'Brien } 5602a55deb1SDavid E. O'Brien *bp++ = 0; 5612a55deb1SDavid E. O'Brien return (char *) buf; 5622a55deb1SDavid E. O'Brien } 563b5253557SWarner Losh 564b5253557SWarner Losh const char *flags2str(int flags) 565b5253557SWarner Losh { 566b5253557SWarner Losh static const struct ftab { 567b5253557SWarner Losh const char *name; 568b5253557SWarner Losh int value; 569b5253557SWarner Losh } flagtab[] = { 570b5253557SWarner Losh { "NUM", NUM }, 571b5253557SWarner Losh { "STR", STR }, 572b5253557SWarner Losh { "DONTFREE", DONTFREE }, 573b5253557SWarner Losh { "CON", CON }, 574b5253557SWarner Losh { "ARR", ARR }, 575b5253557SWarner Losh { "FCN", FCN }, 576b5253557SWarner Losh { "FLD", FLD }, 577b5253557SWarner Losh { "REC", REC }, 578b5253557SWarner Losh { "CONVC", CONVC }, 579b5253557SWarner Losh { "CONVO", CONVO }, 580b5253557SWarner Losh { NULL, 0 } 581b5253557SWarner Losh }; 582b5253557SWarner Losh static char buf[100]; 583b5253557SWarner Losh int i; 584b5253557SWarner Losh char *cp = buf; 585b5253557SWarner Losh 586b5253557SWarner Losh for (i = 0; flagtab[i].name != NULL; i++) { 587b5253557SWarner Losh if ((flags & flagtab[i].value) != 0) { 588b5253557SWarner Losh if (cp > buf) 589b5253557SWarner Losh *cp++ = '|'; 590b5253557SWarner Losh strcpy(cp, flagtab[i].name); 591b5253557SWarner Losh cp += strlen(cp); 592b5253557SWarner Losh } 593b5253557SWarner Losh } 594b5253557SWarner Losh 595b5253557SWarner Losh return buf; 596b5253557SWarner Losh } 597