xref: /dflybsd-src/contrib/awk/tran.c (revision b12bae1807abcf1f0dca9dd069ba090c7167812d)
14b588458SPeter Avalos /****************************************************************
24b588458SPeter Avalos Copyright (C) Lucent Technologies 1997
34b588458SPeter Avalos All Rights Reserved
44b588458SPeter Avalos 
54b588458SPeter Avalos Permission to use, copy, modify, and distribute this software and
64b588458SPeter Avalos its documentation for any purpose and without fee is hereby
74b588458SPeter Avalos granted, provided that the above copyright notice appear in all
84b588458SPeter Avalos copies and that both that the copyright notice and this
94b588458SPeter Avalos permission notice and warranty disclaimer appear in supporting
104b588458SPeter Avalos documentation, and that the name Lucent Technologies or any of
114b588458SPeter Avalos its entities not be used in advertising or publicity pertaining
124b588458SPeter Avalos to distribution of the software without specific, written prior
134b588458SPeter Avalos permission.
144b588458SPeter Avalos 
154b588458SPeter Avalos LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
164b588458SPeter Avalos INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
174b588458SPeter Avalos IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
184b588458SPeter Avalos SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
194b588458SPeter Avalos WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
204b588458SPeter Avalos IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
214b588458SPeter Avalos ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
224b588458SPeter Avalos THIS SOFTWARE.
234b588458SPeter Avalos ****************************************************************/
244b588458SPeter Avalos 
254b588458SPeter Avalos #define	DEBUG
264b588458SPeter Avalos #include <stdio.h>
274b588458SPeter Avalos #include <math.h>
284b588458SPeter Avalos #include <ctype.h>
294b588458SPeter Avalos #include <string.h>
304b588458SPeter Avalos #include <stdlib.h>
314b588458SPeter Avalos #include "awk.h"
324b588458SPeter Avalos #include "ytab.h"
334b588458SPeter Avalos 
344b588458SPeter Avalos #define	FULLTAB	2	/* rehash when table gets this x full */
354b588458SPeter Avalos #define	GROWTAB 4	/* grow table by this factor */
364b588458SPeter Avalos 
374b588458SPeter Avalos Array	*symtab;	/* main symbol table */
384b588458SPeter Avalos 
394b588458SPeter Avalos char	**FS;		/* initial field sep */
404b588458SPeter Avalos char	**RS;		/* initial record sep */
414b588458SPeter Avalos char	**OFS;		/* output field sep */
424b588458SPeter Avalos char	**ORS;		/* output record sep */
434b588458SPeter Avalos char	**OFMT;		/* output format for numbers */
444b588458SPeter Avalos char	**CONVFMT;	/* format for conversions in getsval */
454b588458SPeter Avalos Awkfloat *NF;		/* number of fields in current record */
464b588458SPeter Avalos Awkfloat *NR;		/* number of current record */
474b588458SPeter Avalos Awkfloat *FNR;		/* number of current record in current file */
484b588458SPeter Avalos char	**FILENAME;	/* current filename argument */
494b588458SPeter Avalos Awkfloat *ARGC;		/* number of arguments from command line */
504b588458SPeter Avalos char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
514b588458SPeter Avalos Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
524b588458SPeter Avalos Awkfloat *RLENGTH;	/* length of same */
534b588458SPeter Avalos 
544b588458SPeter Avalos Cell	*fsloc;		/* FS */
554b588458SPeter Avalos Cell	*nrloc;		/* NR */
564b588458SPeter Avalos Cell	*nfloc;		/* NF */
574b588458SPeter Avalos Cell	*fnrloc;	/* FNR */
584b588458SPeter Avalos Array	*ARGVtab;	/* symbol table containing ARGV[...] */
594b588458SPeter Avalos Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
604b588458SPeter Avalos Cell	*rstartloc;	/* RSTART */
614b588458SPeter Avalos Cell	*rlengthloc;	/* RLENGTH */
624b588458SPeter Avalos Cell	*symtabloc;	/* SYMTAB */
634b588458SPeter Avalos 
644b588458SPeter Avalos Cell	*nullloc;	/* a guaranteed empty cell */
654b588458SPeter Avalos Node	*nullnode;	/* zero&null, converted into a node for comparisons */
664b588458SPeter Avalos Cell	*literal0;
674b588458SPeter Avalos 
684b588458SPeter Avalos extern Cell **fldtab;
694b588458SPeter Avalos 
704b588458SPeter Avalos void syminit(void)	/* initialize symbol table with builtin vars */
714b588458SPeter Avalos {
724b588458SPeter Avalos 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
734b588458SPeter Avalos 	/* this is used for if(x)... tests: */
744b588458SPeter Avalos 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
754b588458SPeter Avalos 	nullnode = celltonode(nullloc, CCON);
764b588458SPeter Avalos 
774b588458SPeter Avalos 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
784b588458SPeter Avalos 	FS = &fsloc->sval;
794b588458SPeter Avalos 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
804b588458SPeter Avalos 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
814b588458SPeter Avalos 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
824b588458SPeter Avalos 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
834b588458SPeter Avalos 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
844b588458SPeter Avalos 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
854b588458SPeter Avalos 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
864b588458SPeter Avalos 	NF = &nfloc->fval;
874b588458SPeter Avalos 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
884b588458SPeter Avalos 	NR = &nrloc->fval;
894b588458SPeter Avalos 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
904b588458SPeter Avalos 	FNR = &fnrloc->fval;
914b588458SPeter Avalos 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
924b588458SPeter Avalos 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
934b588458SPeter Avalos 	RSTART = &rstartloc->fval;
944b588458SPeter Avalos 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
954b588458SPeter Avalos 	RLENGTH = &rlengthloc->fval;
964b588458SPeter Avalos 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
974b588458SPeter Avalos 	symtabloc->sval = (char *) symtab;
984b588458SPeter Avalos }
994b588458SPeter Avalos 
1004b588458SPeter Avalos void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1014b588458SPeter Avalos {
1024b588458SPeter Avalos 	Cell *cp;
1034b588458SPeter Avalos 	int i;
1044b588458SPeter Avalos 	char temp[50];
1054b588458SPeter Avalos 
1064b588458SPeter Avalos 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1074b588458SPeter Avalos 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1084b588458SPeter Avalos 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1094b588458SPeter Avalos 	cp->sval = (char *) ARGVtab;
1104b588458SPeter Avalos 	for (i = 0; i < ac; i++) {
1114b588458SPeter Avalos 		sprintf(temp, "%d", i);
1124b588458SPeter Avalos 		if (is_number(*av))
1134b588458SPeter Avalos 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
1144b588458SPeter Avalos 		else
1154b588458SPeter Avalos 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1164b588458SPeter Avalos 		av++;
1174b588458SPeter Avalos 	}
1184b588458SPeter Avalos }
1194b588458SPeter Avalos 
1204b588458SPeter Avalos void envinit(char **envp)	/* set up ENVIRON variable */
1214b588458SPeter Avalos {
1224b588458SPeter Avalos 	Cell *cp;
1234b588458SPeter Avalos 	char *p;
1244b588458SPeter Avalos 
1254b588458SPeter Avalos 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1264b588458SPeter Avalos 	ENVtab = makesymtab(NSYMTAB);
1274b588458SPeter Avalos 	cp->sval = (char *) ENVtab;
1284b588458SPeter Avalos 	for ( ; *envp; envp++) {
1294b588458SPeter Avalos 		if ((p = strchr(*envp, '=')) == NULL)
1304b588458SPeter Avalos 			continue;
1314b588458SPeter Avalos 		if( p == *envp ) /* no left hand side name in env string */
1324b588458SPeter Avalos 			continue;
1334b588458SPeter Avalos 		*p++ = 0;	/* split into two strings at = */
1344b588458SPeter Avalos 		if (is_number(p))
1354b588458SPeter Avalos 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
1364b588458SPeter Avalos 		else
1374b588458SPeter Avalos 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1384b588458SPeter Avalos 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1394b588458SPeter Avalos 	}
1404b588458SPeter Avalos }
1414b588458SPeter Avalos 
1424b588458SPeter Avalos Array *makesymtab(int n)	/* make a new symbol table */
1434b588458SPeter Avalos {
1444b588458SPeter Avalos 	Array *ap;
1454b588458SPeter Avalos 	Cell **tp;
1464b588458SPeter Avalos 
1474b588458SPeter Avalos 	ap = (Array *) malloc(sizeof(Array));
1484b588458SPeter Avalos 	tp = (Cell **) calloc(n, sizeof(Cell *));
1494b588458SPeter Avalos 	if (ap == NULL || tp == NULL)
1504b588458SPeter Avalos 		FATAL("out of space in makesymtab");
1514b588458SPeter Avalos 	ap->nelem = 0;
1524b588458SPeter Avalos 	ap->size = n;
1534b588458SPeter Avalos 	ap->tab = tp;
1544b588458SPeter Avalos 	return(ap);
1554b588458SPeter Avalos }
1564b588458SPeter Avalos 
1574b588458SPeter Avalos void freesymtab(Cell *ap)	/* free a symbol table */
1584b588458SPeter Avalos {
1594b588458SPeter Avalos 	Cell *cp, *temp;
1604b588458SPeter Avalos 	Array *tp;
1614b588458SPeter Avalos 	int i;
1624b588458SPeter Avalos 
1634b588458SPeter Avalos 	if (!isarr(ap))
1644b588458SPeter Avalos 		return;
1654b588458SPeter Avalos 	tp = (Array *) ap->sval;
1664b588458SPeter Avalos 	if (tp == NULL)
1674b588458SPeter Avalos 		return;
1684b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
1694b588458SPeter Avalos 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1704b588458SPeter Avalos 			xfree(cp->nval);
1714b588458SPeter Avalos 			if (freeable(cp))
1724b588458SPeter Avalos 				xfree(cp->sval);
1734b588458SPeter Avalos 			temp = cp->cnext;	/* avoids freeing then using */
1744b588458SPeter Avalos 			free(cp);
1754b588458SPeter Avalos 			tp->nelem--;
1764b588458SPeter Avalos 		}
1774b588458SPeter Avalos 		tp->tab[i] = 0;
1784b588458SPeter Avalos 	}
1794b588458SPeter Avalos 	if (tp->nelem != 0)
1804b588458SPeter Avalos 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
1814b588458SPeter Avalos 	free(tp->tab);
1824b588458SPeter Avalos 	free(tp);
1834b588458SPeter Avalos }
1844b588458SPeter Avalos 
1854b588458SPeter Avalos void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
1864b588458SPeter Avalos {
1874b588458SPeter Avalos 	Array *tp;
1884b588458SPeter Avalos 	Cell *p, *prev = NULL;
1894b588458SPeter Avalos 	int h;
1904b588458SPeter Avalos 
1914b588458SPeter Avalos 	tp = (Array *) ap->sval;
1924b588458SPeter Avalos 	h = hash(s, tp->size);
1934b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
1944b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0) {
1954b588458SPeter Avalos 			if (prev == NULL)	/* 1st one */
1964b588458SPeter Avalos 				tp->tab[h] = p->cnext;
1974b588458SPeter Avalos 			else			/* middle somewhere */
1984b588458SPeter Avalos 				prev->cnext = p->cnext;
1994b588458SPeter Avalos 			if (freeable(p))
2004b588458SPeter Avalos 				xfree(p->sval);
2014b588458SPeter Avalos 			free(p->nval);
2024b588458SPeter Avalos 			free(p);
2034b588458SPeter Avalos 			tp->nelem--;
2044b588458SPeter Avalos 			return;
2054b588458SPeter Avalos 		}
2064b588458SPeter Avalos }
2074b588458SPeter Avalos 
2084b588458SPeter Avalos Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2094b588458SPeter Avalos {
2104b588458SPeter Avalos 	int h;
2114b588458SPeter Avalos 	Cell *p;
2124b588458SPeter Avalos 
2134b588458SPeter Avalos 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
2144b588458SPeter Avalos 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
215*b12bae18SSascha Wildner 			(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
2164b588458SPeter Avalos 		return(p);
2174b588458SPeter Avalos 	}
2184b588458SPeter Avalos 	p = (Cell *) malloc(sizeof(Cell));
2194b588458SPeter Avalos 	if (p == NULL)
2204b588458SPeter Avalos 		FATAL("out of space for symbol table at %s", n);
2214b588458SPeter Avalos 	p->nval = tostring(n);
2224b588458SPeter Avalos 	p->sval = s ? tostring(s) : tostring("");
2234b588458SPeter Avalos 	p->fval = f;
2244b588458SPeter Avalos 	p->tval = t;
2254b588458SPeter Avalos 	p->csub = CUNK;
2264b588458SPeter Avalos 	p->ctype = OCELL;
2274b588458SPeter Avalos 	tp->nelem++;
2284b588458SPeter Avalos 	if (tp->nelem > FULLTAB * tp->size)
2294b588458SPeter Avalos 		rehash(tp);
2304b588458SPeter Avalos 	h = hash(n, tp->size);
2314b588458SPeter Avalos 	p->cnext = tp->tab[h];
2324b588458SPeter Avalos 	tp->tab[h] = p;
2334b588458SPeter Avalos 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
234*b12bae18SSascha Wildner 		(void*)p, p->nval, p->sval, p->fval, p->tval) );
2354b588458SPeter Avalos 	return(p);
2364b588458SPeter Avalos }
2374b588458SPeter Avalos 
2384b588458SPeter Avalos int hash(const char *s, int n)	/* form hash value for string s */
2394b588458SPeter Avalos {
2404b588458SPeter Avalos 	unsigned hashval;
2414b588458SPeter Avalos 
2424b588458SPeter Avalos 	for (hashval = 0; *s != '\0'; s++)
2434b588458SPeter Avalos 		hashval = (*s + 31 * hashval);
2444b588458SPeter Avalos 	return hashval % n;
2454b588458SPeter Avalos }
2464b588458SPeter Avalos 
2474b588458SPeter Avalos void rehash(Array *tp)	/* rehash items in small table into big one */
2484b588458SPeter Avalos {
2494b588458SPeter Avalos 	int i, nh, nsz;
2504b588458SPeter Avalos 	Cell *cp, *op, **np;
2514b588458SPeter Avalos 
2524b588458SPeter Avalos 	nsz = GROWTAB * tp->size;
2534b588458SPeter Avalos 	np = (Cell **) calloc(nsz, sizeof(Cell *));
2544b588458SPeter Avalos 	if (np == NULL)		/* can't do it, but can keep running. */
2554b588458SPeter Avalos 		return;		/* someone else will run out later. */
2564b588458SPeter Avalos 	for (i = 0; i < tp->size; i++) {
2574b588458SPeter Avalos 		for (cp = tp->tab[i]; cp; cp = op) {
2584b588458SPeter Avalos 			op = cp->cnext;
2594b588458SPeter Avalos 			nh = hash(cp->nval, nsz);
2604b588458SPeter Avalos 			cp->cnext = np[nh];
2614b588458SPeter Avalos 			np[nh] = cp;
2624b588458SPeter Avalos 		}
2634b588458SPeter Avalos 	}
2644b588458SPeter Avalos 	free(tp->tab);
2654b588458SPeter Avalos 	tp->tab = np;
2664b588458SPeter Avalos 	tp->size = nsz;
2674b588458SPeter Avalos }
2684b588458SPeter Avalos 
2694b588458SPeter Avalos Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
2704b588458SPeter Avalos {
2714b588458SPeter Avalos 	Cell *p;
2724b588458SPeter Avalos 	int h;
2734b588458SPeter Avalos 
2744b588458SPeter Avalos 	h = hash(s, tp->size);
2754b588458SPeter Avalos 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
2764b588458SPeter Avalos 		if (strcmp(s, p->nval) == 0)
2774b588458SPeter Avalos 			return(p);	/* found it */
2784b588458SPeter Avalos 	return(NULL);			/* not found */
2794b588458SPeter Avalos }
2804b588458SPeter Avalos 
2814b588458SPeter Avalos Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
2824b588458SPeter Avalos {
2834b588458SPeter Avalos 	int fldno;
2844b588458SPeter Avalos 
2854b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
2864b588458SPeter Avalos 		funnyvar(vp, "assign to");
2874b588458SPeter Avalos 	if (isfld(vp)) {
2884b588458SPeter Avalos 		donerec = 0;	/* mark $0 invalid */
2894b588458SPeter Avalos 		fldno = atoi(vp->nval);
2904b588458SPeter Avalos 		if (fldno > *NF)
2914b588458SPeter Avalos 			newfld(fldno);
2924b588458SPeter Avalos 		   dprintf( ("setting field %d to %g\n", fldno, f) );
2934b588458SPeter Avalos 	} else if (isrec(vp)) {
2944b588458SPeter Avalos 		donefld = 0;	/* mark $1... invalid */
2954b588458SPeter Avalos 		donerec = 1;
2964b588458SPeter Avalos 	}
2974b588458SPeter Avalos 	if (freeable(vp))
2984b588458SPeter Avalos 		xfree(vp->sval); /* free any previous string */
2994b588458SPeter Avalos 	vp->tval &= ~STR;	/* mark string invalid */
3004b588458SPeter Avalos 	vp->tval |= NUM;	/* mark number ok */
301*b12bae18SSascha Wildner 	   dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
3024b588458SPeter Avalos 	return vp->fval = f;
3034b588458SPeter Avalos }
3044b588458SPeter Avalos 
3054b588458SPeter Avalos void funnyvar(Cell *vp, const char *rw)
3064b588458SPeter Avalos {
3074b588458SPeter Avalos 	if (isarr(vp))
3084b588458SPeter Avalos 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3094b588458SPeter Avalos 	if (vp->tval & FCN)
3104b588458SPeter Avalos 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
3114b588458SPeter Avalos 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3124b588458SPeter Avalos 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
3134b588458SPeter Avalos }
3144b588458SPeter Avalos 
3154b588458SPeter Avalos char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
3164b588458SPeter Avalos {
3174b588458SPeter Avalos 	char *t;
3184b588458SPeter Avalos 	int fldno;
3194b588458SPeter Avalos 
3204b588458SPeter Avalos 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
321*b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
3224b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3234b588458SPeter Avalos 		funnyvar(vp, "assign to");
3244b588458SPeter Avalos 	if (isfld(vp)) {
3254b588458SPeter Avalos 		donerec = 0;	/* mark $0 invalid */
3264b588458SPeter Avalos 		fldno = atoi(vp->nval);
3274b588458SPeter Avalos 		if (fldno > *NF)
3284b588458SPeter Avalos 			newfld(fldno);
3294b588458SPeter Avalos 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
3304b588458SPeter Avalos 	} else if (isrec(vp)) {
3314b588458SPeter Avalos 		donefld = 0;	/* mark $1... invalid */
3324b588458SPeter Avalos 		donerec = 1;
3334b588458SPeter Avalos 	}
3344b588458SPeter Avalos 	t = tostring(s);	/* in case it's self-assign */
3354b588458SPeter Avalos 	if (freeable(vp))
3364b588458SPeter Avalos 		xfree(vp->sval);
3374b588458SPeter Avalos 	vp->tval &= ~NUM;
3384b588458SPeter Avalos 	vp->tval |= STR;
3394b588458SPeter Avalos 	vp->tval &= ~DONTFREE;
3404b588458SPeter Avalos 	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
341*b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
3424b588458SPeter Avalos 	return(vp->sval = t);
3434b588458SPeter Avalos }
3444b588458SPeter Avalos 
3454b588458SPeter Avalos Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3464b588458SPeter Avalos {
3474b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3484b588458SPeter Avalos 		funnyvar(vp, "read value of");
3494b588458SPeter Avalos 	if (isfld(vp) && donefld == 0)
3504b588458SPeter Avalos 		fldbld();
3514b588458SPeter Avalos 	else if (isrec(vp) && donerec == 0)
3524b588458SPeter Avalos 		recbld();
3534b588458SPeter Avalos 	if (!isnum(vp)) {	/* not a number */
3544b588458SPeter Avalos 		vp->fval = atof(vp->sval);	/* best guess */
3554b588458SPeter Avalos 		if (is_number(vp->sval) && !(vp->tval&CON))
3564b588458SPeter Avalos 			vp->tval |= NUM;	/* make NUM only sparingly */
3574b588458SPeter Avalos 	}
358*b12bae18SSascha Wildner 	   dprintf( ("getfval %p: %s = %g, t=%o\n",
359*b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
3604b588458SPeter Avalos 	return(vp->fval);
3614b588458SPeter Avalos }
3624b588458SPeter Avalos 
3634b588458SPeter Avalos static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
3644b588458SPeter Avalos {
3654b588458SPeter Avalos 	char s[100];	/* BUG: unchecked */
3664b588458SPeter Avalos 	double dtemp;
3674b588458SPeter Avalos 
3684b588458SPeter Avalos 	if ((vp->tval & (NUM | STR)) == 0)
3694b588458SPeter Avalos 		funnyvar(vp, "read value of");
3704b588458SPeter Avalos 	if (isfld(vp) && donefld == 0)
3714b588458SPeter Avalos 		fldbld();
3724b588458SPeter Avalos 	else if (isrec(vp) && donerec == 0)
3734b588458SPeter Avalos 		recbld();
3744b588458SPeter Avalos 	if (isstr(vp) == 0) {
3754b588458SPeter Avalos 		if (freeable(vp))
3764b588458SPeter Avalos 			xfree(vp->sval);
3774b588458SPeter Avalos 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
3784b588458SPeter Avalos 			sprintf(s, "%.30g", vp->fval);
3794b588458SPeter Avalos 		else
3804b588458SPeter Avalos 			sprintf(s, *fmt, vp->fval);
3814b588458SPeter Avalos 		vp->sval = tostring(s);
3824b588458SPeter Avalos 		vp->tval &= ~DONTFREE;
3834b588458SPeter Avalos 		vp->tval |= STR;
3844b588458SPeter Avalos 	}
385*b12bae18SSascha Wildner 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
386*b12bae18SSascha Wildner 		(void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
3874b588458SPeter Avalos 	return(vp->sval);
3884b588458SPeter Avalos }
3894b588458SPeter Avalos 
3904b588458SPeter Avalos char *getsval(Cell *vp)       /* get string val of a Cell */
3914b588458SPeter Avalos {
3924b588458SPeter Avalos       return get_str_val(vp, CONVFMT);
3934b588458SPeter Avalos }
3944b588458SPeter Avalos 
3954b588458SPeter Avalos char *getpssval(Cell *vp)     /* get string val of a Cell for print */
3964b588458SPeter Avalos {
3974b588458SPeter Avalos       return get_str_val(vp, OFMT);
3984b588458SPeter Avalos }
3994b588458SPeter Avalos 
4004b588458SPeter Avalos 
4014b588458SPeter Avalos char *tostring(const char *s)	/* make a copy of string s */
4024b588458SPeter Avalos {
4034b588458SPeter Avalos 	char *p;
4044b588458SPeter Avalos 
4054b588458SPeter Avalos 	p = (char *) malloc(strlen(s)+1);
4064b588458SPeter Avalos 	if (p == NULL)
4074b588458SPeter Avalos 		FATAL("out of space in tostring on %s", s);
4084b588458SPeter Avalos 	strcpy(p, s);
4094b588458SPeter Avalos 	return(p);
4104b588458SPeter Avalos }
4114b588458SPeter Avalos 
4124b588458SPeter Avalos char *qstring(const char *is, int delim)	/* collect string up to next delim */
4134b588458SPeter Avalos {
4144b588458SPeter Avalos 	const char *os = is;
4154b588458SPeter Avalos 	int c, n;
4164b588458SPeter Avalos 	uschar *s = (uschar *) is;
4174b588458SPeter Avalos 	uschar *buf, *bp;
4184b588458SPeter Avalos 
4194b588458SPeter Avalos 	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
4204b588458SPeter Avalos 		FATAL( "out of space in qstring(%s)", s);
4214b588458SPeter Avalos 	for (bp = buf; (c = *s) != delim; s++) {
4224b588458SPeter Avalos 		if (c == '\n')
4234b588458SPeter Avalos 			SYNTAX( "newline in string %.20s...", os );
4244b588458SPeter Avalos 		else if (c != '\\')
4254b588458SPeter Avalos 			*bp++ = c;
4264b588458SPeter Avalos 		else {	/* \something */
4274b588458SPeter Avalos 			c = *++s;
4284b588458SPeter Avalos 			if (c == 0) {	/* \ at end */
4294b588458SPeter Avalos 				*bp++ = '\\';
4304b588458SPeter Avalos 				break;	/* for loop */
4314b588458SPeter Avalos 			}
4324b588458SPeter Avalos 			switch (c) {
4334b588458SPeter Avalos 			case '\\':	*bp++ = '\\'; break;
4344b588458SPeter Avalos 			case 'n':	*bp++ = '\n'; break;
4354b588458SPeter Avalos 			case 't':	*bp++ = '\t'; break;
4364b588458SPeter Avalos 			case 'b':	*bp++ = '\b'; break;
4374b588458SPeter Avalos 			case 'f':	*bp++ = '\f'; break;
4384b588458SPeter Avalos 			case 'r':	*bp++ = '\r'; break;
4394b588458SPeter Avalos 			default:
4404b588458SPeter Avalos 				if (!isdigit(c)) {
4414b588458SPeter Avalos 					*bp++ = c;
4424b588458SPeter Avalos 					break;
4434b588458SPeter Avalos 				}
4444b588458SPeter Avalos 				n = c - '0';
4454b588458SPeter Avalos 				if (isdigit(s[1])) {
4464b588458SPeter Avalos 					n = 8 * n + *++s - '0';
4474b588458SPeter Avalos 					if (isdigit(s[1]))
4484b588458SPeter Avalos 						n = 8 * n + *++s - '0';
4494b588458SPeter Avalos 				}
4504b588458SPeter Avalos 				*bp++ = n;
4514b588458SPeter Avalos 				break;
4524b588458SPeter Avalos 			}
4534b588458SPeter Avalos 		}
4544b588458SPeter Avalos 	}
4554b588458SPeter Avalos 	*bp++ = 0;
4564b588458SPeter Avalos 	return (char *) buf;
4574b588458SPeter Avalos }
458