GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: bin/ksh/tree.c Lines: 256 349 73.4 %
Date: 2016-12-06 Branches: 177 266 66.5 %

Line Branch Exec Source
1
/*	$OpenBSD: tree.c,v 1.27 2015/11/01 15:38:53 mmcc Exp $	*/
2
3
/*
4
 * command tree climbing
5
 */
6
7
#include <string.h>
8
9
#include "sh.h"
10
11
#define INDENT	4
12
13
#define tputc(c, shf)	shf_putchar(c, shf);
14
static void	ptree(struct op *, int, struct shf *);
15
static void	pioact(struct shf *, int, struct ioword *);
16
static void	tputC(int, struct shf *);
17
static void	tputS(char *, struct shf *);
18
static void	vfptreef(struct shf *, int, const char *, va_list);
19
static struct ioword **iocopy(struct ioword **, Area *);
20
static void     iofree(struct ioword **, Area *);
21
22
/*
23
 * print a command tree
24
 */
25
26
static void
27
ptree(struct op *t, int indent, struct shf *shf)
28
23557
{
29
	char **w;
30
	struct ioword **ioact;
31
	struct op *t1;
32
33
23557
 Chain:
34
23557
	if (t == NULL)
35
4
		return;
36




23553
	switch (t->type) {
37
	case TCOM:
38
15248
		if (t->vars)
39
30950
			for (w = t->vars; *w != NULL; )
40
454
				fptreef(shf, indent, "%S ", *w++);
41
		else
42
			fptreef(shf, indent, "#no-vars# ");
43
15248
		if (t->args)
44
83221
			for (w = t->args; *w != NULL; )
45
52725
				fptreef(shf, indent, "%S ", *w++);
46
		else
47
			fptreef(shf, indent, "#no-args# ");
48
		break;
49
	case TEXEC:
50
#if 0 /* ?not useful - can't be called? */
51
		/* Print original vars */
52
		if (t->left->vars)
53
			for (w = t->left->vars; *w != NULL; )
54
				fptreef(shf, indent, "%S ", *w++);
55
		else
56
			fptreef(shf, indent, "#no-vars# ");
57
		/* Print expanded vars */
58
		if (t->args)
59
			for (w = t->args; *w != NULL; )
60
				fptreef(shf, indent, "%s ", *w++);
61
		else
62
			fptreef(shf, indent, "#no-args# ");
63
		/* Print original io */
64
		t = t->left;
65
#else
66
6993
		t = t->left;
67
6993
		goto Chain;
68
#endif
69
	case TPAREN:
70
194
		fptreef(shf, indent + 2, "( %T) ", t->left);
71
194
		break;
72
	case TPIPE:
73
115
		fptreef(shf, indent, "%T| ", t->left);
74
115
		t = t->right;
75
115
		goto Chain;
76
	case TLIST:
77
627
		fptreef(shf, indent, "%T%;", t->left);
78
627
		t = t->right;
79
627
		goto Chain;
80
	case TOR:
81
	case TAND:
82
188
		fptreef(shf, indent, "%T%s %T",
83
		    t->left, (t->type==TOR) ? "||" : "&&", t->right);
84
188
		break;
85
	case TBANG:
86
		fptreef(shf, indent, "! ");
87
		t = t->right;
88
		goto Chain;
89
	case TDBRACKET:
90
	  {
91
		int i;
92
93
		fptreef(shf, indent, "[[");
94
		for (i = 0; t->args[i]; i++)
95
			fptreef(shf, indent, " %S", t->args[i]);
96
		fptreef(shf, indent, " ]] ");
97
		break;
98
	  }
99
	case TSELECT:
100
		fptreef(shf, indent, "select %s ", t->str);
101
		/* FALLTHROUGH */
102
	case TFOR:
103
9
		if (t->type == TFOR)
104
9
			fptreef(shf, indent, "for %s ", t->str);
105
9
		if (t->vars != NULL) {
106
9
			fptreef(shf, indent, "in ");
107
238
			for (w = t->vars; *w; )
108
220
				fptreef(shf, indent, "%S ", *w++);
109
9
			fptreef(shf, indent, "%;");
110
		}
111
9
		fptreef(shf, indent + INDENT, "do%N%T", t->left);
112
9
		fptreef(shf, indent, "%;done ");
113
9
		break;
114
	case TCASE:
115
137
		fptreef(shf, indent, "case %S in", t->str);
116
402
		for (t1 = t->left; t1 != NULL; t1 = t1->right) {
117
265
			fptreef(shf, indent, "%N(");
118
768
			for (w = t1->vars; *w != NULL; w++)
119
503
				fptreef(shf, indent, "%S%c", *w,
120
				    (w[1] != NULL) ? '|' : ')');
121
265
			fptreef(shf, indent + INDENT, "%;%T%N;;", t1->left);
122
		}
123
137
		fptreef(shf, indent, "%Nesac ");
124
137
		break;
125
	case TIF:
126
	case TELIF:
127
		/* 3 == strlen("if ") */
128
10
		fptreef(shf, indent + 3, "if %T", t->left);
129
		for (;;) {
130
10
			t = t->right;
131
10
			if (t->left != NULL) {
132
10
				fptreef(shf, indent, "%;");
133
10
				fptreef(shf, indent + INDENT, "then%N%T",
134
				    t->left);
135
			}
136

10
			if (t->right == NULL || t->right->type != TELIF)
137
				break;
138
			t = t->right;
139
			fptreef(shf, indent, "%;");
140
			/* 5 == strlen("elif ") */
141
			fptreef(shf, indent + 5, "elif %T", t->left);
142
		}
143
10
		if (t->right != NULL) {
144
6
			fptreef(shf, indent, "%;");
145
6
			fptreef(shf, indent + INDENT, "else%;%T", t->right);
146
		}
147
10
		fptreef(shf, indent, "%;fi ");
148
10
		break;
149
	case TWHILE:
150
	case TUNTIL:
151
		/* 6 == strlen("while"/"until") */
152
4
		fptreef(shf, indent + 6, "%s %T",
153
		    (t->type==TWHILE) ? "while" : "until",
154
		    t->left);
155
4
		fptreef(shf, indent, "%;do");
156
4
		fptreef(shf, indent + INDENT, "%;%T", t->right);
157
4
		fptreef(shf, indent, "%;done ");
158
4
		break;
159
	case TBRACE:
160
18
		fptreef(shf, indent + INDENT, "{%;%T", t->left);
161
18
		fptreef(shf, indent, "%;} ");
162
18
		break;
163
	case TCOPROC:
164
		fptreef(shf, indent, "%T|& ", t->left);
165
		break;
166
	case TASYNC:
167
		fptreef(shf, indent, "%T& ", t->left);
168
		break;
169
	case TFUNCT:
170
10
		fptreef(shf, indent,
171
		    t->u.ksh_func ? "function %s %T" : "%s() %T",
172
		    t->str, t->left);
173
10
		break;
174
	case TTIME:
175
		fptreef(shf, indent, "time %T", t->left);
176
		break;
177
	default:
178
		fptreef(shf, indent, "<botch>");
179
		break;
180
	}
181
15818
	if ((ioact = t->ioact) != NULL) {
182
3494
		int	need_nl = 0;
183
184
12015
		while (*ioact != NULL)
185
5027
			pioact(shf, indent, *ioact++);
186
		/* Print here documents after everything else... */
187
12015
		for (ioact = t->ioact; *ioact != NULL; ) {
188
5027
			struct ioword *iop = *ioact++;
189
190
			/* heredoc is 0 when tracing (set -x) */
191

5027
			if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc) {
192
844
				tputc('\n', shf);
193
844
				shf_puts(iop->heredoc, shf);
194
844
				fptreef(shf, indent, "%s",
195
				    evalstr(iop->delim, 0));
196
844
				need_nl = 1;
197
			}
198
		}
199
		/* Last delimiter must be followed by a newline (this often
200
		 * leads to an extra blank line, but its not worth worrying
201
		 * about)
202
		 */
203
3494
		if (need_nl)
204
842
			tputc('\n', shf);
205
	}
206
}
207
208
static void
209
pioact(struct shf *shf, int indent, struct ioword *iop)
210
5027
{
211
5027
	int flag = iop->flag;
212
5027
	int type = flag & IOTYPE;
213
	int expected;
214
215


5027
	expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
216
	    (type == IOCAT || type == IOWRITE) ? 1 :
217
	    (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
218
	    iop->unit + 1;
219
5027
	if (iop->unit != expected)
220
1288
		tputc('0' + iop->unit, shf);
221
222

5027
	switch (type) {
223
	case IOREAD:
224
68
		fptreef(shf, indent, "< ");
225
68
		break;
226
	case IOHERE:
227
844
		if (flag&IOSKIP)
228
46
			fptreef(shf, indent, "<<- ");
229
		else
230
798
			fptreef(shf, indent, "<< ");
231
		break;
232
	case IOCAT:
233
444
		fptreef(shf, indent, ">> ");
234
444
		break;
235
	case IOWRITE:
236
2031
		if (flag&IOCLOB)
237
			fptreef(shf, indent, ">| ");
238
		else
239
2031
			fptreef(shf, indent, "> ");
240
		break;
241
	case IORDWR:
242
		fptreef(shf, indent, "<> ");
243
		break;
244
	case IODUP:
245
1640
		if (flag & IORDUP)
246
			fptreef(shf, indent, "<&");
247
		else
248
1640
			fptreef(shf, indent, ">&");
249
		break;
250
	}
251
	/* name/delim are 0 when printing syntax errors */
252
5027
	if (type == IOHERE) {
253
844
		if (iop->delim)
254
844
			fptreef(shf, indent, "%S ", iop->delim);
255
4183
	} else if (iop->name)
256
4183
		fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
257
		    iop->name);
258
5027
}
259
260
261
/*
262
 * variants of fputc, fputs for ptreef and snptreef
263
 */
264
265
static void
266
tputC(int c, struct shf *shf)
267
573450
{
268
573450
	if ((c&0x60) == 0) {		/* C0|C1 */
269
6206
		tputc((c&0x80) ? '$' : '^', shf);
270
6206
		tputc(((c&0x7F)|0x40), shf);
271
567244
	} else if ((c&0x7F) == 0x7F) {	/* DEL */
272
		tputc((c&0x80) ? '$' : '^', shf);
273
		tputc('?', shf);
274
	} else
275
567244
		tputc(c, shf);
276
573450
}
277
278
static void
279
tputS(char *wp, struct shf *shf)
280
59070
{
281
59070
	int c, quoted=0;
282
283
	/* problems:
284
	 *	`...` -> $(...)
285
	 *	'foo' -> "foo"
286
	 * could change encoding to:
287
	 *	OQUOTE ["'] ... CQUOTE ["']
288
	 *	COMSUB [(`] ...\0	(handle $ ` \ and maybe " in `...` case)
289
	 */
290
	while (1)
291



558296
		switch ((c = *wp++)) {
292
		case EOS:
293
			return;
294
		case CHAR:
295
359738
			tputC(*wp++, shf);
296
359738
			break;
297
		case QCHAR:
298
91949
			c = *wp++;
299

91949
			if (!quoted || (c == '"' || c == '`' || c == '$'))
300
3356
				tputc('\\', shf);
301
91949
			tputC(c, shf);
302
91949
			break;
303
		case COMSUB:
304
109
			tputc('$', shf);
305
109
			tputc('(', shf);
306
4612
			while (*wp != 0)
307
4394
				tputC(*wp++, shf);
308
109
			tputc(')', shf);
309
109
			wp++;
310
109
			break;
311
		case EXPRSUB:
312
			tputc('$', shf);
313
			tputc('(', shf);
314
			tputc('(', shf);
315
			while (*wp != 0)
316
				tputC(*wp++, shf);
317
			tputc(')', shf);
318
			tputc(')', shf);
319
			wp++;
320
			break;
321
		case OQUOTE:
322
8821
			quoted = 1;
323
8821
			tputc('"', shf);
324
8821
			break;
325
		case CQUOTE:
326
8821
			quoted = 0;
327
8821
			tputc('"', shf);
328
8821
			break;
329
		case OSUBST:
330
14894
			tputc('$', shf);
331
14894
			if (*wp++ == '{')
332
5402
				tputc('{', shf);
333
132263
			while ((c = *wp++) != 0)
334
117369
				tputC(c, shf);
335
			break;
336
		case CSUBST:
337
14894
			if (*wp++ == '}')
338
5402
				tputc('}', shf);
339
			break;
340
		case OPAT:
341
			tputc(*wp++, shf);
342
			tputc('(', shf);
343
			break;
344
		case SPAT:
345
			tputc('|', shf);
346
			break;
347
		case CPAT:
348
			tputc(')', shf);
349
			break;
350
		}
351
}
352
353
void
354
fptreef(struct shf *shf, int indent, const char *fmt, ...)
355
66887
{
356
  va_list	va;
357
358
66887
  va_start(va, fmt);
359
66887
  vfptreef(shf, indent, fmt, va);
360
66887
  va_end(va);
361
66887
}
362
363
char *
364
snptreef(char *s, int n, const char *fmt, ...)
365
14178
{
366
  va_list va;
367
  struct shf shf;
368
369
14178
  shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
370
371
14178
  va_start(va, fmt);
372
14178
  vfptreef(&shf, 0, fmt, va);
373
14178
  va_end(va);
374
375
14178
  return shf_sclose(&shf); /* null terminates */
376
}
377
378
static void
379
vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
380
81065
{
381
	int c;
382
383
314215
	while ((c = *fmt++)) {
384
152085
		if (c == '%') {
385
			long n;
386
			char *p;
387
			int neg;
388
389


78126
			switch ((c = *fmt++)) {
390
			case 'c':
391
503
				tputc(va_arg(va, int), shf);
392
503
				break;
393
			case 's':
394
1055
				p = va_arg(va, char *);
395
7379
				while (*p)
396
5269
					tputc(*p++, shf);
397
				break;
398
			case 'S':	/* word */
399
59070
				p = va_arg(va, char *);
400
59070
				tputS(p, shf);
401
59070
				break;
402
			case 'd': case 'u': /* decimal */
403
				n = (c == 'd') ? va_arg(va, int) :
404
				    va_arg(va, unsigned int);
405
				neg = c=='d' && n<0;
406
				p = ulton((neg) ? -n : n, 10);
407
				if (neg)
408
					*--p = '-';
409
				while (*p)
410
					tputc(*p++, shf);
411
				break;
412
			case 'T':	/* format tree */
413
15822
				ptree(va_arg(va, struct op *), indent, shf);
414
15822
				break;
415
			case ';':	/* newline or ; */
416
			case 'N':	/* newline or space */
417
1676
				if (shf->flags & SHF_STRING) {
418
1676
					if (c == ';')
419
990
						tputc(';', shf);
420
1676
					tputc(' ', shf);
421
				} else {
422
					int i;
423
424
					tputc('\n', shf);
425
					for (i = indent; i >= 8; i -= 8)
426
						tputc('\t', shf);
427
					for (; i > 0; --i)
428
						tputc(' ', shf);
429
				}
430
				break;
431
			case 'R':
432
				pioact(shf, indent, va_arg(va, struct ioword *));
433
				break;
434
			default:
435
				tputc(c, shf);
436
				break;
437
			}
438
		} else
439
73959
			tputc(c, shf);
440
	}
441
81065
}
442
443
/*
444
 * copy tree (for function definition)
445
 */
446
447
struct op *
448
tcopy(struct op *t, Area *ap)
449
21456
{
450
	struct op *r;
451
	char **tw, **rw;
452
453
21456
	if (t == NULL)
454
10905
		return NULL;
455
456
10551
	r = alloc(sizeof(struct op), ap);
457
458
10551
	r->type = t->type;
459
10551
	r->u.evalflags = t->u.evalflags;
460
461
10551
	r->str = t->type == TCASE ? wdcopy(t->str, ap) : str_save(t->str, ap);
462
463
10551
	if (t->vars == NULL)
464
5208
		r->vars = NULL;
465
	else {
466
5343
		for (tw = t->vars; *tw++ != NULL; )
467
			;
468
5343
		rw = r->vars = areallocarray(NULL, tw - t->vars + 1,
469
		    sizeof(*tw), ap);
470
12417
		for (tw = t->vars; *tw != NULL; )
471
1731
			*rw++ = wdcopy(*tw++, ap);
472
5343
		*rw = NULL;
473
	}
474
475
10551
	if (t->args == NULL)
476
5758
		r->args = NULL;
477
	else {
478
4793
		for (tw = t->args; *tw++ != NULL; )
479
			;
480
4793
		rw = r->args = areallocarray(NULL, tw - t->args + 1,
481
		    sizeof(*tw), ap);
482
21247
		for (tw = t->args; *tw != NULL; )
483
11661
			*rw++ = wdcopy(*tw++, ap);
484
4793
		*rw = NULL;
485
	}
486
487
10551
	r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
488
489
10551
	r->left = tcopy(t->left, ap);
490
10551
	r->right = tcopy(t->right, ap);
491
10551
	r->lineno = t->lineno;
492
493
10551
	return r;
494
}
495
496
char *
497
wdcopy(const char *wp, Area *ap)
498
14114
{
499
14114
	size_t len = wdscan(wp, EOS) - wp;
500
14114
	return memcpy(alloc(len, ap), wp, len);
501
}
502
503
/* return the position of prefix c in wp plus 1 */
504
char *
505
wdscan(const char *wp, int c)
506
149669
{
507
149669
	int nest = 0;
508
509
	while (1)
510


300222
		switch (*wp++) {
511
		case EOS:
512
14118
			return (char *) wp;
513
		case CHAR:
514
		case QCHAR:
515
135044
			wp++;
516
135044
			break;
517
		case COMSUB:
518
		case EXPRSUB:
519
3600
			while (*wp++ != 0)
520
				;
521
			break;
522
		case OQUOTE:
523
		case CQUOTE:
524
			break;
525
		case OSUBST:
526
5979
			nest++;
527
38129
			while (*wp++ != '\0')
528
				;
529
			break;
530
		case CSUBST:
531
141530
			wp++;
532
141530
			if (c == CSUBST && nest == 0)
533
135551
				return (char *) wp;
534
5979
			nest--;
535
5979
			break;
536
		case OPAT:
537
			nest++;
538
			wp++;
539
			break;
540
		case SPAT:
541
		case CPAT:
542
			if (c == wp[-1] && nest == 0)
543
				return (char *) wp;
544
			if (wp[-1] == CPAT)
545
				nest--;
546
			break;
547
		default:
548
			internal_errorf(0,
549
			    "wdscan: unknown char 0x%x (carrying on)",
550
			    wp[-1]);
551
		}
552
}
553
554
/* return a copy of wp without any of the mark up characters and
555
 * with quote characters (" ' \) stripped.
556
 * (string is allocated from ATEMP)
557
 */
558
char *
559
wdstrip(const char *wp)
560
354
{
561
	struct shf shf;
562
	int c;
563
564
354
	shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
565
566
	/* problems:
567
	 *	`...` -> $(...)
568
	 *	x${foo:-"hi"} -> x${foo:-hi}
569
	 *	x${foo:-'hi'} -> x${foo:-hi}
570
	 */
571
	while (1)
572


2901
		switch ((c = *wp++)) {
573
		case EOS:
574
354
			return shf_sclose(&shf); /* null terminates */
575
		case CHAR:
576
		case QCHAR:
577
2547
			shf_putchar(*wp++, &shf);
578
2547
			break;
579
		case COMSUB:
580
			shf_putchar('$', &shf);
581
			shf_putchar('(', &shf);
582
			while (*wp != 0)
583
				shf_putchar(*wp++, &shf);
584
			shf_putchar(')', &shf);
585
			break;
586
		case EXPRSUB:
587
			shf_putchar('$', &shf);
588
			shf_putchar('(', &shf);
589
			shf_putchar('(', &shf);
590
			while (*wp != 0)
591
				shf_putchar(*wp++, &shf);
592
			shf_putchar(')', &shf);
593
			shf_putchar(')', &shf);
594
			break;
595
		case OQUOTE:
596
			break;
597
		case CQUOTE:
598
			break;
599
		case OSUBST:
600
			shf_putchar('$', &shf);
601
			if (*wp++ == '{')
602
			    shf_putchar('{', &shf);
603
			while ((c = *wp++) != 0)
604
				shf_putchar(c, &shf);
605
			break;
606
		case CSUBST:
607
			if (*wp++ == '}')
608
				shf_putchar('}', &shf);
609
			break;
610
		case OPAT:
611
			shf_putchar(*wp++, &shf);
612
			shf_putchar('(', &shf);
613
			break;
614
		case SPAT:
615
			shf_putchar('|', &shf);
616
			break;
617
		case CPAT:
618
			shf_putchar(')', &shf);
619
			break;
620
		}
621
}
622
623
static	struct ioword **
624
iocopy(struct ioword **iow, Area *ap)
625
644
{
626
	struct ioword **ior;
627
	int i;
628
629
644
	for (ior = iow; *ior++ != NULL; )
630
		;
631
644
	ior = areallocarray(NULL, ior - iow + 1, sizeof(*ior), ap);
632
633
1331
	for (i = 0; iow[i] != NULL; i++) {
634
		struct ioword *p, *q;
635
636
687
		p = iow[i];
637
687
		q = alloc(sizeof(*p), ap);
638
687
		ior[i] = q;
639
687
		*q = *p;
640
687
		if (p->name != NULL)
641
644
			q->name = wdcopy(p->name, ap);
642
687
		if (p->delim != NULL)
643
43
			q->delim = wdcopy(p->delim, ap);
644
687
		if (p->heredoc != NULL)
645
43
			q->heredoc = str_save(p->heredoc, ap);
646
	}
647
644
	ior[i] = NULL;
648
649
644
	return ior;
650
}
651
652
/*
653
 * free tree (for function definition)
654
 */
655
656
void
657
tfree(struct op *t, Area *ap)
658
46
{
659
	char **w;
660
661
46
	if (t == NULL)
662
26
		return;
663
664
20
	afree(t->str, ap);
665
666
20
	if (t->vars != NULL) {
667
8
		for (w = t->vars; *w != NULL; w++)
668
			afree(*w, ap);
669
8
		afree(t->vars, ap);
670
	}
671
672
20
	if (t->args != NULL) {
673
16
		for (w = t->args; *w != NULL; w++)
674
8
			afree(*w, ap);
675
8
		afree(t->args, ap);
676
	}
677
678
20
	if (t->ioact != NULL)
679
8
		iofree(t->ioact, ap);
680
681
20
	tfree(t->left, ap);
682
20
	tfree(t->right, ap);
683
684
20
	afree(t, ap);
685
}
686
687
static	void
688
iofree(struct ioword **iow, Area *ap)
689
8
{
690
	struct ioword **iop;
691
	struct ioword *p;
692
693
24
	for (iop = iow; (p = *iop++) != NULL; ) {
694
8
		afree(p->name, ap);
695
8
		afree(p->delim, ap);
696
8
		afree(p->heredoc, ap);
697
8
		afree(p, ap);
698
	}
699
8
	afree(iow, ap);
700
8
}