GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/tran.c Lines: 169 246 68.7 %
Date: 2017-11-07 Branches: 75 173 43.4 %

Line Branch Exec Source
1
/*	$OpenBSD: tran.c,v 1.15 2011/09/28 19:27:18 millert 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
1962
	literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab);
74
	/* this is used for if(x)... tests: */
75
981
	nullloc = setsymtab("$zero&null", "", 0.0, NUM|STR|CON|DONTFREE, symtab);
76
981
	nullnode = celltonode(nullloc, CCON);
77
78
981
	fsloc = setsymtab("FS", " ", 0.0, STR|DONTFREE, symtab);
79
981
	FS = &fsloc->sval;
80
981
	RS = &setsymtab("RS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
81
981
	OFS = &setsymtab("OFS", " ", 0.0, STR|DONTFREE, symtab)->sval;
82
981
	ORS = &setsymtab("ORS", "\n", 0.0, STR|DONTFREE, symtab)->sval;
83
981
	OFMT = &setsymtab("OFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
84
981
	CONVFMT = &setsymtab("CONVFMT", "%.6g", 0.0, STR|DONTFREE, symtab)->sval;
85
981
	FILENAME = &setsymtab("FILENAME", "", 0.0, STR|DONTFREE, symtab)->sval;
86
981
	nfloc = setsymtab("NF", "", 0.0, NUM, symtab);
87
981
	NF = &nfloc->fval;
88
981
	nrloc = setsymtab("NR", "", 0.0, NUM, symtab);
89
981
	NR = &nrloc->fval;
90
981
	fnrloc = setsymtab("FNR", "", 0.0, NUM, symtab);
91
981
	FNR = &fnrloc->fval;
92
981
	SUBSEP = &setsymtab("SUBSEP", "\034", 0.0, STR|DONTFREE, symtab)->sval;
93
981
	rstartloc = setsymtab("RSTART", "", 0.0, NUM, symtab);
94
981
	RSTART = &rstartloc->fval;
95
981
	rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab);
96
981
	RLENGTH = &rlengthloc->fval;
97
981
	symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab);
98
981
	symtabloc->sval = (char *) symtab;
99
981
}
100
101
void arginit(int ac, char **av)	/* set up ARGV and ARGC */
102
{
103
	Cell *cp;
104
	int i;
105
1962
	char temp[50];
106
107
981
	ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval;
108
981
	cp = setsymtab("ARGV", "", 0.0, ARR, symtab);
109
981
	ARGVtab = makesymtab(NSYMTAB);	/* could be (int) ARGC as well */
110
981
	cp->sval = (char *) ARGVtab;
111
4238
	for (i = 0; i < ac; i++) {
112
1138
		snprintf(temp, sizeof temp, "%d", i);
113
1138
		if (is_number(*av))
114
			setsymtab(temp, *av, atof(*av), STR|NUM, ARGVtab);
115
		else
116
1138
			setsymtab(temp, *av, 0.0, STR, ARGVtab);
117
1138
		av++;
118
	}
119
981
}
120
121
void envinit(char **envp)	/* set up ENVIRON variable */
122
{
123
	Cell *cp;
124
	char *p;
125
126
1962
	cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab);
127
981
	ENVtab = makesymtab(NSYMTAB);
128
981
	cp->sval = (char *) ENVtab;
129
50252
	for ( ; *envp; envp++) {
130
24145
		if ((p = strchr(*envp, '=')) == NULL)
131
			continue;
132
24145
		if( p == *envp ) /* no left hand side name in env string */
133
			continue;
134
24145
		*p++ = 0;	/* split into two strings at = */
135
24145
		if (is_number(p))
136
799
			setsymtab(*envp, p, atof(p), STR|NUM, ENVtab);
137
		else
138
23346
			setsymtab(*envp, p, 0.0, STR, ENVtab);
139
24145
		p[-1] = '=';	/* restore in case env is passed down to a shell */
140
24145
	}
141
981
}
142
143
Array *makesymtab(int n)	/* make a new symbol table */
144
{
145
	Array *ap;
146
	Cell **tp;
147
148
7892
	ap = (Array *) malloc(sizeof(Array));
149
3946
	tp = (Cell **) calloc(n, sizeof(Cell *));
150
3946
	if (ap == NULL || tp == NULL)
151
		FATAL("out of space in makesymtab");
152
3946
	ap->nelem = 0;
153
3946
	ap->size = n;
154
3946
	ap->tab = tp;
155
3946
	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
1960
	if (!isarr(ap))
165
		return;
166
980
	tp = (Array *) ap->sval;
167
980
	if (tp == NULL)
168
		return;
169
99960
	for (i = 0; i < tp->size; i++) {
170
100734
		for (cp = tp->tab[i]; cp != NULL; cp = temp) {
171
2734
			xfree(cp->nval);
172
1367
			if (freeable(cp))
173
2734
				xfree(cp->sval);
174
1367
			temp = cp->cnext;	/* avoids freeing then using */
175
1367
			free(cp);
176
1367
			tp->nelem--;
177
		}
178
49000
		tp->tab[i] = 0;
179
	}
180
980
	if (tp->nelem != 0)
181
		WARNING("can't happen: inconsistent element count freeing %s", ap->nval);
182
980
	free(tp->tab);
183
980
	free(tp);
184
1960
}
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

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

13003
		   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
13003
		return(p);
218
	}
219
51598
	p = (Cell *) malloc(sizeof(Cell));
220
51598
	if (p == NULL)
221
		FATAL("out of space for symbol table at %s", n);
222
51598
	p->nval = tostring(n);
223
51598
	p->sval = s ? tostring(s) : tostring("");
224
51598
	p->fval = f;
225
51598
	p->tval = t;
226
51598
	p->csub = CUNK;
227
51598
	p->ctype = OCELL;
228
51598
	tp->nelem++;
229
51598
	if (tp->nelem > FULLTAB * tp->size)
230
14
		rehash(tp);
231
51598
	h = hash(n, tp->size);
232
51598
	p->cnext = tp->tab[h];
233
51598
	tp->tab[h] = p;
234
51598
	   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
51598
	return(p);
237
64601
}
238
239
int hash(const char *s, int n)	/* form hash value for string s */
240
{
241
	unsigned hashval;
242
243
1771082
	for (hashval = 0; *s != '\0'; s++)
244
708496
		hashval = (*s + 31 * hashval);
245
118030
	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
28
	nsz = GROWTAB * tp->size;
254
14
	np = (Cell **) calloc(nsz, sizeof(Cell *));
255
14
	if (np == NULL)		/* can't do it, but can keep running. */
256
		return;		/* someone else will run out later. */
257
1428
	for (i = 0; i < tp->size; i++) {
258
4200
		for (cp = tp->tab[i]; cp; cp = op) {
259
1400
			op = cp->cnext;
260
1400
			nh = hash(cp->nval, nsz);
261
1400
			cp->cnext = np[nh];
262
1400
			np[nh] = cp;
263
		}
264
	}
265
14
	free(tp->tab);
266
14
	tp->tab = np;
267
14
	tp->size = nsz;
268
28
}
269
270
Cell *lookup(const char *s, Array *tp)	/* look for s in tp */
271
{
272
	Cell *p;
273
	int h;
274
275
130064
	h = hash(s, tp->size);
276
150034
	for (p = tp->tab[h]; p != NULL; p = p->cnext)
277
23419
		if (strcmp(s, p->nval) == 0)
278
13434
			return(p);	/* found it */
279
51598
	return(NULL);			/* not found */
280
65032
}
281
282
Awkfloat setfval(Cell *vp, Awkfloat f)	/* set float val of a Cell */
283
{
284
	int fldno;
285
286
17551536
	if ((vp->tval & (NUM | STR)) == 0)
287
		funnyvar(vp, "assign to");
288
8775768
	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
8775768
	} else if (isrec(vp)) {
295
		donefld = 0;	/* mark $1... invalid */
296
		donerec = 1;
297
	}
298
8775768
	if (freeable(vp))
299
17400
		xfree(vp->sval); /* free any previous string */
300
8775768
	vp->tval &= ~STR;	/* mark string invalid */
301
8775768
	vp->tval |= NUM;	/* mark number ok */
302

8775768
	   dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
303
8775768
	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

3137642
	   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
1568821
	if ((vp->tval & (NUM | STR)) == 0)
324
		funnyvar(vp, "assign to");
325
1568821
	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
1568821
	} else if (isrec(vp)) {
332
		donefld = 0;	/* mark $1... invalid */
333
		donerec = 1;
334
	}
335
1568821
	t = tostring(s);	/* in case it's self-assign */
336
1568821
	if (freeable(vp))
337
2693566
		xfree(vp->sval);
338
1568821
	vp->tval &= ~NUM;
339
1568821
	vp->tval |= STR;
340
1568821
	vp->tval &= ~DONTFREE;
341

1568821
	   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
1568821
	return(vp->sval = t);
344
}
345
346
Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
347
{
348
21583740
	if ((vp->tval & (NUM | STR)) == 0)
349
		funnyvar(vp, "read value of");
350
10791870
	if (isfld(vp) && donefld == 0)
351
		fldbld();
352
10791870
	else if (isrec(vp) && donerec == 0)
353
		recbld();
354
10791870
	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

10791870
	   dprintf( ("getfval %p: %s = %g, t=%o\n",
360
		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
361
10791870
	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
42236198
	double dtemp;
368
369
21118099
	if ((vp->tval & (NUM | STR)) == 0)
370
		funnyvar(vp, "read value of");
371
21118099
	if (isfld(vp) && donefld == 0)
372
		fldbld();
373
21118099
	else if (isrec(vp) && donerec == 0)
374
		recbld();
375
21118099
	if (isstr(vp) == 0) {
376
1084926
		if (freeable(vp))
377
			xfree(vp->sval);
378
1084926
		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
379
4926
			n = asprintf(&vp->sval, "%.30g", vp->fval);
380
		else
381
1080000
			n = asprintf(&vp->sval, *fmt, vp->fval);
382
1084926
		if (n == -1)
383
			FATAL("out of space in get_str_val");
384
1084926
		vp->tval &= ~DONTFREE;
385
1084926
		vp->tval |= STR;
386
1084926
	}
387

21118099
	   dprintf( ("getsval %p: %s = \"%s (%p)\", t=%o\n",
388
		(void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) );
389
42236198
	return(vp->sval);
390
21118099
}
391
392
char *getsval(Cell *vp)       /* get string val of a Cell */
393
{
394
32799518
      return get_str_val(vp, CONVFMT);
395
}
396
397
char *getpssval(Cell *vp)     /* get string val of a Cell for print */
398
{
399
9436680
      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
3381518
	p = strdup(s);
408
1690759
	if (p == NULL)
409
		FATAL("out of space in tostring on %s", s);
410
1690759
	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
142
	if ((buf = (uschar *) malloc(strlen(is)+3)) == NULL)
421
		FATAL( "out of space in qstring(%s)", s);
422
406
	for (bp = buf; (c = *s) != delim; s++) {
423
132
		if (c == '\n')
424
			SYNTAX( "newline in string %.20s...", os );
425
132
		else if (c != '\\')
426
132
			*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
71
	*bp++ = 0;
457
71
	return (char *) buf;
458
}