xref: /plan9-contrib/sys/src/cmd/awk/tran.c (revision a2c41696452f8a895ad2951a6355034fbc3034ed)
17dd7cddfSDavid du Colombier /****************************************************************
27dd7cddfSDavid du Colombier Copyright (C) Lucent Technologies 1997
33e12c5d1SDavid du Colombier All Rights Reserved
43e12c5d1SDavid du Colombier 
57dd7cddfSDavid du Colombier Permission to use, copy, modify, and distribute this software and
67dd7cddfSDavid du Colombier its documentation for any purpose and without fee is hereby
77dd7cddfSDavid du Colombier granted, provided that the above copyright notice appear in all
87dd7cddfSDavid du Colombier copies and that both that the copyright notice and this
97dd7cddfSDavid du Colombier permission notice and warranty disclaimer appear in supporting
107dd7cddfSDavid du Colombier documentation, and that the name Lucent Technologies or any of
117dd7cddfSDavid du Colombier its entities not be used in advertising or publicity pertaining
127dd7cddfSDavid du Colombier to distribution of the software without specific, written prior
137dd7cddfSDavid du Colombier permission.
143e12c5d1SDavid du Colombier 
157dd7cddfSDavid du Colombier LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
167dd7cddfSDavid du Colombier INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
177dd7cddfSDavid du Colombier IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
187dd7cddfSDavid du Colombier SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
197dd7cddfSDavid du Colombier WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
207dd7cddfSDavid du Colombier IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
217dd7cddfSDavid du Colombier ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
227dd7cddfSDavid du Colombier THIS SOFTWARE.
237dd7cddfSDavid du Colombier ****************************************************************/
243e12c5d1SDavid du Colombier 
253e12c5d1SDavid du Colombier #define	DEBUG
263e12c5d1SDavid du Colombier #include <stdio.h>
273e12c5d1SDavid du Colombier #include <math.h>
283e12c5d1SDavid du Colombier #include <ctype.h>
293e12c5d1SDavid du Colombier #include <string.h>
303e12c5d1SDavid du Colombier #include <stdlib.h>
313e12c5d1SDavid du Colombier #include "awk.h"
323e12c5d1SDavid du Colombier #include "y.tab.h"
333e12c5d1SDavid du Colombier 
343e12c5d1SDavid du Colombier #define	FULLTAB	2	/* rehash when table gets this x full */
353e12c5d1SDavid du Colombier #define	GROWTAB 4	/* grow table by this factor */
363e12c5d1SDavid du Colombier 
373e12c5d1SDavid du Colombier Array	*symtab;	/* main symbol table */
383e12c5d1SDavid du Colombier 
397dd7cddfSDavid du Colombier char	**FS;		/* initial field sep */
407dd7cddfSDavid du Colombier char	**RS;		/* initial record sep */
417dd7cddfSDavid du Colombier char	**OFS;		/* output field sep */
427dd7cddfSDavid du Colombier char	**ORS;		/* output record sep */
437dd7cddfSDavid du Colombier char	**OFMT;		/* output format for numbers */
447dd7cddfSDavid du Colombier char	**CONVFMT;	/* format for conversions in getsval */
453e12c5d1SDavid du Colombier Awkfloat *NF;		/* number of fields in current record */
463e12c5d1SDavid du Colombier Awkfloat *NR;		/* number of current record */
473e12c5d1SDavid du Colombier Awkfloat *FNR;		/* number of current record in current file */
487dd7cddfSDavid du Colombier char	**FILENAME;	/* current filename argument */
493e12c5d1SDavid du Colombier Awkfloat *ARGC;		/* number of arguments from command line */
507dd7cddfSDavid du Colombier char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
513e12c5d1SDavid du Colombier Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
523e12c5d1SDavid du Colombier Awkfloat *RLENGTH;	/* length of same */
533e12c5d1SDavid du Colombier 
54*a2c41696SDavid du Colombier Cell	*fsloc;		/* FS */
553e12c5d1SDavid du Colombier Cell	*nrloc;		/* NR */
563e12c5d1SDavid du Colombier Cell	*nfloc;		/* NF */
573e12c5d1SDavid du Colombier Cell	*fnrloc;	/* FNR */
583e12c5d1SDavid du Colombier Array	*ARGVtab;	/* symbol table containing ARGV[...] */
593e12c5d1SDavid du Colombier Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
603e12c5d1SDavid du Colombier Cell	*rstartloc;	/* RSTART */
613e12c5d1SDavid du Colombier Cell	*rlengthloc;	/* RLENGTH */
623e12c5d1SDavid du Colombier Cell	*symtabloc;	/* SYMTAB */
633e12c5d1SDavid du Colombier 
64219b2ee8SDavid du Colombier Cell	*nullloc;	/* a guaranteed empty cell */
653e12c5d1SDavid du Colombier Node	*nullnode;	/* zero&null, converted into a node for comparisons */
667dd7cddfSDavid du Colombier Cell	*literal0;
673e12c5d1SDavid du Colombier 
687dd7cddfSDavid du Colombier extern Cell **fldtab;
693e12c5d1SDavid du Colombier 
syminit(void)70219b2ee8SDavid du Colombier void syminit(void)	/* initialize symbol table with builtin vars */
713e12c5d1SDavid du Colombier {
727dd7cddfSDavid du Colombier 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
733e12c5d1SDavid du Colombier 	/* this is used for if(x)... tests: */
743e12c5d1SDavid du Colombier 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
757dd7cddfSDavid du Colombier 	nullnode = celltonode(nullloc, CCON);
76219b2ee8SDavid du Colombier 
77*a2c41696SDavid du Colombier 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
78*a2c41696SDavid du Colombier 	FS = &fsloc->sval;
793e12c5d1SDavid du Colombier 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
803e12c5d1SDavid du Colombier 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
813e12c5d1SDavid du Colombier 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
823e12c5d1SDavid du Colombier 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
83219b2ee8SDavid du Colombier 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84219b2ee8SDavid du Colombier 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
853e12c5d1SDavid du Colombier 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
863e12c5d1SDavid du Colombier 	NF = &nfloc->fval;
873e12c5d1SDavid du Colombier 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
883e12c5d1SDavid du Colombier 	NR = &nrloc->fval;
893e12c5d1SDavid du Colombier 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
903e12c5d1SDavid du Colombier 	FNR = &fnrloc->fval;
913e12c5d1SDavid du Colombier 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
923e12c5d1SDavid du Colombier 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
933e12c5d1SDavid du Colombier 	RSTART = &rstartloc->fval;
943e12c5d1SDavid du Colombier 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
953e12c5d1SDavid du Colombier 	RLENGTH = &rlengthloc->fval;
963e12c5d1SDavid du Colombier 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
977dd7cddfSDavid du Colombier 	symtabloc->sval = (char *) symtab;
983e12c5d1SDavid du Colombier }
993e12c5d1SDavid du Colombier 
arginit(int ac,char ** av)1007dd7cddfSDavid du Colombier void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1013e12c5d1SDavid du Colombier {
1023e12c5d1SDavid du Colombier 	Cell *cp;
1033e12c5d1SDavid du Colombier 	int i;
1047dd7cddfSDavid du Colombier 	char temp[50];
1053e12c5d1SDavid du Colombier 
1063e12c5d1SDavid du Colombier 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1073e12c5d1SDavid du Colombier 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1083e12c5d1SDavid du Colombier 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1097dd7cddfSDavid du Colombier 	cp->sval = (char *) ARGVtab;
1103e12c5d1SDavid du Colombier 	for (i = 0; i < ac; i++) {
1117dd7cddfSDavid du Colombier 		sprintf(temp, "%d", i);
1127dd7cddfSDavid du Colombier 		if (is_number(*av))
1133e12c5d1SDavid du Colombier 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
1143e12c5d1SDavid du Colombier 		else
1153e12c5d1SDavid du Colombier 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1163e12c5d1SDavid du Colombier 		av++;
1173e12c5d1SDavid du Colombier 	}
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier 
envinit(char ** envp)1207dd7cddfSDavid du Colombier void envinit(char **envp)	/* set up ENVIRON variable */
1213e12c5d1SDavid du Colombier {
1223e12c5d1SDavid du Colombier 	Cell *cp;
1237dd7cddfSDavid du Colombier 	char *p;
1243e12c5d1SDavid du Colombier 
1253e12c5d1SDavid du Colombier 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1263e12c5d1SDavid du Colombier 	ENVtab = makesymtab(NSYMTAB);
1277dd7cddfSDavid du Colombier 	cp->sval = (char *) ENVtab;
1283e12c5d1SDavid du Colombier 	for ( ; *envp; envp++) {
1297dd7cddfSDavid du Colombier 		if ((p = strchr(*envp, '=')) == NULL)
1303e12c5d1SDavid du Colombier 			continue;
131*a2c41696SDavid du Colombier 		if( p == *envp ) /* no left hand side name in env string */
132*a2c41696SDavid du Colombier 			continue;
1333e12c5d1SDavid du Colombier 		*p++ = 0;	/* split into two strings at = */
1347dd7cddfSDavid du Colombier 		if (is_number(p))
1353e12c5d1SDavid du Colombier 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
1363e12c5d1SDavid du Colombier 		else
1373e12c5d1SDavid du Colombier 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1383e12c5d1SDavid du Colombier 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1393e12c5d1SDavid du Colombier 	}
1403e12c5d1SDavid du Colombier }
1413e12c5d1SDavid du Colombier 
makesymtab(int n)142219b2ee8SDavid du Colombier Array *makesymtab(int n)	/* make a new symbol table */
1433e12c5d1SDavid du Colombier {
1443e12c5d1SDavid du Colombier 	Array *ap;
1453e12c5d1SDavid du Colombier 	Cell **tp;
1463e12c5d1SDavid du Colombier 
1473e12c5d1SDavid du Colombier 	ap = (Array *) malloc(sizeof(Array));
1483e12c5d1SDavid du Colombier 	tp = (Cell **) calloc(n, sizeof(Cell *));
1493e12c5d1SDavid du Colombier 	if (ap == NULL || tp == NULL)
1507dd7cddfSDavid du Colombier 		FATAL("out of space in makesymtab");
1513e12c5d1SDavid du Colombier 	ap->nelem = 0;
1523e12c5d1SDavid du Colombier 	ap->size = n;
1533e12c5d1SDavid du Colombier 	ap->tab = tp;
1543e12c5d1SDavid du Colombier 	return(ap);
1553e12c5d1SDavid du Colombier }
1563e12c5d1SDavid du Colombier 
freesymtab(Cell * ap)157219b2ee8SDavid du Colombier void freesymtab(Cell *ap)	/* free a symbol table */
1583e12c5d1SDavid du Colombier {
1593e12c5d1SDavid du Colombier 	Cell *cp, *temp;
1603e12c5d1SDavid du Colombier 	Array *tp;
1613e12c5d1SDavid du Colombier 	int i;
1623e12c5d1SDavid du Colombier 
1633e12c5d1SDavid du Colombier 	if (!isarr(ap))
1643e12c5d1SDavid du Colombier 		return;
1653e12c5d1SDavid du Colombier 	tp = (Array *) ap->sval;
1663e12c5d1SDavid du Colombier 	if (tp == NULL)
1673e12c5d1SDavid du Colombier 		return;
1683e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {
1693e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1703e12c5d1SDavid du Colombier 			xfree(cp->nval);
1713e12c5d1SDavid du Colombier 			if (freeable(cp))
1723e12c5d1SDavid du Colombier 				xfree(cp->sval);
1733e12c5d1SDavid du Colombier 			temp = cp->cnext;	/* avoids freeing then using */
1743e12c5d1SDavid du Colombier 			free(cp);
175*a2c41696SDavid du Colombier 			tp->nelem--;
1763e12c5d1SDavid du Colombier 		}
1777dd7cddfSDavid du Colombier 		tp->tab[i] = 0;
1783e12c5d1SDavid du Colombier 	}
179*a2c41696SDavid du Colombier 	if (tp->nelem != 0)
180*a2c41696SDavid du Colombier 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1813e12c5d1SDavid du Colombier 	free(tp->tab);
1823e12c5d1SDavid du Colombier 	free(tp);
1833e12c5d1SDavid du Colombier }
1843e12c5d1SDavid du Colombier 
freeelem(Cell * ap,const char * s)185*a2c41696SDavid du Colombier void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
1863e12c5d1SDavid du Colombier {
1873e12c5d1SDavid du Colombier 	Array *tp;
1883e12c5d1SDavid du Colombier 	Cell *p, *prev = NULL;
1893e12c5d1SDavid du Colombier 	int h;
1903e12c5d1SDavid du Colombier 
1913e12c5d1SDavid du Colombier 	tp = (Array *) ap->sval;
1923e12c5d1SDavid du Colombier 	h = hash(s, tp->size);
1933e12c5d1SDavid du Colombier 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1947dd7cddfSDavid du Colombier 		if (strcmp(s, p->nval) == 0) {
1953e12c5d1SDavid du Colombier 			if (prev == NULL)	/* 1st one */
1963e12c5d1SDavid du Colombier 				tp->tab[h] = p->cnext;
1973e12c5d1SDavid du Colombier 			else			/* middle somewhere */
1983e12c5d1SDavid du Colombier 				prev->cnext = p->cnext;
1993e12c5d1SDavid du Colombier 			if (freeable(p))
2003e12c5d1SDavid du Colombier 				xfree(p->sval);
2013e12c5d1SDavid du Colombier 			free(p->nval);
2023e12c5d1SDavid du Colombier 			free(p);
2033e12c5d1SDavid du Colombier 			tp->nelem--;
2043e12c5d1SDavid du Colombier 			return;
2053e12c5d1SDavid du Colombier 		}
2063e12c5d1SDavid du Colombier }
2073e12c5d1SDavid du Colombier 
setsymtab(const char * n,const char * s,Awkfloat f,unsigned t,Array * tp)208*a2c41696SDavid du Colombier Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2093e12c5d1SDavid du Colombier {
2107dd7cddfSDavid du Colombier 	int h;
2117dd7cddfSDavid du Colombier 	Cell *p;
2123e12c5d1SDavid du Colombier 
2133e12c5d1SDavid du Colombier 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
2147dd7cddfSDavid du Colombier 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
215*a2c41696SDavid du Colombier 			(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
2163e12c5d1SDavid du Colombier 		return(p);
2173e12c5d1SDavid du Colombier 	}
2183e12c5d1SDavid du Colombier 	p = (Cell *) malloc(sizeof(Cell));
2193e12c5d1SDavid du Colombier 	if (p == NULL)
2207dd7cddfSDavid du Colombier 		FATAL("out of space for symbol table at %s", n);
2213e12c5d1SDavid du Colombier 	p->nval = tostring(n);
2223e12c5d1SDavid du Colombier 	p->sval = s ? tostring(s) : tostring("");
2233e12c5d1SDavid du Colombier 	p->fval = f;
2243e12c5d1SDavid du Colombier 	p->tval = t;
2257dd7cddfSDavid du Colombier 	p->csub = CUNK;
2267dd7cddfSDavid du Colombier 	p->ctype = OCELL;
2273e12c5d1SDavid du Colombier 	tp->nelem++;
2283e12c5d1SDavid du Colombier 	if (tp->nelem > FULLTAB * tp->size)
2293e12c5d1SDavid du Colombier 		rehash(tp);
2303e12c5d1SDavid du Colombier 	h = hash(n, tp->size);
2313e12c5d1SDavid du Colombier 	p->cnext = tp->tab[h];
2323e12c5d1SDavid du Colombier 	tp->tab[h] = p;
2337dd7cddfSDavid du Colombier 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
234*a2c41696SDavid du Colombier 		(void*)p, p->nval, p->sval, p->fval, p->tval) );
2353e12c5d1SDavid du Colombier 	return(p);
2363e12c5d1SDavid du Colombier }
2373e12c5d1SDavid du Colombier 
hash(const char * s,int n)238*a2c41696SDavid du Colombier int hash(const char *s, int n)	/* form hash value for string s */
2393e12c5d1SDavid du Colombier {
2407dd7cddfSDavid du Colombier 	unsigned hashval;
2413e12c5d1SDavid du Colombier 
2423e12c5d1SDavid du Colombier 	for (hashval = 0; *s != '\0'; s++)
2433e12c5d1SDavid du Colombier 		hashval = (*s + 31 * hashval);
2443e12c5d1SDavid du Colombier 	return hashval % n;
2453e12c5d1SDavid du Colombier }
2463e12c5d1SDavid du Colombier 
rehash(Array * tp)2473e12c5d1SDavid du Colombier void rehash(Array *tp)	/* rehash items in small table into big one */
2483e12c5d1SDavid du Colombier {
2493e12c5d1SDavid du Colombier 	int i, nh, nsz;
2503e12c5d1SDavid du Colombier 	Cell *cp, *op, **np;
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier 	nsz = GROWTAB * tp->size;
2533e12c5d1SDavid du Colombier 	np = (Cell **) calloc(nsz, sizeof(Cell *));
254219b2ee8SDavid du Colombier 	if (np == NULL)		/* can't do it, but can keep running. */
255219b2ee8SDavid du Colombier 		return;		/* someone else will run out later. */
2563e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {
2573e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp; cp = op) {
2583e12c5d1SDavid du Colombier 			op = cp->cnext;
2593e12c5d1SDavid du Colombier 			nh = hash(cp->nval, nsz);
2603e12c5d1SDavid du Colombier 			cp->cnext = np[nh];
2613e12c5d1SDavid du Colombier 			np[nh] = cp;
2623e12c5d1SDavid du Colombier 		}
2633e12c5d1SDavid du Colombier 	}
2643e12c5d1SDavid du Colombier 	free(tp->tab);
2653e12c5d1SDavid du Colombier 	tp->tab = np;
2663e12c5d1SDavid du Colombier 	tp->size = nsz;
2673e12c5d1SDavid du Colombier }
2683e12c5d1SDavid du Colombier 
lookup(const char * s,Array * tp)269*a2c41696SDavid du Colombier Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
2703e12c5d1SDavid du Colombier {
2717dd7cddfSDavid du Colombier 	Cell *p;
2723e12c5d1SDavid du Colombier 	int h;
2733e12c5d1SDavid du Colombier 
2743e12c5d1SDavid du Colombier 	h = hash(s, tp->size);
2757dd7cddfSDavid du Colombier 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
2767dd7cddfSDavid du Colombier 		if (strcmp(s, p->nval) == 0)
2773e12c5d1SDavid du Colombier 			return(p);	/* found it */
2783e12c5d1SDavid du Colombier 	return(NULL);			/* not found */
2793e12c5d1SDavid du Colombier }
2803e12c5d1SDavid du Colombier 
setfval(Cell * vp,Awkfloat f)281219b2ee8SDavid du Colombier Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
2823e12c5d1SDavid du Colombier {
2837dd7cddfSDavid du Colombier 	int fldno;
2847dd7cddfSDavid du Colombier 
2853e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
2863e12c5d1SDavid du Colombier 		funnyvar(vp, "assign to");
2877dd7cddfSDavid du Colombier 	if (isfld(vp)) {
2883e12c5d1SDavid du Colombier 		donerec = 0;	/* mark $0 invalid */
2897dd7cddfSDavid du Colombier 		fldno = atoi(vp->nval);
2907dd7cddfSDavid du Colombier 		if (fldno > *NF)
2917dd7cddfSDavid du Colombier 			newfld(fldno);
2927dd7cddfSDavid du Colombier 		   dprintf( ("setting field %d to %g\n", fldno, f) );
2937dd7cddfSDavid du Colombier 	} else if (isrec(vp)) {
2943e12c5d1SDavid du Colombier 		donefld = 0;	/* mark $1... invalid */
2953e12c5d1SDavid du Colombier 		donerec = 1;
2963e12c5d1SDavid du Colombier 	}
2977dd7cddfSDavid du Colombier 	if (freeable(vp))
2987dd7cddfSDavid du Colombier 		xfree(vp->sval); /* free any previous string */
2993e12c5d1SDavid du Colombier 	vp->tval &= ~STR;	/* mark string invalid */
3003e12c5d1SDavid du Colombier 	vp->tval |= NUM;	/* mark number ok */
301*a2c41696SDavid du Colombier 	if (f == -0)  /* who would have thought this possible? */
302*a2c41696SDavid du Colombier 		f = 0;
303*a2c41696SDavid du Colombier 	   dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
3043e12c5d1SDavid du Colombier 	return vp->fval = f;
3053e12c5d1SDavid du Colombier }
3063e12c5d1SDavid du Colombier 
funnyvar(Cell * vp,const char * rw)307*a2c41696SDavid du Colombier void funnyvar(Cell *vp, const char *rw)
3083e12c5d1SDavid du Colombier {
3097dd7cddfSDavid du Colombier 	if (isarr(vp))
3107dd7cddfSDavid du Colombier 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3113e12c5d1SDavid du Colombier 	if (vp->tval & FCN)
3127dd7cddfSDavid du Colombier 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
3137dd7cddfSDavid du Colombier 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3147dd7cddfSDavid du Colombier 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
3153e12c5d1SDavid du Colombier }
3163e12c5d1SDavid du Colombier 
setsval(Cell * vp,const char * s)317*a2c41696SDavid du Colombier char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
3183e12c5d1SDavid du Colombier {
319219b2ee8SDavid du Colombier 	char *t;
3207dd7cddfSDavid du Colombier 	int fldno;
321219b2ee8SDavid du Colombier 
322*a2c41696SDavid du Colombier 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
323*a2c41696SDavid du Colombier 		(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
3243e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
3253e12c5d1SDavid du Colombier 		funnyvar(vp, "assign to");
3267dd7cddfSDavid du Colombier 	if (isfld(vp)) {
3273e12c5d1SDavid du Colombier 		donerec = 0;	/* mark $0 invalid */
3287dd7cddfSDavid du Colombier 		fldno = atoi(vp->nval);
3297dd7cddfSDavid du Colombier 		if (fldno > *NF)
3307dd7cddfSDavid du Colombier 			newfld(fldno);
3317dd7cddfSDavid du Colombier 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
3327dd7cddfSDavid du Colombier 	} else if (isrec(vp)) {
3333e12c5d1SDavid du Colombier 		donefld = 0;	/* mark $1... invalid */
3343e12c5d1SDavid du Colombier 		donerec = 1;
3353e12c5d1SDavid du Colombier 	}
336219b2ee8SDavid du Colombier 	t = tostring(s);	/* in case it's self-assign */
3373e12c5d1SDavid du Colombier 	if (freeable(vp))
3383e12c5d1SDavid du Colombier 		xfree(vp->sval);
339*a2c41696SDavid du Colombier 	vp->tval &= ~NUM;
340*a2c41696SDavid du Colombier 	vp->tval |= STR;
3413e12c5d1SDavid du Colombier 	vp->tval &= ~DONTFREE;
342*a2c41696SDavid du Colombier 	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
343*a2c41696SDavid du Colombier 		(void*)vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
344219b2ee8SDavid du Colombier 	return(vp->sval = t);
3453e12c5d1SDavid du Colombier }
3463e12c5d1SDavid du Colombier 
getfval(Cell * vp)3477dd7cddfSDavid du Colombier Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3483e12c5d1SDavid du Colombier {
3493e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
3503e12c5d1SDavid du Colombier 		funnyvar(vp, "read value of");
3517dd7cddfSDavid du Colombier 	if (isfld(vp) && donefld == 0)
3523e12c5d1SDavid du Colombier 		fldbld();
3537dd7cddfSDavid du Colombier 	else if (isrec(vp) && donerec == 0)
3543e12c5d1SDavid du Colombier 		recbld();
3553e12c5d1SDavid du Colombier 	if (!isnum(vp)) {	/* not a number */
3563e12c5d1SDavid du Colombier 		vp->fval = atof(vp->sval);	/* best guess */
3577dd7cddfSDavid du Colombier 		if (is_number(vp->sval) && !(vp->tval&CON))
3583e12c5d1SDavid du Colombier 			vp->tval |= NUM;	/* make NUM only sparingly */
3593e12c5d1SDavid du Colombier 	}
360*a2c41696SDavid du Colombier 	   dprintf( ("getfval %p: %s = %g, t=%o\n",
361*a2c41696SDavid du Colombier 		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
3623e12c5d1SDavid du Colombier 	return(vp->fval);
3633e12c5d1SDavid du Colombier }
3643e12c5d1SDavid du Colombier 
get_str_val(Cell * vp,char ** fmt)365*a2c41696SDavid du Colombier static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
3663e12c5d1SDavid du Colombier {
3677dd7cddfSDavid du Colombier 	char s[100];	/* BUG: unchecked */
3683e12c5d1SDavid du Colombier 	double dtemp;
3693e12c5d1SDavid du Colombier 
3703e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
3713e12c5d1SDavid du Colombier 		funnyvar(vp, "read value of");
3727dd7cddfSDavid du Colombier 	if (isfld(vp) && donefld == 0)
3733e12c5d1SDavid du Colombier 		fldbld();
3747dd7cddfSDavid du Colombier 	else if (isrec(vp) && donerec == 0)
3753e12c5d1SDavid du Colombier 		recbld();
3767dd7cddfSDavid du Colombier 	if (isstr(vp) == 0) {
3777dd7cddfSDavid du Colombier 		if (freeable(vp))
3783e12c5d1SDavid du Colombier 			xfree(vp->sval);
3793e12c5d1SDavid du Colombier 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
3807dd7cddfSDavid du Colombier 			sprintf(s, "%.30g", vp->fval);
3813e12c5d1SDavid du Colombier 		else
382*a2c41696SDavid du Colombier 			sprintf(s, *fmt, vp->fval);
3833e12c5d1SDavid du Colombier 		vp->sval = tostring(s);
3843e12c5d1SDavid du Colombier 		vp->tval &= ~DONTFREE;
3853e12c5d1SDavid du Colombier 		vp->tval |= STR;
3863e12c5d1SDavid du Colombier 	}
387*a2c41696SDavid du Colombier 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
388*a2c41696SDavid du Colombier 		(void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
3893e12c5d1SDavid du Colombier 	return(vp->sval);
3903e12c5d1SDavid du Colombier }
3913e12c5d1SDavid du Colombier 
getsval(Cell * vp)392*a2c41696SDavid du Colombier char *getsval(Cell *vp)       /* get string val of a Cell */
393*a2c41696SDavid du Colombier {
394*a2c41696SDavid du Colombier       return get_str_val(vp, CONVFMT);
395*a2c41696SDavid du Colombier }
396*a2c41696SDavid du Colombier 
getpssval(Cell * vp)397*a2c41696SDavid du Colombier char *getpssval(Cell *vp)     /* get string val of a Cell for print */
398*a2c41696SDavid du Colombier {
399*a2c41696SDavid du Colombier       return get_str_val(vp, OFMT);
400*a2c41696SDavid du Colombier }
401*a2c41696SDavid du Colombier 
402*a2c41696SDavid du Colombier 
tostring(const char * s)403*a2c41696SDavid du Colombier char *tostring(const char *s)	/* make a copy of string s */
4043e12c5d1SDavid du Colombier {
4057dd7cddfSDavid du Colombier 	char *p;
4063e12c5d1SDavid du Colombier 
4077dd7cddfSDavid du Colombier 	p = (char *) malloc(strlen(s)+1);
4083e12c5d1SDavid du Colombier 	if (p == NULL)
4097dd7cddfSDavid du Colombier 		FATAL("out of space in tostring on %s", s);
4107dd7cddfSDavid du Colombier 	strcpy(p, s);
4113e12c5d1SDavid du Colombier 	return(p);
4123e12c5d1SDavid du Colombier }
4133e12c5d1SDavid du Colombier 
qstring(const char * is,int delim)414*a2c41696SDavid du Colombier char *qstring(const char *is, int delim)	/* collect string up to next delim */
4153e12c5d1SDavid du Colombier {
416*a2c41696SDavid du Colombier 	const char *os = is;
4173e12c5d1SDavid du Colombier 	int c, n;
418*a2c41696SDavid du Colombier 	uschar *s = (uschar *) is;
419*a2c41696SDavid du Colombier 	uschar *buf, *bp;
4203e12c5d1SDavid du Colombier 
421*a2c41696SDavid du Colombier 	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
4227dd7cddfSDavid du Colombier 		FATAL( "out of space in qstring(%s)", s);
4237dd7cddfSDavid du Colombier 	for (bp = buf; (c = *s) != delim; s++) {
4247dd7cddfSDavid du Colombier 		if (c == '\n')
4257dd7cddfSDavid du Colombier 			SYNTAX( "newline in string %.20s...", os );
4263e12c5d1SDavid du Colombier 		else if (c != '\\')
4277dd7cddfSDavid du Colombier 			*bp++ = c;
4287dd7cddfSDavid du Colombier 		else {	/* \something */
4297dd7cddfSDavid du Colombier 			c = *++s;
4307dd7cddfSDavid du Colombier 			if (c == 0) {	/* \ at end */
4317dd7cddfSDavid du Colombier 				*bp++ = '\\';
4327dd7cddfSDavid du Colombier 				break;	/* for loop */
4337dd7cddfSDavid du Colombier 			}
4347dd7cddfSDavid du Colombier 			switch (c) {
4357dd7cddfSDavid du Colombier 			case '\\':	*bp++ = '\\'; break;
4367dd7cddfSDavid du Colombier 			case 'n':	*bp++ = '\n'; break;
4377dd7cddfSDavid du Colombier 			case 't':	*bp++ = '\t'; break;
4387dd7cddfSDavid du Colombier 			case 'b':	*bp++ = '\b'; break;
4397dd7cddfSDavid du Colombier 			case 'f':	*bp++ = '\f'; break;
4407dd7cddfSDavid du Colombier 			case 'r':	*bp++ = '\r'; break;
4413e12c5d1SDavid du Colombier 			default:
4423e12c5d1SDavid du Colombier 				if (!isdigit(c)) {
4437dd7cddfSDavid du Colombier 					*bp++ = c;
4443e12c5d1SDavid du Colombier 					break;
4453e12c5d1SDavid du Colombier 				}
4463e12c5d1SDavid du Colombier 				n = c - '0';
4473e12c5d1SDavid du Colombier 				if (isdigit(s[1])) {
4483e12c5d1SDavid du Colombier 					n = 8 * n + *++s - '0';
4493e12c5d1SDavid du Colombier 					if (isdigit(s[1]))
4503e12c5d1SDavid du Colombier 						n = 8 * n + *++s - '0';
4513e12c5d1SDavid du Colombier 				}
4527dd7cddfSDavid du Colombier 				*bp++ = n;
4533e12c5d1SDavid du Colombier 				break;
4543e12c5d1SDavid du Colombier 			}
4553e12c5d1SDavid du Colombier 		}
4567dd7cddfSDavid du Colombier 	}
4577dd7cddfSDavid du Colombier 	*bp++ = 0;
458*a2c41696SDavid du Colombier 	return (char *) buf;
4593e12c5d1SDavid du Colombier }
460