xref: /plan9-contrib/sys/src/cmd/awk/tran.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
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