1 /* $OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $ */
2
3 /*-
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5 * 2011, 2012, 2013, 2015, 2016
6 * mirabilos <m@mirbsd.org>
7 *
8 * Provided that these terms and disclaimer and all copyright notices
9 * are retained or reproduced in an accompanying document, permission
10 * is granted to deal in this work without restriction, including un-
11 * limited rights to use, publicly perform, distribute, sell, modify,
12 * merge, give away, or sublicence.
13 *
14 * This work is provided "AS IS" and WITHOUT WARRANTY of any kind, to
15 * the utmost extent permitted by applicable law, neither express nor
16 * implied; without malicious intent or gross negligence. In no event
17 * may a licensor, author or contributor be held liable for indirect,
18 * direct, other damage, loss, or other issues arising in any way out
19 * of dealing in the work, even if advised of the possibility of such
20 * damage or existence of a defect, except proven that it results out
21 * of said person's immediate fault when using the work as intended.
22 */
23
24 #include "sh.h"
25
26 __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.80 2016/01/14 22:30:43 tg Exp $");
27
28 #define INDENT 8
29
30 static void ptree(struct op *, int, struct shf *);
31 static void pioact(struct shf *, struct ioword *);
32 static const char *wdvarput(struct shf *, const char *, int, int);
33 static void vfptreef(struct shf *, int, const char *, va_list);
34 static struct ioword **iocopy(struct ioword **, Area *);
35 static void iofree(struct ioword **, Area *);
36
37 /* "foo& ; bar" and "foo |& ; bar" are invalid */
38 static bool prevent_semicolon;
39
40 static const char Telif_pT[] = "elif %T";
41
42 /*
43 * print a command tree
44 */
45 static void
ptree(struct op * t,int indent,struct shf * shf)46 ptree(struct op *t, int indent, struct shf *shf)
47 {
48 const char **w;
49 struct ioword **ioact;
50 struct op *t1;
51 int i;
52
53 Chain:
54 if (t == NULL)
55 return;
56 switch (t->type) {
57 case TCOM:
58 prevent_semicolon = false;
59 /*
60 * special-case 'var=<<EOF' (rough; see
61 * exec.c:execute() for full code)
62 */
63 if (
64 /* we have zero arguments, i.e. no programme to run */
65 t->args[0] == NULL &&
66 /* we have exactly one variable assignment */
67 t->vars[0] != NULL && t->vars[1] == NULL &&
68 /* we have exactly one I/O redirection */
69 t->ioact != NULL && t->ioact[0] != NULL &&
70 t->ioact[1] == NULL &&
71 /* of type "here document" (or "here string") */
72 (t->ioact[0]->ioflag & IOTYPE) == IOHERE) {
73 fptreef(shf, indent, "%S", t->vars[0]);
74 break;
75 }
76
77 if (t->vars) {
78 w = (const char **)t->vars;
79 while (*w)
80 fptreef(shf, indent, "%S ", *w++);
81 } else
82 shf_puts("#no-vars# ", shf);
83 if (t->args) {
84 w = t->args;
85 while (*w)
86 fptreef(shf, indent, "%S ", *w++);
87 } else
88 shf_puts("#no-args# ", shf);
89 break;
90 case TEXEC:
91 t = t->left;
92 goto Chain;
93 case TPAREN:
94 fptreef(shf, indent + 2, "( %T) ", t->left);
95 break;
96 case TPIPE:
97 fptreef(shf, indent, "%T| ", t->left);
98 t = t->right;
99 goto Chain;
100 case TLIST:
101 fptreef(shf, indent, "%T%;", t->left);
102 t = t->right;
103 goto Chain;
104 case TOR:
105 case TAND:
106 fptreef(shf, indent, "%T%s %T",
107 t->left, (t->type == TOR) ? "||" : "&&", t->right);
108 break;
109 case TBANG:
110 shf_puts("! ", shf);
111 prevent_semicolon = false;
112 t = t->right;
113 goto Chain;
114 case TDBRACKET:
115 w = t->args;
116 shf_puts("[[", shf);
117 while (*w)
118 fptreef(shf, indent, " %S", *w++);
119 shf_puts(" ]] ", shf);
120 break;
121 case TSELECT:
122 case TFOR:
123 fptreef(shf, indent, "%s %s ",
124 (t->type == TFOR) ? "for" : Tselect, t->str);
125 if (t->vars != NULL) {
126 shf_puts("in ", shf);
127 w = (const char **)t->vars;
128 while (*w)
129 fptreef(shf, indent, "%S ", *w++);
130 fptreef(shf, indent, "%;");
131 }
132 fptreef(shf, indent + INDENT, "do%N%T", t->left);
133 fptreef(shf, indent, "%;done ");
134 break;
135 case TCASE:
136 fptreef(shf, indent, "case %S in", t->str);
137 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
138 fptreef(shf, indent, "%N(");
139 w = (const char **)t1->vars;
140 while (*w) {
141 fptreef(shf, indent, "%S%c", *w,
142 (w[1] != NULL) ? '|' : ')');
143 ++w;
144 }
145 fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
146 t1->u.charflag);
147 }
148 fptreef(shf, indent, "%Nesac ");
149 break;
150 #ifdef DEBUG
151 case TELIF:
152 internal_errorf("TELIF in tree.c:ptree() unexpected");
153 /* FALLTHROUGH */
154 #endif
155 case TIF:
156 i = 2;
157 t1 = t;
158 goto process_TIF;
159 do {
160 t1 = t1->right;
161 i = 0;
162 fptreef(shf, indent, "%;");
163 process_TIF:
164 /* 5 == strlen("elif ") */
165 fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
166 t1 = t1->right;
167 if (t1->left != NULL) {
168 fptreef(shf, indent, "%;");
169 fptreef(shf, indent + INDENT, "%s%N%T",
170 "then", t1->left);
171 }
172 } while (t1->right && t1->right->type == TELIF);
173 if (t1->right != NULL) {
174 fptreef(shf, indent, "%;");
175 fptreef(shf, indent + INDENT, "%s%N%T",
176 "else", t1->right);
177 }
178 fptreef(shf, indent, "%;fi ");
179 break;
180 case TWHILE:
181 case TUNTIL:
182 /* 6 == strlen("while "/"until ") */
183 fptreef(shf, indent + 6, "%s %T",
184 (t->type == TWHILE) ? "while" : "until",
185 t->left);
186 fptreef(shf, indent, "%;");
187 fptreef(shf, indent + INDENT, "do%N%T", t->right);
188 fptreef(shf, indent, "%;done ");
189 break;
190 case TBRACE:
191 fptreef(shf, indent + INDENT, "{%N%T", t->left);
192 fptreef(shf, indent, "%;} ");
193 break;
194 case TCOPROC:
195 fptreef(shf, indent, "%T|& ", t->left);
196 prevent_semicolon = true;
197 break;
198 case TASYNC:
199 fptreef(shf, indent, "%T& ", t->left);
200 prevent_semicolon = true;
201 break;
202 case TFUNCT:
203 fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
204 break;
205 case TTIME:
206 fptreef(shf, indent, "%s %T", "time", t->left);
207 break;
208 default:
209 shf_puts("<botch>", shf);
210 prevent_semicolon = false;
211 break;
212 }
213 if ((ioact = t->ioact) != NULL) {
214 bool need_nl = false;
215
216 while (*ioact != NULL)
217 pioact(shf, *ioact++);
218 /* Print here documents after everything else... */
219 ioact = t->ioact;
220 while (*ioact != NULL) {
221 struct ioword *iop = *ioact++;
222
223 /* heredoc is NULL when tracing (set -x) */
224 if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
225 iop->heredoc) {
226 shf_putc('\n', shf);
227 shf_puts(iop->heredoc, shf);
228 fptreef(shf, indent, "%s",
229 evalstr(iop->delim, 0));
230 need_nl = true;
231 }
232 }
233 /*
234 * Last delimiter must be followed by a newline (this
235 * often leads to an extra blank line, but it's not
236 * worth worrying about)
237 */
238 if (need_nl) {
239 shf_putc('\n', shf);
240 prevent_semicolon = true;
241 }
242 }
243 }
244
245 static void
pioact(struct shf * shf,struct ioword * iop)246 pioact(struct shf *shf, struct ioword *iop)
247 {
248 unsigned short flag = iop->ioflag;
249 unsigned short type = flag & IOTYPE;
250 short expected;
251
252 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
253 (type == IOCAT || type == IOWRITE) ? 1 :
254 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
255 iop->unit + 1;
256 if (iop->unit != expected)
257 shf_fprintf(shf, "%d", (int)iop->unit);
258
259 switch (type) {
260 case IOREAD:
261 shf_putc('<', shf);
262 break;
263 case IOHERE:
264 shf_puts("<<", shf);
265 if (flag & IOSKIP)
266 shf_putc('-', shf);
267 else if (flag & IOHERESTR)
268 shf_putc('<', shf);
269 break;
270 case IOCAT:
271 shf_puts(">>", shf);
272 break;
273 case IOWRITE:
274 shf_putc('>', shf);
275 if (flag & IOCLOB)
276 shf_putc('|', shf);
277 break;
278 case IORDWR:
279 shf_puts("<>", shf);
280 break;
281 case IODUP:
282 shf_puts(flag & IORDUP ? "<&" : ">&", shf);
283 break;
284 }
285 /* name/delim are NULL when printing syntax errors */
286 if (type == IOHERE) {
287 if (iop->delim && !(iop->ioflag & IONDELIM))
288 wdvarput(shf, iop->delim, 0, WDS_TPUTS);
289 } else if (iop->ioname) {
290 if (flag & IONAMEXP)
291 print_value_quoted(shf, iop->ioname);
292 else
293 wdvarput(shf, iop->ioname, 0, WDS_TPUTS);
294 }
295 shf_putc(' ', shf);
296 prevent_semicolon = false;
297 }
298
299 /* variant of fputs for ptreef and wdstrip */
300 static const char *
wdvarput(struct shf * shf,const char * wp,int quotelevel,int opmode)301 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
302 {
303 int c;
304 const char *cs;
305
306 /*-
307 * problems:
308 * `...` -> $(...)
309 * 'foo' -> "foo"
310 * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
311 * x${foo:-'hi'} -> x${foo:-hi}
312 * could change encoding to:
313 * OQUOTE ["'] ... CQUOTE ["']
314 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
315 */
316 while (/* CONSTCOND */ 1)
317 switch (*wp++) {
318 case EOS:
319 return (--wp);
320 case ADELIM:
321 if (*wp == /*{*/'}') {
322 ++wp;
323 goto wdvarput_csubst;
324 }
325 case CHAR:
326 c = *wp++;
327 shf_putc(c, shf);
328 break;
329 case QCHAR: {
330 bool doq;
331
332 c = *wp++;
333 doq = (c == '"' || c == '`' || c == '$' || c == '\\');
334 if (opmode & WDS_TPUTS) {
335 if (quotelevel == 0)
336 doq = true;
337 } else {
338 doq = false;
339 }
340 if (doq)
341 shf_putc('\\', shf);
342 shf_putc(c, shf);
343 break;
344 }
345 case COMSUB:
346 shf_puts("$(", shf);
347 cs = ")";
348 pSUB:
349 while ((c = *wp++) != 0)
350 shf_putc(c, shf);
351 shf_puts(cs, shf);
352 break;
353 case FUNSUB:
354 c = ' ';
355 if (0)
356 /* FALLTHROUGH */
357 case VALSUB:
358 c = '|';
359 shf_putc('$', shf);
360 shf_putc('{', shf);
361 shf_putc(c, shf);
362 cs = ";}";
363 goto pSUB;
364 case EXPRSUB:
365 shf_puts("$((", shf);
366 cs = "))";
367 goto pSUB;
368 case OQUOTE:
369 if (opmode & WDS_TPUTS) {
370 quotelevel++;
371 shf_putc('"', shf);
372 }
373 break;
374 case CQUOTE:
375 if (opmode & WDS_TPUTS) {
376 if (quotelevel)
377 quotelevel--;
378 shf_putc('"', shf);
379 }
380 break;
381 case OSUBST:
382 shf_putc('$', shf);
383 if (*wp++ == '{')
384 shf_putc('{', shf);
385 while ((c = *wp++) != 0)
386 shf_putc(c, shf);
387 wp = wdvarput(shf, wp, 0, opmode);
388 break;
389 case CSUBST:
390 if (*wp++ == '}') {
391 wdvarput_csubst:
392 shf_putc('}', shf);
393 }
394 return (wp);
395 case OPAT:
396 shf_putchar(*wp++, shf);
397 shf_putc('(', shf);
398 break;
399 case SPAT:
400 c = '|';
401 if (0)
402 case CPAT:
403 c = /*(*/ ')';
404 shf_putc(c, shf);
405 break;
406 }
407 }
408
409 /*
410 * this is the _only_ way to reliably handle
411 * variable args with an ANSI compiler
412 */
413 /* VARARGS */
414 void
fptreef(struct shf * shf,int indent,const char * fmt,...)415 fptreef(struct shf *shf, int indent, const char *fmt, ...)
416 {
417 va_list va;
418
419 va_start(va, fmt);
420 vfptreef(shf, indent, fmt, va);
421 va_end(va);
422 }
423
424 /* VARARGS */
425 char *
snptreef(char * s,ssize_t n,const char * fmt,...)426 snptreef(char *s, ssize_t n, const char *fmt, ...)
427 {
428 va_list va;
429 struct shf shf;
430
431 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
432
433 va_start(va, fmt);
434 vfptreef(&shf, 0, fmt, va);
435 va_end(va);
436
437 /* shf_sclose NUL terminates */
438 return (shf_sclose(&shf));
439 }
440
441 static void
vfptreef(struct shf * shf,int indent,const char * fmt,va_list va)442 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
443 {
444 int c;
445
446 while ((c = *fmt++)) {
447 if (c == '%') {
448 switch ((c = *fmt++)) {
449 case 'c':
450 /* character (octet, probably) */
451 shf_putchar(va_arg(va, int), shf);
452 break;
453 case 's':
454 /* string */
455 shf_puts(va_arg(va, char *), shf);
456 break;
457 case 'S':
458 /* word */
459 wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
460 break;
461 case 'd':
462 /* signed decimal */
463 shf_fprintf(shf, "%d", va_arg(va, int));
464 break;
465 case 'u':
466 /* unsigned decimal */
467 shf_fprintf(shf, "%u", va_arg(va, unsigned int));
468 break;
469 case 'T':
470 /* format tree */
471 ptree(va_arg(va, struct op *), indent, shf);
472 goto dont_trash_prevent_semicolon;
473 case ';':
474 /* newline or ; */
475 case 'N':
476 /* newline or space */
477 if (shf->flags & SHF_STRING) {
478 if (c == ';' && !prevent_semicolon)
479 shf_putc(';', shf);
480 shf_putc(' ', shf);
481 } else {
482 int i;
483
484 shf_putc('\n', shf);
485 i = indent;
486 while (i >= 8) {
487 shf_putc('\t', shf);
488 i -= 8;
489 }
490 while (i--)
491 shf_putc(' ', shf);
492 }
493 break;
494 case 'R':
495 /* I/O redirection */
496 pioact(shf, va_arg(va, struct ioword *));
497 break;
498 default:
499 shf_putc(c, shf);
500 break;
501 }
502 } else
503 shf_putc(c, shf);
504 prevent_semicolon = false;
505 dont_trash_prevent_semicolon:
506 ;
507 }
508 }
509
510 /*
511 * copy tree (for function definition)
512 */
513 struct op *
tcopy(struct op * t,Area * ap)514 tcopy(struct op *t, Area *ap)
515 {
516 struct op *r;
517 const char **tw;
518 char **rw;
519
520 if (t == NULL)
521 return (NULL);
522
523 r = alloc(sizeof(struct op), ap);
524
525 r->type = t->type;
526 r->u.evalflags = t->u.evalflags;
527
528 if (t->type == TCASE)
529 r->str = wdcopy(t->str, ap);
530 else
531 strdupx(r->str, t->str, ap);
532
533 if (t->vars == NULL)
534 r->vars = NULL;
535 else {
536 tw = (const char **)t->vars;
537 while (*tw)
538 ++tw;
539 rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
540 sizeof(*tw), ap);
541 tw = (const char **)t->vars;
542 while (*tw)
543 *rw++ = wdcopy(*tw++, ap);
544 *rw = NULL;
545 }
546
547 if (t->args == NULL)
548 r->args = NULL;
549 else {
550 tw = t->args;
551 while (*tw)
552 ++tw;
553 r->args = (const char **)(rw = alloc2(tw - t->args + 1,
554 sizeof(*tw), ap));
555 tw = t->args;
556 while (*tw)
557 *rw++ = wdcopy(*tw++, ap);
558 *rw = NULL;
559 }
560
561 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
562
563 r->left = tcopy(t->left, ap);
564 r->right = tcopy(t->right, ap);
565 r->lineno = t->lineno;
566
567 return (r);
568 }
569
570 char *
wdcopy(const char * wp,Area * ap)571 wdcopy(const char *wp, Area *ap)
572 {
573 size_t len;
574
575 len = wdscan(wp, EOS) - wp;
576 return (memcpy(alloc(len, ap), wp, len));
577 }
578
579 /* return the position of prefix c in wp plus 1 */
580 const char *
wdscan(const char * wp,int c)581 wdscan(const char *wp, int c)
582 {
583 int nest = 0;
584
585 while (/* CONSTCOND */ 1)
586 switch (*wp++) {
587 case EOS:
588 return (wp);
589 case ADELIM:
590 if (c == ADELIM && nest == 0)
591 return (wp + 1);
592 if (*wp == /*{*/'}')
593 goto wdscan_csubst;
594 /* FALLTHROUGH */
595 case CHAR:
596 case QCHAR:
597 wp++;
598 break;
599 case COMSUB:
600 case FUNSUB:
601 case VALSUB:
602 case EXPRSUB:
603 while (*wp++ != 0)
604 ;
605 break;
606 case OQUOTE:
607 case CQUOTE:
608 break;
609 case OSUBST:
610 nest++;
611 while (*wp++ != '\0')
612 ;
613 break;
614 case CSUBST:
615 wdscan_csubst:
616 wp++;
617 if (c == CSUBST && nest == 0)
618 return (wp);
619 nest--;
620 break;
621 case OPAT:
622 nest++;
623 wp++;
624 break;
625 case SPAT:
626 case CPAT:
627 if (c == wp[-1] && nest == 0)
628 return (wp);
629 if (wp[-1] == CPAT)
630 nest--;
631 break;
632 default:
633 internal_warningf(
634 "wdscan: unknown char 0x%x (carrying on)",
635 wp[-1]);
636 }
637 }
638
639 /*
640 * return a copy of wp without any of the mark up characters and with
641 * quote characters (" ' \) stripped. (string is allocated from ATEMP)
642 */
643 char *
wdstrip(const char * wp,int opmode)644 wdstrip(const char *wp, int opmode)
645 {
646 struct shf shf;
647
648 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
649 wdvarput(&shf, wp, 0, opmode);
650 /* shf_sclose NUL terminates */
651 return (shf_sclose(&shf));
652 }
653
654 static struct ioword **
iocopy(struct ioword ** iow,Area * ap)655 iocopy(struct ioword **iow, Area *ap)
656 {
657 struct ioword **ior;
658 int i;
659
660 ior = iow;
661 while (*ior)
662 ++ior;
663 ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
664
665 for (i = 0; iow[i] != NULL; i++) {
666 struct ioword *p, *q;
667
668 p = iow[i];
669 q = alloc(sizeof(struct ioword), ap);
670 ior[i] = q;
671 *q = *p;
672 if (p->ioname != NULL)
673 q->ioname = wdcopy(p->ioname, ap);
674 if (p->delim != NULL)
675 q->delim = wdcopy(p->delim, ap);
676 if (p->heredoc != NULL)
677 strdupx(q->heredoc, p->heredoc, ap);
678 }
679 ior[i] = NULL;
680
681 return (ior);
682 }
683
684 /*
685 * free tree (for function definition)
686 */
687 void
tfree(struct op * t,Area * ap)688 tfree(struct op *t, Area *ap)
689 {
690 char **w;
691
692 if (t == NULL)
693 return;
694
695 afree(t->str, ap);
696
697 if (t->vars != NULL) {
698 for (w = t->vars; *w != NULL; w++)
699 afree(*w, ap);
700 afree(t->vars, ap);
701 }
702
703 if (t->args != NULL) {
704 /*XXX we assume the caller is right */
705 union mksh_ccphack cw;
706
707 cw.ro = t->args;
708 for (w = cw.rw; *w != NULL; w++)
709 afree(*w, ap);
710 afree(t->args, ap);
711 }
712
713 if (t->ioact != NULL)
714 iofree(t->ioact, ap);
715
716 tfree(t->left, ap);
717 tfree(t->right, ap);
718
719 afree(t, ap);
720 }
721
722 static void
iofree(struct ioword ** iow,Area * ap)723 iofree(struct ioword **iow, Area *ap)
724 {
725 struct ioword **iop;
726 struct ioword *p;
727
728 iop = iow;
729 while ((p = *iop++) != NULL) {
730 afree(p->ioname, ap);
731 afree(p->delim, ap);
732 afree(p->heredoc, ap);
733 afree(p, ap);
734 }
735 afree(iow, ap);
736 }
737
738 void
fpFUNCTf(struct shf * shf,int i,bool isksh,const char * k,struct op * v)739 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
740 {
741 if (isksh)
742 fptreef(shf, i, "%s %s %T", Tfunction, k, v);
743 else if (ktsearch(&keywords, k, hash(k)))
744 fptreef(shf, i, "%s %s() %T", Tfunction, k, v);
745 else
746 fptreef(shf, i, "%s() %T", k, v);
747 }
748
749
750 /* for jobs.c */
751 void
vistree(char * dst,size_t sz,struct op * t)752 vistree(char *dst, size_t sz, struct op *t)
753 {
754 unsigned int c;
755 char *cp, *buf;
756 size_t n;
757
758 buf = alloc(sz + 16, ATEMP);
759 snptreef(buf, sz + 16, "%T", t);
760 cp = buf;
761 vist_loop:
762 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
763 if (c == 0 || n >= sz)
764 /* NUL or not enough free space */
765 goto vist_out;
766 /* copy multibyte char */
767 sz -= n;
768 while (n--)
769 *dst++ = *cp++;
770 goto vist_loop;
771 }
772 if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
773 /* NUL or not enough free space */
774 goto vist_out;
775 if (ISCTRL(c & 0x7F)) {
776 /* C0 or C1 control character or DEL */
777 if (--sz == 0)
778 /* not enough free space for two chars */
779 goto vist_out;
780 *dst++ = (c & 0x80) ? '$' : '^';
781 c = UNCTRL(c & 0x7F);
782 } else if (UTFMODE && c > 0x7F) {
783 /* better not try to display broken multibyte chars */
784 /* also go easy on the Unicode: no U+FFFD here */
785 c = '?';
786 }
787 *dst++ = c;
788 goto vist_loop;
789
790 vist_out:
791 *dst = '\0';
792 afree(buf, ATEMP);
793 }
794
795 #ifdef DEBUG
796 void
dumpchar(struct shf * shf,int c)797 dumpchar(struct shf *shf, int c)
798 {
799 if (ISCTRL(c & 0x7F)) {
800 /* C0 or C1 control character or DEL */
801 shf_putc((c & 0x80) ? '$' : '^', shf);
802 c = UNCTRL(c & 0x7F);
803 }
804 shf_putc(c, shf);
805 }
806
807 /* see: wdvarput */
808 static const char *
dumpwdvar_i(struct shf * shf,const char * wp,int quotelevel)809 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
810 {
811 int c;
812
813 while (/* CONSTCOND */ 1) {
814 switch(*wp++) {
815 case EOS:
816 shf_puts("EOS", shf);
817 return (--wp);
818 case ADELIM:
819 if (*wp == /*{*/'}') {
820 shf_puts("]ADELIM(})", shf);
821 return (wp + 1);
822 }
823 shf_puts("ADELIM=", shf);
824 if (0)
825 case CHAR:
826 shf_puts("CHAR=", shf);
827 dumpchar(shf, *wp++);
828 break;
829 case QCHAR:
830 shf_puts("QCHAR<", shf);
831 c = *wp++;
832 if (quotelevel == 0 ||
833 (c == '"' || c == '`' || c == '$' || c == '\\'))
834 shf_putc('\\', shf);
835 dumpchar(shf, c);
836 goto closeandout;
837 case COMSUB:
838 shf_puts("COMSUB<", shf);
839 dumpsub:
840 while ((c = *wp++) != 0)
841 dumpchar(shf, c);
842 closeandout:
843 shf_putc('>', shf);
844 break;
845 case FUNSUB:
846 shf_puts("FUNSUB<", shf);
847 goto dumpsub;
848 case VALSUB:
849 shf_puts("VALSUB<", shf);
850 goto dumpsub;
851 case EXPRSUB:
852 shf_puts("EXPRSUB<", shf);
853 goto dumpsub;
854 case OQUOTE:
855 shf_fprintf(shf, "OQUOTE{%d", ++quotelevel);
856 break;
857 case CQUOTE:
858 shf_fprintf(shf, "%d}CQUOTE", quotelevel);
859 if (quotelevel)
860 quotelevel--;
861 else
862 shf_puts("(err)", shf);
863 break;
864 case OSUBST:
865 shf_puts("OSUBST(", shf);
866 dumpchar(shf, *wp++);
867 shf_puts(")[", shf);
868 while ((c = *wp++) != 0)
869 dumpchar(shf, c);
870 shf_putc('|', shf);
871 wp = dumpwdvar_i(shf, wp, 0);
872 break;
873 case CSUBST:
874 shf_puts("]CSUBST(", shf);
875 dumpchar(shf, *wp++);
876 shf_putc(')', shf);
877 return (wp);
878 case OPAT:
879 shf_puts("OPAT=", shf);
880 dumpchar(shf, *wp++);
881 break;
882 case SPAT:
883 shf_puts("SPAT", shf);
884 break;
885 case CPAT:
886 shf_puts("CPAT", shf);
887 break;
888 default:
889 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
890 break;
891 }
892 shf_putc(' ', shf);
893 }
894 }
895 void
dumpwdvar(struct shf * shf,const char * wp)896 dumpwdvar(struct shf *shf, const char *wp)
897 {
898 dumpwdvar_i(shf, wp, 0);
899 }
900
901 void
dumpioact(struct shf * shf,struct op * t)902 dumpioact(struct shf *shf, struct op *t)
903 {
904 struct ioword **ioact, *iop;
905
906 if ((ioact = t->ioact) == NULL)
907 return;
908
909 shf_puts("{IOACT", shf);
910 while ((iop = *ioact++) != NULL) {
911 unsigned short type = iop->ioflag & IOTYPE;
912 #define DT(x) case x: shf_puts(#x, shf); break;
913 #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
914
915 shf_putc(';', shf);
916 switch (type) {
917 DT(IOREAD)
918 DT(IOWRITE)
919 DT(IORDWR)
920 DT(IOHERE)
921 DT(IOCAT)
922 DT(IODUP)
923 default:
924 shf_fprintf(shf, "unk%d", type);
925 }
926 DB(IOEVAL)
927 DB(IOSKIP)
928 DB(IOCLOB)
929 DB(IORDUP)
930 DB(IONAMEXP)
931 DB(IOBASH)
932 DB(IOHERESTR)
933 DB(IONDELIM)
934 shf_fprintf(shf, ",unit=%d", (int)iop->unit);
935 if (iop->delim && !(iop->ioflag & IONDELIM)) {
936 shf_puts(",delim<", shf);
937 dumpwdvar(shf, iop->delim);
938 shf_putc('>', shf);
939 }
940 if (iop->ioname) {
941 if (iop->ioflag & IONAMEXP) {
942 shf_puts(",name=", shf);
943 print_value_quoted(shf, iop->ioname);
944 } else {
945 shf_puts(",name<", shf);
946 dumpwdvar(shf, iop->ioname);
947 shf_putc('>', shf);
948 }
949 }
950 if (iop->heredoc) {
951 shf_puts(",heredoc=", shf);
952 print_value_quoted(shf, iop->heredoc);
953 }
954 #undef DT
955 #undef DB
956 }
957 shf_putc('}', shf);
958 }
959
960 void
dumptree(struct shf * shf,struct op * t)961 dumptree(struct shf *shf, struct op *t)
962 {
963 int i, j;
964 const char **w, *name;
965 struct op *t1;
966 static int nesting;
967
968 for (i = 0; i < nesting; ++i)
969 shf_putc('\t', shf);
970 ++nesting;
971 shf_puts("{tree:" /*}*/, shf);
972 if (t == NULL) {
973 name = "(null)";
974 goto out;
975 }
976 dumpioact(shf, t);
977 switch (t->type) {
978 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
979
980 OPEN(TCOM)
981 if (t->vars) {
982 i = 0;
983 w = (const char **)t->vars;
984 while (*w) {
985 shf_putc('\n', shf);
986 for (j = 0; j < nesting; ++j)
987 shf_putc('\t', shf);
988 shf_fprintf(shf, " var%d<", i++);
989 dumpwdvar(shf, *w++);
990 shf_putc('>', shf);
991 }
992 } else
993 shf_puts(" #no-vars#", shf);
994 if (t->args) {
995 i = 0;
996 w = t->args;
997 while (*w) {
998 shf_putc('\n', shf);
999 for (j = 0; j < nesting; ++j)
1000 shf_putc('\t', shf);
1001 shf_fprintf(shf, " arg%d<", i++);
1002 dumpwdvar(shf, *w++);
1003 shf_putc('>', shf);
1004 }
1005 } else
1006 shf_puts(" #no-args#", shf);
1007 break;
1008 OPEN(TEXEC)
1009 dumpleftandout:
1010 t = t->left;
1011 dumpandout:
1012 shf_putc('\n', shf);
1013 dumptree(shf, t);
1014 break;
1015 OPEN(TPAREN)
1016 goto dumpleftandout;
1017 OPEN(TPIPE)
1018 dumpleftmidrightandout:
1019 shf_putc('\n', shf);
1020 dumptree(shf, t->left);
1021 /* middumprightandout: (unused) */
1022 shf_fprintf(shf, "/%s:", name);
1023 dumprightandout:
1024 t = t->right;
1025 goto dumpandout;
1026 OPEN(TLIST)
1027 goto dumpleftmidrightandout;
1028 OPEN(TOR)
1029 goto dumpleftmidrightandout;
1030 OPEN(TAND)
1031 goto dumpleftmidrightandout;
1032 OPEN(TBANG)
1033 goto dumprightandout;
1034 OPEN(TDBRACKET)
1035 i = 0;
1036 w = t->args;
1037 while (*w) {
1038 shf_putc('\n', shf);
1039 for (j = 0; j < nesting; ++j)
1040 shf_putc('\t', shf);
1041 shf_fprintf(shf, " arg%d<", i++);
1042 dumpwdvar(shf, *w++);
1043 shf_putc('>', shf);
1044 }
1045 break;
1046 OPEN(TFOR)
1047 dumpfor:
1048 shf_fprintf(shf, " str<%s>", t->str);
1049 if (t->vars != NULL) {
1050 i = 0;
1051 w = (const char **)t->vars;
1052 while (*w) {
1053 shf_putc('\n', shf);
1054 for (j = 0; j < nesting; ++j)
1055 shf_putc('\t', shf);
1056 shf_fprintf(shf, " var%d<", i++);
1057 dumpwdvar(shf, *w++);
1058 shf_putc('>', shf);
1059 }
1060 }
1061 goto dumpleftandout;
1062 OPEN(TSELECT)
1063 goto dumpfor;
1064 OPEN(TCASE)
1065 shf_fprintf(shf, " str<%s>", t->str);
1066 i = 0;
1067 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1068 shf_putc('\n', shf);
1069 for (j = 0; j < nesting; ++j)
1070 shf_putc('\t', shf);
1071 shf_fprintf(shf, " sub%d[(", i);
1072 w = (const char **)t1->vars;
1073 while (*w) {
1074 dumpwdvar(shf, *w);
1075 if (w[1] != NULL)
1076 shf_putc('|', shf);
1077 ++w;
1078 }
1079 shf_putc(')', shf);
1080 dumpioact(shf, t);
1081 shf_putc('\n', shf);
1082 dumptree(shf, t1->left);
1083 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
1084 }
1085 break;
1086 OPEN(TWHILE)
1087 goto dumpleftmidrightandout;
1088 OPEN(TUNTIL)
1089 goto dumpleftmidrightandout;
1090 OPEN(TBRACE)
1091 goto dumpleftandout;
1092 OPEN(TCOPROC)
1093 goto dumpleftandout;
1094 OPEN(TASYNC)
1095 goto dumpleftandout;
1096 OPEN(TFUNCT)
1097 shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
1098 t->u.ksh_func ? "yes" : "no");
1099 goto dumpleftandout;
1100 OPEN(TTIME)
1101 goto dumpleftandout;
1102 OPEN(TIF)
1103 dumpif:
1104 shf_putc('\n', shf);
1105 dumptree(shf, t->left);
1106 t = t->right;
1107 dumpioact(shf, t);
1108 if (t->left != NULL) {
1109 shf_puts(" /TTHEN:\n", shf);
1110 dumptree(shf, t->left);
1111 }
1112 if (t->right && t->right->type == TELIF) {
1113 shf_puts(" /TELIF:", shf);
1114 t = t->right;
1115 dumpioact(shf, t);
1116 goto dumpif;
1117 }
1118 if (t->right != NULL) {
1119 shf_puts(" /TELSE:\n", shf);
1120 dumptree(shf, t->right);
1121 }
1122 break;
1123 OPEN(TEOF)
1124 dumpunexpected:
1125 shf_puts("unexpected", shf);
1126 break;
1127 OPEN(TELIF)
1128 goto dumpunexpected;
1129 OPEN(TPAT)
1130 goto dumpunexpected;
1131 default:
1132 name = "TINVALID";
1133 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
1134 goto dumpunexpected;
1135
1136 #undef OPEN
1137 }
1138 out:
1139 shf_fprintf(shf, /*{*/ " /%s}\n", name);
1140 --nesting;
1141 }
1142 #endif
1143