xref: /illumos-gate/usr/src/cmd/oawk/tran.c (revision 7c478bd9)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
23*7c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
24*7c478bd9Sstevel@tonic-gate 
25*7c478bd9Sstevel@tonic-gate 
26*7c478bd9Sstevel@tonic-gate /*
27*7c478bd9Sstevel@tonic-gate  * Copyright 2003 Sun Microsystems, Inc.  All rights reserved.
28*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
29*7c478bd9Sstevel@tonic-gate  */
30*7c478bd9Sstevel@tonic-gate 
31*7c478bd9Sstevel@tonic-gate #ident	"%Z%%M%	%I%	%E% SMI"
32*7c478bd9Sstevel@tonic-gate 
33*7c478bd9Sstevel@tonic-gate #include "stdio.h"
34*7c478bd9Sstevel@tonic-gate #include "awk.def"
35*7c478bd9Sstevel@tonic-gate #include "awk.h"
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate CELL *symtab[MAXSYM];	/* symbol table pointers */
38*7c478bd9Sstevel@tonic-gate 
39*7c478bd9Sstevel@tonic-gate 
40*7c478bd9Sstevel@tonic-gate wchar_t	**FS;	/* initial field sep */
41*7c478bd9Sstevel@tonic-gate wchar_t	**RS;	/* initial record sep */
42*7c478bd9Sstevel@tonic-gate wchar_t	**OFS;	/* output field sep */
43*7c478bd9Sstevel@tonic-gate wchar_t	**ORS;	/* output record sep */
44*7c478bd9Sstevel@tonic-gate wchar_t	**OFMT;	/* output format for numbers */
45*7c478bd9Sstevel@tonic-gate awkfloat *NF;	/* number of fields in current record */
46*7c478bd9Sstevel@tonic-gate awkfloat *NR;	/* number of current record */
47*7c478bd9Sstevel@tonic-gate wchar_t	**FILENAME;	/* current filename argument */
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate 
50*7c478bd9Sstevel@tonic-gate CELL	*recloc;	/* location of record */
51*7c478bd9Sstevel@tonic-gate CELL	*nrloc;		/* NR */
52*7c478bd9Sstevel@tonic-gate CELL	*nfloc;		/* NF */
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate syminit()
56*7c478bd9Sstevel@tonic-gate {
57*7c478bd9Sstevel@tonic-gate 	static wchar_t L_0[] = L"0";
58*7c478bd9Sstevel@tonic-gate 	static wchar_t L_zeronull[] = L"$zero&null";
59*7c478bd9Sstevel@tonic-gate 	static wchar_t L_record[] = L"$record";
60*7c478bd9Sstevel@tonic-gate 	static wchar_t L_FS[] = L"FS";
61*7c478bd9Sstevel@tonic-gate 	static wchar_t L_OFS[] = L"OFS";
62*7c478bd9Sstevel@tonic-gate 	static wchar_t L_ORS[] = L"ORS";
63*7c478bd9Sstevel@tonic-gate 	static wchar_t L_RS[] = L"RS";
64*7c478bd9Sstevel@tonic-gate 	static wchar_t L_OFMT[] = L"OFMT";
65*7c478bd9Sstevel@tonic-gate 	static wchar_t L_space[] = L" ";
66*7c478bd9Sstevel@tonic-gate 	static wchar_t L_newline[] = L"\n";
67*7c478bd9Sstevel@tonic-gate 	static wchar_t L_dot6g[] = L"%.6g";
68*7c478bd9Sstevel@tonic-gate 	static wchar_t L_FILENAME[] = L"FILENAME";
69*7c478bd9Sstevel@tonic-gate 	static wchar_t L_NF[] = L"NF";
70*7c478bd9Sstevel@tonic-gate 	static wchar_t L_NR[] = L"NR";
71*7c478bd9Sstevel@tonic-gate 
72*7c478bd9Sstevel@tonic-gate 
73*7c478bd9Sstevel@tonic-gate 	setsymtab(L_0, tostring(L_0), 0.0, NUM|STR|CON|FLD, symtab);
74*7c478bd9Sstevel@tonic-gate 	/* this one is used for if (x)... tests: */
75*7c478bd9Sstevel@tonic-gate 	setsymtab(L_zeronull, tostring(L_NULL), 0.0, NUM|STR|CON|FLD, symtab);
76*7c478bd9Sstevel@tonic-gate 	recloc = setsymtab(L_record, record, 0.0, STR|FLD, symtab);
77*7c478bd9Sstevel@tonic-gate 	dprintf("recloc %o lookup %o\n",
78*7c478bd9Sstevel@tonic-gate 		recloc, lookup(L_record, symtab, 0), NULL);
79*7c478bd9Sstevel@tonic-gate 	FS = &setsymtab(L_FS, tostring(L_space), 0.0, STR|FLD, symtab)->sval;
80*7c478bd9Sstevel@tonic-gate 	RS = &setsymtab(L_RS, tostring(L_newline), 0.0, STR|FLD, symtab)->sval;
81*7c478bd9Sstevel@tonic-gate 	OFS = &setsymtab(L_OFS, tostring(L_space), 0.0, STR|FLD, symtab)->sval;
82*7c478bd9Sstevel@tonic-gate 	ORS = &setsymtab(L_ORS, tostring(L_newline), 0.0, STR|FLD,
83*7c478bd9Sstevel@tonic-gate 		symtab)->sval;
84*7c478bd9Sstevel@tonic-gate 	OFMT = &setsymtab(L_OFMT, tostring(L_dot6g), 0.0, STR|FLD,
85*7c478bd9Sstevel@tonic-gate 		symtab)->sval;
86*7c478bd9Sstevel@tonic-gate 	FILENAME = &setsymtab(L_FILENAME, NULL, 0.0, STR|FLD, symtab)->sval;
87*7c478bd9Sstevel@tonic-gate 	nfloc = setsymtab(L_NF, NULL, 0.0, NUM, symtab);
88*7c478bd9Sstevel@tonic-gate 	NF = &nfloc->fval;
89*7c478bd9Sstevel@tonic-gate 	nrloc = setsymtab(L_NR, NULL, 0.0, NUM, symtab);
90*7c478bd9Sstevel@tonic-gate 	NR = &nrloc->fval;
91*7c478bd9Sstevel@tonic-gate }
92*7c478bd9Sstevel@tonic-gate 
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate CELL **makesymtab()
95*7c478bd9Sstevel@tonic-gate {
96*7c478bd9Sstevel@tonic-gate 	int i;
97*7c478bd9Sstevel@tonic-gate 	CELL **cp;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate 	cp = (CELL **) malloc(MAXSYM * sizeof (CELL *));
101*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
102*7c478bd9Sstevel@tonic-gate 		error(FATAL, "out of space in makesymtab");
103*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXSYM; i++)
104*7c478bd9Sstevel@tonic-gate 		cp[i] = 0;
105*7c478bd9Sstevel@tonic-gate 	return (cp);
106*7c478bd9Sstevel@tonic-gate }
107*7c478bd9Sstevel@tonic-gate 
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate freesymtab(ap)	/* free symbol table */
110*7c478bd9Sstevel@tonic-gate CELL *ap;
111*7c478bd9Sstevel@tonic-gate {
112*7c478bd9Sstevel@tonic-gate 	CELL *cp, **tp, *next;
113*7c478bd9Sstevel@tonic-gate 	int i;
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	if (!(ap->tval & ARR))
117*7c478bd9Sstevel@tonic-gate 		return;
118*7c478bd9Sstevel@tonic-gate 	tp = (CELL **) ap->sval;
119*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAXSYM; i++) {
120*7c478bd9Sstevel@tonic-gate 		for (cp = tp[i]; cp != NULL; cp = next) {
121*7c478bd9Sstevel@tonic-gate 			next = cp->nextval;
122*7c478bd9Sstevel@tonic-gate 			xfree(cp->nval);
123*7c478bd9Sstevel@tonic-gate 			xfree(cp->sval);
124*7c478bd9Sstevel@tonic-gate 			free(cp);
125*7c478bd9Sstevel@tonic-gate 		}
126*7c478bd9Sstevel@tonic-gate 	}
127*7c478bd9Sstevel@tonic-gate 	xfree(tp);
128*7c478bd9Sstevel@tonic-gate }
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate CELL *setsymtab(n, s, f, t, tab)
132*7c478bd9Sstevel@tonic-gate wchar_t *n, *s;
133*7c478bd9Sstevel@tonic-gate awkfloat f;
134*7c478bd9Sstevel@tonic-gate unsigned t;
135*7c478bd9Sstevel@tonic-gate CELL **tab;
136*7c478bd9Sstevel@tonic-gate {
137*7c478bd9Sstevel@tonic-gate 	register h;
138*7c478bd9Sstevel@tonic-gate 	register CELL *p;
139*7c478bd9Sstevel@tonic-gate 	CELL *lookup();
140*7c478bd9Sstevel@tonic-gate 
141*7c478bd9Sstevel@tonic-gate 
142*7c478bd9Sstevel@tonic-gate 	if (n != NULL && (p = lookup(n, tab, 0)) != NULL) {
143*7c478bd9Sstevel@tonic-gate 		xfree(s);
144*7c478bd9Sstevel@tonic-gate 		dprintf("setsymtab found %o: %ws\n", p, p->nval, NULL);
145*7c478bd9Sstevel@tonic-gate 		dprintf(" %ws %g %o\n", p->sval, p->fval, p->tval);
146*7c478bd9Sstevel@tonic-gate 		return (p);
147*7c478bd9Sstevel@tonic-gate 	}
148*7c478bd9Sstevel@tonic-gate 	p = (CELL *) malloc(sizeof (CELL));
149*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
150*7c478bd9Sstevel@tonic-gate 		error(FATAL, "symbol table overflow at %ws", n);
151*7c478bd9Sstevel@tonic-gate 	p->nval = tostring(n);
152*7c478bd9Sstevel@tonic-gate 	p->sval = s;
153*7c478bd9Sstevel@tonic-gate 	p->fval = f;
154*7c478bd9Sstevel@tonic-gate 	p->tval = t;
155*7c478bd9Sstevel@tonic-gate 	h = hash(n);
156*7c478bd9Sstevel@tonic-gate 	p->nextval = tab[h];
157*7c478bd9Sstevel@tonic-gate 	tab[h] = p;
158*7c478bd9Sstevel@tonic-gate 	dprintf("setsymtab set %o: %ws\n", p, p->nval, NULL);
159*7c478bd9Sstevel@tonic-gate 	dprintf(" %ws %g %o\n", p->sval, p->fval, p->tval);
160*7c478bd9Sstevel@tonic-gate 	return (p);
161*7c478bd9Sstevel@tonic-gate }
162*7c478bd9Sstevel@tonic-gate 
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate hash(s)	/* form hash value for string s */
165*7c478bd9Sstevel@tonic-gate register wchar_t *s;
166*7c478bd9Sstevel@tonic-gate {
167*7c478bd9Sstevel@tonic-gate 	register unsigned hashval;
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 
170*7c478bd9Sstevel@tonic-gate 	for (hashval = 0; *s != '\0'; /* dummy */)
171*7c478bd9Sstevel@tonic-gate 		hashval += *s++;
172*7c478bd9Sstevel@tonic-gate 	return (hashval % MAXSYM);
173*7c478bd9Sstevel@tonic-gate }
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate CELL *lookup(s, tab, flag)	/* look for s in tab, flag must match */
177*7c478bd9Sstevel@tonic-gate register wchar_t *s;
178*7c478bd9Sstevel@tonic-gate CELL **tab;
179*7c478bd9Sstevel@tonic-gate {
180*7c478bd9Sstevel@tonic-gate 	register CELL *p;
181*7c478bd9Sstevel@tonic-gate 
182*7c478bd9Sstevel@tonic-gate 
183*7c478bd9Sstevel@tonic-gate 	for (p = tab[hash(s)]; p != NULL; p = p->nextval)
184*7c478bd9Sstevel@tonic-gate 		if (wscmp(s, p->nval) == 0 &&
185*7c478bd9Sstevel@tonic-gate 			(flag == 0 || flag == p->tval))
186*7c478bd9Sstevel@tonic-gate 			return (p);	/* found it */
187*7c478bd9Sstevel@tonic-gate 	return (NULL);	/* not found */
188*7c478bd9Sstevel@tonic-gate }
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 
191*7c478bd9Sstevel@tonic-gate awkfloat setfval(vp, f)
192*7c478bd9Sstevel@tonic-gate register CELL *vp;
193*7c478bd9Sstevel@tonic-gate awkfloat f;
194*7c478bd9Sstevel@tonic-gate {
195*7c478bd9Sstevel@tonic-gate 	dprintf("setfval: %o %g\n", vp, f, NULL);
196*7c478bd9Sstevel@tonic-gate /* imb */
197*7c478bd9Sstevel@tonic-gate 	if (vp->tval & ARR)
198*7c478bd9Sstevel@tonic-gate 		error(FATAL, "illegal reference to array %s", vp->nval);
199*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
200*7c478bd9Sstevel@tonic-gate 		error(FATAL, "funny variable %o: %ws %ws %g %o", vp, vp->nval,
201*7c478bd9Sstevel@tonic-gate 			vp->sval, vp->fval, vp->tval);
202*7c478bd9Sstevel@tonic-gate /* imb */
203*7c478bd9Sstevel@tonic-gate 	if (vp == recloc)
204*7c478bd9Sstevel@tonic-gate 		error(FATAL, "can't set $0");
205*7c478bd9Sstevel@tonic-gate 	vp->tval &= ~STR;	/* mark string invalid */
206*7c478bd9Sstevel@tonic-gate 	vp->tval |= NUM;	/* mark number ok */
207*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & FLD) && vp->nval == 0) {
208*7c478bd9Sstevel@tonic-gate 		/*
209*7c478bd9Sstevel@tonic-gate 		 * FLD really means that the string value was not
210*7c478bd9Sstevel@tonic-gate 		 * "malloc"ed and should not be freed.  All fields
211*7c478bd9Sstevel@tonic-gate 		 * have this property, but not all cells with this
212*7c478bd9Sstevel@tonic-gate 		 * property are fields.  However, all cells with
213*7c478bd9Sstevel@tonic-gate 		 * this property and with a NULL "nval" are fields.
214*7c478bd9Sstevel@tonic-gate 		 * If we are setting the value of a field, indicate
215*7c478bd9Sstevel@tonic-gate 		 * that the value of the record has to be recomputed,
216*7c478bd9Sstevel@tonic-gate 		 * and if it's a higher field than the last one we
217*7c478bd9Sstevel@tonic-gate 		 * assigned to, remember it for when we clear the
218*7c478bd9Sstevel@tonic-gate 		 * fields out for the next record.
219*7c478bd9Sstevel@tonic-gate 		 */
220*7c478bd9Sstevel@tonic-gate 		donerec = 0;
221*7c478bd9Sstevel@tonic-gate 		if (vp > maxmfld)
222*7c478bd9Sstevel@tonic-gate 			maxmfld = vp;
223*7c478bd9Sstevel@tonic-gate 	}
224*7c478bd9Sstevel@tonic-gate 	return (vp->fval = f);
225*7c478bd9Sstevel@tonic-gate }
226*7c478bd9Sstevel@tonic-gate 
227*7c478bd9Sstevel@tonic-gate 
228*7c478bd9Sstevel@tonic-gate wchar_t *setsval(vp, s)
229*7c478bd9Sstevel@tonic-gate register CELL *vp;
230*7c478bd9Sstevel@tonic-gate wchar_t *s;
231*7c478bd9Sstevel@tonic-gate {
232*7c478bd9Sstevel@tonic-gate 	dprintf("setsval: %o %ws\n", vp, s, NULL);
233*7c478bd9Sstevel@tonic-gate 	if (vp->tval & ARR)
234*7c478bd9Sstevel@tonic-gate 		error(FATAL, "illegal reference to array %ws", vp->nval);
235*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
236*7c478bd9Sstevel@tonic-gate 		error(FATAL, "funny variable %o: %ws %ws %g %o", vp, vp->nval,
237*7c478bd9Sstevel@tonic-gate 			vp->sval, vp->fval, vp->tval);
238*7c478bd9Sstevel@tonic-gate 	if (vp == recloc)
239*7c478bd9Sstevel@tonic-gate 		error(FATAL, "can't set $0");
240*7c478bd9Sstevel@tonic-gate 	vp->tval &= ~NUM;
241*7c478bd9Sstevel@tonic-gate 	vp->tval |= STR;
242*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & FLD) && vp->nval == 0) {
243*7c478bd9Sstevel@tonic-gate 		/*
244*7c478bd9Sstevel@tonic-gate 		 * See comment in "setfval".
245*7c478bd9Sstevel@tonic-gate 		 */
246*7c478bd9Sstevel@tonic-gate 		donerec = 0;
247*7c478bd9Sstevel@tonic-gate 		if (vp > maxmfld)
248*7c478bd9Sstevel@tonic-gate 			maxmfld = vp;
249*7c478bd9Sstevel@tonic-gate 	}
250*7c478bd9Sstevel@tonic-gate 	if (!(vp->tval&FLD))
251*7c478bd9Sstevel@tonic-gate 		xfree(vp->sval);
252*7c478bd9Sstevel@tonic-gate 	vp->tval &= ~FLD;
253*7c478bd9Sstevel@tonic-gate 	return (vp->sval = tostring(s));
254*7c478bd9Sstevel@tonic-gate }
255*7c478bd9Sstevel@tonic-gate 
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate awkfloat getfval(vp)
258*7c478bd9Sstevel@tonic-gate register CELL *vp;
259*7c478bd9Sstevel@tonic-gate {
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate 	if (vp->sval == record && donerec == 0)
263*7c478bd9Sstevel@tonic-gate 		recbld();
264*7c478bd9Sstevel@tonic-gate 	dprintf("getfval: %o", vp, NULL, NULL);
265*7c478bd9Sstevel@tonic-gate 	if (vp->tval & ARR)
266*7c478bd9Sstevel@tonic-gate 		error(FATAL, "illegal reference to array %ws", vp->nval);
267*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
268*7c478bd9Sstevel@tonic-gate 		error(FATAL, "funny variable %o: %ws %ws %g %o", vp, vp->nval,
269*7c478bd9Sstevel@tonic-gate 			vp->sval, vp->fval, vp->tval);
270*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & NUM) == 0) {
271*7c478bd9Sstevel@tonic-gate 		/* the problem is to make non-numeric things */
272*7c478bd9Sstevel@tonic-gate 		/* have unlikely numeric variables, so that */
273*7c478bd9Sstevel@tonic-gate 		/* $1 == $2 comparisons sort of make sense when */
274*7c478bd9Sstevel@tonic-gate 		/* one or the other is numeric */
275*7c478bd9Sstevel@tonic-gate 		if (isanumber(vp->sval)) {
276*7c478bd9Sstevel@tonic-gate 			vp->fval = watof(vp->sval);
277*7c478bd9Sstevel@tonic-gate 			if (!(vp->tval & CON))
278*7c478bd9Sstevel@tonic-gate 				/* don't change type of a constant */
279*7c478bd9Sstevel@tonic-gate 				vp->tval |= NUM;
280*7c478bd9Sstevel@tonic-gate 		}
281*7c478bd9Sstevel@tonic-gate 		else
282*7c478bd9Sstevel@tonic-gate 			vp->fval = 0.0;	/* not a very good idea */
283*7c478bd9Sstevel@tonic-gate 	}
284*7c478bd9Sstevel@tonic-gate 	dprintf("  %g\n", vp->fval, NULL, NULL);
285*7c478bd9Sstevel@tonic-gate 	return (vp->fval);
286*7c478bd9Sstevel@tonic-gate }
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate 
289*7c478bd9Sstevel@tonic-gate wchar_t *getsval(vp)
290*7c478bd9Sstevel@tonic-gate register CELL *vp;
291*7c478bd9Sstevel@tonic-gate {
292*7c478bd9Sstevel@tonic-gate 	char s[100];
293*7c478bd9Sstevel@tonic-gate 	wchar_t ws[100];
294*7c478bd9Sstevel@tonic-gate 
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	if (vp->sval == record && donerec == 0)
297*7c478bd9Sstevel@tonic-gate 		recbld();
298*7c478bd9Sstevel@tonic-gate 	dprintf("getsval: %o", vp, NULL, NULL);
299*7c478bd9Sstevel@tonic-gate 	if (vp->tval & ARR)
300*7c478bd9Sstevel@tonic-gate 		error(FATAL, "illegal reference to array %ws", vp->nval);
301*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & (NUM | STR)) == 0)
302*7c478bd9Sstevel@tonic-gate 		error(FATAL, "funny variable %o: %ws %ws %g %o", vp, vp->nval,
303*7c478bd9Sstevel@tonic-gate 			vp->sval, vp->fval, vp->tval);
304*7c478bd9Sstevel@tonic-gate 	if ((vp->tval & STR) == 0) {
305*7c478bd9Sstevel@tonic-gate 		if (!(vp->tval&FLD))
306*7c478bd9Sstevel@tonic-gate 			xfree(vp->sval);
307*7c478bd9Sstevel@tonic-gate 		if ((long long)vp->fval==vp->fval)
308*7c478bd9Sstevel@tonic-gate 			sprintf(s, "%.20g", vp->fval);
309*7c478bd9Sstevel@tonic-gate 		else
310*7c478bd9Sstevel@tonic-gate 			sprintf(s, toeuccode(*OFMT), vp->fval);
311*7c478bd9Sstevel@tonic-gate 		mbstowcs(ws, s, sizeof (ws) / sizeof (wchar_t));
312*7c478bd9Sstevel@tonic-gate 		vp->sval = tostring(ws);
313*7c478bd9Sstevel@tonic-gate 		vp->tval &= ~FLD;
314*7c478bd9Sstevel@tonic-gate 		vp->tval |= STR;
315*7c478bd9Sstevel@tonic-gate 	}
316*7c478bd9Sstevel@tonic-gate 	dprintf("  %ws\n", vp->sval, NULL, NULL);
317*7c478bd9Sstevel@tonic-gate 	return (vp->sval);
318*7c478bd9Sstevel@tonic-gate }
319*7c478bd9Sstevel@tonic-gate 
320*7c478bd9Sstevel@tonic-gate 
321*7c478bd9Sstevel@tonic-gate wchar_t *tostring(s)
322*7c478bd9Sstevel@tonic-gate register wchar_t *s;
323*7c478bd9Sstevel@tonic-gate {
324*7c478bd9Sstevel@tonic-gate 	register wchar_t *p;
325*7c478bd9Sstevel@tonic-gate 
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 	p = (wchar_t *) malloc((wslen(s)+1)*sizeof (wchar_t));
328*7c478bd9Sstevel@tonic-gate 	if (p == NULL)
329*7c478bd9Sstevel@tonic-gate 		error(FATAL, "out of space in tostring on %ws", s);
330*7c478bd9Sstevel@tonic-gate 	wscpy(p, s);
331*7c478bd9Sstevel@tonic-gate 	return (p);
332*7c478bd9Sstevel@tonic-gate }
333*7c478bd9Sstevel@tonic-gate 
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate #ifndef yfree
336*7c478bd9Sstevel@tonic-gate yfree(a) char *a;
337*7c478bd9Sstevel@tonic-gate {
338*7c478bd9Sstevel@tonic-gate 	printf("%o\n", a);
339*7c478bd9Sstevel@tonic-gate 	free(a);
340*7c478bd9Sstevel@tonic-gate }
341*7c478bd9Sstevel@tonic-gate #endif
342