xref: /onnv-gate/usr/src/cmd/awk/tran.c (revision 2615:71e502f72e48)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*2615Snakanon  * Common Development and Distribution License (the "License").
6*2615Snakanon  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
21289Snakanon 
22289Snakanon /*
23*2615Snakanon  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24289Snakanon  * Use is subject to license terms.
25289Snakanon  */
26289Snakanon 
270Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
30289Snakanon #pragma ident	"%Z%%M%	%I%	%E% SMI"
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #define	DEBUG
330Sstevel@tonic-gate #include <stdio.h>
34289Snakanon #include <stdlib.h>
350Sstevel@tonic-gate #include <ctype.h>
360Sstevel@tonic-gate #include <string.h>
370Sstevel@tonic-gate #include "awk.h"
380Sstevel@tonic-gate #include "y.tab.h"
390Sstevel@tonic-gate 
400Sstevel@tonic-gate #define	FULLTAB	2	/* rehash when table gets this x full */
410Sstevel@tonic-gate #define	GROWTAB 4	/* grow table by this factor */
420Sstevel@tonic-gate 
430Sstevel@tonic-gate Array	*symtab;	/* main symbol table */
440Sstevel@tonic-gate 
450Sstevel@tonic-gate uchar	**FS;		/* initial field sep */
460Sstevel@tonic-gate uchar	**RS;		/* initial record sep */
470Sstevel@tonic-gate uchar	**OFS;		/* output field sep */
480Sstevel@tonic-gate uchar	**ORS;		/* output record sep */
49289Snakanon uchar	**OFMT;		/* output format for numbers */
500Sstevel@tonic-gate Awkfloat *NF;		/* number of fields in current record */
510Sstevel@tonic-gate Awkfloat *NR;		/* number of current record */
520Sstevel@tonic-gate Awkfloat *FNR;		/* number of current record in current file */
530Sstevel@tonic-gate uchar	**FILENAME;	/* current filename argument */
540Sstevel@tonic-gate Awkfloat *ARGC;		/* number of arguments from command line */
550Sstevel@tonic-gate uchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
560Sstevel@tonic-gate Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
570Sstevel@tonic-gate Awkfloat *RLENGTH;	/* length of same */
580Sstevel@tonic-gate 
590Sstevel@tonic-gate Cell	*recloc;	/* location of record */
600Sstevel@tonic-gate Cell	*nrloc;		/* NR */
610Sstevel@tonic-gate Cell	*nfloc;		/* NF */
620Sstevel@tonic-gate Cell	*fnrloc;	/* FNR */
630Sstevel@tonic-gate Array	*ARGVtab;	/* symbol table containing ARGV[...] */
640Sstevel@tonic-gate Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
650Sstevel@tonic-gate Cell	*rstartloc;	/* RSTART */
660Sstevel@tonic-gate Cell	*rlengthloc;	/* RLENGTH */
670Sstevel@tonic-gate Cell	*symtabloc;	/* SYMTAB */
680Sstevel@tonic-gate 
690Sstevel@tonic-gate Cell	*nullloc;
700Sstevel@tonic-gate Node	*nullnode;	/* zero&null, converted into a node for comparisons */
710Sstevel@tonic-gate 
72289Snakanon static	void	rehash(Array *);
730Sstevel@tonic-gate 
74289Snakanon void
syminit(void)75289Snakanon syminit(void)
760Sstevel@tonic-gate {
77*2615Snakanon 	init_buf(&record, &record_size, LINE_INCR);
780Sstevel@tonic-gate 
79289Snakanon 	/* initialize $0 */
80*2615Snakanon 	recloc = getfld(0);
81*2615Snakanon 	recloc->nval = (uchar *)"$0";
82*2615Snakanon 	recloc->sval = record;
83*2615Snakanon 	recloc->tval = REC|STR|DONTFREE;
84289Snakanon 
850Sstevel@tonic-gate 	symtab = makesymtab(NSYMTAB);
86289Snakanon 	(void) setsymtab((uchar *)"0", (uchar *)"0", 0.0,
87289Snakanon 	    NUM|STR|CON|DONTFREE, symtab);
880Sstevel@tonic-gate 	/* this is used for if(x)... tests: */
89289Snakanon 	nullloc = setsymtab((uchar *)"$zero&null", (uchar *)"", 0.0,
90289Snakanon 	    NUM|STR|CON|DONTFREE, symtab);
910Sstevel@tonic-gate 	nullnode = valtonode(nullloc, CCON);
92289Snakanon 	FS = &setsymtab((uchar *)"FS", (uchar *)" ", 0.0,
93289Snakanon 	    STR|DONTFREE, symtab)->sval;
94289Snakanon 	RS = &setsymtab((uchar *)"RS", (uchar *)"\n", 0.0,
95289Snakanon 	    STR|DONTFREE, symtab)->sval;
96289Snakanon 	OFS = &setsymtab((uchar *)"OFS", (uchar *)" ", 0.0,
97289Snakanon 	    STR|DONTFREE, symtab)->sval;
98289Snakanon 	ORS = &setsymtab((uchar *)"ORS", (uchar *)"\n", 0.0,
99289Snakanon 	    STR|DONTFREE, symtab)->sval;
100289Snakanon 	OFMT = &setsymtab((uchar *)"OFMT", (uchar *)"%.6g", 0.0,
101289Snakanon 	    STR|DONTFREE, symtab)->sval;
102289Snakanon 	FILENAME = &setsymtab((uchar *)"FILENAME", (uchar *)"-", 0.0,
103289Snakanon 	    STR|DONTFREE, symtab)->sval;
104289Snakanon 	nfloc = setsymtab((uchar *)"NF", (uchar *)"", 0.0, NUM, symtab);
1050Sstevel@tonic-gate 	NF = &nfloc->fval;
106289Snakanon 	nrloc = setsymtab((uchar *)"NR", (uchar *)"", 0.0, NUM, symtab);
1070Sstevel@tonic-gate 	NR = &nrloc->fval;
108289Snakanon 	fnrloc = setsymtab((uchar *)"FNR", (uchar *)"", 0.0, NUM, symtab);
1090Sstevel@tonic-gate 	FNR = &fnrloc->fval;
110289Snakanon 	SUBSEP = &setsymtab((uchar *)"SUBSEP", (uchar *)"\034", 0.0,
111289Snakanon 	    STR|DONTFREE, symtab)->sval;
112289Snakanon 	rstartloc = setsymtab((uchar *)"RSTART", (uchar *)"", 0.0,
113289Snakanon 	    NUM, symtab);
1140Sstevel@tonic-gate 	RSTART = &rstartloc->fval;
115289Snakanon 	rlengthloc = setsymtab((uchar *)"RLENGTH", (uchar *)"", 0.0,
116289Snakanon 	    NUM, symtab);
1170Sstevel@tonic-gate 	RLENGTH = &rlengthloc->fval;
118289Snakanon 	symtabloc = setsymtab((uchar *)"SYMTAB", (uchar *)"", 0.0, ARR, symtab);
119289Snakanon 	symtabloc->sval = (uchar *)symtab;
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate 
122289Snakanon void
arginit(int ac,uchar * av[])123289Snakanon arginit(int ac, uchar *av[])
1240Sstevel@tonic-gate {
1250Sstevel@tonic-gate 	Cell *cp;
1260Sstevel@tonic-gate 	int i;
127289Snakanon 	uchar temp[11];
1280Sstevel@tonic-gate 
129289Snakanon 	/* first make FILENAME first real argument */
130289Snakanon 	for (i = 1; i < ac; i++) {
1310Sstevel@tonic-gate 		if (!isclvar(av[i])) {
132289Snakanon 			(void) setsval(lookup((uchar *)"FILENAME", symtab),
133289Snakanon 			    av[i]);
1340Sstevel@tonic-gate 			break;
1350Sstevel@tonic-gate 		}
136289Snakanon 	}
137289Snakanon 	ARGC = &setsymtab((uchar *)"ARGC", (uchar *)"", (Awkfloat)ac,
138289Snakanon 	    NUM, symtab)->fval;
139289Snakanon 	cp = setsymtab((uchar *)"ARGV", (uchar *)"", 0.0, ARR, symtab);
1400Sstevel@tonic-gate 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
1410Sstevel@tonic-gate 	cp->sval = (uchar *) ARGVtab;
1420Sstevel@tonic-gate 	for (i = 0; i < ac; i++) {
143289Snakanon 		(void) sprintf((char *)temp, "%d", i);
144289Snakanon 		if (is_number(*av)) {
145289Snakanon 			(void) setsymtab(temp, *av, atof((const char *)*av),
146289Snakanon 			    STR|NUM, ARGVtab);
147289Snakanon 		} else {
148289Snakanon 			(void) setsymtab(temp, *av, 0.0, STR, ARGVtab);
149289Snakanon 		}
1500Sstevel@tonic-gate 		av++;
1510Sstevel@tonic-gate 	}
1520Sstevel@tonic-gate }
1530Sstevel@tonic-gate 
154289Snakanon void
envinit(uchar * envp[])155289Snakanon envinit(uchar *envp[])
1560Sstevel@tonic-gate {
1570Sstevel@tonic-gate 	Cell *cp;
1580Sstevel@tonic-gate 	uchar *p;
1590Sstevel@tonic-gate 
160289Snakanon 	cp = setsymtab((uchar *)"ENVIRON", (uchar *)"", 0.0, ARR, symtab);
1610Sstevel@tonic-gate 	ENVtab = makesymtab(NSYMTAB);
1620Sstevel@tonic-gate 	cp->sval = (uchar *) ENVtab;
163289Snakanon 	for (; *envp; envp++) {
164289Snakanon 		if ((p = (uchar *)strchr((char *)*envp, '=')) == NULL)
1650Sstevel@tonic-gate 			continue;
1660Sstevel@tonic-gate 		*p++ = 0;	/* split into two strings at = */
167289Snakanon 		if (is_number(p)) {
168289Snakanon 			(void) setsymtab(*envp, p, atof((const char *)p),
169289Snakanon 			    STR|NUM, ENVtab);
170289Snakanon 		} else {
171289Snakanon 			(void) setsymtab(*envp, p, 0.0, STR, ENVtab);
172289Snakanon 		}
173289Snakanon 		/* restore in case env is passed down to a shell */
174289Snakanon 		p[-1] = '=';
1750Sstevel@tonic-gate 	}
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
178289Snakanon Array *
makesymtab(int n)179289Snakanon makesymtab(int n)
1800Sstevel@tonic-gate {
1810Sstevel@tonic-gate 	Array *ap;
1820Sstevel@tonic-gate 	Cell **tp;
1830Sstevel@tonic-gate 
184289Snakanon 	ap = (Array *)malloc(sizeof (Array));
185289Snakanon 	tp = (Cell **)calloc(n, sizeof (Cell *));
1860Sstevel@tonic-gate 	if (ap == NULL || tp == NULL)
1870Sstevel@tonic-gate 		ERROR "out of space in makesymtab" FATAL;
1880Sstevel@tonic-gate 	ap->nelem = 0;
1890Sstevel@tonic-gate 	ap->size = n;
1900Sstevel@tonic-gate 	ap->tab = tp;
191289Snakanon 	return (ap);
1920Sstevel@tonic-gate }
1930Sstevel@tonic-gate 
194289Snakanon void
freesymtab(Cell * ap)195289Snakanon freesymtab(Cell *ap)	/* free symbol table */
1960Sstevel@tonic-gate {
1970Sstevel@tonic-gate 	Cell *cp, *next;
1980Sstevel@tonic-gate 	Array *tp;
1990Sstevel@tonic-gate 	int i;
2000Sstevel@tonic-gate 
2010Sstevel@tonic-gate 	if (!isarr(ap))
2020Sstevel@tonic-gate 		return;
203289Snakanon 	/*LINTED align*/
204289Snakanon 	tp = (Array *)ap->sval;
2050Sstevel@tonic-gate 	if (tp == NULL)
2060Sstevel@tonic-gate 		return;
2070Sstevel@tonic-gate 	for (i = 0; i < tp->size; i++) {
2080Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp != NULL; cp = next) {
2090Sstevel@tonic-gate 			next = cp->cnext;
2100Sstevel@tonic-gate 			xfree(cp->nval);
2110Sstevel@tonic-gate 			if (freeable(cp))
2120Sstevel@tonic-gate 				xfree(cp->sval);
2130Sstevel@tonic-gate 			free(cp);
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 	}
2160Sstevel@tonic-gate 	free(tp->tab);
2170Sstevel@tonic-gate 	free(tp);
2180Sstevel@tonic-gate }
2190Sstevel@tonic-gate 
220289Snakanon void
freeelem(Cell * ap,uchar * s)221289Snakanon freeelem(Cell *ap, uchar *s)		/* free elem s from ap (i.e., ap["s"] */
2220Sstevel@tonic-gate {
2230Sstevel@tonic-gate 	Array *tp;
2240Sstevel@tonic-gate 	Cell *p, *prev = NULL;
2250Sstevel@tonic-gate 	int h;
226289Snakanon 
227289Snakanon 	/*LINTED align*/
228289Snakanon 	tp = (Array *)ap->sval;
2290Sstevel@tonic-gate 	h = hash(s, tp->size);
2300Sstevel@tonic-gate 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
231289Snakanon 		if (strcmp((char *)s, (char *)p->nval) == 0) {
2320Sstevel@tonic-gate 			if (prev == NULL)	/* 1st one */
2330Sstevel@tonic-gate 				tp->tab[h] = p->cnext;
2340Sstevel@tonic-gate 			else			/* middle somewhere */
2350Sstevel@tonic-gate 				prev->cnext = p->cnext;
2360Sstevel@tonic-gate 			if (freeable(p))
2370Sstevel@tonic-gate 				xfree(p->sval);
2380Sstevel@tonic-gate 			free(p->nval);
2390Sstevel@tonic-gate 			free(p);
2400Sstevel@tonic-gate 			tp->nelem--;
2410Sstevel@tonic-gate 			return;
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate }
2440Sstevel@tonic-gate 
245289Snakanon Cell *
setsymtab(uchar * n,uchar * s,Awkfloat f,unsigned int t,Array * tp)246289Snakanon setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned int t, Array *tp)
2470Sstevel@tonic-gate {
2480Sstevel@tonic-gate 	register int h;
2490Sstevel@tonic-gate 	register Cell *p;
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
252289Snakanon 		dprintf(("setsymtab found %p: n=%s", (void *)p, p->nval));
253289Snakanon 		dprintf((" s=\"%s\" f=%g t=%p\n",
254289Snakanon 		    p->sval, p->fval, (void *)p->tval));
255289Snakanon 		return (p);
2560Sstevel@tonic-gate 	}
257289Snakanon 	p = (Cell *)malloc(sizeof (Cell));
2580Sstevel@tonic-gate 	if (p == NULL)
2590Sstevel@tonic-gate 		ERROR "symbol table overflow at %s", n FATAL;
2600Sstevel@tonic-gate 	p->nval = tostring(n);
261289Snakanon 	p->sval = s ? tostring(s) : tostring((uchar *)"");
2620Sstevel@tonic-gate 	p->fval = f;
2630Sstevel@tonic-gate 	p->tval = t;
2640Sstevel@tonic-gate 	p->csub = 0;
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate 	tp->nelem++;
2670Sstevel@tonic-gate 	if (tp->nelem > FULLTAB * tp->size)
2680Sstevel@tonic-gate 		rehash(tp);
2690Sstevel@tonic-gate 	h = hash(n, tp->size);
2700Sstevel@tonic-gate 	p->cnext = tp->tab[h];
2710Sstevel@tonic-gate 	tp->tab[h] = p;
272289Snakanon 	dprintf(("setsymtab set %p: n=%s", (void *)p, p->nval));
273289Snakanon 	dprintf((" s=\"%s\" f=%g t=%p\n", p->sval, p->fval, (void *)p->tval));
274289Snakanon 	return (p);
2750Sstevel@tonic-gate }
2760Sstevel@tonic-gate 
277289Snakanon int
hash(uchar * s,int n)278289Snakanon hash(uchar *s, int n)	/* form hash value for string s */
2790Sstevel@tonic-gate {
2800Sstevel@tonic-gate 	register unsigned hashval;
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	for (hashval = 0; *s != '\0'; s++)
2830Sstevel@tonic-gate 		hashval = (*s + 31 * hashval);
284289Snakanon 	return (hashval % n);
2850Sstevel@tonic-gate }
2860Sstevel@tonic-gate 
287289Snakanon static void
rehash(Array * tp)288289Snakanon rehash(Array *tp)	/* rehash items in small table into big one */
2890Sstevel@tonic-gate {
2900Sstevel@tonic-gate 	int i, nh, nsz;
2910Sstevel@tonic-gate 	Cell *cp, *op, **np;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	nsz = GROWTAB * tp->size;
294289Snakanon 	np = (Cell **)calloc(nsz, sizeof (Cell *));
2950Sstevel@tonic-gate 	if (np == NULL)
2960Sstevel@tonic-gate 		ERROR "out of space in rehash" FATAL;
2970Sstevel@tonic-gate 	for (i = 0; i < tp->size; i++) {
2980Sstevel@tonic-gate 		for (cp = tp->tab[i]; cp; cp = op) {
2990Sstevel@tonic-gate 			op = cp->cnext;
3000Sstevel@tonic-gate 			nh = hash(cp->nval, nsz);
3010Sstevel@tonic-gate 			cp->cnext = np[nh];
3020Sstevel@tonic-gate 			np[nh] = cp;
3030Sstevel@tonic-gate 		}
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 	free(tp->tab);
3060Sstevel@tonic-gate 	tp->tab = np;
3070Sstevel@tonic-gate 	tp->size = nsz;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
310289Snakanon Cell *
lookup(uchar * s,Array * tp)311289Snakanon lookup(uchar *s, Array *tp)	/* look for s in tp */
3120Sstevel@tonic-gate {
313289Snakanon 	register Cell *p;
3140Sstevel@tonic-gate 	int h;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	h = hash(s, tp->size);
317289Snakanon 	for (p = tp->tab[h]; p != NULL; p = p->cnext) {
318289Snakanon 		if (strcmp((char *)s, (char *)p->nval) == 0)
319289Snakanon 			return (p);	/* found it */
320289Snakanon 	}
321289Snakanon 	return (NULL);			/* not found */
3220Sstevel@tonic-gate }
3230Sstevel@tonic-gate 
324289Snakanon Awkfloat
setfval(Cell * vp,Awkfloat f)325289Snakanon setfval(Cell *vp, Awkfloat f)
3260Sstevel@tonic-gate {
327289Snakanon 	int	i;
328289Snakanon 
329289Snakanon 	if ((vp->tval & (NUM | STR)) == 0)
3300Sstevel@tonic-gate 		funnyvar(vp, "assign to");
3310Sstevel@tonic-gate 	if (vp->tval & FLD) {
3320Sstevel@tonic-gate 		donerec = 0;	/* mark $0 invalid */
333289Snakanon 		i = fldidx(vp);
334289Snakanon 		if (i > *NF)
335289Snakanon 			newfld(i);
336289Snakanon 		dprintf(("setting field %d to %g\n", i, f));
3370Sstevel@tonic-gate 	} else if (vp->tval & REC) {
3380Sstevel@tonic-gate 		donefld = 0;	/* mark $1... invalid */
3390Sstevel@tonic-gate 		donerec = 1;
3400Sstevel@tonic-gate 	}
3410Sstevel@tonic-gate 	vp->tval &= ~STR;	/* mark string invalid */
3420Sstevel@tonic-gate 	vp->tval |= NUM;	/* mark number ok */
343289Snakanon 	dprintf(("setfval %p: %s = %g, t=%p\n", (void *)vp,
344289Snakanon 	    vp->nval ? vp->nval : (unsigned char *)"NULL",
345289Snakanon 	    f, (void *)vp->tval));
346289Snakanon 	return (vp->fval = f);
3470Sstevel@tonic-gate }
3480Sstevel@tonic-gate 
349289Snakanon void
funnyvar(Cell * vp,char * rw)350289Snakanon funnyvar(Cell *vp, char *rw)
3510Sstevel@tonic-gate {
3520Sstevel@tonic-gate 	if (vp->tval & ARR)
3530Sstevel@tonic-gate 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
3540Sstevel@tonic-gate 	if (vp->tval & FCN)
3550Sstevel@tonic-gate 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
3560Sstevel@tonic-gate 	ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
357289Snakanon 	    vp, vp->nval, vp->sval, vp->fval, vp->tval CONT;
3580Sstevel@tonic-gate }
3590Sstevel@tonic-gate 
360289Snakanon uchar *
setsval(Cell * vp,uchar * s)361289Snakanon setsval(Cell *vp, uchar *s)
3620Sstevel@tonic-gate {
363289Snakanon 	int	i;
364289Snakanon 
3650Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
3660Sstevel@tonic-gate 		funnyvar(vp, "assign to");
3670Sstevel@tonic-gate 	if (vp->tval & FLD) {
3680Sstevel@tonic-gate 		donerec = 0;	/* mark $0 invalid */
369289Snakanon 		i = fldidx(vp);
370289Snakanon 		if (i > *NF)
371289Snakanon 			newfld(i);
372289Snakanon 		dprintf(("setting field %d to %s\n", i, s));
3730Sstevel@tonic-gate 	} else if (vp->tval & REC) {
3740Sstevel@tonic-gate 		donefld = 0;	/* mark $1... invalid */
3750Sstevel@tonic-gate 		donerec = 1;
3760Sstevel@tonic-gate 	}
3770Sstevel@tonic-gate 	vp->tval &= ~NUM;
3780Sstevel@tonic-gate 	vp->tval |= STR;
3790Sstevel@tonic-gate 	if (freeable(vp))
3800Sstevel@tonic-gate 		xfree(vp->sval);
3810Sstevel@tonic-gate 	vp->tval &= ~DONTFREE;
382289Snakanon 	dprintf(("setsval %p: %s = \"%s\", t=%p\n",
383289Snakanon 	    (void *)vp,
384289Snakanon 	    vp->nval ? (char *)vp->nval : "",
385289Snakanon 	    s,
386289Snakanon 	    (void *)(vp->tval ? (char *)vp->tval : "")));
387289Snakanon 	return (vp->sval = tostring(s));
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
390289Snakanon Awkfloat
r_getfval(Cell * vp)391289Snakanon r_getfval(Cell *vp)
3920Sstevel@tonic-gate {
3930Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
3940Sstevel@tonic-gate 		funnyvar(vp, "read value of");
3950Sstevel@tonic-gate 	if ((vp->tval & FLD) && donefld == 0)
3960Sstevel@tonic-gate 		fldbld();
3970Sstevel@tonic-gate 	else if ((vp->tval & REC) && donerec == 0)
3980Sstevel@tonic-gate 		recbld();
3990Sstevel@tonic-gate 	if (!isnum(vp)) {	/* not a number */
400289Snakanon 		vp->fval = atof((const char *)vp->sval);	/* best guess */
401289Snakanon 		if (is_number(vp->sval) && !(vp->tval&CON))
4020Sstevel@tonic-gate 			vp->tval |= NUM;	/* make NUM only sparingly */
4030Sstevel@tonic-gate 	}
404289Snakanon 	dprintf(("getfval %p: %s = %g, t=%p\n",
405289Snakanon 	    (void *)vp, vp->nval, vp->fval, (void *)vp->tval));
406289Snakanon 	return (vp->fval);
4070Sstevel@tonic-gate }
4080Sstevel@tonic-gate 
409289Snakanon uchar *
r_getsval(Cell * vp)410289Snakanon r_getsval(Cell *vp)
4110Sstevel@tonic-gate {
412289Snakanon 	uchar s[256];
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
4150Sstevel@tonic-gate 		funnyvar(vp, "read value of");
4160Sstevel@tonic-gate 	if ((vp->tval & FLD) && donefld == 0)
4170Sstevel@tonic-gate 		fldbld();
4180Sstevel@tonic-gate 	else if ((vp->tval & REC) && donerec == 0)
4190Sstevel@tonic-gate 		recbld();
4200Sstevel@tonic-gate 	if ((vp->tval & STR) == 0) {
4210Sstevel@tonic-gate 		if (!(vp->tval&DONTFREE))
4220Sstevel@tonic-gate 			xfree(vp->sval);
423289Snakanon 		if ((long long)vp->fval == vp->fval) {
424289Snakanon 			(void) snprintf((char *)s, sizeof (s),
425289Snakanon 			    "%.20g", vp->fval);
426289Snakanon 		} else {
427289Snakanon 			/*LINTED*/
428289Snakanon 			(void) snprintf((char *)s, sizeof (s),
429289Snakanon 			    (char *)*OFMT, vp->fval);
430289Snakanon 		}
4310Sstevel@tonic-gate 		vp->sval = tostring(s);
4320Sstevel@tonic-gate 		vp->tval &= ~DONTFREE;
4330Sstevel@tonic-gate 		vp->tval |= STR;
4340Sstevel@tonic-gate 	}
435289Snakanon 	dprintf(("getsval %p: %s = \"%s\", t=%p\n",
436289Snakanon 	    (void *)vp,
437289Snakanon 	    vp->nval ? (char *)vp->nval : "",
438289Snakanon 	    vp->sval ? (char *)vp->sval : "",
439289Snakanon 	    (void *)vp->tval));
440289Snakanon 	return (vp->sval);
4410Sstevel@tonic-gate }
4420Sstevel@tonic-gate 
443289Snakanon uchar *
tostring(uchar * s)444289Snakanon tostring(uchar *s)
4450Sstevel@tonic-gate {
4460Sstevel@tonic-gate 	register uchar *p;
4470Sstevel@tonic-gate 
448289Snakanon 	p = (uchar *)malloc(strlen((char *)s)+1);
4490Sstevel@tonic-gate 	if (p == NULL)
4500Sstevel@tonic-gate 		ERROR "out of space in tostring on %s", s FATAL;
451289Snakanon 	(void) strcpy((char *)p, (char *)s);
452289Snakanon 	return (p);
4530Sstevel@tonic-gate }
4540Sstevel@tonic-gate 
455289Snakanon uchar *
qstring(uchar * s,int delim)456289Snakanon qstring(uchar *s, int delim)	/* collect string up to delim */
4570Sstevel@tonic-gate {
458289Snakanon 	uchar *cbuf, *ret;
4590Sstevel@tonic-gate 	int c, n;
460289Snakanon 	size_t	cbufsz, cnt;
461289Snakanon 
462289Snakanon 	init_buf(&cbuf, &cbufsz, LINE_INCR);
4630Sstevel@tonic-gate 
464289Snakanon 	for (cnt = 0; (c = *s) != delim; s++) {
465289Snakanon 		if (c == '\n') {
4660Sstevel@tonic-gate 			ERROR "newline in string %.10s...", cbuf SYNTAX;
467289Snakanon 		} else if (c != '\\') {
468289Snakanon 			expand_buf(&cbuf, &cbufsz, cnt);
469289Snakanon 			cbuf[cnt++] = c;
470289Snakanon 		} else {	/* \something */
471289Snakanon 			expand_buf(&cbuf, &cbufsz, cnt);
4720Sstevel@tonic-gate 			switch (c = *++s) {
473289Snakanon 			case '\\':	cbuf[cnt++] = '\\'; break;
474289Snakanon 			case 'n':	cbuf[cnt++] = '\n'; break;
475289Snakanon 			case 't':	cbuf[cnt++] = '\t'; break;
476289Snakanon 			case 'b':	cbuf[cnt++] = '\b'; break;
477289Snakanon 			case 'f':	cbuf[cnt++] = '\f'; break;
478289Snakanon 			case 'r':	cbuf[cnt++] = '\r'; break;
4790Sstevel@tonic-gate 			default:
4800Sstevel@tonic-gate 				if (!isdigit(c)) {
481289Snakanon 					cbuf[cnt++] = c;
4820Sstevel@tonic-gate 					break;
4830Sstevel@tonic-gate 				}
4840Sstevel@tonic-gate 				n = c - '0';
4850Sstevel@tonic-gate 				if (isdigit(s[1])) {
4860Sstevel@tonic-gate 					n = 8 * n + *++s - '0';
4870Sstevel@tonic-gate 					if (isdigit(s[1]))
4880Sstevel@tonic-gate 						n = 8 * n + *++s - '0';
4890Sstevel@tonic-gate 				}
490289Snakanon 				cbuf[cnt++] = n;
4910Sstevel@tonic-gate 				break;
4920Sstevel@tonic-gate 			}
493289Snakanon 		}
4940Sstevel@tonic-gate 	}
495289Snakanon 	cbuf[cnt] = '\0';
496289Snakanon 	ret = tostring(cbuf);
497289Snakanon 	free(cbuf);
498289Snakanon 	return (ret);
4990Sstevel@tonic-gate }
500