xref: /plan9/sys/src/cmd/awk/tran.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier /*
2*3e12c5d1SDavid du Colombier Copyright (c) 1989 AT&T
3*3e12c5d1SDavid du Colombier 	All Rights Reserved
4*3e12c5d1SDavid du Colombier 
5*3e12c5d1SDavid du Colombier THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T.
6*3e12c5d1SDavid du Colombier 
7*3e12c5d1SDavid du Colombier The copyright notice above does not evidence any
8*3e12c5d1SDavid du Colombier actual or intended publication of such source code.
9*3e12c5d1SDavid du Colombier */
10*3e12c5d1SDavid du Colombier 
11*3e12c5d1SDavid du Colombier #define	DEBUG
12*3e12c5d1SDavid du Colombier #include <stdio.h>
13*3e12c5d1SDavid du Colombier #include <math.h>
14*3e12c5d1SDavid du Colombier #include <ctype.h>
15*3e12c5d1SDavid du Colombier #include <string.h>
16*3e12c5d1SDavid du Colombier #include <stdlib.h>
17*3e12c5d1SDavid du Colombier #include "awk.h"
18*3e12c5d1SDavid du Colombier #include "y.tab.h"
19*3e12c5d1SDavid du Colombier 
20*3e12c5d1SDavid du Colombier #define	FULLTAB	2	/* rehash when table gets this x full */
21*3e12c5d1SDavid du Colombier #define	GROWTAB 4	/* grow table by this factor */
22*3e12c5d1SDavid du Colombier 
23*3e12c5d1SDavid du Colombier Array	*symtab;	/* main symbol table */
24*3e12c5d1SDavid du Colombier 
25*3e12c5d1SDavid du Colombier uchar	**FS;		/* initial field sep */
26*3e12c5d1SDavid du Colombier uchar	**RS;		/* initial record sep */
27*3e12c5d1SDavid du Colombier uchar	**OFS;		/* output field sep */
28*3e12c5d1SDavid du Colombier uchar	**ORS;		/* output record sep */
29*3e12c5d1SDavid du Colombier uchar	**OFMT;		/* output format for numbers*/
30*3e12c5d1SDavid du Colombier Awkfloat *NF;		/* number of fields in current record */
31*3e12c5d1SDavid du Colombier Awkfloat *NR;		/* number of current record */
32*3e12c5d1SDavid du Colombier Awkfloat *FNR;		/* number of current record in current file */
33*3e12c5d1SDavid du Colombier uchar	**FILENAME;	/* current filename argument */
34*3e12c5d1SDavid du Colombier Awkfloat *ARGC;		/* number of arguments from command line */
35*3e12c5d1SDavid du Colombier uchar	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
36*3e12c5d1SDavid du Colombier Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
37*3e12c5d1SDavid du Colombier Awkfloat *RLENGTH;	/* length of same */
38*3e12c5d1SDavid du Colombier 
39*3e12c5d1SDavid du Colombier Cell	*recloc;	/* location of record */
40*3e12c5d1SDavid du Colombier Cell	*nrloc;		/* NR */
41*3e12c5d1SDavid du Colombier Cell	*nfloc;		/* NF */
42*3e12c5d1SDavid du Colombier Cell	*fnrloc;	/* FNR */
43*3e12c5d1SDavid du Colombier Array	*ARGVtab;	/* symbol table containing ARGV[...] */
44*3e12c5d1SDavid du Colombier Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
45*3e12c5d1SDavid du Colombier Cell	*rstartloc;	/* RSTART */
46*3e12c5d1SDavid du Colombier Cell	*rlengthloc;	/* RLENGTH */
47*3e12c5d1SDavid du Colombier Cell	*symtabloc;	/* SYMTAB */
48*3e12c5d1SDavid du Colombier 
49*3e12c5d1SDavid du Colombier Cell	*nullloc;
50*3e12c5d1SDavid du Colombier Node	*nullnode;	/* zero&null, converted into a node for comparisons */
51*3e12c5d1SDavid du Colombier 
52*3e12c5d1SDavid du Colombier extern Cell fldtab[];
53*3e12c5d1SDavid du Colombier 
54*3e12c5d1SDavid du Colombier void syminit(void)
55*3e12c5d1SDavid du Colombier {
56*3e12c5d1SDavid du Colombier 	symtab = makesymtab(NSYMTAB);
57*3e12c5d1SDavid du Colombier 	setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
58*3e12c5d1SDavid du Colombier 	/* this is used for if(x)... tests: */
59*3e12c5d1SDavid du Colombier 	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
60*3e12c5d1SDavid du Colombier 	nullnode = valtonode(nullloc, CCON);
61*3e12c5d1SDavid du Colombier 	/* recloc = setsymtab("$0", record, 0.0, REC|STR|DONTFREE, symtab); */
62*3e12c5d1SDavid du Colombier 	recloc = &fldtab[0];
63*3e12c5d1SDavid du Colombier 	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
64*3e12c5d1SDavid du Colombier 	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
65*3e12c5d1SDavid du Colombier 	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
66*3e12c5d1SDavid du Colombier 	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
67*3e12c5d1SDavid du Colombier 	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
68*3e12c5d1SDavid du Colombier 	FILENAME = &setsymtab("FILENAME", "-", 0.0, STR|DONTFREE, symtab)->sval;
69*3e12c5d1SDavid du Colombier 	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
70*3e12c5d1SDavid du Colombier 	NF = &nfloc->fval;
71*3e12c5d1SDavid du Colombier 	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
72*3e12c5d1SDavid du Colombier 	NR = &nrloc->fval;
73*3e12c5d1SDavid du Colombier 	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
74*3e12c5d1SDavid du Colombier 	FNR = &fnrloc->fval;
75*3e12c5d1SDavid du Colombier 	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
76*3e12c5d1SDavid du Colombier 	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
77*3e12c5d1SDavid du Colombier 	RSTART = &rstartloc->fval;
78*3e12c5d1SDavid du Colombier 	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
79*3e12c5d1SDavid du Colombier 	RLENGTH = &rlengthloc->fval;
80*3e12c5d1SDavid du Colombier 	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
81*3e12c5d1SDavid du Colombier 	symtabloc->sval = (uchar *) symtab;
82*3e12c5d1SDavid du Colombier }
83*3e12c5d1SDavid du Colombier 
84*3e12c5d1SDavid du Colombier void arginit(int ac, uchar *av[])
85*3e12c5d1SDavid du Colombier {
86*3e12c5d1SDavid du Colombier 	Cell *cp;
87*3e12c5d1SDavid du Colombier 	int i;
88*3e12c5d1SDavid du Colombier 	uchar temp[5];
89*3e12c5d1SDavid du Colombier 
90*3e12c5d1SDavid du Colombier 	for (i = 1; i < ac; i++)	/* first make FILENAME first real argument */
91*3e12c5d1SDavid du Colombier 		if (!isclvar(av[i])) {
92*3e12c5d1SDavid du Colombier 			setsval(lookup("FILENAME", symtab), av[i]);
93*3e12c5d1SDavid du Colombier 			break;
94*3e12c5d1SDavid du Colombier 		}
95*3e12c5d1SDavid du Colombier 	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
96*3e12c5d1SDavid du Colombier 	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
97*3e12c5d1SDavid du Colombier 	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
98*3e12c5d1SDavid du Colombier 	cp->sval = (uchar *) ARGVtab;
99*3e12c5d1SDavid du Colombier 	for (i = 0; i < ac; i++) {
100*3e12c5d1SDavid du Colombier 		sprintf((char *)temp, "%d", i);
101*3e12c5d1SDavid du Colombier 		if (isnumber(*av))
102*3e12c5d1SDavid du Colombier 			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
103*3e12c5d1SDavid du Colombier 		else
104*3e12c5d1SDavid du Colombier 			setsymtab(temp, *av, 0.0, STR, ARGVtab);
105*3e12c5d1SDavid du Colombier 		av++;
106*3e12c5d1SDavid du Colombier 	}
107*3e12c5d1SDavid du Colombier }
108*3e12c5d1SDavid du Colombier 
109*3e12c5d1SDavid du Colombier void envinit(uchar **envp)
110*3e12c5d1SDavid du Colombier {
111*3e12c5d1SDavid du Colombier 	Cell *cp;
112*3e12c5d1SDavid du Colombier 	uchar *p;
113*3e12c5d1SDavid du Colombier 
114*3e12c5d1SDavid du Colombier 	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
115*3e12c5d1SDavid du Colombier 	ENVtab = makesymtab(NSYMTAB);
116*3e12c5d1SDavid du Colombier 	cp->sval = (uchar *) ENVtab;
117*3e12c5d1SDavid du Colombier 	for ( ; *envp; envp++) {
118*3e12c5d1SDavid du Colombier 		if ((p = (uchar *) strchr((char *) *envp, '=')) == NULL)	/* index() on bsd */
119*3e12c5d1SDavid du Colombier 			continue;
120*3e12c5d1SDavid du Colombier 		*p++ = 0;	/* split into two strings at = */
121*3e12c5d1SDavid du Colombier 		if (isnumber(p))
122*3e12c5d1SDavid du Colombier 			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
123*3e12c5d1SDavid du Colombier 		else
124*3e12c5d1SDavid du Colombier 			setsymtab(*envp, p, 0.0, STR, ENVtab);
125*3e12c5d1SDavid du Colombier 		p[-1] = '=';	/* restore in case env is passed down to a shell */
126*3e12c5d1SDavid du Colombier 	}
127*3e12c5d1SDavid du Colombier }
128*3e12c5d1SDavid du Colombier 
129*3e12c5d1SDavid du Colombier Array *makesymtab(int n)
130*3e12c5d1SDavid du Colombier {
131*3e12c5d1SDavid du Colombier 	Array *ap;
132*3e12c5d1SDavid du Colombier 	Cell **tp;
133*3e12c5d1SDavid du Colombier 
134*3e12c5d1SDavid du Colombier 	ap = (Array *) malloc(sizeof(Array));
135*3e12c5d1SDavid du Colombier 	tp = (Cell **) calloc(n, sizeof(Cell *));
136*3e12c5d1SDavid du Colombier 	if (ap == NULL || tp == NULL)
137*3e12c5d1SDavid du Colombier 		ERROR "out of space in makesymtab" FATAL;
138*3e12c5d1SDavid du Colombier 	ap->nelem = 0;
139*3e12c5d1SDavid du Colombier 	ap->size = n;
140*3e12c5d1SDavid du Colombier 	ap->tab = tp;
141*3e12c5d1SDavid du Colombier 	return(ap);
142*3e12c5d1SDavid du Colombier }
143*3e12c5d1SDavid du Colombier 
144*3e12c5d1SDavid du Colombier void freesymtab(Cell *ap)	/* free symbol table */
145*3e12c5d1SDavid du Colombier {
146*3e12c5d1SDavid du Colombier 	Cell *cp, *temp;
147*3e12c5d1SDavid du Colombier 	Array *tp;
148*3e12c5d1SDavid du Colombier 	int i;
149*3e12c5d1SDavid du Colombier 
150*3e12c5d1SDavid du Colombier 	if (!isarr(ap))
151*3e12c5d1SDavid du Colombier 		return;
152*3e12c5d1SDavid du Colombier 	tp = (Array *) ap->sval;
153*3e12c5d1SDavid du Colombier 	if (tp == NULL)
154*3e12c5d1SDavid du Colombier 		return;
155*3e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {
156*3e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
157*3e12c5d1SDavid du Colombier 			xfree(cp->nval);
158*3e12c5d1SDavid du Colombier 			if (freeable(cp))
159*3e12c5d1SDavid du Colombier 				xfree(cp->sval);
160*3e12c5d1SDavid du Colombier 			temp = cp->cnext;	/* avoids freeing then using */
161*3e12c5d1SDavid du Colombier 			free(cp);
162*3e12c5d1SDavid du Colombier 		}
163*3e12c5d1SDavid du Colombier 	}
164*3e12c5d1SDavid du Colombier 	free(tp->tab);
165*3e12c5d1SDavid du Colombier 	free(tp);
166*3e12c5d1SDavid du Colombier }
167*3e12c5d1SDavid du Colombier 
168*3e12c5d1SDavid du Colombier void freeelem(Cell *ap, uchar *s)	/* free elem s from ap (i.e., ap["s"] */
169*3e12c5d1SDavid du Colombier {
170*3e12c5d1SDavid du Colombier 	Array *tp;
171*3e12c5d1SDavid du Colombier 	Cell *p, *prev = NULL;
172*3e12c5d1SDavid du Colombier 	int h;
173*3e12c5d1SDavid du Colombier 
174*3e12c5d1SDavid du Colombier 	tp = (Array *) ap->sval;
175*3e12c5d1SDavid du Colombier 	h = hash(s, tp->size);
176*3e12c5d1SDavid du Colombier 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
177*3e12c5d1SDavid du Colombier 		if (strcmp((char *) s, (char *) p->nval) == 0) {
178*3e12c5d1SDavid du Colombier 			if (prev == NULL)	/* 1st one */
179*3e12c5d1SDavid du Colombier 				tp->tab[h] = p->cnext;
180*3e12c5d1SDavid du Colombier 			else			/* middle somewhere */
181*3e12c5d1SDavid du Colombier 				prev->cnext = p->cnext;
182*3e12c5d1SDavid du Colombier 			if (freeable(p))
183*3e12c5d1SDavid du Colombier 				xfree(p->sval);
184*3e12c5d1SDavid du Colombier 			free(p->nval);
185*3e12c5d1SDavid du Colombier 			free(p);
186*3e12c5d1SDavid du Colombier 			tp->nelem--;
187*3e12c5d1SDavid du Colombier 			return;
188*3e12c5d1SDavid du Colombier 		}
189*3e12c5d1SDavid du Colombier }
190*3e12c5d1SDavid du Colombier 
191*3e12c5d1SDavid du Colombier Cell *setsymtab(uchar *n, uchar *s, Awkfloat f, unsigned t, Array *tp)
192*3e12c5d1SDavid du Colombier {
193*3e12c5d1SDavid du Colombier 	register int h;
194*3e12c5d1SDavid du Colombier 	register Cell *p;
195*3e12c5d1SDavid du Colombier 
196*3e12c5d1SDavid du Colombier 	if (n != NULL && (p = lookup(n, tp)) != NULL) {
197*3e12c5d1SDavid du Colombier 		dprintf( ("setsymtab found %o: n=%s", p, p->nval) );
198*3e12c5d1SDavid du Colombier 		dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
199*3e12c5d1SDavid du Colombier 		return(p);
200*3e12c5d1SDavid du Colombier 	}
201*3e12c5d1SDavid du Colombier 	p = (Cell *) malloc(sizeof(Cell));
202*3e12c5d1SDavid du Colombier 	if (p == NULL)
203*3e12c5d1SDavid du Colombier 		ERROR "symbol table overflow at %s", n FATAL;
204*3e12c5d1SDavid du Colombier 	p->nval = tostring(n);
205*3e12c5d1SDavid du Colombier 	p->sval = s ? tostring(s) : tostring("");
206*3e12c5d1SDavid du Colombier 	p->fval = f;
207*3e12c5d1SDavid du Colombier 	p->tval = t;
208*3e12c5d1SDavid du Colombier 	tp->nelem++;
209*3e12c5d1SDavid du Colombier 	if (tp->nelem > FULLTAB * tp->size)
210*3e12c5d1SDavid du Colombier 		rehash(tp);
211*3e12c5d1SDavid du Colombier 	h = hash(n, tp->size);
212*3e12c5d1SDavid du Colombier 	p->cnext = tp->tab[h];
213*3e12c5d1SDavid du Colombier 	tp->tab[h] = p;
214*3e12c5d1SDavid du Colombier 	dprintf( ("setsymtab set %o: n=%s", p, p->nval) );
215*3e12c5d1SDavid du Colombier 	dprintf( (" s=\"%s\" f=%g t=%o\n", p->sval, p->fval, p->tval) );
216*3e12c5d1SDavid du Colombier 	return(p);
217*3e12c5d1SDavid du Colombier }
218*3e12c5d1SDavid du Colombier 
219*3e12c5d1SDavid du Colombier hash(uchar *s, int n)	/* form hash value for string s */
220*3e12c5d1SDavid du Colombier {
221*3e12c5d1SDavid du Colombier 	register unsigned hashval;
222*3e12c5d1SDavid du Colombier 
223*3e12c5d1SDavid du Colombier 	for (hashval = 0; *s != '\0'; s++)
224*3e12c5d1SDavid du Colombier 		hashval = (*s + 31 * hashval);
225*3e12c5d1SDavid du Colombier 	return hashval % n;
226*3e12c5d1SDavid du Colombier }
227*3e12c5d1SDavid du Colombier 
228*3e12c5d1SDavid du Colombier void rehash(Array *tp)	/* rehash items in small table into big one */
229*3e12c5d1SDavid du Colombier {
230*3e12c5d1SDavid du Colombier 	int i, nh, nsz;
231*3e12c5d1SDavid du Colombier 	Cell *cp, *op, **np;
232*3e12c5d1SDavid du Colombier 
233*3e12c5d1SDavid du Colombier 	nsz = GROWTAB * tp->size;
234*3e12c5d1SDavid du Colombier 	np = (Cell **) calloc(nsz, sizeof(Cell *));
235*3e12c5d1SDavid du Colombier 	if (np == NULL)
236*3e12c5d1SDavid du Colombier 		ERROR "out of space in rehash" FATAL;
237*3e12c5d1SDavid du Colombier 	for (i = 0; i < tp->size; i++) {
238*3e12c5d1SDavid du Colombier 		for (cp = tp->tab[i]; cp; cp = op) {
239*3e12c5d1SDavid du Colombier 			op = cp->cnext;
240*3e12c5d1SDavid du Colombier 			nh = hash(cp->nval, nsz);
241*3e12c5d1SDavid du Colombier 			cp->cnext = np[nh];
242*3e12c5d1SDavid du Colombier 			np[nh] = cp;
243*3e12c5d1SDavid du Colombier 		}
244*3e12c5d1SDavid du Colombier 	}
245*3e12c5d1SDavid du Colombier 	free(tp->tab);
246*3e12c5d1SDavid du Colombier 	tp->tab = np;
247*3e12c5d1SDavid du Colombier 	tp->size = nsz;
248*3e12c5d1SDavid du Colombier }
249*3e12c5d1SDavid du Colombier 
250*3e12c5d1SDavid du Colombier Cell *lookup(uchar *s, Array *tp)	/* look for s in tp */
251*3e12c5d1SDavid du Colombier {
252*3e12c5d1SDavid du Colombier 	register Cell *p, *prev = NULL;
253*3e12c5d1SDavid du Colombier 	int h;
254*3e12c5d1SDavid du Colombier 
255*3e12c5d1SDavid du Colombier 	h = hash(s, tp->size);
256*3e12c5d1SDavid du Colombier 	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
257*3e12c5d1SDavid du Colombier 		if (strcmp((char *) s, (char *) p->nval) == 0)
258*3e12c5d1SDavid du Colombier 			return(p);	/* found it */
259*3e12c5d1SDavid du Colombier 	return(NULL);			/* not found */
260*3e12c5d1SDavid du Colombier }
261*3e12c5d1SDavid du Colombier 
262*3e12c5d1SDavid du Colombier Awkfloat setfval(Cell *vp, Awkfloat f)
263*3e12c5d1SDavid du Colombier {
264*3e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
265*3e12c5d1SDavid du Colombier 		funnyvar(vp, "assign to");
266*3e12c5d1SDavid du Colombier 	if (vp->tval & FLD) {
267*3e12c5d1SDavid du Colombier 		donerec = 0;	/* mark $0 invalid */
268*3e12c5d1SDavid du Colombier 		if (vp-fldtab > *NF)
269*3e12c5d1SDavid du Colombier 			newfld(vp-fldtab);
270*3e12c5d1SDavid du Colombier 		dprintf( ("setting field %d to %g\n", vp-fldtab, f) );
271*3e12c5d1SDavid du Colombier 	} else if (vp->tval & REC) {
272*3e12c5d1SDavid du Colombier 		donefld = 0;	/* mark $1... invalid */
273*3e12c5d1SDavid du Colombier 		donerec = 1;
274*3e12c5d1SDavid du Colombier 	}
275*3e12c5d1SDavid du Colombier 	vp->tval &= ~STR;	/* mark string invalid */
276*3e12c5d1SDavid du Colombier 	vp->tval |= NUM;	/* mark number ok */
277*3e12c5d1SDavid du Colombier 	dprintf( ("setfval %o: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
278*3e12c5d1SDavid du Colombier 	return vp->fval = f;
279*3e12c5d1SDavid du Colombier }
280*3e12c5d1SDavid du Colombier 
281*3e12c5d1SDavid du Colombier void funnyvar(Cell *vp, char *rw)
282*3e12c5d1SDavid du Colombier {
283*3e12c5d1SDavid du Colombier 	if (vp->tval & ARR)
284*3e12c5d1SDavid du Colombier 		ERROR "can't %s %s; it's an array name.", rw, vp->nval FATAL;
285*3e12c5d1SDavid du Colombier 	if (vp->tval & FCN)
286*3e12c5d1SDavid du Colombier 		ERROR "can't %s %s; it's a function.", rw, vp->nval FATAL;
287*3e12c5d1SDavid du Colombier 	ERROR "funny variable %o: n=%s s=\"%s\" f=%g t=%o",
288*3e12c5d1SDavid du Colombier 		vp, vp->nval, vp->sval, vp->fval, vp->tval);
289*3e12c5d1SDavid du Colombier }
290*3e12c5d1SDavid du Colombier 
291*3e12c5d1SDavid du Colombier uchar *setsval(Cell *vp, uchar *s)
292*3e12c5d1SDavid du Colombier {
293*3e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
294*3e12c5d1SDavid du Colombier 		funnyvar(vp, "assign to");
295*3e12c5d1SDavid du Colombier 	if (vp->tval & FLD) {
296*3e12c5d1SDavid du Colombier 		donerec = 0;	/* mark $0 invalid */
297*3e12c5d1SDavid du Colombier 		if (vp-fldtab > *NF)
298*3e12c5d1SDavid du Colombier 			newfld(vp-fldtab);
299*3e12c5d1SDavid du Colombier 		dprintf( ("setting field %d to %s\n", vp-fldtab, s) );
300*3e12c5d1SDavid du Colombier 	} else if (vp->tval & REC) {
301*3e12c5d1SDavid du Colombier 		donefld = 0;	/* mark $1... invalid */
302*3e12c5d1SDavid du Colombier 		donerec = 1;
303*3e12c5d1SDavid du Colombier 	}
304*3e12c5d1SDavid du Colombier 	vp->tval &= ~NUM;
305*3e12c5d1SDavid du Colombier 	vp->tval |= STR;
306*3e12c5d1SDavid du Colombier 	if (freeable(vp))
307*3e12c5d1SDavid du Colombier 		xfree(vp->sval);
308*3e12c5d1SDavid du Colombier 	vp->tval &= ~DONTFREE;
309*3e12c5d1SDavid du Colombier 	dprintf( ("setsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
310*3e12c5d1SDavid du Colombier 	return(vp->sval = tostring(s));
311*3e12c5d1SDavid du Colombier }
312*3e12c5d1SDavid du Colombier 
313*3e12c5d1SDavid du Colombier Awkfloat r_getfval(Cell *vp)
314*3e12c5d1SDavid du Colombier {
315*3e12c5d1SDavid du Colombier 	/* if (vp->tval & ARR)
316*3e12c5d1SDavid du Colombier 		ERROR "illegal reference to array %s", vp->nval FATAL;
317*3e12c5d1SDavid du Colombier 		return 0.0; */
318*3e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
319*3e12c5d1SDavid du Colombier 		funnyvar(vp, "read value of");
320*3e12c5d1SDavid du Colombier 	if ((vp->tval & FLD) && donefld == 0)
321*3e12c5d1SDavid du Colombier 		fldbld();
322*3e12c5d1SDavid du Colombier 	else if ((vp->tval & REC) && donerec == 0)
323*3e12c5d1SDavid du Colombier 		recbld();
324*3e12c5d1SDavid du Colombier 	if (!isnum(vp)) {	/* not a number */
325*3e12c5d1SDavid du Colombier 		vp->fval = atof(vp->sval);	/* best guess */
326*3e12c5d1SDavid du Colombier 		if (isnumber(vp->sval) && !(vp->tval&CON))
327*3e12c5d1SDavid du Colombier 			vp->tval |= NUM;	/* make NUM only sparingly */
328*3e12c5d1SDavid du Colombier 	}
329*3e12c5d1SDavid du Colombier 	dprintf( ("getfval %o: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
330*3e12c5d1SDavid du Colombier 	return(vp->fval);
331*3e12c5d1SDavid du Colombier }
332*3e12c5d1SDavid du Colombier 
333*3e12c5d1SDavid du Colombier uchar *r_getsval(Cell *vp)
334*3e12c5d1SDavid du Colombier {
335*3e12c5d1SDavid du Colombier 	uchar s[100];
336*3e12c5d1SDavid du Colombier 	double dtemp;
337*3e12c5d1SDavid du Colombier 
338*3e12c5d1SDavid du Colombier 	/* if (vp->tval & ARR)
339*3e12c5d1SDavid du Colombier 		ERROR "illegal reference to array %s", vp->nval FATAL;
340*3e12c5d1SDavid du Colombier 		return ""; */
341*3e12c5d1SDavid du Colombier 	if ((vp->tval & (NUM | STR)) == 0)
342*3e12c5d1SDavid du Colombier 		funnyvar(vp, "read value of");
343*3e12c5d1SDavid du Colombier 	if ((vp->tval & FLD) && donefld == 0)
344*3e12c5d1SDavid du Colombier 		fldbld();
345*3e12c5d1SDavid du Colombier 	else if ((vp->tval & REC) && donerec == 0)
346*3e12c5d1SDavid du Colombier 		recbld();
347*3e12c5d1SDavid du Colombier 	if ((vp->tval & STR) == 0) {
348*3e12c5d1SDavid du Colombier 		if (!(vp->tval&DONTFREE))
349*3e12c5d1SDavid du Colombier 			xfree(vp->sval);
350*3e12c5d1SDavid du Colombier 		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
351*3e12c5d1SDavid du Colombier 			sprintf((char *)s, "%.20g", vp->fval);
352*3e12c5d1SDavid du Colombier 		else
353*3e12c5d1SDavid du Colombier 			sprintf((char *)s, (char *)*OFMT, vp->fval);
354*3e12c5d1SDavid du Colombier 		vp->sval = tostring(s);
355*3e12c5d1SDavid du Colombier 		vp->tval &= ~DONTFREE;
356*3e12c5d1SDavid du Colombier 		vp->tval |= STR;
357*3e12c5d1SDavid du Colombier 	}
358*3e12c5d1SDavid du Colombier 	dprintf( ("getsval %o: %s = \"%s\", t=%o\n", vp, vp->nval, vp->sval, vp->tval) );
359*3e12c5d1SDavid du Colombier 	return(vp->sval);
360*3e12c5d1SDavid du Colombier }
361*3e12c5d1SDavid du Colombier 
362*3e12c5d1SDavid du Colombier uchar *tostring(uchar *s)
363*3e12c5d1SDavid du Colombier {
364*3e12c5d1SDavid du Colombier 	register uchar *p;
365*3e12c5d1SDavid du Colombier 
366*3e12c5d1SDavid du Colombier 	p = (uchar *) malloc(strlen((char *) s)+1);
367*3e12c5d1SDavid du Colombier 	if (p == NULL)
368*3e12c5d1SDavid du Colombier 		ERROR "out of space in tostring on %s", s FATAL;
369*3e12c5d1SDavid du Colombier 	strcpy((char *) p, (char *) s);
370*3e12c5d1SDavid du Colombier 	return(p);
371*3e12c5d1SDavid du Colombier }
372*3e12c5d1SDavid du Colombier 
373*3e12c5d1SDavid du Colombier uchar *qstring(uchar *s, int delim)	/* collect string up to delim */
374*3e12c5d1SDavid du Colombier {
375*3e12c5d1SDavid du Colombier 	uchar *q;
376*3e12c5d1SDavid du Colombier 	int c, n;
377*3e12c5d1SDavid du Colombier 
378*3e12c5d1SDavid du Colombier 	for (q = cbuf; (c = *s) != delim; s++) {
379*3e12c5d1SDavid du Colombier 		if (q >= cbuf + CBUFLEN - 1)
380*3e12c5d1SDavid du Colombier 			ERROR "string %.10s... too long", cbuf SYNTAX;
381*3e12c5d1SDavid du Colombier 		else if (c == '\n')
382*3e12c5d1SDavid du Colombier 			ERROR "newline in string %.10s...", cbuf SYNTAX;
383*3e12c5d1SDavid du Colombier 		else if (c != '\\')
384*3e12c5d1SDavid du Colombier 			*q++ = c;
385*3e12c5d1SDavid du Colombier 		else	/* \something */
386*3e12c5d1SDavid du Colombier 			switch (c = *++s) {
387*3e12c5d1SDavid du Colombier 			case '\\':	*q++ = '\\'; break;
388*3e12c5d1SDavid du Colombier 			case 'n':	*q++ = '\n'; break;
389*3e12c5d1SDavid du Colombier 			case 't':	*q++ = '\t'; break;
390*3e12c5d1SDavid du Colombier 			case 'b':	*q++ = '\b'; break;
391*3e12c5d1SDavid du Colombier 			case 'f':	*q++ = '\f'; break;
392*3e12c5d1SDavid du Colombier 			case 'r':	*q++ = '\r'; break;
393*3e12c5d1SDavid du Colombier 			default:
394*3e12c5d1SDavid du Colombier 				if (!isdigit(c)) {
395*3e12c5d1SDavid du Colombier 					*q++ = c;
396*3e12c5d1SDavid du Colombier 					break;
397*3e12c5d1SDavid du Colombier 				}
398*3e12c5d1SDavid du Colombier 				n = c - '0';
399*3e12c5d1SDavid du Colombier 				if (isdigit(s[1])) {
400*3e12c5d1SDavid du Colombier 					n = 8 * n + *++s - '0';
401*3e12c5d1SDavid du Colombier 					if (isdigit(s[1]))
402*3e12c5d1SDavid du Colombier 						n = 8 * n + *++s - '0';
403*3e12c5d1SDavid du Colombier 				}
404*3e12c5d1SDavid du Colombier 				*q++ = n;
405*3e12c5d1SDavid du Colombier 				break;
406*3e12c5d1SDavid du Colombier 			}
407*3e12c5d1SDavid du Colombier 	}
408*3e12c5d1SDavid du Colombier 	*q = '\0';
409*3e12c5d1SDavid du Colombier 	return cbuf;
410*3e12c5d1SDavid du Colombier }
411