GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/tran.c Lines: 153 245 62.4 %
Date: 2017-11-13 Branches: 65 173 37.6 %

Line Branch Exec Source
1
/*	$OpenBSD: tran.c,v 1.16 2017/10/09 14:51:31 deraadt Exp $	*/
2
/****************************************************************
3
Copyright (C) Lucent Technologies 1997
4
All Rights Reserved
5
6
Permission to use, copy, modify, and distribute this software and
7
its documentation for any purpose and without fee is hereby
8
granted, provided that the above copyright notice appear in all
9
copies and that both that the copyright notice and this
10
permission notice and warranty disclaimer appear in supporting
11
documentation, and that the name Lucent Technologies or any of
12
its entities not be used in advertising or publicity pertaining
13
to distribution of the software without specific, written prior
14
permission.
15
16
LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17
INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
18
IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY
19
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
21
IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
23
THIS SOFTWARE.
24
****************************************************************/
25
26
#define	DEBUG
27
#include <stdio.h>
28
#include <math.h>
29
#include <ctype.h>
30
#include <string.h>
31
#include <stdlib.h>
32
#include "awk.h"
33
#include "ytab.h"
34
35
#define	FULLTAB	2	/* rehash when table gets this x full */
36
#define	GROWTAB 4	/* grow table by this factor */
37
38
Array	*symtab;	/* main symbol table */
39
40
char	**FS;		/* initial field sep */
41
char	**RS;		/* initial record sep */
42
char	**OFS;		/* output field sep */
43
char	**ORS;		/* output record sep */
44
char	**OFMT;		/* output format for numbers */
45
char	**CONVFMT;	/* format for conversions in getsval */
46
Awkfloat *NF;		/* number of fields in current record */
47
Awkfloat *NR;		/* number of current record */
48
Awkfloat *FNR;		/* number of current record in current file */
49
char	**FILENAME;	/* current filename argument */
50
Awkfloat *ARGC;		/* number of arguments from command line */
51
char	**SUBSEP;	/* subscript separator for a[i,j,k]; default \034 */
52
Awkfloat *RSTART;	/* start of re matched with ~; origin 1 (!) */
53
Awkfloat *RLENGTH;	/* length of same */
54
55
Cell	*fsloc;		/* FS */
56
Cell	*nrloc;		/* NR */
57
Cell	*nfloc;		/* NF */
58
Cell	*fnrloc;	/* FNR */
59
Array	*ARGVtab;	/* symbol table containing ARGV[...] */
60
Array	*ENVtab;	/* symbol table containing ENVIRON[...] */
61
Cell	*rstartloc;	/* RSTART */
62
Cell	*rlengthloc;	/* RLENGTH */
63
Cell	*symtabloc;	/* SYMTAB */
64
65
Cell	*nullloc;	/* a guaranteed empty cell */
66
Node	*nullnode;	/* zero&null, converted into a node for comparisons */
67
Cell	*literal0;
68
69
extern Cell **fldtab;
70
71
void syminit(void)	/* initialize symbol table with builtin vars */
72
{
73
974
	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
74
	/* this is used for if(x)... tests: */
75
487
	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
76
487
	nullnode = celltonode(nullloc, CCON);
77
78
487
	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
79
487
	FS = &fsloc->sval;
80
487
	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
81
487
	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
82
487
	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
83
487
	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84
487
	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
85
487
	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
86
487
	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
87
487
	NF = &nfloc->fval;
88
487
	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
89
487
	NR = &nrloc->fval;
90
487
	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
91
487
	FNR = &fnrloc->fval;
92
487
	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
93
487
	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
94
487
	RSTART = &rstartloc->fval;
95
487
	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
96
487
	RLENGTH = &rlengthloc->fval;
97
487
	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
98
487
	symtabloc->sval = (char *) symtab;
99
487
}
100
101
void arginit(int ac, char **av)	/* set up ARGV and ARGC */
102
{
103
	Cell *cp;
104
	int i;
105
974
	char temp[50];
106
107
487
	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
108
487
	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
109
487
	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
110
487
	cp->sval = (char *) ARGVtab;
111
2124
	for (i = 0; i < ac; i++) {
112
575
		snprintf(temp, sizeof temp, "%d", i);
113
575
		if (is_number(*av))
114
			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
115
		else
116
575
			setsymtab(temp, *av, 0.0, STR, ARGVtab);
117
575
		av++;
118
	}
119
487
}
120
121
void envinit(char **envp)	/* set up ENVIRON variable */
122
{
123
	Cell *cp;
124
	char *p;
125
126
974
	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
127
487
	ENVtab = makesymtab(NSYMTAB);
128
487
	cp->sval = (char *) ENVtab;
129
24660
	for ( ; *envp; envp++) {
130
11843
		if ((p = strchr(*envp, '=')) == NULL)
131
			continue;
132
11843
		if( p == *envp ) /* no left hand side name in env string */
133
			continue;
134
11843
		*p++ = 0;	/* split into two strings at = */
135
11843
		if (is_number(p))
136
326
			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
137
		else
138
11517
			setsymtab(*envp, p, 0.0, STR, ENVtab);
139
11843
		p[-1] = '=';	/* restore in case env is passed down to a shell */
140
11843
	}
141
487
}
142
143
Array *makesymtab(int n)	/* make a new symbol table */
144
{
145
	Array *ap;
146
	Cell **tp;
147
148
2942
	ap = (Array *) malloc(sizeof(Array));
149
1471
	tp = (Cell **) calloc(n, sizeof(Cell *));
150
1471
	if (ap == NULL || tp == NULL)
151
		FATAL("out of space in makesymtab");
152
1471
	ap->nelem = 0;
153
1471
	ap->size = n;
154
1471
	ap->tab = tp;
155
1471
	return(ap);
156
}
157
158
void freesymtab(Cell *ap)	/* free a symbol table */
159
{
160
	Cell *cp, *temp;
161
	Array *tp;
162
	int i;
163
164
	if (!isarr(ap))
165
		return;
166
	tp = (Array *) ap->sval;
167
	if (tp == NULL)
168
		return;
169
	for (i = 0; i < tp->size; i++) {
170
		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
171
			xfree(cp->nval);
172
			if (freeable(cp))
173
				xfree(cp->sval);
174
			temp = cp->cnext;	/* avoids freeing then using */
175
			free(cp);
176
			tp->nelem--;
177
		}
178
		tp->tab[i] = 0;
179
	}
180
	if (tp->nelem != 0)
181
		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
182
	free(tp->tab);
183
	free(tp);
184
}
185
186
void freeelem(Cell *ap, const char *s)	/* free elem s from ap (i.e., ap["s"] */
187
{
188
	Array *tp;
189
	Cell *p, *prev = NULL;
190
	int h;
191
192
	tp = (Array *) ap->sval;
193
	h = hash(s, tp->size);
194
	for (p = tp->tab[h]; p != NULL; prev = p, p = p->cnext)
195
		if (strcmp(s, p->nval) == 0) {
196
			if (prev == NULL)	/* 1st one */
197
				tp->tab[h] = p->cnext;
198
			else			/* middle somewhere */
199
				prev->cnext = p->cnext;
200
			if (freeable(p))
201
				xfree(p->sval);
202
			free(p->nval);
203
			free(p);
204
			tp->nelem--;
205
			return;
206
		}
207
}
208
209
Cell *setsymtab(const char *n, const char *s, Awkfloat f, unsigned t, Array *tp)
210
{
211
	int h;
212
	Cell *p;
213
214

93489
	if (n != NULL && (p = lookup(n, tp)) != NULL) {
215

6496
		   DPRINTF( ("setsymtab found %p: n=%s s=\"%s\" f=%g t=%o\n",
216
			(void*)p, NN(p->nval), NN(p->sval), p->fval, p->tval) );
217
6496
		return(p);
218
	}
219
24667
	p = (Cell *) malloc(sizeof(Cell));
220
24667
	if (p == NULL)
221
		FATAL("out of space for symbol table at %s", n);
222
24667
	p->nval = tostring(n);
223
24667
	p->sval = s ? tostring(s) : tostring("");
224
24667
	p->fval = f;
225
24667
	p->tval = t;
226
24667
	p->csub = CUNK;
227
24667
	p->ctype = OCELL;
228
24667
	tp->nelem++;
229
24667
	if (tp->nelem > FULLTAB * tp->size)
230
8
		rehash(tp);
231
24667
	h = hash(n, tp->size);
232
24667
	p->cnext = tp->tab[h];
233
24667
	tp->tab[h] = p;
234
24667
	   DPRINTF( ("setsymtab set %p: n=%s s=\"%s\" f=%g t=%o\n",
235
		(void*)p, p->nval, p->sval, p->fval, p->tval) );
236
24667
	return(p);
237
31163
}
238
239
int hash(const char *s, int n)	/* form hash value for string s */
240
{
241
	unsigned hashval;
242
243
872226
	for (hashval = 0; *s != '\0'; s++)
244
350820
		hashval = (*s + 31 * hashval);
245
56862
	return hashval % n;
246
}
247
248
void rehash(Array *tp)	/* rehash items in small table into big one */
249
{
250
	int i, nh, nsz;
251
	Cell *cp, *op, **np;
252
253
16
	nsz = GROWTAB * tp->size;
254
8
	np = (Cell **) calloc(nsz, sizeof(Cell *));
255
8
	if (np == NULL)		/* can't do it, but can keep running. */
256
		return;		/* someone else will run out later. */
257
816
	for (i = 0; i < tp->size; i++) {
258
2400
		for (cp = tp->tab[i]; cp; cp = op) {
259
800
			op = cp->cnext;
260
800
			nh = hash(cp->nval, nsz);
261
800
			cp->cnext = np[nh];
262
800
			np[nh] = cp;
263
		}
264
	}
265
8
	free(tp->tab);
266
8
	tp->tab = np;
267
8
	tp->size = nsz;
268
16
}
269
270
Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
271
{
272
	Cell *p;
273
	int h;
274
275
62790
	h = hash(s, tp->size);
276
72852
	for (p = tp->tab[h]; p != NULL; p = p->cnext)
277
11759
		if (strcmp(s, p->nval) == 0)
278
6728
			return(p);	/* found it */
279
24667
	return(NULL);			/* not found */
280
31395
}
281
282
Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
283
{
284
	int fldno;
285
286
7628122
	if ((vp->tval & (NUM | STR)) == 0)
287
		funnyvar(vp, "assign to");
288
3814061
	if (isfld(vp)) {
289
		donerec = 0;	/* mark $0 invalid */
290
		fldno = atoi(vp->nval);
291
		if (fldno > *NF)
292
			newfld(fldno);
293
		   DPRINTF( ("setting field %d to %g\n", fldno, f) );
294
3814061
	} else if (isrec(vp)) {
295
		donefld = 0;	/* mark $1... invalid */
296
		donerec = 1;
297
	}
298
3814061
	if (freeable(vp))
299
11446
		xfree(vp->sval); /* free any previous string */
300
3814061
	vp->tval &= ~STR;	/* mark string invalid */
301
3814061
	vp->tval |= NUM;	/* mark number ok */
302

3814061
	   DPRINTF( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
303
3814061
	return vp->fval = f;
304
}
305
306
void funnyvar(Cell *vp, const char *rw)
307
{
308
	if (isarr(vp))
309
		FATAL("can't %s %s; it's an array name.", rw, vp->nval);
310
	if (vp->tval & FCN)
311
		FATAL("can't %s %s; it's a function.", rw, vp->nval);
312
	WARNING("funny variable %p: n=%s s=\"%s\" f=%g t=%o",
313
		vp, vp->nval, vp->sval, vp->fval, vp->tval);
314
}
315
316
char *setsval(Cell *vp, const char *s)	/* set string val of a Cell */
317
{
318
	char *t;
319
	int fldno;
320
321

1363156
	   DPRINTF( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n",
322
		(void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) );
323
681578
	if ((vp->tval & (NUM | STR)) == 0)
324
		funnyvar(vp, "assign to");
325
681578
	if (isfld(vp)) {
326
		donerec = 0;	/* mark $0 invalid */
327
		fldno = atoi(vp->nval);
328
		if (fldno > *NF)
329
			newfld(fldno);
330
		   DPRINTF( ("setting field %d to %s (%p)\n", fldno, s, s) );
331
681578
	} else if (isrec(vp)) {
332
		donefld = 0;	/* mark $1... invalid */
333
		donerec = 1;
334
	}
335
681578
	t = tostring(s);	/* in case it's self-assign */
336
681578
	if (freeable(vp))
337
1200366
		xfree(vp->sval);
338
681578
	vp->tval &= ~NUM;
339
681578
	vp->tval |= STR;
340
681578
	vp->tval &= ~DONTFREE;
341

681578
	   DPRINTF( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n",
342
		(void*)vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) );
343
681578
	return(vp->sval = t);
344
}
345
346
Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
347
{
348
9222170
	if ((vp->tval & (NUM | STR)) == 0)
349
		funnyvar(vp, "read value of");
350
4611085
	if (isfld(vp) && donefld == 0)
351
		fldbld();
352
4611085
	else if (isrec(vp) && donerec == 0)
353
		recbld();
354
4611085
	if (!isnum(vp)) {	/* not a number */
355
		vp->fval = atof(vp->sval);	/* best guess */
356
		if (is_number(vp->sval) && !(vp->tval&CON))
357
			vp->tval |= NUM;	/* make NUM only sparingly */
358
	}
359

4611085
	   DPRINTF( ("getfval %p: %s = %g, t=%o\n",
360
		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
361
4611085
	return(vp->fval);
362
}
363
364
static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
365
{
366
	int n;
367
18741218
	double dtemp;
368
369
9370609
	if ((vp->tval & (NUM | STR)) == 0)
370
		funnyvar(vp, "read value of");
371
9370609
	if (isfld(vp) && donefld == 0)
372
		fldbld();
373
9370609
	else if (isrec(vp) && donerec == 0)
374
		recbld();
375
9370609
	if (isstr(vp) == 0) {
376
483084
		if (freeable(vp))
377
			xfree(vp->sval);
378
483084
		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
379
3084
			n = asprintf(&vp->sval, "%.30g", vp->fval);
380
		else
381
480000
			n = asprintf(&vp->sval, *fmt, vp->fval);
382
483084
		if (n == -1)
383
			FATAL("out of space in get_str_val");
384
483084
		vp->tval &= ~DONTFREE;
385
483084
		vp->tval |= STR;
386
483084
	}
387

9370609
	   DPRINTF( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
388
		(void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
389
18741218
	return(vp->sval);
390
9370609
}
391
392
char *getsval(Cell *vp)       /* get string val of a Cell */
393
{
394
14582374
      return get_str_val(vp, CONVFMT);
395
}
396
397
char *getpssval(Cell *vp)     /* get string val of a Cell for print */
398
{
399
4158844
      return get_str_val(vp, OFMT);
400
}
401
402
403
char *tostring(const char *s)	/* make a copy of string s */
404
{
405
	char *p;
406
407
1487420
	p = strdup(s);
408
743710
	if (p == NULL)
409
		FATAL("out of space in tostring on %s", s);
410
743710
	return p;
411
}
412
413
char *qstring(const char *is, int delim)	/* collect string up to next delim */
414
{
415
	const char *os = is;
416
	int c, n;
417
	uschar *s = (uschar *) is;
418
	uschar *buf, *bp;
419
420
130
	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
421
		FATAL( "out of space in qstring(%s)", s);
422
352
	for (bp = buf; (c = *s) != delim; s++) {
423
111
		if (c == '\n')
424
			SYNTAX( "newline in string %.20s...", os );
425
111
		else if (c != '\\')
426
111
			*bp++ = c;
427
		else {	/* \something */
428
			c = *++s;
429
			if (c == 0) {	/* \ at end */
430
				*bp++ = '\\';
431
				break;	/* for loop */
432
			}
433
			switch (c) {
434
			case '\\':	*bp++ = '\\'; break;
435
			case 'n':	*bp++ = '\n'; break;
436
			case 't':	*bp++ = '\t'; break;
437
			case 'b':	*bp++ = '\b'; break;
438
			case 'f':	*bp++ = '\f'; break;
439
			case 'r':	*bp++ = '\r'; break;
440
			default:
441
				if (!isdigit(c)) {
442
					*bp++ = c;
443
					break;
444
				}
445
				n = c - '0';
446
				if (isdigit(s[1])) {
447
					n = 8 * n + *++s - '0';
448
					if (isdigit(s[1]))
449
						n = 8 * n + *++s - '0';
450
				}
451
				*bp++ = n;
452
				break;
453
			}
454
		}
455
	}
456
65
	*bp++ = 0;
457
65
	return (char *) buf;
458
}