13e12c5d1SDavid du Colombier /* 23e12c5d1SDavid du Colombier Copyright (c) 1989 AT&T 33e12c5d1SDavid du Colombier All Rights Reserved 43e12c5d1SDavid du Colombier 53e12c5d1SDavid du Colombier THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. 63e12c5d1SDavid du Colombier 73e12c5d1SDavid du Colombier The copyright notice above does not evidence any 83e12c5d1SDavid du Colombier actual or intended publication of such source code. 93e12c5d1SDavid du Colombier */ 103e12c5d1SDavid du Colombier 113e12c5d1SDavid du Colombier #define DEBUG 123e12c5d1SDavid du Colombier #include <stdio.h> 133e12c5d1SDavid du Colombier #include <math.h> 143e12c5d1SDavid du Colombier #include <ctype.h> 153e12c5d1SDavid du Colombier #include <string.h> 163e12c5d1SDavid du Colombier #include <stdlib.h> 173e12c5d1SDavid du Colombier #include "awk.h" 183e12c5d1SDavid du Colombier #include "y.tab.h" 193e12c5d1SDavid du Colombier 203e12c5d1SDavid du Colombier #define FULLTAB 2 /* rehash when table gets this x full */ 213e12c5d1SDavid du Colombier #define GROWTAB 4 /* grow table by this factor */ 223e12c5d1SDavid du Colombier 233e12c5d1SDavid du Colombier Array *symtab; /* main symbol table */ 243e12c5d1SDavid du Colombier 253e12c5d1SDavid du Colombier uchar **FS; /* initial field sep */ 263e12c5d1SDavid du Colombier uchar **RS; /* initial record sep */ 273e12c5d1SDavid du Colombier uchar **OFS; /* output field sep */ 283e12c5d1SDavid du Colombier uchar **ORS; /* output record sep */ 293e12c5d1SDavid du Colombier uchar **OFMT; /* output format for numbers */ 30*219b2ee8SDavid du Colombier uchar **CONVFMT; /* format for conversions in getsval */ 313e12c5d1SDavid du Colombier Awkfloat *NF; /* number of fields in current record */ 323e12c5d1SDavid du Colombier Awkfloat *NR; /* number of current record */ 333e12c5d1SDavid du Colombier Awkfloat *FNR; /* number of current record in current file */ 343e12c5d1SDavid du Colombier uchar **FILENAME; /* current filename argument */ 353e12c5d1SDavid du Colombier Awkfloat *ARGC; /* number of arguments from command line */ 363e12c5d1SDavid du Colombier uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */ 373e12c5d1SDavid du Colombier Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */ 383e12c5d1SDavid du Colombier Awkfloat *RLENGTH; /* length of same */ 393e12c5d1SDavid du Colombier 403e12c5d1SDavid du Colombier Cell *recloc; /* location of record */ 413e12c5d1SDavid du Colombier Cell *nrloc; /* NR */ 423e12c5d1SDavid du Colombier Cell *nfloc; /* NF */ 433e12c5d1SDavid du Colombier Cell *fnrloc; /* FNR */ 443e12c5d1SDavid du Colombier Array *ARGVtab; /* symbol table containing ARGV[...] */ 453e12c5d1SDavid du Colombier Array *ENVtab; /* symbol table containing ENVIRON[...] */ 463e12c5d1SDavid du Colombier Cell *rstartloc; /* RSTART */ 473e12c5d1SDavid du Colombier Cell *rlengthloc; /* RLENGTH */ 483e12c5d1SDavid du Colombier Cell *symtabloc; /* SYMTAB */ 493e12c5d1SDavid du Colombier 50*219b2ee8SDavid du Colombier Cell *nullloc; /* a guaranteed empty cell */ 513e12c5d1SDavid du Colombier Node *nullnode; /* zero&null, converted into a node for comparisons */ 523e12c5d1SDavid du Colombier 53*219b2ee8SDavid du Colombier extern Cell *fldtab; 543e12c5d1SDavid du Colombier 55*219b2ee8SDavid du Colombier void syminit(void) /* initialize symbol table with builtin vars */ 563e12c5d1SDavid du Colombier { 573e12c5d1SDavid du Colombier setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); 583e12c5d1SDavid du Colombier /* this is used for if(x)... tests: */ 593e12c5d1SDavid du Colombier nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); 603e12c5d1SDavid du Colombier nullnode = valtonode(nullloc, CCON); 61*219b2ee8SDavid du Colombier 623e12c5d1SDavid du Colombier /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */ 63*219b2ee8SDavid du Colombier /* has been done elsewhere */ 643e12c5d1SDavid du Colombier recloc = &fldtab[0]; 653e12c5d1SDavid du Colombier FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; 663e12c5d1SDavid du Colombier RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 673e12c5d1SDavid du Colombier OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; 683e12c5d1SDavid du Colombier ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; 693e12c5d1SDavid du Colombier OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 70*219b2ee8SDavid du Colombier CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; 71*219b2ee8SDavid du Colombier FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; 723e12c5d1SDavid du Colombier nfloc = setsymtab("NF", "", 0.0, NUM, symtab); 733e12c5d1SDavid du Colombier NF = &nfloc->fval; 743e12c5d1SDavid du Colombier nrloc = setsymtab("NR", "", 0.0, NUM, symtab); 753e12c5d1SDavid du Colombier NR = &nrloc->fval; 763e12c5d1SDavid du Colombier fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); 773e12c5d1SDavid du Colombier FNR = &fnrloc->fval; 783e12c5d1SDavid du Colombier SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; 793e12c5d1SDavid du Colombier rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); 803e12c5d1SDavid du Colombier RSTART = &rstartloc->fval; 813e12c5d1SDavid du Colombier rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); 823e12c5d1SDavid du Colombier RLENGTH = &rlengthloc->fval; 833e12c5d1SDavid du Colombier symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); 843e12c5d1SDavid du Colombier symtabloc->sval = (uchar *) symtab; 853e12c5d1SDavid du Colombier } 863e12c5d1SDavid du Colombier 87*219b2ee8SDavid du Colombier void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */ 883e12c5d1SDavid du Colombier { 893e12c5d1SDavid du Colombier Cell *cp; 903e12c5d1SDavid du Colombier int i; 913e12c5d1SDavid du Colombier uchar temp[5]; 923e12c5d1SDavid du Colombier 933e12c5d1SDavid du Colombier ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; 943e12c5d1SDavid du Colombier cp = setsymtab("ARGV", "", 0.0, ARR, symtab); 953e12c5d1SDavid du Colombier ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ 963e12c5d1SDavid du Colombier cp->sval = (uchar *) ARGVtab; 973e12c5d1SDavid du Colombier for (i = 0; i < ac; i++) { 983e12c5d1SDavid du Colombier sprintf((char *)temp, "%d", i); 993e12c5d1SDavid du Colombier if (isnumber(*av)) 1003e12c5d1SDavid du Colombier setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); 1013e12c5d1SDavid du Colombier else 1023e12c5d1SDavid du Colombier setsymtab(temp, *av, 0.0, STR, ARGVtab); 1033e12c5d1SDavid du Colombier av++; 1043e12c5d1SDavid du Colombier } 1053e12c5d1SDavid du Colombier } 1063e12c5d1SDavid du Colombier 107*219b2ee8SDavid du Colombier void envinit(uchar **envp) /* set up ENVIRON variable */ 1083e12c5d1SDavid du Colombier { 1093e12c5d1SDavid du Colombier Cell *cp; 1103e12c5d1SDavid du Colombier uchar *p; 1113e12c5d1SDavid du Colombier 1123e12c5d1SDavid du Colombier cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); 1133e12c5d1SDavid du Colombier ENVtab = makesymtab(NSYMTAB); 1143e12c5d1SDavid du Colombier cp->sval = (uchar *) ENVtab; 1153e12c5d1SDavid du Colombier for ( ; *envp; envp++) { 116*219b2ee8SDavid du Colombier if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL) 1173e12c5d1SDavid du Colombier continue; 1183e12c5d1SDavid du Colombier *p++ = 0; /* split into two strings at = */ 1193e12c5d1SDavid du Colombier if (isnumber(p)) 1203e12c5d1SDavid du Colombier setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); 1213e12c5d1SDavid du Colombier else 1223e12c5d1SDavid du Colombier setsymtab(*envp, p, 0.0, STR, ENVtab); 1233e12c5d1SDavid du Colombier p[-1] = '='; /* restore in case env is passed down to a shell */ 1243e12c5d1SDavid du Colombier } 1253e12c5d1SDavid du Colombier } 1263e12c5d1SDavid du Colombier 127*219b2ee8SDavid du Colombier Array *makesymtab(int n) /* make a new symbol table */ 1283e12c5d1SDavid du Colombier { 1293e12c5d1SDavid du Colombier Array *ap; 1303e12c5d1SDavid du Colombier Cell **tp; 1313e12c5d1SDavid du Colombier 1323e12c5d1SDavid du Colombier ap = (Array *) malloc(sizeof(Array)); 1333e12c5d1SDavid du Colombier tp = (Cell **) calloc(n, sizeof(Cell *)); 1343e12c5d1SDavid du Colombier if (ap == NULL || tp == NULL) 1353e12c5d1SDavid du Colombier ERROR "out of space in makesymtab" FATAL; 1363e12c5d1SDavid du Colombier ap->nelem = 0; 1373e12c5d1SDavid du Colombier ap->size = n; 1383e12c5d1SDavid du Colombier ap->tab = tp; 1393e12c5d1SDavid du Colombier return(ap); 1403e12c5d1SDavid du Colombier } 1413e12c5d1SDavid du Colombier 142*219b2ee8SDavid du Colombier void freesymtab(Cell *ap) /* free a symbol table */ 1433e12c5d1SDavid du Colombier { 1443e12c5d1SDavid du Colombier Cell *cp, *temp; 1453e12c5d1SDavid du Colombier Array *tp; 1463e12c5d1SDavid du Colombier int i; 1473e12c5d1SDavid du Colombier 1483e12c5d1SDavid du Colombier if (!isarr(ap)) 1493e12c5d1SDavid du Colombier return; 1503e12c5d1SDavid du Colombier tp = (Array *) ap->sval; 1513e12c5d1SDavid du Colombier if (tp == NULL) 1523e12c5d1SDavid du Colombier return; 1533e12c5d1SDavid du Colombier for (i = 0; i < tp->size; i++) { 1543e12c5d1SDavid du Colombier for (cp = tp->tab[i]; cp != NULL; cp = temp) { 1553e12c5d1SDavid du Colombier xfree(cp->nval); 1563e12c5d1SDavid du Colombier if (freeable(cp)) 1573e12c5d1SDavid du Colombier xfree(cp->sval); 1583e12c5d1SDavid du Colombier temp = cp->cnext; /* avoids freeing then using */ 1593e12c5d1SDavid du Colombier free(cp); 1603e12c5d1SDavid du Colombier } 1613e12c5d1SDavid du Colombier } 1623e12c5d1SDavid du Colombier free(tp->tab); 1633e12c5d1SDavid du Colombier free(tp); 1643e12c5d1SDavid du Colombier } 1653e12c5d1SDavid du Colombier 1663e12c5d1SDavid du Colombier void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */ 1673e12c5d1SDavid du Colombier { 1683e12c5d1SDavid du Colombier Array *tp; 1693e12c5d1SDavid du Colombier Cell *p, *prev = NULL; 1703e12c5d1SDavid du Colombier int h; 1713e12c5d1SDavid du Colombier 1723e12c5d1SDavid du Colombier tp = (Array *) ap->sval; 1733e12c5d1SDavid du Colombier h = hash(s, tp->size); 1743e12c5d1SDavid du Colombier for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 1753e12c5d1SDavid du Colombier if (strcmp((char *) s, (char *) p->nval) == 0) { 1763e12c5d1SDavid du Colombier if (prev == NULL) /* 1st one */ 1773e12c5d1SDavid du Colombier tp->tab[h] = p->cnext; 1783e12c5d1SDavid du Colombier else /* middle somewhere */ 1793e12c5d1SDavid du Colombier prev->cnext = p->cnext; 1803e12c5d1SDavid du Colombier if (freeable(p)) 1813e12c5d1SDavid du Colombier xfree(p->sval); 1823e12c5d1SDavid du Colombier free(p->nval); 1833e12c5d1SDavid du Colombier free(p); 1843e12c5d1SDavid du Colombier tp->nelem--; 1853e12c5d1SDavid du Colombier return; 1863e12c5d1SDavid du Colombier } 1873e12c5d1SDavid du Colombier } 1883e12c5d1SDavid du Colombier 1893e12c5d1SDavid du Colombier Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp) 1903e12c5d1SDavid du Colombier { 1913e12c5d1SDavid du Colombier register int h; 1923e12c5d1SDavid du Colombier register Cell *p; 1933e12c5d1SDavid du Colombier 1943e12c5d1SDavid du Colombier if (n != NULL && (p = lookup(n, tp)) != NULL) { 195*219b2ee8SDavid du Colombier dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n", 196*219b2ee8SDavid du Colombier p, p->nval, p->sval, p->fval, p->tval) ); 1973e12c5d1SDavid du Colombier return(p); 1983e12c5d1SDavid du Colombier } 1993e12c5d1SDavid du Colombier p = (Cell *) malloc(sizeof(Cell)); 2003e12c5d1SDavid du Colombier if (p == NULL) 201*219b2ee8SDavid du Colombier ERROR "out of space for symbol table at %s", n FATAL; 2023e12c5d1SDavid du Colombier p->nval = tostring(n); 2033e12c5d1SDavid du Colombier p->sval = s ? tostring(s) : tostring(""); 2043e12c5d1SDavid du Colombier p->fval = f; 2053e12c5d1SDavid du Colombier p->tval = t; 2063e12c5d1SDavid du Colombier tp->nelem++; 2073e12c5d1SDavid du Colombier if (tp->nelem > FULLTAB * tp->size) 2083e12c5d1SDavid du Colombier rehash(tp); 2093e12c5d1SDavid du Colombier h = hash(n, tp->size); 2103e12c5d1SDavid du Colombier p->cnext = tp->tab[h]; 2113e12c5d1SDavid du Colombier tp->tab[h] = p; 212*219b2ee8SDavid du Colombier dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n", 213*219b2ee8SDavid du Colombier p, p->nval, p->sval, p->fval, p->tval) ); 2143e12c5d1SDavid du Colombier return(p); 2153e12c5d1SDavid du Colombier } 2163e12c5d1SDavid du Colombier 2173e12c5d1SDavid du Colombier hash(uchar *s, int n) /* form hash value for string s */ 2183e12c5d1SDavid du Colombier { 2193e12c5d1SDavid du Colombier register unsigned hashval; 2203e12c5d1SDavid du Colombier 2213e12c5d1SDavid du Colombier for (hashval = 0; *s != '\0'; s++) 2223e12c5d1SDavid du Colombier hashval = (*s + 31 * hashval); 2233e12c5d1SDavid du Colombier return hashval % n; 2243e12c5d1SDavid du Colombier } 2253e12c5d1SDavid du Colombier 2263e12c5d1SDavid du Colombier void rehash(Array *tp) /* rehash items in small table into big one */ 2273e12c5d1SDavid du Colombier { 2283e12c5d1SDavid du Colombier int i, nh, nsz; 2293e12c5d1SDavid du Colombier Cell *cp, *op, **np; 2303e12c5d1SDavid du Colombier 2313e12c5d1SDavid du Colombier nsz = GROWTAB * tp->size; 2323e12c5d1SDavid du Colombier np = (Cell **) calloc(nsz, sizeof(Cell *)); 233*219b2ee8SDavid du Colombier if (np == NULL) /* can't do it, but can keep running. */ 234*219b2ee8SDavid du Colombier return; /* someone else will run out later. */ 2353e12c5d1SDavid du Colombier for (i = 0; i < tp->size; i++) { 2363e12c5d1SDavid du Colombier for (cp = tp->tab[i]; cp; cp = op) { 2373e12c5d1SDavid du Colombier op = cp->cnext; 2383e12c5d1SDavid du Colombier nh = hash(cp->nval, nsz); 2393e12c5d1SDavid du Colombier cp->cnext = np[nh]; 2403e12c5d1SDavid du Colombier np[nh] = cp; 2413e12c5d1SDavid du Colombier } 2423e12c5d1SDavid du Colombier } 2433e12c5d1SDavid du Colombier free(tp->tab); 2443e12c5d1SDavid du Colombier tp->tab = np; 2453e12c5d1SDavid du Colombier tp->size = nsz; 2463e12c5d1SDavid du Colombier } 2473e12c5d1SDavid du Colombier 2483e12c5d1SDavid du Colombier Cell *lookup(uchar *s, Array *tp) /* look for s in tp */ 2493e12c5d1SDavid du Colombier { 2503e12c5d1SDavid du Colombier register Cell *p, *prev = NULL; 2513e12c5d1SDavid du Colombier int h; 2523e12c5d1SDavid du Colombier 2533e12c5d1SDavid du Colombier h = hash(s, tp->size); 2543e12c5d1SDavid du Colombier for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) 2553e12c5d1SDavid du Colombier if (strcmp((char *) s, (char *) p->nval) == 0) 2563e12c5d1SDavid du Colombier return(p); /* found it */ 2573e12c5d1SDavid du Colombier return(NULL); /* not found */ 2583e12c5d1SDavid du Colombier } 2593e12c5d1SDavid du Colombier 260*219b2ee8SDavid du Colombier Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ 2613e12c5d1SDavid du Colombier { 2623e12c5d1SDavid du Colombier if ((vp->tval & (NUM | STR)) == 0) 2633e12c5d1SDavid du Colombier funnyvar(vp, "assign to"); 2643e12c5d1SDavid du Colombier if (vp->tval & FLD) { 2653e12c5d1SDavid du Colombier donerec = 0; /* mark $0 invalid */ 2663e12c5d1SDavid du Colombier if (vp-fldtab > *NF) 2673e12c5d1SDavid du Colombier newfld(vp-fldtab); 2683e12c5d1SDavid du Colombier dprintf( ("setting field %d to %g\n", vp-fldtab, f) ); 2693e12c5d1SDavid du Colombier } else if (vp->tval & REC) { 2703e12c5d1SDavid du Colombier donefld = 0; /* mark $1... invalid */ 2713e12c5d1SDavid du Colombier donerec = 1; 2723e12c5d1SDavid du Colombier } 2733e12c5d1SDavid du Colombier vp->tval &= ~STR; /* mark string invalid */ 2743e12c5d1SDavid du Colombier vp->tval |= NUM; /* mark number ok */ 2753e12c5d1SDavid du Colombier dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); 2763e12c5d1SDavid du Colombier return vp->fval = f; 2773e12c5d1SDavid du Colombier } 2783e12c5d1SDavid du Colombier 2793e12c5d1SDavid du Colombier void funnyvar(Cell *vp, char *rw) 2803e12c5d1SDavid du Colombier { 2813e12c5d1SDavid du Colombier if (vp->tval & ARR) 2823e12c5d1SDavid du Colombier ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; 2833e12c5d1SDavid du Colombier if (vp->tval & FCN) 2843e12c5d1SDavid du Colombier ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; 2853e12c5d1SDavid du Colombier ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o", 286*219b2ee8SDavid du Colombier vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING; 2873e12c5d1SDavid du Colombier } 2883e12c5d1SDavid du Colombier 289*219b2ee8SDavid du Colombier uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */ 2903e12c5d1SDavid du Colombier { 291*219b2ee8SDavid du Colombier char *t; 292*219b2ee8SDavid du Colombier 2933e12c5d1SDavid du Colombier if ((vp->tval & (NUM | STR)) == 0) 2943e12c5d1SDavid du Colombier funnyvar(vp, "assign to"); 2953e12c5d1SDavid du Colombier if (vp->tval & FLD) { 2963e12c5d1SDavid du Colombier donerec = 0; /* mark $0 invalid */ 2973e12c5d1SDavid du Colombier if (vp-fldtab > *NF) 2983e12c5d1SDavid du Colombier newfld(vp-fldtab); 299*219b2ee8SDavid du Colombier dprintf( ("setting field %d to %s (%o)\n", vp-fldtab, s, s) ); 3003e12c5d1SDavid du Colombier } else if (vp->tval & REC) { 3013e12c5d1SDavid du Colombier donefld = 0; /* mark $1... invalid */ 3023e12c5d1SDavid du Colombier donerec = 1; 3033e12c5d1SDavid du Colombier } 304*219b2ee8SDavid du Colombier t = tostring(s); /* in case it's self-assign */ 3053e12c5d1SDavid du Colombier vp->tval &= ~NUM; 3063e12c5d1SDavid du Colombier vp->tval |= STR; 3073e12c5d1SDavid du Colombier if (freeable(vp)) 3083e12c5d1SDavid du Colombier xfree(vp->sval); 3093e12c5d1SDavid du Colombier vp->tval &= ~DONTFREE; 310*219b2ee8SDavid du Colombier dprintf( ("setsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); 311*219b2ee8SDavid du Colombier return(vp->sval = t); 3123e12c5d1SDavid du Colombier } 3133e12c5d1SDavid du Colombier 314*219b2ee8SDavid du Colombier Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */ 3153e12c5d1SDavid du Colombier { 3163e12c5d1SDavid du Colombier if ((vp->tval & (NUM | STR)) == 0) 3173e12c5d1SDavid du Colombier funnyvar(vp, "read value of"); 3183e12c5d1SDavid du Colombier if ((vp->tval & FLD) && donefld == 0) 3193e12c5d1SDavid du Colombier fldbld(); 3203e12c5d1SDavid du Colombier else if ((vp->tval & REC) && donerec == 0) 3213e12c5d1SDavid du Colombier recbld(); 3223e12c5d1SDavid du Colombier if (!isnum(vp)) { /* not a number */ 3233e12c5d1SDavid du Colombier vp->fval = atof(vp->sval); /* best guess */ 3243e12c5d1SDavid du Colombier if (isnumber(vp->sval) && !(vp->tval&CON)) 3253e12c5d1SDavid du Colombier vp->tval |= NUM; /* make NUM only sparingly */ 3263e12c5d1SDavid du Colombier } 3273e12c5d1SDavid du Colombier dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); 3283e12c5d1SDavid du Colombier return(vp->fval); 3293e12c5d1SDavid du Colombier } 3303e12c5d1SDavid du Colombier 331*219b2ee8SDavid du Colombier uchar *r_getsval(Cell *vp) /* get string val of a Cell */ 3323e12c5d1SDavid du Colombier { 3333e12c5d1SDavid du Colombier uchar s[100]; 3343e12c5d1SDavid du Colombier double dtemp; 3353e12c5d1SDavid du Colombier 3363e12c5d1SDavid du Colombier if ((vp->tval & (NUM | STR)) == 0) 3373e12c5d1SDavid du Colombier funnyvar(vp, "read value of"); 3383e12c5d1SDavid du Colombier if ((vp->tval & FLD) && donefld == 0) 3393e12c5d1SDavid du Colombier fldbld(); 3403e12c5d1SDavid du Colombier else if ((vp->tval & REC) && donerec == 0) 3413e12c5d1SDavid du Colombier recbld(); 3423e12c5d1SDavid du Colombier if ((vp->tval & STR) == 0) { 3433e12c5d1SDavid du Colombier if (!(vp->tval&DONTFREE)) 3443e12c5d1SDavid du Colombier xfree(vp->sval); 3453e12c5d1SDavid du Colombier if (modf(vp->fval, &dtemp) == 0) /* it's integral */ 3463e12c5d1SDavid du Colombier sprintf((char *)s, "%.20g", vp->fval); 3473e12c5d1SDavid du Colombier else 348*219b2ee8SDavid du Colombier sprintf((char *)s, (char *)*CONVFMT, vp->fval); 3493e12c5d1SDavid du Colombier vp->sval = tostring(s); 3503e12c5d1SDavid du Colombier vp->tval &= ~DONTFREE; 3513e12c5d1SDavid du Colombier vp->tval |= STR; 3523e12c5d1SDavid du Colombier } 353*219b2ee8SDavid du Colombier dprintf( ("getsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); 3543e12c5d1SDavid du Colombier return(vp->sval); 3553e12c5d1SDavid du Colombier } 3563e12c5d1SDavid du Colombier 357*219b2ee8SDavid du Colombier uchar *tostring(uchar *s) /* make a copy of string s */ 3583e12c5d1SDavid du Colombier { 3593e12c5d1SDavid du Colombier register uchar *p; 3603e12c5d1SDavid du Colombier 3613e12c5d1SDavid du Colombier p = (uchar *) malloc(strlen((char *) s)+1); 3623e12c5d1SDavid du Colombier if (p == NULL) 3633e12c5d1SDavid du Colombier ERROR "out of space in tostring on %s", s FATAL; 3643e12c5d1SDavid du Colombier strcpy((char *) p, (char *) s); 3653e12c5d1SDavid du Colombier return(p); 3663e12c5d1SDavid du Colombier } 3673e12c5d1SDavid du Colombier 368*219b2ee8SDavid du Colombier uchar *qstring(uchar *s, int delim) /* collect string up to next delim */ 3693e12c5d1SDavid du Colombier { 3703e12c5d1SDavid du Colombier uchar *q; 3713e12c5d1SDavid du Colombier int c, n; 3723e12c5d1SDavid du Colombier 3733e12c5d1SDavid du Colombier for (q = cbuf; (c = *s) != delim; s++) { 3743e12c5d1SDavid du Colombier if (q >= cbuf + CBUFLEN - 1) 3753e12c5d1SDavid du Colombier ERROR "string %.10s... too long", cbuf SYNTAX; 3763e12c5d1SDavid du Colombier else if (c == '\n') 3773e12c5d1SDavid du Colombier ERROR "newline in string %.10s...", cbuf SYNTAX; 3783e12c5d1SDavid du Colombier else if (c != '\\') 3793e12c5d1SDavid du Colombier *q++ = c; 3803e12c5d1SDavid du Colombier else /* \something */ 3813e12c5d1SDavid du Colombier switch (c = *++s) { 3823e12c5d1SDavid du Colombier case '\\': *q++ = '\\'; break; 3833e12c5d1SDavid du Colombier case 'n': *q++ = '\n'; break; 3843e12c5d1SDavid du Colombier case 't': *q++ = '\t'; break; 3853e12c5d1SDavid du Colombier case 'b': *q++ = '\b'; break; 3863e12c5d1SDavid du Colombier case 'f': *q++ = '\f'; break; 3873e12c5d1SDavid du Colombier case 'r': *q++ = '\r'; break; 3883e12c5d1SDavid du Colombier default: 3893e12c5d1SDavid du Colombier if (!isdigit(c)) { 3903e12c5d1SDavid du Colombier *q++ = c; 3913e12c5d1SDavid du Colombier break; 3923e12c5d1SDavid du Colombier } 3933e12c5d1SDavid du Colombier n = c - '0'; 3943e12c5d1SDavid du Colombier if (isdigit(s[1])) { 3953e12c5d1SDavid du Colombier n = 8 * n + *++s - '0'; 3963e12c5d1SDavid du Colombier if (isdigit(s[1])) 3973e12c5d1SDavid du Colombier n = 8 * n + *++s - '0'; 3983e12c5d1SDavid du Colombier } 3993e12c5d1SDavid du Colombier *q++ = n; 4003e12c5d1SDavid du Colombier break; 4013e12c5d1SDavid du Colombier } 4023e12c5d1SDavid du Colombier } 4033e12c5d1SDavid du Colombier *q = '\0'; 4043e12c5d1SDavid du Colombier return cbuf; 4053e12c5d1SDavid du Colombier } 406