GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/awk/tran.c Lines: 168 256 65.6 %
Date: 2016-12-06 Branches: 72 183 39.3 %

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

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

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

166664
	   dprintf( ("setfval %p: %s = %g, t=%o\n", (void*)vp, NN(vp->nval), f, vp->tval) );
303
166664
	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
49015
{
318
	char *t;
319
	int fldno;
320
321

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

49015
	   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
49015
	return(vp->sval = t);
344
}
345
346
Awkfloat getfval(Cell *vp)	/* get float val of a Cell */
347
284153
{
348
284153
	if ((vp->tval & (NUM | STR)) == 0)
349
		funnyvar(vp, "read value of");
350

284153
	if (isfld(vp) && donefld == 0)
351
		fldbld();
352

284153
	else if (isrec(vp) && donerec == 0)
353
		recbld();
354
284153
	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

284153
	   dprintf( ("getfval %p: %s = %g, t=%o\n",
360
		(void*)vp, NN(vp->nval), vp->fval, vp->tval) );
361
284153
	return(vp->fval);
362
}
363
364
static char *get_str_val(Cell *vp, char **fmt)        /* get string val of a Cell */
365
236625
{
366
	int n;
367
	double dtemp;
368
369
236625
	if ((vp->tval & (NUM | STR)) == 0)
370
		funnyvar(vp, "read value of");
371

236625
	if (isfld(vp) && donefld == 0)
372
		fldbld();
373

236625
	else if (isrec(vp) && donerec == 0)
374
		recbld();
375
236625
	if (isstr(vp) == 0) {
376
83
		if (freeable(vp))
377
			xfree(vp->sval);
378
83
		if (modf(vp->fval, &dtemp) == 0)	/* it's integral */
379
83
			n = asprintf(&vp->sval, "%.30g", vp->fval);
380
		else
381
			n = asprintf(&vp->sval, *fmt, vp->fval);
382
83
		if (n == -1)
383
			FATAL("out of space in get_str_val");
384
83
		vp->tval &= ~DONTFREE;
385
83
		vp->tval |= STR;
386
	}
387

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