Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/****************************************************************
2
Copyright (C) Lucent Technologies 1997
3
All Rights Reserved
4
 
5
Permission to use, copy, modify, and distribute this software and
6
its documentation for any purpose and without fee is hereby
7
granted, provided that the above copyright notice appear in all
8
copies and that both that the copyright notice and this
9
permission notice and warranty disclaimer appear in supporting
10
documentation, and that the name Lucent Technologies or any of
11
its entities not be used in advertising or publicity pertaining
12
to distribution of the software without specific, written prior
13
permission.
14
 
15
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
16
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
17
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
18
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
20
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
22
THIS SOFTWARE.
23
****************************************************************/
24
 
25
#define	DEBUG
26
#include <stdio.h>
27
#include <math.h>
28
#include <ctype.h>
29
#include <string.h>
30
#include <stdlib.h>
31
#include "awk.h"
32
#include "y.tab.h"
33
 
34
#define	FULLTAB	2	/* rehash when table gets this x full */
35
#define	GROWTAB 4	/* grow table by this factor */
36
 
37
Array	*symtab;	/* main symbol table */
38
 
39
char	**FS;		/* initial field sep */
40
char	**RS;		/* initial record sep */
41
char	**OFS;		/* output field sep */
42
char	**ORS;		/* output record sep */
43
char	**OFMT;		/* output format for numbers */
44
char	**CONVFMT;	/* format for conversions in getsval */
45
Awkfloat *NF;		/* number of fields in current record */
46
Awkfloat *NR;		/* number of current record */
47
Awkfloat *FNR;		/* number of current record in current file */
48
char	**FILENAME;	/* current filename argument */
49
Awkfloat *ARGC;		/* number of arguments from command line */
50
char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
51
Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
52
Awkfloat *RLENGTH;	/* length of same */
53
 
54
Cell	*nrloc;		/* NR */
55
Cell	*nfloc;		/* NF */
56
Cell	*fnrloc;	/* FNR */
57
Array	*ARGVtab;	/* symbol table containing ARGV[...] */
58
Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
59
Cell	*rstartloc;	/* RSTART */
60
Cell	*rlengthloc;	/* RLENGTH */
61
Cell	*symtabloc;	/* SYMTAB */
62
 
63
Cell	*nullloc;	/* a guaranteed empty cell */
64
Node	*nullnode;	/* zero&null, converted into a node for comparisons */
65
Cell	*literal0;
66
 
67
extern Cell **fldtab;
68
 
69
void syminit(void)	/* initialize symbol table with builtin vars */
70
{
71
	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
72
	/* this is used for if(x)... tests: */
73
	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
74
	nullnode = celltonode(nullloc, CCON);
75
 
76
	FS = &setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab)->sval;
77
	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
78
	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
79
	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
80
	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
81
	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
82
	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
83
	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
84
	NF = &nfloc->fval;
85
	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
86
	NR = &nrloc->fval;
87
	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
88
	FNR = &fnrloc->fval;
89
	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
90
	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
91
	RSTART = &rstartloc->fval;
92
	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
93
	RLENGTH = &rlengthloc->fval;
94
	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
95
	symtabloc->sval = (char *) symtab;
96
}
97
 
98
void arginit(int ac, char **av)	/* set up ARGV and ARGC */
99
{
100
	Cell *cp;
101
	int i;
102
	char temp[50];
103
 
104
	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
105
	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
106
	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
107
	cp->sval = (char *) ARGVtab;
108
	for (i = 0; i < ac; i++) {
109
		sprintf(temp, "%d", i);
110
		if (is_number(*av))
111
			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
112
		else
113
			setsymtab(temp, *av, 0.0, STR, ARGVtab);
114
		av++;
115
	}
116
}
117
 
118
void envinit(char **envp)	/* set up ENVIRON variable */
119
{
120
	Cell *cp;
121
	char *p;
122
 
123
	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
124
	ENVtab = makesymtab(NSYMTAB);
125
	cp->sval = (char *) ENVtab;
126
	for ( ; *envp; envp++) {
127
		if ((p = strchr(*envp, '=')) == NULL)
128
			continue;
129
		*p++ = 0;	/* split into two strings at = */
130
		if (is_number(p))
131
			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
132
		else
133
			setsymtab(*envp, p, 0.0, STR, ENVtab);
134
		p[-1] = '=';	/* restore in case env is passed down to a shell */
135
	}
136
}
137
 
138
Array *makesymtab(int n)	/* make a new symbol table */
139
{
140
	Array *ap;
141
	Cell **tp;
142
 
143
	ap = (Array *) malloc(sizeof(Array));
144
	tp = (Cell **) calloc(n, sizeof(Cell *));
145
	if (ap == NULL || tp == NULL)
146
		FATAL("out of space in makesymtab");
147
	ap->nelem = 0;
148
	ap->size = n;
149
	ap->tab = tp;
150
	return(ap);
151
}
152
 
153
void freesymtab(Cell *ap)	/* free a symbol table */
154
{
155
	Cell *cp, *temp;
156
	Array *tp;
157
	int i;
158
 
159
	if (!isarr(ap))
160
		return;
161
	tp = (Array *) ap->sval;
162
	if (tp == NULL)
163
		return;
164
	for (i = 0; i < tp->size; i++) {
165
		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
166
			xfree(cp->nval);
167
			if (freeable(cp))
168
				xfree(cp->sval);
169
			temp = cp->cnext;	/* avoids freeing then using */
170
			free(cp); 
171
		}
172
		tp->tab[i] = 0;
173
	}
174
	free(tp->tab);
175
	free(tp);
176
}
177
 
178
void freeelem(Cell *ap, char *s)	/* free elem s from ap (i.e., ap["s"] */
179
{
180
	Array *tp;
181
	Cell *p, *prev = NULL;
182
	int h;
183
 
184
	tp = (Array *) ap->sval;
185
	h = hash(s, tp->size);
186
	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
187
		if (strcmp(s, p->nval) == 0) {
188
			if (prev == NULL)	/* 1st one */
189
				tp->tab[h] = p->cnext;
190
			else			/* middle somewhere */
191
				prev->cnext = p->cnext;
192
			if (freeable(p))
193
				xfree(p->sval);
194
			free(p->nval);
195
			free(p);
196
			tp->nelem--;
197
			return;
198
		}
199
}
200
 
201
Cell *setsymtab(char *n, char *s, Awkfloat f, unsigned t, Array *tp)
202
{
203
	int h;
204
	Cell *p;
205
 
206
	if (n != NULL && (p = lookup(n, tp)) != NULL) {
207
		   dprintf( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
208
			p, p->nval, p->sval, p->fval, p->tval) );
209
		return(p);
210
	}
211
	p = (Cell *) malloc(sizeof(Cell));
212
	if (p == NULL)
213
		FATAL("out of space for symbol table at %s", n);
214
	p->nval = tostring(n);
215
	p->sval = s ? tostring(s) : tostring("");
216
	p->fval = f;
217
	p->tval = t;
218
	p->csub = CUNK;
219
	p->ctype = OCELL;
220
	tp->nelem++;
221
	if (tp->nelem > FULLTAB * tp->size)
222
		rehash(tp);
223
	h = hash(n, tp->size);
224
	p->cnext = tp->tab[h];
225
	tp->tab[h] = p;
226
	   dprintf( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
227
		p, p->nval, p->sval, p->fval, p->tval) );
228
	return(p);
229
}
230
 
231
int hash(char *s, int n)	/* form hash value for string s */
232
{
233
	unsigned hashval;
234
 
235
	for (hashval = 0; *s != '\0'; s++)
236
		hashval = (*s + 31 * hashval);
237
	return hashval % n;
238
}
239
 
240
void rehash(Array *tp)	/* rehash items in small table into big one */
241
{
242
	int i, nh, nsz;
243
	Cell *cp, *op, **np;
244
 
245
	nsz = GROWTAB * tp->size;
246
	np = (Cell **) calloc(nsz, sizeof(Cell *));
247
	if (np == NULL)		/* can't do it, but can keep running. */
248
		return;		/* someone else will run out later. */
249
	for (i = 0; i < tp->size; i++) {
250
		for (cp = tp->tab[i]; cp; cp = op) {
251
			op = cp->cnext;
252
			nh = hash(cp->nval, nsz);
253
			cp->cnext = np[nh];
254
			np[nh] = cp;
255
		}
256
	}
257
	free(tp->tab);
258
	tp->tab = np;
259
	tp->size = nsz;
260
}
261
 
262
Cell *lookup(char *s, Array *tp)	/* look for s in tp */
263
{
264
	Cell *p;
265
	int h;
266
 
267
	h = hash(s, tp->size);
268
	for (p = tp->tab[h]; p != NULL; p = p->cnext)
269
		if (strcmp(s, p->nval) == 0)
270
			return(p);	/* found it */
271
	return(NULL);			/* not found */
272
}
273
 
274
Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
275
{
276
	int fldno;
277
 
278
	if ((vp->tval & (NUM | STR)) == 0) 
279
		funnyvar(vp, "assign to");
280
	if (isfld(vp)) {
281
		donerec = 0;	/* mark $0 invalid */
282
		fldno = atoi(vp->nval);
283
		if (fldno > *NF)
284
			newfld(fldno);
285
		   dprintf( ("setting field %d to %g\n", fldno, f) );
286
	} else if (isrec(vp)) {
287
		donefld = 0;	/* mark $1... invalid */
288
		donerec = 1;
289
	}
290
	if (freeable(vp))
291
		xfree(vp->sval); /* free any previous string */
292
	vp->tval &= ~STR;	/* mark string invalid */
293
	vp->tval |= NUM;	/* mark number ok */
294
	   dprintf( ("setfval %p: %s = %g, t=%o\n", vp, vp->nval, f, vp->tval) );
295
	return vp->fval = f;
296
}
297
 
298
void funnyvar(Cell *vp, char *rw)
299
{
300
	if (isarr(vp))
301
		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
302
	if (vp->tval & FCN)
303
		FATAL("can't %s %s; it's a function.", rw, vp->nval);
304
	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
305
		vp, vp->nval, vp->sval, vp->fval, vp->tval);
306
}
307
 
308
char *setsval(Cell *vp, char *s)	/* set string val of a Cell */
309
{
310
	char *t;
311
	int fldno;
312
 
313
	   dprintf( ("starting setsval %p: %s = \"%s\", t=%o\n", vp, vp->nval, s, vp->tval) );
314
	if ((vp->tval & (NUM | STR)) == 0)
315
		funnyvar(vp, "assign to");
316
	if (isfld(vp)) {
317
		donerec = 0;	/* mark $0 invalid */
318
		fldno = atoi(vp->nval);
319
		if (fldno > *NF)
320
			newfld(fldno);
321
		   dprintf( ("setting field %d to %s (%p)\n", fldno, s, s) );
322
	} else if (isrec(vp)) {
323
		donefld = 0;	/* mark $1... invalid */
324
		donerec = 1;
325
	}
326
	t = tostring(s);	/* in case it's self-assign */
327
	vp->tval &= ~NUM;
328
	vp->tval |= STR;
329
	if (freeable(vp))
330
		xfree(vp->sval);
331
	vp->tval &= ~DONTFREE;
332
	   dprintf( ("setsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, t,t, vp->tval) );
333
	return(vp->sval = t);
334
}
335
 
336
Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
337
{
338
	if ((vp->tval & (NUM | STR)) == 0)
339
		funnyvar(vp, "read value of");
340
	if (isfld(vp) && donefld == 0)
341
		fldbld();
342
	else if (isrec(vp) && donerec == 0)
343
		recbld();
344
	if (!isnum(vp)) {	/* not a number */
345
		vp->fval = atof(vp->sval);	/* best guess */
346
		if (is_number(vp->sval) && !(vp->tval&CON))
347
			vp->tval |= NUM;	/* make NUM only sparingly */
348
	}
349
	   dprintf( ("getfval %p: %s = %g, t=%o\n", vp, vp->nval, vp->fval, vp->tval) );
350
	return(vp->fval);
351
}
352
 
353
char *getsval(Cell *vp)	/* get string val of a Cell */
354
{
355
	char s[100];	/* BUG: unchecked */
356
	double dtemp;
357
 
358
	if ((vp->tval & (NUM | STR)) == 0)
359
		funnyvar(vp, "read value of");
360
	if (isfld(vp) && donefld == 0)
361
		fldbld();
362
	else if (isrec(vp) && donerec == 0)
363
		recbld();
364
	if (isstr(vp) == 0) {
365
		if (freeable(vp))
366
			xfree(vp->sval);
367
		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
368
			sprintf(s, "%.30g", vp->fval);
369
		else
370
			sprintf(s, *CONVFMT, vp->fval);
371
		vp->sval = tostring(s);
372
		vp->tval &= ~DONTFREE;
373
		vp->tval |= STR;
374
	}
375
	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n", vp, vp->nval, vp->sval, vp->sval, vp->tval) );
376
	return(vp->sval);
377
}
378
 
379
char *tostring(char *s)	/* make a copy of string s */
380
{
381
	char *p;
382
 
383
	p = (char *) malloc(strlen(s)+1);
384
	if (p == NULL)
385
		FATAL("out of space in tostring on %s", s);
386
	strcpy(p, s);
387
	return(p);
388
}
389
 
390
char *qstring(char *s, int delim)	/* collect string up to next delim */
391
{
392
	char *os = s;
393
	int c, n;
394
	char *buf, *bp;
395
 
396
	if ((buf = (char *) malloc(strlen(s)+3)) == NULL)
397
		FATAL( "out of space in qstring(%s)", s);
398
	for (bp = buf; (c = *s) != delim; s++) {
399
		if (c == '\n')
400
			SYNTAX( "newline in string %.20s...", os );
401
		else if (c != '\\')
402
			*bp++ = c;
403
		else {	/* \something */
404
			c = *++s;
405
			if (c == 0) {	/* \ at end */
406
				*bp++ = '\\';
407
				break;	/* for loop */
408
			}	
409
			switch (c) {
410
			case '\\':	*bp++ = '\\'; break;
411
			case 'n':	*bp++ = '\n'; break;
412
			case 't':	*bp++ = '\t'; break;
413
			case 'b':	*bp++ = '\b'; break;
414
			case 'f':	*bp++ = '\f'; break;
415
			case 'r':	*bp++ = '\r'; break;
416
			default:
417
				if (!isdigit(c)) {
418
					*bp++ = c;
419
					break;
420
				}
421
				n = c - '0';
422
				if (isdigit(s[1])) {
423
					n = 8 * n + *++s - '0';
424
					if (isdigit(s[1]))
425
						n = 8 * n + *++s - '0';
426
				}
427
				*bp++ = n;
428
				break;
429
			}
430
		}
431
	}
432
	*bp++ = 0;
433
	return buf;
434
}