xref: /openbsd/usr.bin/awk/tran.c (revision 4eb91dac)
1*4eb91dacSjmc /*	$OpenBSD: tran.c,v 1.14 2006/11/04 19:10:15 jmc 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 
5523cb51abSmillert Cell	*fsloc;		/* FS */
566ab05f83Stholo Cell	*nrloc;		/* NR */
576ab05f83Stholo Cell	*nfloc;		/* NF */
586ab05f83Stholo Cell	*fnrloc;	/* FNR */
596ab05f83Stholo Array	*ARGVtab;	/* symbol table containing ARGV[...] */
606ab05f83Stholo Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
616ab05f83Stholo Cell	*rstartloc;	/* RSTART */
626ab05f83Stholo Cell	*rlengthloc;	/* RLENGTH */
636ab05f83Stholo Cell	*symtabloc;	/* SYMTAB */
646ab05f83Stholo 
656ab05f83Stholo Cell	*nullloc;	/* a guaranteed empty cell */
666ab05f83Stholo Node	*nullnode;	/* zero&null, converted into a node for comparisons */
6707edfa4aSkstailey Cell	*literal0;
686ab05f83Stholo 
6907edfa4aSkstailey extern Cell **fldtab;
706ab05f83Stholo 
716ab05f83Stholo void syminit(void)	/* initialize symbol table with builtin vars */
726ab05f83Stholo {
7307edfa4aSkstailey 	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
746ab05f83Stholo 	/* this is used for if(x)... tests: */
756ab05f83Stholo 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
7607edfa4aSkstailey 	nullnode = celltonode(nullloc, CCON);
776ab05f83Stholo 
7823cb51abSmillert 	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
7923cb51abSmillert 	FS = &fsloc->sval;
806ab05f83Stholo 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
816ab05f83Stholo 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
826ab05f83Stholo 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
836ab05f83Stholo 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
846ab05f83Stholo 	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
85b2698ba9Smillert 	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
866ab05f83Stholo 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
876ab05f83Stholo 	NF = &nfloc->fval;
886ab05f83Stholo 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
896ab05f83Stholo 	NR = &nrloc->fval;
906ab05f83Stholo 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
916ab05f83Stholo 	FNR = &fnrloc->fval;
926ab05f83Stholo 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
936ab05f83Stholo 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
946ab05f83Stholo 	RSTART = &rstartloc->fval;
956ab05f83Stholo 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
966ab05f83Stholo 	RLENGTH = &rlengthloc->fval;
976ab05f83Stholo 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
986ab05f83Stholo 	symtabloc->sval = (char *) symtab;
996ab05f83Stholo }
1006ab05f83Stholo 
10107edfa4aSkstailey void arginit(int ac, char **av)	/* set up ARGV and ARGC */
1026ab05f83Stholo {
1036ab05f83Stholo 	Cell *cp;
1046ab05f83Stholo 	int i;
10507edfa4aSkstailey 	char temp[50];
1066ab05f83Stholo 
1076ab05f83Stholo 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
1086ab05f83Stholo 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
1096ab05f83Stholo 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1106ab05f83Stholo 	cp->sval = (char *) ARGVtab;
1116ab05f83Stholo 	for (i = 0; i < ac; i++) {
1129e405e78Sderaadt 		snprintf(temp, sizeof temp, "%d", i);
113a4fa8700Smillert 		if (is_number(*av))
1146ab05f83Stholo 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
1156ab05f83Stholo 		else
1166ab05f83Stholo 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
1176ab05f83Stholo 		av++;
1186ab05f83Stholo 	}
1196ab05f83Stholo }
1206ab05f83Stholo 
1216ab05f83Stholo void envinit(char **envp)	/* set up ENVIRON variable */
1226ab05f83Stholo {
1236ab05f83Stholo 	Cell *cp;
1246ab05f83Stholo 	char *p;
1256ab05f83Stholo 
1266ab05f83Stholo 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
1276ab05f83Stholo 	ENVtab = makesymtab(NSYMTAB);
1286ab05f83Stholo 	cp->sval = (char *) ENVtab;
1296ab05f83Stholo 	for ( ; *envp; envp++) {
13007edfa4aSkstailey 		if ((p = strchr(*envp, '=')) == NULL)
1316ab05f83Stholo 			continue;
132a27f5228Smillert 		if( p == *envp ) /* no left hand side name in env string */
133a27f5228Smillert 			continue;
1346ab05f83Stholo 		*p++ = 0;	/* split into two strings at = */
135a4fa8700Smillert 		if (is_number(p))
1366ab05f83Stholo 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
1376ab05f83Stholo 		else
1386ab05f83Stholo 			setsymtab(*envp, p, 0.0, STR, ENVtab);
1396ab05f83Stholo 		p[-1] = '=';	/* restore in case env is passed down to a shell */
1406ab05f83Stholo 	}
1416ab05f83Stholo }
1426ab05f83Stholo 
1436ab05f83Stholo Array *makesymtab(int n)	/* make a new symbol table */
1446ab05f83Stholo {
1456ab05f83Stholo 	Array *ap;
1466ab05f83Stholo 	Cell **tp;
1476ab05f83Stholo 
1486ab05f83Stholo 	ap = (Array *) malloc(sizeof(Array));
1496ab05f83Stholo 	tp = (Cell **) calloc(n, sizeof(Cell *));
1506ab05f83Stholo 	if (ap == NULL || tp == NULL)
1517b11b857Smillert 		FATAL("out of space in makesymtab");
1526ab05f83Stholo 	ap->nelem = 0;
1536ab05f83Stholo 	ap->size = n;
1546ab05f83Stholo 	ap->tab = tp;
1556ab05f83Stholo 	return(ap);
1566ab05f83Stholo }
1576ab05f83Stholo 
1586ab05f83Stholo void freesymtab(Cell *ap)	/* free a symbol table */
1596ab05f83Stholo {
1606ab05f83Stholo 	Cell *cp, *temp;
1616ab05f83Stholo 	Array *tp;
1626ab05f83Stholo 	int i;
1636ab05f83Stholo 
1646ab05f83Stholo 	if (!isarr(ap))
1656ab05f83Stholo 		return;
1666ab05f83Stholo 	tp = (Array *) ap->sval;
1676ab05f83Stholo 	if (tp == NULL)
1686ab05f83Stholo 		return;
1696ab05f83Stholo 	for (i = 0; i < tp->size; i++) {
1706ab05f83Stholo 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
1716ab05f83Stholo 			xfree(cp->nval);
1726ab05f83Stholo 			if (freeable(cp))
1736ab05f83Stholo 				xfree(cp->sval);
1746ab05f83Stholo 			temp = cp->cnext;	/* avoids freeing then using */
17507edfa4aSkstailey 			free(cp);
1769a69093aSmillert 			tp->nelem--;
1776ab05f83Stholo 		}
1786ab05f83Stholo 		tp->tab[i] = 0;
1796ab05f83Stholo 	}
1809a69093aSmillert 	if (tp->nelem != 0)
1819a69093aSmillert 		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
18207edfa4aSkstailey 	free(tp->tab);
18307edfa4aSkstailey 	free(tp);
1846ab05f83Stholo }
1856ab05f83Stholo 
1869a69093aSmillert void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
1876ab05f83Stholo {
1886ab05f83Stholo 	Array *tp;
1896ab05f83Stholo 	Cell *p, *prev = NULL;
1906ab05f83Stholo 	int h;
1916ab05f83Stholo 
1926ab05f83Stholo 	tp = (Array *) ap->sval;
1936ab05f83Stholo 	h = hash(s, tp->size);
1946ab05f83Stholo 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
19507edfa4aSkstailey 		if (strcmp(s, p->nval) == 0) {
1966ab05f83Stholo 			if (prev == NULL)	/* 1st one */
1976ab05f83Stholo 				tp->tab[h] = p->cnext;
1986ab05f83Stholo 			else			/* middle somewhere */
1996ab05f83Stholo 				prev->cnext = p->cnext;
2006ab05f83Stholo 			if (freeable(p))
2016ab05f83Stholo 				xfree(p->sval);
2026ab05f83Stholo 			free(p->nval);
20307edfa4aSkstailey 			free(p);
2046ab05f83Stholo 			tp->nelem--;
2056ab05f83Stholo 			return;
2066ab05f83Stholo 		}
2076ab05f83Stholo }
2086ab05f83Stholo 
2099a69093aSmillert Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
2106ab05f83Stholo {
2116ab05f83Stholo 	int h;
2126ab05f83Stholo 	Cell *p;
2136ab05f83Stholo 
2146ab05f83Stholo 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
2156ab05f83Stholo 		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
2169a69093aSmillert 			p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
2176ab05f83Stholo 		return(p);
2186ab05f83Stholo 	}
2196ab05f83Stholo 	p = (Cell *) malloc(sizeof(Cell));
2206ab05f83Stholo 	if (p == NULL)
2217b11b857Smillert 		FATAL("out of space for symbol table at %s", n);
2226ab05f83Stholo 	p->nval = tostring(n);
2236ab05f83Stholo 	p->sval = s ? tostring(s) : tostring("");
2246ab05f83Stholo 	p->fval = f;
2256ab05f83Stholo 	p->tval = t;
2266ab05f83Stholo 	p->csub = CUNK;
2276ab05f83Stholo 	p->ctype = OCELL;
2286ab05f83Stholo 	tp->nelem++;
2296ab05f83Stholo 	if (tp->nelem > FULLTAB * tp->size)
2306ab05f83Stholo 		rehash(tp);
2316ab05f83Stholo 	h = hash(n, tp->size);
2326ab05f83Stholo 	p->cnext = tp->tab[h];
2336ab05f83Stholo 	tp->tab[h] = p;
2346ab05f83Stholo 	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
2356ab05f83Stholo 		p, p->nval, p->sval, p->fval, p->tval) );
2366ab05f83Stholo 	return(p);
2376ab05f83Stholo }
2386ab05f83Stholo 
2399a69093aSmillert int hash(const char *s, int n)	/* form hash value for string s */
2406ab05f83Stholo {
2416ab05f83Stholo 	unsigned hashval;
2426ab05f83Stholo 
2436ab05f83Stholo 	for (hashval = 0; *s != '\0'; s++)
2446ab05f83Stholo 		hashval = (*s + 31 * hashval);
2456ab05f83Stholo 	return hashval % n;
2466ab05f83Stholo }
2476ab05f83Stholo 
2486ab05f83Stholo void rehash(Array *tp)	/* rehash items in small table into big one */
2496ab05f83Stholo {
2506ab05f83Stholo 	int i, nh, nsz;
2516ab05f83Stholo 	Cell *cp, *op, **np;
2526ab05f83Stholo 
2536ab05f83Stholo 	nsz = GROWTAB * tp->size;
2546ab05f83Stholo 	np = (Cell **) calloc(nsz, sizeof(Cell *));
2556ab05f83Stholo 	if (np == NULL)		/* can't do it, but can keep running. */
2566ab05f83Stholo 		return;		/* someone else will run out later. */
2576ab05f83Stholo 	for (i = 0; i < tp->size; i++) {
2586ab05f83Stholo 		for (cp = tp->tab[i]; cp; cp = op) {
2596ab05f83Stholo 			op = cp->cnext;
2606ab05f83Stholo 			nh = hash(cp->nval, nsz);
2616ab05f83Stholo 			cp->cnext = np[nh];
2626ab05f83Stholo 			np[nh] = cp;
2636ab05f83Stholo 		}
2646ab05f83Stholo 	}
26507edfa4aSkstailey 	free(tp->tab);
2666ab05f83Stholo 	tp->tab = np;
2676ab05f83Stholo 	tp->size = nsz;
2686ab05f83Stholo }
2696ab05f83Stholo 
2709a69093aSmillert Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
2716ab05f83Stholo {
272271018d0Smillert 	Cell *p;
2736ab05f83Stholo 	int h;
2746ab05f83Stholo 
2756ab05f83Stholo 	h = hash(s, tp->size);
276271018d0Smillert 	for (p = tp->tab[h]; p != NULL; p = p->cnext)
27707edfa4aSkstailey 		if (strcmp(s, p->nval) == 0)
2786ab05f83Stholo 			return(p);	/* found it */
2796ab05f83Stholo 	return(NULL);			/* not found */
2806ab05f83Stholo }
2816ab05f83Stholo 
2826ab05f83Stholo Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
2836ab05f83Stholo {
28407edfa4aSkstailey 	int fldno;
28507edfa4aSkstailey 
2866ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
2876ab05f83Stholo 		funnyvar(vp, "assign to");
28807edfa4aSkstailey 	if (isfld(vp)) {
2896ab05f83Stholo 		donerec = 0;	/* mark $0 invalid */
29007edfa4aSkstailey 		fldno = atoi(vp->nval);
29107edfa4aSkstailey 		if (fldno > *NF)
29207edfa4aSkstailey 			newfld(fldno);
29307edfa4aSkstailey 		   dprintf( ("setting field %d to %g\n", fldno, f) );
29407edfa4aSkstailey 	} else if (isrec(vp)) {
2956ab05f83Stholo 		donefld = 0;	/* mark $1... invalid */
2966ab05f83Stholo 		donerec = 1;
2976ab05f83Stholo 	}
298a4fa8700Smillert 	if (freeable(vp))
299a4fa8700Smillert 		xfree(vp->sval); /* free any previous string */
3006ab05f83Stholo 	vp->tval &= ~STR;	/* mark string invalid */
3016ab05f83Stholo 	vp->tval |= NUM;	/* mark number ok */
3029a69093aSmillert 	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), f, vp->tval) );
3036ab05f83Stholo 	return vp->fval = f;
3046ab05f83Stholo }
3056ab05f83Stholo 
3069a69093aSmillert void funnyvar(Cell *vp, const char *rw)
3076ab05f83Stholo {
30807edfa4aSkstailey 	if (isarr(vp))
3097b11b857Smillert 		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
3106ab05f83Stholo 	if (vp->tval & FCN)
3117b11b857Smillert 		FATAL("can't %s %s; it's a function.", rw, vp->nval);
3127b11b857Smillert 	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
3137b11b857Smillert 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
3146ab05f83Stholo }
3156ab05f83Stholo 
3169a69093aSmillert char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
3176ab05f83Stholo {
3186ab05f83Stholo 	char *t;
31907edfa4aSkstailey 	int fldno;
3206ab05f83Stholo 
32123cb51abSmillert 	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
32223cb51abSmillert 		vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
3236ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3246ab05f83Stholo 		funnyvar(vp, "assign to");
32507edfa4aSkstailey 	if (isfld(vp)) {
3266ab05f83Stholo 		donerec = 0;	/* mark $0 invalid */
32707edfa4aSkstailey 		fldno = atoi(vp->nval);
32807edfa4aSkstailey 		if (fldno > *NF)
32907edfa4aSkstailey 			newfld(fldno);
33007edfa4aSkstailey 		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
33107edfa4aSkstailey 	} else if (isrec(vp)) {
3326ab05f83Stholo 		donefld = 0;	/* mark $1... invalid */
3336ab05f83Stholo 		donerec = 1;
3346ab05f83Stholo 	}
3356ab05f83Stholo 	t = tostring(s);	/* in case it's self-assign */
3366ab05f83Stholo 	if (freeable(vp))
3376ab05f83Stholo 		xfree(vp->sval);
338*4eb91dacSjmc 	vp->tval &= ~NUM;
339*4eb91dacSjmc 	vp->tval |= STR;
3406ab05f83Stholo 	vp->tval &= ~DONTFREE;
34123cb51abSmillert 	   dprintf( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
34223cb51abSmillert 		vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
3436ab05f83Stholo 	return(vp->sval = t);
3446ab05f83Stholo }
3456ab05f83Stholo 
3466ab05f83Stholo Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
3476ab05f83Stholo {
3486ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3496ab05f83Stholo 		funnyvar(vp, "read value of");
35007edfa4aSkstailey 	if (isfld(vp) && donefld == 0)
3516ab05f83Stholo 		fldbld();
35207edfa4aSkstailey 	else if (isrec(vp) && donerec == 0)
3536ab05f83Stholo 		recbld();
3546ab05f83Stholo 	if (!isnum(vp)) {	/* not a number */
3556ab05f83Stholo 		vp->fval = atof(vp->sval);	/* best guess */
356a4fa8700Smillert 		if (is_number(vp->sval) && !(vp->tval&CON))
3576ab05f83Stholo 			vp->tval |= NUM;	/* make NUM only sparingly */
3586ab05f83Stholo 	}
3599a69093aSmillert 	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, NN(vp->nval), vp->fval, vp->tval) );
3606ab05f83Stholo 	return(vp->fval);
3616ab05f83Stholo }
3626ab05f83Stholo 
3639a69093aSmillert static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
3646ab05f83Stholo {
365a4a48c73Smillert 	int n;
3666ab05f83Stholo 	double dtemp;
3676ab05f83Stholo 
3686ab05f83Stholo 	if ((vp->tval & (NUM | STR)) == 0)
3696ab05f83Stholo 		funnyvar(vp, "read value of");
37007edfa4aSkstailey 	if (isfld(vp) && donefld == 0)
3716ab05f83Stholo 		fldbld();
37207edfa4aSkstailey 	else if (isrec(vp) && donerec == 0)
3736ab05f83Stholo 		recbld();
37407edfa4aSkstailey 	if (isstr(vp) == 0) {
37507edfa4aSkstailey 		if (freeable(vp))
3766ab05f83Stholo 			xfree(vp->sval);
3776ab05f83Stholo 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
378a4a48c73Smillert 			n = asprintf(&vp->sval, "%.30g", vp->fval);
3796ab05f83Stholo 		else
380a4a48c73Smillert 			n = asprintf(&vp->sval, *fmt, vp->fval);
381a4a48c73Smillert 		if (n == -1)
382a4a48c73Smillert 			FATAL("out of space in get_str_val");
3836ab05f83Stholo 		vp->tval &= ~DONTFREE;
3846ab05f83Stholo 		vp->tval |= STR;
3856ab05f83Stholo 	}
3869a69093aSmillert 	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
3876ab05f83Stholo 	return(vp->sval);
3886ab05f83Stholo }
3896ab05f83Stholo 
3909a69093aSmillert char *getsval(Cell *vp)       /* get string val of a Cell */
3919a69093aSmillert {
3929a69093aSmillert       return get_str_val(vp, CONVFMT);
3939a69093aSmillert }
3949a69093aSmillert 
3959a69093aSmillert char *getpssval(Cell *vp)     /* get string val of a Cell for print */
3969a69093aSmillert {
3979a69093aSmillert       return get_str_val(vp, OFMT);
3989a69093aSmillert }
3999a69093aSmillert 
4009a69093aSmillert 
4019a69093aSmillert char *tostring(const char *s)	/* make a copy of string s */
4026ab05f83Stholo {
4038055ea94Smillert 	char *p;
4048055ea94Smillert 
4058055ea94Smillert 	p = strdup(s);
4068055ea94Smillert 	if (p == NULL)
4078055ea94Smillert 		FATAL("out of space in tostring on %s", s);
4088055ea94Smillert 	return p;
4096ab05f83Stholo }
4106ab05f83Stholo 
4119a69093aSmillert char *qstring(const char *is, int delim)	/* collect string up to next delim */
4126ab05f83Stholo {
4139a69093aSmillert 	const char *os = is;
4146ab05f83Stholo 	int c, n;
415a27f5228Smillert 	uschar *s = (uschar *) is;
416a27f5228Smillert 	uschar *buf, *bp;
4176ab05f83Stholo 
4189a69093aSmillert 	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
4197b11b857Smillert 		FATAL( "out of space in qstring(%s)", s);
42007edfa4aSkstailey 	for (bp = buf; (c = *s) != delim; s++) {
4216ab05f83Stholo 		if (c == '\n')
4227b11b857Smillert 			SYNTAX( "newline in string %.20s...", os );
4236ab05f83Stholo 		else if (c != '\\')
42407edfa4aSkstailey 			*bp++ = c;
42507edfa4aSkstailey 		else {	/* \something */
4267b11b857Smillert 			c = *++s;
4277b11b857Smillert 			if (c == 0) {	/* \ at end */
4287b11b857Smillert 				*bp++ = '\\';
4297b11b857Smillert 				break;	/* for loop */
4307b11b857Smillert 			}
4317b11b857Smillert 			switch (c) {
43207edfa4aSkstailey 			case '\\':	*bp++ = '\\'; break;
43307edfa4aSkstailey 			case 'n':	*bp++ = '\n'; break;
43407edfa4aSkstailey 			case 't':	*bp++ = '\t'; break;
43507edfa4aSkstailey 			case 'b':	*bp++ = '\b'; break;
43607edfa4aSkstailey 			case 'f':	*bp++ = '\f'; break;
43707edfa4aSkstailey 			case 'r':	*bp++ = '\r'; break;
4386ab05f83Stholo 			default:
4396ab05f83Stholo 				if (!isdigit(c)) {
44007edfa4aSkstailey 					*bp++ = c;
4416ab05f83Stholo 					break;
4426ab05f83Stholo 				}
4436ab05f83Stholo 				n = c - '0';
4446ab05f83Stholo 				if (isdigit(s[1])) {
4456ab05f83Stholo 					n = 8 * n + *++s - '0';
4466ab05f83Stholo 					if (isdigit(s[1]))
4476ab05f83Stholo 						n = 8 * n + *++s - '0';
4486ab05f83Stholo 				}
44907edfa4aSkstailey 				*bp++ = n;
4506ab05f83Stholo 				break;
4516ab05f83Stholo 			}
4526ab05f83Stholo 		}
45307edfa4aSkstailey 	}
45407edfa4aSkstailey 	*bp++ = 0;
455a27f5228Smillert 	return (char *) buf;
4566ab05f83Stholo }
457