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