xref: /openbsd/usr.bin/awk/tran.c (revision 271018d0)
1*271018d0Smillert /*	$OpenBSD: tran.c,v 1.5 1999/04/20 17:31:31 millert Exp $	*/
26ab05f83Stholo /****************************************************************
307edfa4aSkstailey Copyright (C) Lucent Technologies 1997
46ab05f83Stholo All Rights Reserved
56ab05f83Stholo 
66ab05f83Stholo Permission to use, copy, modify, and distribute this software and
76ab05f83Stholo its documentation for any purpose and without fee is hereby
86ab05f83Stholo granted, provided that the above copyright notice appear in all
96ab05f83Stholo copies and that both that the copyright notice and this
106ab05f83Stholo permission notice and warranty disclaimer appear in supporting
1107edfa4aSkstailey documentation, and that the name Lucent Technologies or any of
1207edfa4aSkstailey its entities not be used in advertising or publicity pertaining
1307edfa4aSkstailey to distribution of the software without specific, written prior
1407edfa4aSkstailey permission.
156ab05f83Stholo 
1607edfa4aSkstailey LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1707edfa4aSkstailey INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
1807edfa4aSkstailey IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
1907edfa4aSkstailey SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
2007edfa4aSkstailey WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
2107edfa4aSkstailey IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
2207edfa4aSkstailey ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
2307edfa4aSkstailey THIS SOFTWARE.
246ab05f83Stholo ****************************************************************/
256ab05f83Stholo 
266ab05f83Stholo #define	DEBUG
276ab05f83Stholo #include <stdio.h>
286ab05f83Stholo #include <math.h>
296ab05f83Stholo #include <ctype.h>
306ab05f83Stholo #include <string.h>
316ab05f83Stholo #include <stdlib.h>
326ab05f83Stholo #include "awk.h"
3307edfa4aSkstailey #include "ytab.h"
346ab05f83Stholo 
356ab05f83Stholo #define	FULLTAB	2	/* rehash when table gets this x full */
366ab05f83Stholo #define	GROWTAB 4	/* grow table by this factor */
376ab05f83Stholo 
386ab05f83Stholo Array	*symtab;	/* main symbol table */
396ab05f83Stholo 
406ab05f83Stholo char	**FS;		/* initial field sep */
416ab05f83Stholo char	**RS;		/* initial record sep */
426ab05f83Stholo char	**OFS;		/* output field sep */
436ab05f83Stholo char	**ORS;		/* output record sep */
446ab05f83Stholo char	**OFMT;		/* output format for numbers */
456ab05f83Stholo char	**CONVFMT;	/* format for conversions in getsval */
466ab05f83Stholo Awkfloat *NF;		/* number of fields in current record */
476ab05f83Stholo Awkfloat *NR;		/* number of current record */
486ab05f83Stholo Awkfloat *FNR;		/* number of current record in current file */
496ab05f83Stholo char	**FILENAME;	/* current filename argument */
506ab05f83Stholo Awkfloat *ARGC;		/* number of arguments from command line */
516ab05f83Stholo char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
526ab05f83Stholo Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
536ab05f83Stholo Awkfloat *RLENGTH;	/* length of same */
546ab05f83Stholo 
556ab05f83Stholo Cell	*nrloc;		/* NR */
566ab05f83Stholo Cell	*nfloc;		/* NF */
576ab05f83Stholo Cell	*fnrloc;	/* FNR */
586ab05f83Stholo Array	*ARGVtab;	/* symbol table containing ARGV[...] */
596ab05f83Stholo Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
606ab05f83Stholo Cell	*rstartloc;	/* RSTART */
616ab05f83Stholo Cell	*rlengthloc;	/* RLENGTH */
626ab05f83Stholo Cell	*symtabloc;	/* SYMTAB */
636ab05f83Stholo 
646ab05f83Stholo Cell	*nullloc;	/* a guaranteed empty cell */
656ab05f83Stholo Node	*nullnode;	/* zero&null, converted into a node for comparisons */
6607edfa4aSkstailey Cell	*literal0;
676ab05f83Stholo 
6807edfa4aSkstailey extern Cell **fldtab;
696ab05f83Stholo 
706ab05f83Stholo void syminit(void)	/* initialize symbol table with builtin vars */
716ab05f83Stholo {
7207edfa4aSkstailey 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
736ab05f83Stholo 	/* this is used for if(x)... tests: */
746ab05f83Stholo 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
7507edfa4aSkstailey 	nullnode = celltonode(nullloc, CCON);
766ab05f83Stholo 
776ab05f83Stholo 	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
786ab05f83Stholo 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
796ab05f83Stholo 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
806ab05f83Stholo 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
816ab05f83Stholo 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
826ab05f83Stholo 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
83b2698ba9Smillert 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
846ab05f83Stholo 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
856ab05f83Stholo 	NF = &nfloc->fval;
866ab05f83Stholo 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
876ab05f83Stholo 	NR = &nrloc->fval;
886ab05f83Stholo 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
896ab05f83Stholo 	FNR = &fnrloc->fval;
906ab05f83Stholo 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
916ab05f83Stholo 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
926ab05f83Stholo 	RSTART = &rstartloc->fval;
936ab05f83Stholo 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
946ab05f83Stholo 	RLENGTH = &rlengthloc->fval;
956ab05f83Stholo 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
966ab05f83Stholo 	symtabloc->sval = (char *) symtab;
976ab05f83Stholo }
986ab05f83Stholo 
9907edfa4aSkstailey void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1006ab05f83Stholo {
1016ab05f83Stholo 	Cell *cp;
1026ab05f83Stholo 	int i;
10307edfa4aSkstailey 	char temp[50];
1046ab05f83Stholo 
1056ab05f83Stholo 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1066ab05f83Stholo 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1076ab05f83Stholo 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1086ab05f83Stholo 	cp->sval = (char *) ARGVtab;
1096ab05f83Stholo 	for (i = 0; i < ac; i++) {
11007edfa4aSkstailey 		sprintf(temp, "%d", i);
111a4fa8700Smillert 		if (is_number(*av))
1126ab05f83Stholo 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
1136ab05f83Stholo 		else
1146ab05f83Stholo 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1156ab05f83Stholo 		av++;
1166ab05f83Stholo 	}
1176ab05f83Stholo }
1186ab05f83Stholo 
1196ab05f83Stholo void envinit(char **envp)	/* set up ENVIRON variable */
1206ab05f83Stholo {
1216ab05f83Stholo 	Cell *cp;
1226ab05f83Stholo 	char *p;
1236ab05f83Stholo 
1246ab05f83Stholo 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1256ab05f83Stholo 	ENVtab = makesymtab(NSYMTAB);
1266ab05f83Stholo 	cp->sval = (char *) ENVtab;
1276ab05f83Stholo 	for ( ; *envp; envp++) {
12807edfa4aSkstailey 		if ((p = strchr(*envp, '=')) == NULL)
1296ab05f83Stholo 			continue;
1306ab05f83Stholo 		*p++ = 0;	/* split into two strings at = */
131a4fa8700Smillert 		if (is_number(p))
1326ab05f83Stholo 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
1336ab05f83Stholo 		else
1346ab05f83Stholo 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1356ab05f83Stholo 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1366ab05f83Stholo 	}
1376ab05f83Stholo }
1386ab05f83Stholo 
1396ab05f83Stholo Array *makesymtab(int n)	/* make a new symbol table */
1406ab05f83Stholo {
1416ab05f83Stholo 	Array *ap;
1426ab05f83Stholo 	Cell **tp;
1436ab05f83Stholo 
1446ab05f83Stholo 	ap = (Array *) malloc(sizeof(Array));
1456ab05f83Stholo 	tp = (Cell **) calloc(n, sizeof(Cell *));
1466ab05f83Stholo 	if (ap == NULL || tp == NULL)
1476ab05f83Stholo 		ERROR "out of space in makesymtab" FATAL;
1486ab05f83Stholo 	ap->nelem = 0;
1496ab05f83Stholo 	ap->size = n;
1506ab05f83Stholo 	ap->tab = tp;
1516ab05f83Stholo 	return(ap);
1526ab05f83Stholo }
1536ab05f83Stholo 
1546ab05f83Stholo void freesymtab(Cell *ap)	/* free a symbol table */
1556ab05f83Stholo {
1566ab05f83Stholo 	Cell *cp, *temp;
1576ab05f83Stholo 	Array *tp;
1586ab05f83Stholo 	int i;
1596ab05f83Stholo 
1606ab05f83Stholo 	if (!isarr(ap))
1616ab05f83Stholo 		return;
1626ab05f83Stholo 	tp = (Array *) ap->sval;
1636ab05f83Stholo 	if (tp == NULL)
1646ab05f83Stholo 		return;
1656ab05f83Stholo 	for (i = 0; i < tp->size; i++) {
1666ab05f83Stholo 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1676ab05f83Stholo 			xfree(cp->nval);
1686ab05f83Stholo 			if (freeable(cp))
1696ab05f83Stholo 				xfree(cp->sval);
1706ab05f83Stholo 			temp = cp->cnext;	/* avoids freeing then using */
17107edfa4aSkstailey 			free(cp);
1726ab05f83Stholo 		}
1736ab05f83Stholo 		tp->tab[i] = 0;
1746ab05f83Stholo 	}
17507edfa4aSkstailey 	free(tp->tab);
17607edfa4aSkstailey 	free(tp);
1776ab05f83Stholo }
1786ab05f83Stholo 
1796ab05f83Stholo void freeelem(Cell *ap, char *s)	/* free elem s from ap (i.e., ap["s"] */
1806ab05f83Stholo {
1816ab05f83Stholo 	Array *tp;
1826ab05f83Stholo 	Cell *p, *prev = NULL;
1836ab05f83Stholo 	int h;
1846ab05f83Stholo 
1856ab05f83Stholo 	tp = (Array *) ap->sval;
1866ab05f83Stholo 	h = hash(s, tp->size);
1876ab05f83Stholo 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
18807edfa4aSkstailey 		if (strcmp(s, p->nval) == 0) {
1896ab05f83Stholo 			if (prev == NULL)	/* 1st one */
1906ab05f83Stholo 				tp->tab[h] = p->cnext;
1916ab05f83Stholo 			else			/* middle somewhere */
1926ab05f83Stholo 				prev->cnext = p->cnext;
1936ab05f83Stholo 			if (freeable(p))
1946ab05f83Stholo 				xfree(p->sval);
1956ab05f83Stholo 			free(p->nval);
19607edfa4aSkstailey 			free(p);
1976ab05f83Stholo 			tp->nelem--;
1986ab05f83Stholo 			return;
1996ab05f83Stholo 		}
2006ab05f83Stholo }
2016ab05f83Stholo 
2026ab05f83Stholo Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
2036ab05f83Stholo {
2046ab05f83Stholo 	int h;
2056ab05f83Stholo 	Cell *p;
2066ab05f83Stholo 
2076ab05f83Stholo 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
2086ab05f83Stholo 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
2096ab05f83Stholo 			p, p->nval, p->sval, p->fval, p->tval) );
2106ab05f83Stholo 		return(p);
2116ab05f83Stholo 	}
2126ab05f83Stholo 	p = (Cell *) malloc(sizeof(Cell));
2136ab05f83Stholo 	if (p == NULL)
2146ab05f83Stholo 		ERROR "out of space for symbol table at %s", n FATAL;
2156ab05f83Stholo 	p->nval = tostring(n);
2166ab05f83Stholo 	p->sval = s ? tostring(s) : tostring("");
2176ab05f83Stholo 	p->fval = f;
2186ab05f83Stholo 	p->tval = t;
2196ab05f83Stholo 	p->csub = CUNK;
2206ab05f83Stholo 	p->ctype = OCELL;
2216ab05f83Stholo 	tp->nelem++;
2226ab05f83Stholo 	if (tp->nelem > FULLTAB * tp->size)
2236ab05f83Stholo 		rehash(tp);
2246ab05f83Stholo 	h = hash(n, tp->size);
2256ab05f83Stholo 	p->cnext = tp->tab[h];
2266ab05f83Stholo 	tp->tab[h] = p;
2276ab05f83Stholo 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
2286ab05f83Stholo 		p, p->nval, p->sval, p->fval, p->tval) );
2296ab05f83Stholo 	return(p);
2306ab05f83Stholo }
2316ab05f83Stholo 
2326ab05f83Stholo int hash(char *s, int n)	/* form hash value for string s */
2336ab05f83Stholo {
2346ab05f83Stholo 	unsigned hashval;
2356ab05f83Stholo 
2366ab05f83Stholo 	for (hashval = 0; *s != '\0'; s++)
2376ab05f83Stholo 		hashval = (*s + 31 * hashval);
2386ab05f83Stholo 	return hashval % n;
2396ab05f83Stholo }
2406ab05f83Stholo 
2416ab05f83Stholo void rehash(Array *tp)	/* rehash items in small table into big one */
2426ab05f83Stholo {
2436ab05f83Stholo 	int i, nh, nsz;
2446ab05f83Stholo 	Cell *cp, *op, **np;
2456ab05f83Stholo 
2466ab05f83Stholo 	nsz = GROWTAB * tp->size;
2476ab05f83Stholo 	np = (Cell **) calloc(nsz, sizeof(Cell *));
2486ab05f83Stholo 	if (np == NULL)		/* can't do it, but can keep running. */
2496ab05f83Stholo 		return;		/* someone else will run out later. */
2506ab05f83Stholo 	for (i = 0; i < tp->size; i++) {
2516ab05f83Stholo 		for (cp = tp->tab[i]; cp; cp = op) {
2526ab05f83Stholo 			op = cp->cnext;
2536ab05f83Stholo 			nh = hash(cp->nval, nsz);
2546ab05f83Stholo 			cp->cnext = np[nh];
2556ab05f83Stholo 			np[nh] = cp;
2566ab05f83Stholo 		}
2576ab05f83Stholo 	}
25807edfa4aSkstailey 	free(tp->tab);
2596ab05f83Stholo 	tp->tab = np;
2606ab05f83Stholo 	tp->size = nsz;
2616ab05f83Stholo }
2626ab05f83Stholo 
2636ab05f83Stholo Cell *lookup(char *s, Array *tp)	/* look for s in tp */
2646ab05f83Stholo {
265*271018d0Smillert 	Cell *p;
2666ab05f83Stholo 	int h;
2676ab05f83Stholo 
2686ab05f83Stholo 	h = hash(s, tp->size);
269*271018d0Smillert 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
27007edfa4aSkstailey 		if (strcmp(s, p->nval) == 0)
2716ab05f83Stholo 			return(p);	/* found it */
2726ab05f83Stholo 	return(NULL);			/* not found */
2736ab05f83Stholo }
2746ab05f83Stholo 
2756ab05f83Stholo Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
2766ab05f83Stholo {
27707edfa4aSkstailey 	int fldno;
27807edfa4aSkstailey 
2796ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
2806ab05f83Stholo 		funnyvar(vp, "assign to");
28107edfa4aSkstailey 	if (isfld(vp)) {
2826ab05f83Stholo 		donerec = 0;	/* mark $0 invalid */
28307edfa4aSkstailey 		fldno = atoi(vp->nval);
28407edfa4aSkstailey 		if (fldno > *NF)
28507edfa4aSkstailey 			newfld(fldno);
28607edfa4aSkstailey 		   dprintf( ("setting field %d to %g\n", fldno, f) );
28707edfa4aSkstailey 	} else if (isrec(vp)) {
2886ab05f83Stholo 		donefld = 0;	/* mark $1... invalid */
2896ab05f83Stholo 		donerec = 1;
2906ab05f83Stholo 	}
291a4fa8700Smillert 	if (freeable(vp))
292a4fa8700Smillert 		xfree(vp->sval); /* free any previous string */
2936ab05f83Stholo 	vp->tval &= ~STR;	/* mark string invalid */
2946ab05f83Stholo 	vp->tval |= NUM;	/* mark number ok */
2956ab05f83Stholo 	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
2966ab05f83Stholo 	return vp->fval = f;
2976ab05f83Stholo }
2986ab05f83Stholo 
2996ab05f83Stholo void funnyvar(Cell *vp, char *rw)
3006ab05f83Stholo {
30107edfa4aSkstailey 	if (isarr(vp))
3026ab05f83Stholo 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
3036ab05f83Stholo 	if (vp->tval & FCN)
3046ab05f83Stholo 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
3056ab05f83Stholo 	ERROR "funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3066ab05f83Stholo 		vp, vp->nval, vp->sval, vp->fval, vp->tval WARNING;
3076ab05f83Stholo }
3086ab05f83Stholo 
3096ab05f83Stholo char *setsval(Cell *vp, char *s)	/* set string val of a Cell */
3106ab05f83Stholo {
3116ab05f83Stholo 	char *t;
31207edfa4aSkstailey 	int fldno;
3136ab05f83Stholo 
31407edfa4aSkstailey 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
3156ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3166ab05f83Stholo 		funnyvar(vp, "assign to");
31707edfa4aSkstailey 	if (isfld(vp)) {
3186ab05f83Stholo 		donerec = 0;	/* mark $0 invalid */
31907edfa4aSkstailey 		fldno = atoi(vp->nval);
32007edfa4aSkstailey 		if (fldno > *NF)
32107edfa4aSkstailey 			newfld(fldno);
32207edfa4aSkstailey 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
32307edfa4aSkstailey 	} else if (isrec(vp)) {
3246ab05f83Stholo 		donefld = 0;	/* mark $1... invalid */
3256ab05f83Stholo 		donerec = 1;
3266ab05f83Stholo 	}
3276ab05f83Stholo 	t = tostring(s);	/* in case it's self-assign */
3286ab05f83Stholo 	vp->tval &= ~NUM;
3296ab05f83Stholo 	vp->tval |= STR;
3306ab05f83Stholo 	if (freeable(vp))
3316ab05f83Stholo 		xfree(vp->sval);
3326ab05f83Stholo 	vp->tval &= ~DONTFREE;
3336ab05f83Stholo 	   dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
3346ab05f83Stholo 	return(vp->sval = t);
3356ab05f83Stholo }
3366ab05f83Stholo 
3376ab05f83Stholo Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3386ab05f83Stholo {
3396ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3406ab05f83Stholo 		funnyvar(vp, "read value of");
34107edfa4aSkstailey 	if (isfld(vp) && donefld == 0)
3426ab05f83Stholo 		fldbld();
34307edfa4aSkstailey 	else if (isrec(vp) && donerec == 0)
3446ab05f83Stholo 		recbld();
3456ab05f83Stholo 	if (!isnum(vp)) {	/* not a number */
3466ab05f83Stholo 		vp->fval = atof(vp->sval);	/* best guess */
347a4fa8700Smillert 		if (is_number(vp->sval) && !(vp->tval&CON))
3486ab05f83Stholo 			vp->tval |= NUM;	/* make NUM only sparingly */
3496ab05f83Stholo 	}
3506ab05f83Stholo 	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
3516ab05f83Stholo 	return(vp->fval);
3526ab05f83Stholo }
3536ab05f83Stholo 
3546ab05f83Stholo char *getsval(Cell *vp)	/* get string val of a Cell */
3556ab05f83Stholo {
35607edfa4aSkstailey 	char s[100];	/* BUG: unchecked */
3576ab05f83Stholo 	double dtemp;
3586ab05f83Stholo 
3596ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3606ab05f83Stholo 		funnyvar(vp, "read value of");
36107edfa4aSkstailey 	if (isfld(vp) && donefld == 0)
3626ab05f83Stholo 		fldbld();
36307edfa4aSkstailey 	else if (isrec(vp) && donerec == 0)
3646ab05f83Stholo 		recbld();
36507edfa4aSkstailey 	if (isstr(vp) == 0) {
36607edfa4aSkstailey 		if (freeable(vp))
3676ab05f83Stholo 			xfree(vp->sval);
3686ab05f83Stholo 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
36907edfa4aSkstailey 			sprintf(s, "%.30g", vp->fval);
3706ab05f83Stholo 		else
37107edfa4aSkstailey 			sprintf(s, *CONVFMT, vp->fval);
3726ab05f83Stholo 		vp->sval = tostring(s);
3736ab05f83Stholo 		vp->tval &= ~DONTFREE;
3746ab05f83Stholo 		vp->tval |= STR;
3756ab05f83Stholo 	}
3766ab05f83Stholo 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
3776ab05f83Stholo 	return(vp->sval);
3786ab05f83Stholo }
3796ab05f83Stholo 
3806ab05f83Stholo char *tostring(char *s)	/* make a copy of string s */
3816ab05f83Stholo {
3826ab05f83Stholo 	char *p;
3836ab05f83Stholo 
38407edfa4aSkstailey 	p = (char *) malloc(strlen(s)+1);
3856ab05f83Stholo 	if (p == NULL)
3866ab05f83Stholo 		ERROR "out of space in tostring on %s", s FATAL;
38707edfa4aSkstailey 	strcpy(p, s);
3886ab05f83Stholo 	return(p);
3896ab05f83Stholo }
3906ab05f83Stholo 
3916ab05f83Stholo char *qstring(char *s, int delim)	/* collect string up to next delim */
3926ab05f83Stholo {
3936ab05f83Stholo 	int c, n;
39407edfa4aSkstailey 	char *buf = 0, *bp;
3956ab05f83Stholo 
39607edfa4aSkstailey 	if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
39707edfa4aSkstailey 		ERROR "out of space in qstring(%s)", s);
39807edfa4aSkstailey 	for (bp = buf; (c = *s) != delim; s++) {
3996ab05f83Stholo 		if (c == '\n')
40007edfa4aSkstailey 			ERROR "newline in string %.10s...", buf SYNTAX;
4016ab05f83Stholo 		else if (c != '\\')
40207edfa4aSkstailey 			*bp++ = c;
40307edfa4aSkstailey 		else {	/* \something */
4046ab05f83Stholo 			switch (c = *++s) {
40507edfa4aSkstailey 			case '\\':	*bp++ = '\\'; break;
40607edfa4aSkstailey 			case 'n':	*bp++ = '\n'; break;
40707edfa4aSkstailey 			case 't':	*bp++ = '\t'; break;
40807edfa4aSkstailey 			case 'b':	*bp++ = '\b'; break;
40907edfa4aSkstailey 			case 'f':	*bp++ = '\f'; break;
41007edfa4aSkstailey 			case 'r':	*bp++ = '\r'; break;
4116ab05f83Stholo 			default:
4126ab05f83Stholo 				if (!isdigit(c)) {
41307edfa4aSkstailey 					*bp++ = c;
4146ab05f83Stholo 					break;
4156ab05f83Stholo 				}
4166ab05f83Stholo 				n = c - '0';
4176ab05f83Stholo 				if (isdigit(s[1])) {
4186ab05f83Stholo 					n = 8 * n + *++s - '0';
4196ab05f83Stholo 					if (isdigit(s[1]))
4206ab05f83Stholo 						n = 8 * n + *++s - '0';
4216ab05f83Stholo 				}
42207edfa4aSkstailey 				*bp++ = n;
4236ab05f83Stholo 				break;
4246ab05f83Stholo 			}
4256ab05f83Stholo 		}
42607edfa4aSkstailey 	}
42707edfa4aSkstailey 	*bp++ = 0;
42807edfa4aSkstailey 	return buf;
4296ab05f83Stholo }
430