/*Copyright (c) 1989 AT&T All Rights Reserved THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T. The copyright notice above does not evidence anyactual or intended publication of such source code.*/ #define DEBUG#include <stdio.h>#include <math.h>#include <ctype.h>#include <string.h>#include <stdlib.h>#include "awk.h"#include "y.tab.h" #define FULLTAB 2 /* rehash when table gets this x full */#define GROWTAB 4 /* grow table by this factor */ Array *symtab; /* main symbol table */ uchar **FS; /* initial field sep */uchar **RS; /* initial record sep */uchar **OFS; /* output field sep */uchar **ORS; /* output record sep */uchar **OFMT; /* output format for numbers */uchar **CONVFMT; /* format for conversions in getsval */Awkfloat *NF; /* number of fields in current record */Awkfloat *NR; /* number of current record */Awkfloat *FNR; /* number of current record in current file */uchar **FILENAME; /* current filename argument */Awkfloat *ARGC; /* number of arguments from command line */uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */Awkfloat *RLENGTH; /* length of same */ Cell *recloc; /* location of record */Cell *nrloc; /* NR */Cell *nfloc; /* NF */Cell *fnrloc; /* FNR */Array *ARGVtab; /* symbol table containing ARGV[...] */Array *ENVtab; /* symbol table containing ENVIRON[...] */Cell *rstartloc; /* RSTART */Cell *rlengthloc; /* RLENGTH */Cell *symtabloc; /* SYMTAB */ Cell *nullloc; /* a guaranteed empty cell */Node *nullnode; /* zero&null, converted into a node for comparisons */ extern Cell *fldtab; void syminit(void) /* initialize symbol table with builtin vars */{ setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); /* this is used for if(x)... tests: */ nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab); nullnode = valtonode(nullloc, CCON); /* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */ /* has been done elsewhere */ recloc = &fldtab[0]; FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval; RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval; OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval; ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval; OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval; FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval; nfloc = setsymtab("NF", "", 0.0, NUM, symtab); NF = &nfloc->fval; nrloc = setsymtab("NR", "", 0.0, NUM, symtab); NR = &nrloc->fval; fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab); FNR = &fnrloc->fval; SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval; rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab); RSTART = &rstartloc->fval; rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); RLENGTH = &rlengthloc->fval; symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); symtabloc->sval = (uchar *) symtab;} void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */{ Cell *cp; int i; uchar temp[5]; ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; cp = setsymtab("ARGV", "", 0.0, ARR, symtab); ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ cp->sval = (uchar *) ARGVtab; for (i = 0; i < ac; i++) { sprintf((char *)temp, "%d", i); if (isnumber(*av)) setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab); else setsymtab(temp, *av, 0.0, STR, ARGVtab); av++; }} void envinit(uchar **envp) /* set up ENVIRON variable */{ Cell *cp; uchar *p; cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); ENVtab = makesymtab(NSYMTAB); cp->sval = (uchar *) ENVtab; for ( ; *envp; envp++) { if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL) continue; *p++ = 0; /* split into two strings at = */ if (isnumber(p)) setsymtab(*envp, p, atof(p), STR|NUM, ENVtab); else setsymtab(*envp, p, 0.0, STR, ENVtab); p[-1] = '='; /* restore in case env is passed down to a shell */ }} Array *makesymtab(int n) /* make a new symbol table */{ Array *ap; Cell **tp; ap = (Array *) malloc(sizeof(Array)); tp = (Cell **) calloc(n, sizeof(Cell *)); if (ap == NULL || tp == NULL) ERROR "out of space in makesymtab" FATAL; ap->nelem = 0; ap->size = n; ap->tab = tp; return(ap);} void freesymtab(Cell *ap) /* free a symbol table */{ Cell *cp, *temp; Array *tp; int i; if (!isarr(ap)) return; tp = (Array *) ap->sval; if (tp == NULL) return; for (i = 0; i < tp->size; i++) { for (cp = tp->tab[i]; cp != NULL; cp = temp) { xfree(cp->nval); if (freeable(cp)) xfree(cp->sval); temp = cp->cnext; /* avoids freeing then using */ free(cp); } } free(tp->tab); free(tp);} void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */{ Array *tp; Cell *p, *prev = NULL; int h; tp = (Array *) ap->sval; h = hash(s, tp->size); for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) if (strcmp((char *) s, (char *) p->nval) == 0) { if (prev == NULL) /* 1st one */ tp->tab[h] = p->cnext; else /* middle somewhere */ prev->cnext = p->cnext; if (freeable(p)) xfree(p->sval); free(p->nval); free(p); tp->nelem--; return; }} Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp){ register int h; register Cell *p; if (n != NULL && (p = lookup(n, tp)) != NULL) { dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n", p, p->nval, p->sval, p->fval, p->tval) ); return(p); } p = (Cell *) malloc(sizeof(Cell)); if (p == NULL) ERROR "out of space for symbol table at %s", n FATAL; p->nval = tostring(n); p->sval = s ? tostring(s) : tostring(""); p->fval = f; p->tval = t; tp->nelem++; if (tp->nelem > FULLTAB * tp->size) rehash(tp); h = hash(n, tp->size); p->cnext = tp->tab[h]; tp->tab[h] = p; dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n", p, p->nval, p->sval, p->fval, p->tval) ); return(p);} hash(uchar *s, int n) /* form hash value for string s */{ register unsigned hashval; for (hashval = 0; *s != '\0'; s++) hashval = (*s + 31 * hashval); return hashval % n;} void rehash(Array *tp) /* rehash items in small table into big one */{ int i, nh, nsz; Cell *cp, *op, **np; nsz = GROWTAB * tp->size; np = (Cell **) calloc(nsz, sizeof(Cell *)); if (np == NULL) /* can't do it, but can keep running. */ return; /* someone else will run out later. */ for (i = 0; i < tp->size; i++) { for (cp = tp->tab[i]; cp; cp = op) { op = cp->cnext; nh = hash(cp->nval, nsz); cp->cnext = np[nh]; np[nh] = cp; } } free(tp->tab); tp->tab = np; tp->size = nsz;} Cell *lookup(uchar *s, Array *tp) /* look for s in tp */{ register Cell *p, *prev = NULL; int h; h = hash(s, tp->size); for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext) if (strcmp((char *) s, (char *) p->nval) == 0) return(p); /* found it */ return(NULL); /* not found */} Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */{ if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); if (vp->tval & FLD) { donerec = 0; /* mark $0 invalid */ if (vp-fldtab > *NF) newfld(vp-fldtab); dprintf( ("setting field %d to %g\n", vp-fldtab, f) ); } else if (vp->tval & REC) { donefld = 0; /* mark $1... invalid */ donerec = 1; } vp->tval &= ~STR; /* mark string invalid */ vp->tval |= NUM; /* mark number ok */ dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) ); return vp->fval = f;} void funnyvar(Cell *vp, char *rw){ if (vp->tval & ARR) ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL; if (vp->tval & FCN) ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL; ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o", vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;} uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */{ char *t; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); if (vp->tval & FLD) { donerec = 0; /* mark $0 invalid */ if (vp-fldtab > *NF) newfld(vp-fldtab); dprintf( ("setting field %d to %s (%o)\n", vp-fldtab, s, s) ); } else if (vp->tval & REC) { donefld = 0; /* mark $1... invalid */ donerec = 1; } t = tostring(s); /* in case it's self-assign */ vp->tval &= ~NUM; vp->tval |= STR; if (freeable(vp)) xfree(vp->sval); vp->tval &= ~DONTFREE; dprintf( ("setsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, t,t, vp->tval) ); return(vp->sval = t);} Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */{ if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); if ((vp->tval & FLD) && donefld == 0) fldbld(); else if ((vp->tval & REC) && donerec == 0) recbld(); if (!isnum(vp)) { /* not a number */ vp->fval = atof(vp->sval); /* best guess */ if (isnumber(vp->sval) && !(vp->tval&CON)) vp->tval |= NUM; /* make NUM only sparingly */ } dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) ); return(vp->fval);} uchar *r_getsval(Cell *vp) /* get string val of a Cell */{ uchar s[100]; double dtemp; if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "read value of"); if ((vp->tval & FLD) && donefld == 0) fldbld(); else if ((vp->tval & REC) && donerec == 0) recbld(); if ((vp->tval & STR) == 0) { if (!(vp->tval&DONTFREE)) xfree(vp->sval); if (modf(vp->fval, &dtemp) == 0) /* it's integral */ sprintf((char *)s, "%.20g", vp->fval); else sprintf((char *)s, (char *)*CONVFMT, vp->fval); vp->sval = tostring(s); vp->tval &= ~DONTFREE; vp->tval |= STR; } dprintf( ("getsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) ); return(vp->sval);} uchar *tostring(uchar *s) /* make a copy of string s */{ register uchar *p; p = (uchar *) malloc(strlen((char *) s)+1); if (p == NULL) ERROR "out of space in tostring on %s", s FATAL; strcpy((char *) p, (char *) s); return(p);} uchar *qstring(uchar *s, int delim) /* collect string up to next delim */{ uchar *q; int c, n; for (q = cbuf; (c = *s) != delim; s++) { if (q >= cbuf + CBUFLEN - 1) ERROR "string %.10s... too long", cbuf SYNTAX; else if (c == '\n') ERROR "newline in string %.10s...", cbuf SYNTAX; else if (c != '\\') *q++ = c; else /* \something */ switch (c = *++s) { case '\\': *q++ = '\\'; break; case 'n': *q++ = '\n'; break; case 't': *q++ = '\t'; break; case 'b': *q++ = '\b'; break; case 'f': *q++ = '\f'; break; case 'r': *q++ = '\r'; break; default: if (!isdigit(c)) { *q++ = c; break; } n = c - '0'; if (isdigit(s[1])) { n = 8 * n + *++s - '0'; if (isdigit(s[1])) n = 8 * n + *++s - '0'; } *q++ = n; break; } } *q = '\0'; return cbuf;}
/*
Copyright (c) 1989 AT&T
All Rights Reserved
THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.
The copyright notice above does not evidence any
actual or intended publication of such source code.
*/
#define DEBUG
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "awk.h"
#include "y.tab.h"
#define FULLTAB 2 /* rehash when table gets this x full */
#define GROWTAB 4 /* grow table by this factor */
Array *symtab; /* main symbol table */
uchar **FS; /* initial field sep */
uchar **RS; /* initial record sep */
uchar **OFS; /* output field sep */
uchar **ORS; /* output record sep */
uchar **OFMT; /* output format for numbers */
uchar **CONVFMT; /* format for conversions in getsval */
Awkfloat *NF; /* number of fields in current record */
Awkfloat *NR; /* number of current record */
Awkfloat *FNR; /* number of current record in current file */
uchar **FILENAME; /* current filename argument */
Awkfloat *ARGC; /* number of arguments from command line */
uchar **SUBSEP; /* subscript separator for a[i,j,k]; default \034 */
Awkfloat *RSTART; /* start of re matched with ~; origin 1 (!) */
Awkfloat *RLENGTH; /* length of same */
Cell *recloc; /* location of record */
Cell *nrloc; /* NR */
Cell *nfloc; /* NF */
Cell *fnrloc; /* FNR */
Array *ARGVtab; /* symbol table containing ARGV[...] */
Array *ENVtab; /* symbol table containing ENVIRON[...] */
Cell *rstartloc; /* RSTART */
Cell *rlengthloc; /* RLENGTH */
Cell *symtabloc; /* SYMTAB */
Cell *nullloc; /* a guaranteed empty cell */
Node *nullnode; /* zero&null, converted into a node for comparisons */
extern Cell *fldtab;
void syminit(void) /* initialize symbol table with builtin vars */
{
setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
/* this is used for if(x)... tests: */
nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
nullnode = valtonode(nullloc, CCON);
/* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
/* has been done elsewhere */
recloc = &fldtab[0];
FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
NF = &nfloc->fval;
nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
NR = &nrloc->fval;
fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
FNR = &fnrloc->fval;
SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
RSTART = &rstartloc->fval;
rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
RLENGTH = &rlengthloc->fval;
symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
symtabloc->sval = (uchar *) symtab;
}
void arginit(int ac, uchar *av[]) /* set up ARGV and ARGC */
{
Cell *cp;
int i;
uchar temp[5];
ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */
cp->sval = (uchar *) ARGVtab;
for (i = 0; i < ac; i++) {
sprintf((char *)temp, "%d", i);
if (isnumber(*av))
setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
else
setsymtab(temp, *av, 0.0, STR, ARGVtab);
av++;
}
}
void envinit(uchar **envp) /* set up ENVIRON variable */
{
Cell *cp;
uchar *p;
cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
ENVtab = makesymtab(NSYMTAB);
cp->sval = (uchar *) ENVtab;
for ( ; *envp; envp++) {
if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)
continue;
*p++ = 0; /* split into two strings at = */
if (isnumber(p))
setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
else
setsymtab(*envp, p, 0.0, STR, ENVtab);
p[-1] = '='; /* restore in case env is passed down to a shell */
}
}
Array *makesymtab(int n) /* make a new symbol table */
{
Array *ap;
Cell **tp;
ap = (Array *) malloc(sizeof(Array));
tp = (Cell **) calloc(n, sizeof(Cell *));
if (ap == NULL || tp == NULL)
ERROR "out of space in makesymtab" FATAL;
ap->nelem = 0;
ap->size = n;
ap->tab = tp;
return(ap);
}
void freesymtab(Cell *ap) /* free a symbol table */
{
Cell *cp, *temp;
Array *tp;
int i;
if (!isarr(ap))
return;
tp = (Array *) ap->sval;
if (tp == NULL)
return;
for (i = 0; i < tp->size; i++) {
for (cp = tp->tab[i]; cp != NULL; cp = temp) {
xfree(cp->nval);
if (freeable(cp))
xfree(cp->sval);
temp = cp->cnext; /* avoids freeing then using */
free(cp);
}
}
free(tp->tab);
free(tp);
}
void freeelem(Cell *ap, uchar *s) /* free elem s from ap (i.e., ap["s"] */
{
Array *tp;
Cell *p, *prev = NULL;
int h;
tp = (Array *) ap->sval;
h = hash(s, tp->size);
for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
if (strcmp((char *) s, (char *) p->nval) == 0) {
if (prev == NULL) /* 1st one */
tp->tab[h] = p->cnext;
else /* middle somewhere */
prev->cnext = p->cnext;
if (freeable(p))
xfree(p->sval);
free(p->nval);
free(p);
tp->nelem--;
return;
}
}
Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
{
register int h;
register Cell *p;
if (n != NULL && (p = lookup(n, tp)) != NULL) {
dprintf( ("setsymtab found %o: n=%s s=\"%s\" f=%g t=%o\n",
p, p->nval, p->sval, p->fval, p->tval) );
return(p);
}
p = (Cell *) malloc(sizeof(Cell));
if (p == NULL)
ERROR "out of space for symbol table at %s", n FATAL;
p->nval = tostring(n);
p->sval = s ? tostring(s) : tostring("");
p->fval = f;
p->tval = t;
tp->nelem++;
if (tp->nelem > FULLTAB * tp->size)
rehash(tp);
h = hash(n, tp->size);
p->cnext = tp->tab[h];
tp->tab[h] = p;
dprintf( ("setsymtab set %o: n=%s s=\"%s\" f=%g t=%o\n",
p, p->nval, p->sval, p->fval, p->tval) );
return(p);
}
hash(uchar *s, int n) /* form hash value for string s */
{
register unsigned hashval;
for (hashval = 0; *s != '\0'; s++)
hashval = (*s + 31 * hashval);
return hashval % n;
}
void rehash(Array *tp) /* rehash items in small table into big one */
{
int i, nh, nsz;
Cell *cp, *op, **np;
nsz = GROWTAB * tp->size;
np = (Cell **) calloc(nsz, sizeof(Cell *));
if (np == NULL) /* can't do it, but can keep running. */
return; /* someone else will run out later. */
for (i = 0; i < tp->size; i++) {
for (cp = tp->tab[i]; cp; cp = op) {
op = cp->cnext;
nh = hash(cp->nval, nsz);
cp->cnext = np[nh];
np[nh] = cp;
}
}
free(tp->tab);
tp->tab = np;
tp->size = nsz;
}
Cell *lookup(uchar *s, Array *tp) /* look for s in tp */
{
register Cell *p, *prev = NULL;
int h;
h = hash(s, tp->size);
for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
if (strcmp((char *) s, (char *) p->nval) == 0)
return(p); /* found it */
return(NULL); /* not found */
}
Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */
{
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "assign to");
if (vp->tval & FLD) {
donerec = 0; /* mark $0 invalid */
if (vp-fldtab > *NF)
newfld(vp-fldtab);
dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
} else if (vp->tval & REC) {
donefld = 0; /* mark $1... invalid */
donerec = 1;
}
vp->tval &= ~STR; /* mark string invalid */
vp->tval |= NUM; /* mark number ok */
dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
return vp->fval = f;
}
void funnyvar(Cell *vp, char *rw)
{
if (vp->tval & ARR)
ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
if (vp->tval & FCN)
ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
}
uchar *setsval(Cell *vp, uchar *s) /* set string val of a Cell */
{
char *t;
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "assign to");
if (vp->tval & FLD) {
donerec = 0; /* mark $0 invalid */
if (vp-fldtab > *NF)
newfld(vp-fldtab);
dprintf( ("setting field %d to %s (%o)\n", vp-fldtab, s, s) );
} else if (vp->tval & REC) {
donefld = 0; /* mark $1... invalid */
donerec = 1;
}
t = tostring(s); /* in case it's self-assign */
vp->tval &= ~NUM;
vp->tval |= STR;
if (freeable(vp))
xfree(vp->sval);
vp->tval &= ~DONTFREE;
dprintf( ("setsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
return(vp->sval = t);
}
Awkfloat r_getfval(Cell *vp) /* get float val of a Cell */
{
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "read value of");
if ((vp->tval & FLD) && donefld == 0)
fldbld();
else if ((vp->tval & REC) && donerec == 0)
recbld();
if (!isnum(vp)) { /* not a number */
vp->fval = atof(vp->sval); /* best guess */
if (isnumber(vp->sval) && !(vp->tval&CON))
vp->tval |= NUM; /* make NUM only sparingly */
}
dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
return(vp->fval);
}
uchar *r_getsval(Cell *vp) /* get string val of a Cell */
{
uchar s[100];
double dtemp;
if ((vp->tval & (NUM | STR)) == 0)
funnyvar(vp, "read value of");
if ((vp->tval & FLD) && donefld == 0)
fldbld();
else if ((vp->tval & REC) && donerec == 0)
recbld();
if ((vp->tval & STR) == 0) {
if (!(vp->tval&DONTFREE))
xfree(vp->sval);
if (modf(vp->fval, &dtemp) == 0) /* it's integral */
sprintf((char *)s, "%.20g", vp->fval);
else
sprintf((char *)s, (char *)*CONVFMT, vp->fval);
vp->sval = tostring(s);
vp->tval &= ~DONTFREE;
vp->tval |= STR;
}
dprintf( ("getsval %o: %s = \"%s (%o)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
return(vp->sval);
}
uchar *tostring(uchar *s) /* make a copy of string s */
{
register uchar *p;
p = (uchar *) malloc(strlen((char *) s)+1);
if (p == NULL)
ERROR "out of space in tostring on %s", s FATAL;
strcpy((char *) p, (char *) s);
return(p);
}
uchar *qstring(uchar *s, int delim) /* collect string up to next delim */
{
uchar *q;
int c, n;
for (q = cbuf; (c = *s) != delim; s++) {
if (q >= cbuf + CBUFLEN - 1)
ERROR "string %.10s... too long", cbuf SYNTAX;
else if (c == '\n')
ERROR "newline in string %.10s...", cbuf SYNTAX;
else if (c != '\\')
*q++ = c;
else /* \something */
switch (c = *++s) {
case '\\': *q++ = '\\'; break;
case 'n': *q++ = '\n'; break;
case 't': *q++ = '\t'; break;
case 'b': *q++ = '\b'; break;
case 'f': *q++ = '\f'; break;
case 'r': *q++ = '\r'; break;
default:
if (!isdigit(c)) {
*q++ = c;
break;
}
n = c - '0';
if (isdigit(s[1])) {
n = 8 * n + *++s - '0';
if (isdigit(s[1]))
n = 8 * n + *++s - '0';
}
*q++ = n;
break;
}
}
*q = '\0';
return cbuf;
}