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