1 /* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
2
3 /*-
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5 * 2011, 2012
6 * Thorsten Glaser <tg@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.67 2012/12/04 01:10:35 tg Exp $");
27
28 #define INDENT 8
29
30 static void ptree(struct op *, int, struct shf *);
31 static void pioact(struct shf *, int, 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]->flag & 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, indent, *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->flag & (IOTYPE | IOHERESTR)) == IOHERE &&
225 iop->heredoc) {
226 shf_putc('\n', shf);
227 shf_puts(iop->heredoc, shf);
228 fptreef(shf, indent, "%s",
229 iop->flag & IONDELIM ? "<<" :
230 evalstr(iop->delim, 0));
231 need_nl = true;
232 }
233 }
234 /*
235 * Last delimiter must be followed by a newline (this
236 * often leads to an extra blank line, but it's not
237 * worth worrying about)
238 */
239 if (need_nl) {
240 shf_putc('\n', shf);
241 prevent_semicolon = true;
242 }
243 }
244 }
245
246 static void
pioact(struct shf * shf,int indent,struct ioword * iop)247 pioact(struct shf *shf, int indent, struct ioword *iop)
248 {
249 int flag = iop->flag;
250 int type = flag & IOTYPE;
251 int expected;
252
253 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
254 (type == IOCAT || type == IOWRITE) ? 1 :
255 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
256 iop->unit + 1;
257 if (iop->unit != expected)
258 shf_fprintf(shf, "%d", iop->unit);
259
260 switch (type) {
261 case IOREAD:
262 shf_puts("<", shf);
263 break;
264 case IOHERE:
265 shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
266 break;
267 case IOCAT:
268 shf_puts(">>", shf);
269 break;
270 case IOWRITE:
271 shf_puts(flag & IOCLOB ? ">|" : ">", shf);
272 break;
273 case IORDWR:
274 shf_puts("<>", shf);
275 break;
276 case IODUP:
277 shf_puts(flag & IORDUP ? "<&" : ">&", shf);
278 break;
279 }
280 /* name/delim are NULL when printing syntax errors */
281 if (type == IOHERE) {
282 if (iop->delim)
283 wdvarput(shf, iop->delim, 0, WDS_TPUTS);
284 if (iop->flag & IOHERESTR)
285 shf_putc(' ', shf);
286 } else if (iop->name)
287 fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
288 iop->name);
289 prevent_semicolon = false;
290 }
291
292 /* variant of fputs for ptreef and wdstrip */
293 static const char *
wdvarput(struct shf * shf,const char * wp,int quotelevel,int opmode)294 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
295 {
296 int c;
297 const char *cs;
298
299 /*-
300 * problems:
301 * `...` -> $(...)
302 * 'foo' -> "foo"
303 * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
304 * x${foo:-'hi'} -> x${foo:-hi} unless WDS_KEEPQ
305 * could change encoding to:
306 * OQUOTE ["'] ... CQUOTE ["']
307 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
308 */
309 while (/* CONSTCOND */ 1)
310 switch (*wp++) {
311 case EOS:
312 return (--wp);
313 case ADELIM:
314 case CHAR:
315 c = *wp++;
316 if ((opmode & WDS_MAGIC) &&
317 (ISMAGIC(c) || c == '[' || c == '!' ||
318 c == '-' || c == ']' || c == '*' || c == '?'))
319 shf_putc(MAGIC, shf);
320 shf_putc(c, shf);
321 break;
322 case QCHAR: {
323 bool doq;
324
325 c = *wp++;
326 doq = (c == '"' || c == '`' || c == '$' || c == '\\');
327 if (opmode & WDS_TPUTS) {
328 if (quotelevel == 0)
329 doq = true;
330 } else {
331 if (!(opmode & WDS_KEEPQ))
332 doq = false;
333 }
334 if (doq)
335 shf_putc('\\', shf);
336 shf_putc(c, shf);
337 break;
338 }
339 case COMSUB:
340 shf_puts("$(", shf);
341 cs = ")";
342 pSUB:
343 while ((c = *wp++) != 0)
344 shf_putc(c, shf);
345 shf_puts(cs, shf);
346 break;
347 case FUNSUB:
348 shf_puts("${ ", shf);
349 cs = ";}";
350 goto pSUB;
351 case EXPRSUB:
352 shf_puts("$((", shf);
353 cs = "))";
354 goto pSUB;
355 case OQUOTE:
356 if (opmode & WDS_TPUTS) {
357 quotelevel++;
358 shf_putc('"', shf);
359 }
360 break;
361 case CQUOTE:
362 if (opmode & WDS_TPUTS) {
363 if (quotelevel)
364 quotelevel--;
365 shf_putc('"', shf);
366 }
367 break;
368 case OSUBST:
369 shf_putc('$', shf);
370 if (*wp++ == '{')
371 shf_putc('{', shf);
372 while ((c = *wp++) != 0)
373 shf_putc(c, shf);
374 wp = wdvarput(shf, wp, 0, opmode);
375 break;
376 case CSUBST:
377 if (*wp++ == '}')
378 shf_putc('}', shf);
379 return (wp);
380 case OPAT:
381 if (opmode & WDS_MAGIC) {
382 shf_putc(MAGIC, shf);
383 shf_putchar(*wp++ | 0x80, shf);
384 } else {
385 shf_putchar(*wp++, shf);
386 shf_putc('(', shf);
387 }
388 break;
389 case SPAT:
390 c = '|';
391 if (0)
392 case CPAT:
393 c = /*(*/ ')';
394 if (opmode & WDS_MAGIC)
395 shf_putc(MAGIC, shf);
396 shf_putc(c, shf);
397 break;
398 }
399 }
400
401 /*
402 * this is the _only_ way to reliably handle
403 * variable args with an ANSI compiler
404 */
405 /* VARARGS */
406 void
fptreef(struct shf * shf,int indent,const char * fmt,...)407 fptreef(struct shf *shf, int indent, const char *fmt, ...)
408 {
409 va_list va;
410
411 va_start(va, fmt);
412 vfptreef(shf, indent, fmt, va);
413 va_end(va);
414 }
415
416 /* VARARGS */
417 char *
snptreef(char * s,ssize_t n,const char * fmt,...)418 snptreef(char *s, ssize_t n, const char *fmt, ...)
419 {
420 va_list va;
421 struct shf shf;
422
423 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
424
425 va_start(va, fmt);
426 vfptreef(&shf, 0, fmt, va);
427 va_end(va);
428
429 /* shf_sclose NUL terminates */
430 return (shf_sclose(&shf));
431 }
432
433 static void
vfptreef(struct shf * shf,int indent,const char * fmt,va_list va)434 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
435 {
436 int c;
437
438 while ((c = *fmt++)) {
439 if (c == '%') {
440 switch ((c = *fmt++)) {
441 case 'c':
442 /* character (octet, probably) */
443 shf_putchar(va_arg(va, int), shf);
444 break;
445 case 's':
446 /* string */
447 shf_puts(va_arg(va, char *), shf);
448 break;
449 case 'S':
450 /* word */
451 wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
452 break;
453 case 'd':
454 /* signed decimal */
455 shf_fprintf(shf, "%d", va_arg(va, int));
456 break;
457 case 'u':
458 /* unsigned decimal */
459 shf_fprintf(shf, "%u", va_arg(va, unsigned int));
460 break;
461 case 'T':
462 /* format tree */
463 ptree(va_arg(va, struct op *), indent, shf);
464 goto dont_trash_prevent_semicolon;
465 case ';':
466 /* newline or ; */
467 case 'N':
468 /* newline or space */
469 if (shf->flags & SHF_STRING) {
470 if (c == ';' && !prevent_semicolon)
471 shf_putc(';', shf);
472 shf_putc(' ', shf);
473 } else {
474 int i;
475
476 shf_putc('\n', shf);
477 i = indent;
478 while (i >= 8) {
479 shf_putc('\t', shf);
480 i -= 8;
481 }
482 while (i--)
483 shf_putc(' ', shf);
484 }
485 break;
486 case 'R':
487 /* I/O redirection */
488 pioact(shf, indent, va_arg(va, struct ioword *));
489 break;
490 default:
491 shf_putc(c, shf);
492 break;
493 }
494 } else
495 shf_putc(c, shf);
496 prevent_semicolon = false;
497 dont_trash_prevent_semicolon:
498 ;
499 }
500 }
501
502 /*
503 * copy tree (for function definition)
504 */
505 struct op *
tcopy(struct op * t,Area * ap)506 tcopy(struct op *t, Area *ap)
507 {
508 struct op *r;
509 const char **tw;
510 char **rw;
511
512 if (t == NULL)
513 return (NULL);
514
515 r = alloc(sizeof(struct op), ap);
516
517 r->type = t->type;
518 r->u.evalflags = t->u.evalflags;
519
520 if (t->type == TCASE)
521 r->str = wdcopy(t->str, ap);
522 else
523 strdupx(r->str, t->str, ap);
524
525 if (t->vars == NULL)
526 r->vars = NULL;
527 else {
528 tw = (const char **)t->vars;
529 while (*tw)
530 ++tw;
531 rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
532 sizeof(*tw), ap);
533 tw = (const char **)t->vars;
534 while (*tw)
535 *rw++ = wdcopy(*tw++, ap);
536 *rw = NULL;
537 }
538
539 if (t->args == NULL)
540 r->args = NULL;
541 else {
542 tw = t->args;
543 while (*tw)
544 ++tw;
545 r->args = (const char **)(rw = alloc2(tw - t->args + 1,
546 sizeof(*tw), ap));
547 tw = t->args;
548 while (*tw)
549 *rw++ = wdcopy(*tw++, ap);
550 *rw = NULL;
551 }
552
553 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
554
555 r->left = tcopy(t->left, ap);
556 r->right = tcopy(t->right, ap);
557 r->lineno = t->lineno;
558
559 return (r);
560 }
561
562 char *
wdcopy(const char * wp,Area * ap)563 wdcopy(const char *wp, Area *ap)
564 {
565 size_t len;
566
567 len = wdscan(wp, EOS) - wp;
568 return (memcpy(alloc(len, ap), wp, len));
569 }
570
571 /* return the position of prefix c in wp plus 1 */
572 const char *
wdscan(const char * wp,int c)573 wdscan(const char *wp, int c)
574 {
575 int nest = 0;
576
577 while (/* CONSTCOND */ 1)
578 switch (*wp++) {
579 case EOS:
580 return (wp);
581 case ADELIM:
582 if (c == ADELIM)
583 return (wp + 1);
584 /* FALLTHROUGH */
585 case CHAR:
586 case QCHAR:
587 wp++;
588 break;
589 case COMSUB:
590 case FUNSUB:
591 case EXPRSUB:
592 while (*wp++ != 0)
593 ;
594 break;
595 case OQUOTE:
596 case CQUOTE:
597 break;
598 case OSUBST:
599 nest++;
600 while (*wp++ != '\0')
601 ;
602 break;
603 case CSUBST:
604 wp++;
605 if (c == CSUBST && nest == 0)
606 return (wp);
607 nest--;
608 break;
609 case OPAT:
610 nest++;
611 wp++;
612 break;
613 case SPAT:
614 case CPAT:
615 if (c == wp[-1] && nest == 0)
616 return (wp);
617 if (wp[-1] == CPAT)
618 nest--;
619 break;
620 default:
621 internal_warningf(
622 "wdscan: unknown char 0x%x (carrying on)",
623 wp[-1]);
624 }
625 }
626
627 /*
628 * return a copy of wp without any of the mark up characters and with
629 * quote characters (" ' \) stripped. (string is allocated from ATEMP)
630 */
631 char *
wdstrip(const char * wp,int opmode)632 wdstrip(const char *wp, int opmode)
633 {
634 struct shf shf;
635
636 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
637 wdvarput(&shf, wp, 0, opmode);
638 /* shf_sclose NUL terminates */
639 return (shf_sclose(&shf));
640 }
641
642 static struct ioword **
iocopy(struct ioword ** iow,Area * ap)643 iocopy(struct ioword **iow, Area *ap)
644 {
645 struct ioword **ior;
646 int i;
647
648 ior = iow;
649 while (*ior)
650 ++ior;
651 ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
652
653 for (i = 0; iow[i] != NULL; i++) {
654 struct ioword *p, *q;
655
656 p = iow[i];
657 q = alloc(sizeof(struct ioword), ap);
658 ior[i] = q;
659 *q = *p;
660 if (p->name != NULL)
661 q->name = wdcopy(p->name, ap);
662 if (p->delim != NULL)
663 q->delim = wdcopy(p->delim, ap);
664 if (p->heredoc != NULL)
665 strdupx(q->heredoc, p->heredoc, ap);
666 }
667 ior[i] = NULL;
668
669 return (ior);
670 }
671
672 /*
673 * free tree (for function definition)
674 */
675 void
tfree(struct op * t,Area * ap)676 tfree(struct op *t, Area *ap)
677 {
678 char **w;
679
680 if (t == NULL)
681 return;
682
683 if (t->str != NULL)
684 afree(t->str, ap);
685
686 if (t->vars != NULL) {
687 for (w = t->vars; *w != NULL; w++)
688 afree(*w, ap);
689 afree(t->vars, ap);
690 }
691
692 if (t->args != NULL) {
693 /*XXX we assume the caller is right */
694 union mksh_ccphack cw;
695
696 cw.ro = t->args;
697 for (w = cw.rw; *w != NULL; w++)
698 afree(*w, ap);
699 afree(t->args, ap);
700 }
701
702 if (t->ioact != NULL)
703 iofree(t->ioact, ap);
704
705 tfree(t->left, ap);
706 tfree(t->right, ap);
707
708 afree(t, ap);
709 }
710
711 static void
iofree(struct ioword ** iow,Area * ap)712 iofree(struct ioword **iow, Area *ap)
713 {
714 struct ioword **iop;
715 struct ioword *p;
716
717 iop = iow;
718 while ((p = *iop++) != NULL) {
719 if (p->name != NULL)
720 afree(p->name, ap);
721 if (p->delim != NULL)
722 afree(p->delim, ap);
723 if (p->heredoc != NULL)
724 afree(p->heredoc, ap);
725 afree(p, ap);
726 }
727 afree(iow, ap);
728 }
729
730 void
fpFUNCTf(struct shf * shf,int i,bool isksh,const char * k,struct op * v)731 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
732 {
733 if (isksh)
734 fptreef(shf, i, "%s %s %T", Tfunction, k, v);
735 else
736 fptreef(shf, i, "%s() %T", k, v);
737 }
738
739
740 /* for jobs.c */
741 void
vistree(char * dst,size_t sz,struct op * t)742 vistree(char *dst, size_t sz, struct op *t)
743 {
744 unsigned int c;
745 char *cp, *buf;
746 size_t n;
747
748 buf = alloc(sz + 8, ATEMP);
749 snptreef(buf, sz + 8, "%T", t);
750 cp = buf;
751 vist_loop:
752 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
753 if (c == 0 || n >= sz)
754 /* NUL or not enough free space */
755 goto vist_out;
756 /* copy multibyte char */
757 sz -= n;
758 while (n--)
759 *dst++ = *cp++;
760 goto vist_loop;
761 }
762 if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
763 /* NUL or not enough free space */
764 goto vist_out;
765 if ((c & 0x60) == 0 || (c & 0x7F) == 0x7F) {
766 /* C0 or C1 control character or DEL */
767 if (--sz == 0)
768 /* not enough free space for two chars */
769 goto vist_out;
770 *dst++ = (c & 0x80) ? '$' : '^';
771 c = (c & 0x7F) ^ 0x40;
772 } else if (UTFMODE && c > 0x7F) {
773 /* better not try to display broken multibyte chars */
774 c = '?';
775 }
776 *dst++ = c;
777 goto vist_loop;
778
779 vist_out:
780 *dst = '\0';
781 afree(buf, ATEMP);
782 }
783
784 #ifdef DEBUG
785 void
dumpchar(struct shf * shf,int c)786 dumpchar(struct shf *shf, int c)
787 {
788 if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) {
789 /* C0 or C1 control character or DEL */
790 shf_putc((c & 0x80) ? '$' : '^', shf);
791 c = (c & 0x7F) ^ 0x40;
792 }
793 shf_putc(c, shf);
794 }
795
796 /* see: wdvarput */
797 static const char *
dumpwdvar_i(struct shf * shf,const char * wp,int quotelevel)798 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
799 {
800 int c;
801
802 while (/* CONSTCOND */ 1) {
803 switch(*wp++) {
804 case EOS:
805 shf_puts("EOS", shf);
806 return (--wp);
807 case ADELIM:
808 shf_puts("ADELIM=", shf);
809 if (0)
810 case CHAR:
811 shf_puts("CHAR=", shf);
812 dumpchar(shf, *wp++);
813 break;
814 case QCHAR:
815 shf_puts("QCHAR<", shf);
816 c = *wp++;
817 if (quotelevel == 0 ||
818 (c == '"' || c == '`' || c == '$' || c == '\\'))
819 shf_putc('\\', shf);
820 dumpchar(shf, c);
821 goto closeandout;
822 case COMSUB:
823 shf_puts("COMSUB<", shf);
824 dumpsub:
825 while ((c = *wp++) != 0)
826 dumpchar(shf, c);
827 closeandout:
828 shf_putc('>', shf);
829 break;
830 case FUNSUB:
831 shf_puts("FUNSUB<", shf);
832 goto dumpsub;
833 case EXPRSUB:
834 shf_puts("EXPRSUB<", shf);
835 goto dumpsub;
836 case OQUOTE:
837 shf_fprintf(shf, "OQUOTE{%d", ++quotelevel);
838 break;
839 case CQUOTE:
840 shf_fprintf(shf, "%d}CQUOTE", quotelevel);
841 if (quotelevel)
842 quotelevel--;
843 else
844 shf_puts("(err)", shf);
845 break;
846 case OSUBST:
847 shf_puts("OSUBST(", shf);
848 dumpchar(shf, *wp++);
849 shf_puts(")[", shf);
850 while ((c = *wp++) != 0)
851 dumpchar(shf, c);
852 shf_putc('|', shf);
853 wp = dumpwdvar_i(shf, wp, 0);
854 break;
855 case CSUBST:
856 shf_puts("]CSUBST(", shf);
857 dumpchar(shf, *wp++);
858 shf_putc(')', shf);
859 return (wp);
860 case OPAT:
861 shf_puts("OPAT=", shf);
862 dumpchar(shf, *wp++);
863 break;
864 case SPAT:
865 shf_puts("SPAT", shf);
866 break;
867 case CPAT:
868 shf_puts("CPAT", shf);
869 break;
870 default:
871 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
872 break;
873 }
874 shf_putc(' ', shf);
875 }
876 }
877 void
dumpwdvar(struct shf * shf,const char * wp)878 dumpwdvar(struct shf *shf, const char *wp)
879 {
880 dumpwdvar_i(shf, wp, 0);
881 }
882
883 void
dumpioact(struct shf * shf,struct op * t)884 dumpioact(struct shf *shf, struct op *t)
885 {
886 struct ioword **ioact, *iop;
887
888 if ((ioact = t->ioact) == NULL)
889 return;
890
891 shf_puts("{IOACT", shf);
892 while ((iop = *ioact++) != NULL) {
893 int type = iop->flag & IOTYPE;
894 #define DT(x) case x: shf_puts(#x, shf); break;
895 #define DB(x) if (iop->flag & x) shf_puts("|" #x, shf);
896
897 shf_putc(';', shf);
898 switch (type) {
899 DT(IOREAD)
900 DT(IOWRITE)
901 DT(IORDWR)
902 DT(IOHERE)
903 DT(IOCAT)
904 DT(IODUP)
905 default:
906 shf_fprintf(shf, "unk%d", type);
907 }
908 DB(IOEVAL)
909 DB(IOSKIP)
910 DB(IOCLOB)
911 DB(IORDUP)
912 DB(IONAMEXP)
913 DB(IOBASH)
914 DB(IOHERESTR)
915 DB(IONDELIM)
916 shf_fprintf(shf, ",unit=%d", iop->unit);
917 if (iop->delim) {
918 shf_puts(",delim<", shf);
919 dumpwdvar(shf, iop->delim);
920 shf_putc('>', shf);
921 }
922 if (iop->name) {
923 if (iop->flag & IONAMEXP) {
924 shf_puts(",name=", shf);
925 print_value_quoted(shf, iop->name);
926 } else {
927 shf_puts(",name<", shf);
928 dumpwdvar(shf, iop->name);
929 shf_putc('>', shf);
930 }
931 }
932 if (iop->heredoc) {
933 shf_puts(",heredoc=", shf);
934 print_value_quoted(shf, iop->heredoc);
935 }
936 #undef DT
937 #undef DB
938 }
939 shf_putc('}', shf);
940 }
941
942 void
dumptree(struct shf * shf,struct op * t)943 dumptree(struct shf *shf, struct op *t)
944 {
945 int i, j;
946 const char **w, *name;
947 struct op *t1;
948 static int nesting;
949
950 for (i = 0; i < nesting; ++i)
951 shf_putc('\t', shf);
952 ++nesting;
953 shf_puts("{tree:" /*}*/, shf);
954 if (t == NULL) {
955 name = "(null)";
956 goto out;
957 }
958 dumpioact(shf, t);
959 switch (t->type) {
960 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
961
962 OPEN(TCOM)
963 if (t->vars) {
964 i = 0;
965 w = (const char **)t->vars;
966 while (*w) {
967 shf_putc('\n', shf);
968 for (j = 0; j < nesting; ++j)
969 shf_putc('\t', shf);
970 shf_fprintf(shf, " var%d<", i++);
971 dumpwdvar(shf, *w++);
972 shf_putc('>', shf);
973 }
974 } else
975 shf_puts(" #no-vars#", shf);
976 if (t->args) {
977 i = 0;
978 w = t->args;
979 while (*w) {
980 shf_putc('\n', shf);
981 for (j = 0; j < nesting; ++j)
982 shf_putc('\t', shf);
983 shf_fprintf(shf, " arg%d<", i++);
984 dumpwdvar(shf, *w++);
985 shf_putc('>', shf);
986 }
987 } else
988 shf_puts(" #no-args#", shf);
989 break;
990 OPEN(TEXEC)
991 dumpleftandout:
992 t = t->left;
993 dumpandout:
994 shf_putc('\n', shf);
995 dumptree(shf, t);
996 break;
997 OPEN(TPAREN)
998 goto dumpleftandout;
999 OPEN(TPIPE)
1000 dumpleftmidrightandout:
1001 shf_putc('\n', shf);
1002 dumptree(shf, t->left);
1003 /* middumprightandout: (unused) */
1004 shf_fprintf(shf, "/%s:", name);
1005 dumprightandout:
1006 t = t->right;
1007 goto dumpandout;
1008 OPEN(TLIST)
1009 goto dumpleftmidrightandout;
1010 OPEN(TOR)
1011 goto dumpleftmidrightandout;
1012 OPEN(TAND)
1013 goto dumpleftmidrightandout;
1014 OPEN(TBANG)
1015 goto dumprightandout;
1016 OPEN(TDBRACKET)
1017 i = 0;
1018 w = t->args;
1019 while (*w) {
1020 shf_putc('\n', shf);
1021 for (j = 0; j < nesting; ++j)
1022 shf_putc('\t', shf);
1023 shf_fprintf(shf, " arg%d<", i++);
1024 dumpwdvar(shf, *w++);
1025 shf_putc('>', shf);
1026 }
1027 break;
1028 OPEN(TFOR)
1029 dumpfor:
1030 shf_fprintf(shf, " str<%s>", t->str);
1031 if (t->vars != NULL) {
1032 i = 0;
1033 w = (const char **)t->vars;
1034 while (*w) {
1035 shf_putc('\n', shf);
1036 for (j = 0; j < nesting; ++j)
1037 shf_putc('\t', shf);
1038 shf_fprintf(shf, " var%d<", i++);
1039 dumpwdvar(shf, *w++);
1040 shf_putc('>', shf);
1041 }
1042 }
1043 goto dumpleftandout;
1044 OPEN(TSELECT)
1045 goto dumpfor;
1046 OPEN(TCASE)
1047 shf_fprintf(shf, " str<%s>", t->str);
1048 i = 0;
1049 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1050 shf_putc('\n', shf);
1051 for (j = 0; j < nesting; ++j)
1052 shf_putc('\t', shf);
1053 shf_fprintf(shf, " sub%d[(", i);
1054 w = (const char **)t1->vars;
1055 while (*w) {
1056 dumpwdvar(shf, *w);
1057 if (w[1] != NULL)
1058 shf_putc('|', shf);
1059 ++w;
1060 }
1061 shf_putc(')', shf);
1062 dumpioact(shf, t);
1063 shf_putc('\n', shf);
1064 dumptree(shf, t1->left);
1065 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
1066 }
1067 break;
1068 OPEN(TWHILE)
1069 goto dumpleftmidrightandout;
1070 OPEN(TUNTIL)
1071 goto dumpleftmidrightandout;
1072 OPEN(TBRACE)
1073 goto dumpleftandout;
1074 OPEN(TCOPROC)
1075 goto dumpleftandout;
1076 OPEN(TASYNC)
1077 goto dumpleftandout;
1078 OPEN(TFUNCT)
1079 shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
1080 t->u.ksh_func ? "yes" : "no");
1081 goto dumpleftandout;
1082 OPEN(TTIME)
1083 goto dumpleftandout;
1084 OPEN(TIF)
1085 dumpif:
1086 shf_putc('\n', shf);
1087 dumptree(shf, t->left);
1088 t = t->right;
1089 dumpioact(shf, t);
1090 if (t->left != NULL) {
1091 shf_puts(" /TTHEN:\n", shf);
1092 dumptree(shf, t->left);
1093 }
1094 if (t->right && t->right->type == TELIF) {
1095 shf_puts(" /TELIF:", shf);
1096 t = t->right;
1097 dumpioact(shf, t);
1098 goto dumpif;
1099 }
1100 if (t->right != NULL) {
1101 shf_puts(" /TELSE:\n", shf);
1102 dumptree(shf, t->right);
1103 }
1104 break;
1105 OPEN(TEOF)
1106 dumpunexpected:
1107 shf_puts("unexpected", shf);
1108 break;
1109 OPEN(TELIF)
1110 goto dumpunexpected;
1111 OPEN(TPAT)
1112 goto dumpunexpected;
1113 default:
1114 name = "TINVALID";
1115 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
1116 goto dumpunexpected;
1117
1118 #undef OPEN
1119 }
1120 out:
1121 shf_fprintf(shf, /*{*/ " /%s}\n", name);
1122 --nesting;
1123 }
1124 #endif
1125