1 /* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5 * 2011, 2012, 2013, 2015
6 * Thorsten Glaser <tg@mirbsd.org>
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.
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.
26 __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.72.2.1 2015/04/12 22:32:35 tg Exp $");
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 *);
37 /* "foo& ; bar" and "foo |& ; bar" are invalid */
38 static bool prevent_semicolon;
40 static const char Telif_pT[] = "elif %T";
43 * print a command tree
46 ptree(struct op *t, int indent, struct shf *shf)
49 struct ioword **ioact;
58 prevent_semicolon = false;
60 * special-case 'var=<<EOF' (rough; see
61 * exec.c:execute() for full code)
64 /* we have zero arguments, i.e. no programme to run */
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]);
78 w = (const char **)t->vars;
80 fptreef(shf, indent, "%S ", *w++);
82 shf_puts("#no-vars# ", shf);
86 fptreef(shf, indent, "%S ", *w++);
88 shf_puts("#no-args# ", shf);
94 fptreef(shf, indent + 2, "( %T) ", t->left);
97 fptreef(shf, indent, "%T| ", t->left);
101 fptreef(shf, indent, "%T%;", t->left);
106 fptreef(shf, indent, "%T%s %T",
107 t->left, (t->type == TOR) ? "||" : "&&", t->right);
111 prevent_semicolon = false;
118 fptreef(shf, indent, " %S", *w++);
119 shf_puts(" ]] ", shf);
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;
129 fptreef(shf, indent, "%S ", *w++);
130 fptreef(shf, indent, "%;");
132 fptreef(shf, indent + INDENT, "do%N%T", t->left);
133 fptreef(shf, indent, "%;done ");
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;
141 fptreef(shf, indent, "%S%c", *w,
142 (w[1] != NULL) ? '|' : ')');
145 fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
148 fptreef(shf, indent, "%Nesac ");
152 internal_errorf("TELIF in tree.c:ptree() unexpected");
162 fptreef(shf, indent, "%;");
164 /* 5 == strlen("elif ") */
165 fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
167 if (t1->left != NULL) {
168 fptreef(shf, indent, "%;");
169 fptreef(shf, indent + INDENT, "%s%N%T",
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",
178 fptreef(shf, indent, "%;fi ");
182 /* 6 == strlen("while "/"until ") */
183 fptreef(shf, indent + 6, "%s %T",
184 (t->type == TWHILE) ? "while" : "until",
186 fptreef(shf, indent, "%;");
187 fptreef(shf, indent + INDENT, "do%N%T", t->right);
188 fptreef(shf, indent, "%;done ");
191 fptreef(shf, indent + INDENT, "{%N%T", t->left);
192 fptreef(shf, indent, "%;} ");
195 fptreef(shf, indent, "%T|& ", t->left);
196 prevent_semicolon = true;
199 fptreef(shf, indent, "%T& ", t->left);
200 prevent_semicolon = true;
203 fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
206 fptreef(shf, indent, "%s %T", "time", t->left);
209 shf_puts("<botch>", shf);
210 prevent_semicolon = false;
213 if ((ioact = t->ioact) != NULL) {
214 bool need_nl = false;
216 while (*ioact != NULL)
217 pioact(shf, *ioact++);
218 /* Print here documents after everything else... */
220 while (*ioact != NULL) {
221 struct ioword *iop = *ioact++;
223 /* heredoc is NULL when tracing (set -x) */
224 if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
227 shf_puts(iop->heredoc, shf);
228 fptreef(shf, indent, "%s",
229 iop->ioflag & IONDELIM ? "<<" :
230 evalstr(iop->delim, 0));
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)
241 prevent_semicolon = true;
247 pioact(struct shf *shf, struct ioword *iop)
249 unsigned short flag = iop->ioflag;
250 unsigned short type = flag & IOTYPE;
253 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
254 (type == IOCAT || type == IOWRITE) ? 1 :
255 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
257 if (iop->unit != expected)
258 shf_fprintf(shf, "%d", (int)iop->unit);
281 shf_puts(flag & IORDUP ? "<&" : ">&", shf);
284 /* name/delim are NULL when printing syntax errors */
285 if (type == IOHERE) {
287 wdvarput(shf, iop->delim, 0, WDS_TPUTS);
288 if (flag & IOHERESTR)
290 } else if (iop->name) {
292 print_value_quoted(shf, iop->name);
294 wdvarput(shf, iop->name, 0, WDS_TPUTS);
297 prevent_semicolon = false;
300 /* variant of fputs for ptreef and wdstrip */
302 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
311 * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
312 * x${foo:-'hi'} -> x${foo:-hi} unless WDS_KEEPQ
313 * could change encoding to:
314 * OQUOTE ["'] ... CQUOTE ["']
315 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
317 while (/* CONSTCOND */ 1)
324 if ((opmode & WDS_MAGIC) &&
325 (ISMAGIC(c) || c == '[' || c == '!' ||
326 c == '-' || c == ']' || c == '*' || c == '?'))
327 shf_putc(MAGIC, shf);
334 doq = (c == '"' || c == '`' || c == '$' || c == '\\');
335 if (opmode & WDS_TPUTS) {
339 if (!(opmode & WDS_KEEPQ))
351 while ((c = *wp++) != 0)
367 shf_puts("$((", shf);
371 if (opmode & WDS_TPUTS) {
377 if (opmode & WDS_TPUTS) {
387 while ((c = *wp++) != 0)
389 wp = wdvarput(shf, wp, 0, opmode);
396 if (opmode & WDS_MAGIC) {
397 shf_putc(MAGIC, shf);
398 shf_putchar(*wp++ | 0x80, shf);
400 shf_putchar(*wp++, shf);
409 if (opmode & WDS_MAGIC)
410 shf_putc(MAGIC, shf);
417 * this is the _only_ way to reliably handle
418 * variable args with an ANSI compiler
422 fptreef(struct shf *shf, int indent, const char *fmt, ...)
427 vfptreef(shf, indent, fmt, va);
433 snptreef(char *s, ssize_t n, const char *fmt, ...)
438 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
441 vfptreef(&shf, 0, fmt, va);
444 /* shf_sclose NUL terminates */
445 return (shf_sclose(&shf));
449 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
453 while ((c = *fmt++)) {
455 switch ((c = *fmt++)) {
457 /* character (octet, probably) */
458 shf_putchar(va_arg(va, int), shf);
462 shf_puts(va_arg(va, char *), shf);
466 wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
470 shf_fprintf(shf, "%d", va_arg(va, int));
473 /* unsigned decimal */
474 shf_fprintf(shf, "%u", va_arg(va, unsigned int));
478 ptree(va_arg(va, struct op *), indent, shf);
479 goto dont_trash_prevent_semicolon;
483 /* newline or space */
484 if (shf->flags & SHF_STRING) {
485 if (c == ';' && !prevent_semicolon)
502 /* I/O redirection */
503 pioact(shf, va_arg(va, struct ioword *));
511 prevent_semicolon = false;
512 dont_trash_prevent_semicolon:
518 * copy tree (for function definition)
521 tcopy(struct op *t, Area *ap)
530 r = alloc(sizeof(struct op), ap);
533 r->u.evalflags = t->u.evalflags;
535 if (t->type == TCASE)
536 r->str = wdcopy(t->str, ap);
538 strdupx(r->str, t->str, ap);
543 tw = (const char **)t->vars;
546 rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
548 tw = (const char **)t->vars;
550 *rw++ = wdcopy(*tw++, ap);
560 r->args = (const char **)(rw = alloc2(tw - t->args + 1,
564 *rw++ = wdcopy(*tw++, ap);
568 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
570 r->left = tcopy(t->left, ap);
571 r->right = tcopy(t->right, ap);
572 r->lineno = t->lineno;
578 wdcopy(const char *wp, Area *ap)
582 len = wdscan(wp, EOS) - wp;
583 return (memcpy(alloc(len, ap), wp, len));
586 /* return the position of prefix c in wp plus 1 */
588 wdscan(const char *wp, int c)
592 while (/* CONSTCOND */ 1)
616 while (*wp++ != '\0')
621 if (c == CSUBST && nest == 0)
631 if (c == wp[-1] && nest == 0)
638 "wdscan: unknown char 0x%x (carrying on)",
644 * return a copy of wp without any of the mark up characters and with
645 * quote characters (" ' \) stripped. (string is allocated from ATEMP)
648 wdstrip(const char *wp, int opmode)
652 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
653 wdvarput(&shf, wp, 0, opmode);
654 /* shf_sclose NUL terminates */
655 return (shf_sclose(&shf));
658 static struct ioword **
659 iocopy(struct ioword **iow, Area *ap)
667 ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
669 for (i = 0; iow[i] != NULL; i++) {
670 struct ioword *p, *q;
673 q = alloc(sizeof(struct ioword), ap);
677 q->name = wdcopy(p->name, ap);
678 if (p->delim != NULL)
679 q->delim = wdcopy(p->delim, ap);
680 if (p->heredoc != NULL)
681 strdupx(q->heredoc, p->heredoc, ap);
689 * free tree (for function definition)
692 tfree(struct op *t, Area *ap)
702 if (t->vars != NULL) {
703 for (w = t->vars; *w != NULL; w++)
708 if (t->args != NULL) {
709 /*XXX we assume the caller is right */
710 union mksh_ccphack cw;
713 for (w = cw.rw; *w != NULL; w++)
718 if (t->ioact != NULL)
719 iofree(t->ioact, ap);
728 iofree(struct ioword **iow, Area *ap)
734 while ((p = *iop++) != NULL) {
737 if (p->delim != NULL)
739 if (p->heredoc != NULL)
740 afree(p->heredoc, ap);
747 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
750 fptreef(shf, i, "%s %s %T", Tfunction, k, v);
752 fptreef(shf, i, "%s() %T", k, v);
758 vistree(char *dst, size_t sz, struct op *t)
764 buf = alloc(sz + 16, ATEMP);
765 snptreef(buf, sz + 16, "%T", t);
768 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
769 if (c == 0 || n >= sz)
770 /* NUL or not enough free space */
772 /* copy multibyte char */
778 if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
779 /* NUL or not enough free space */
781 if (ISCTRL(c & 0x7F)) {
782 /* C0 or C1 control character or DEL */
784 /* not enough free space for two chars */
786 *dst++ = (c & 0x80) ? '$' : '^';
787 c = UNCTRL(c & 0x7F);
788 } else if (UTFMODE && c > 0x7F) {
789 /* better not try to display broken multibyte chars */
790 /* also go easy on the Unicode: no U+FFFD here */
803 dumpchar(struct shf *shf, int c)
805 if (ISCTRL(c & 0x7F)) {
806 /* C0 or C1 control character or DEL */
807 shf_putc((c & 0x80) ? '$' : '^', shf);
808 c = UNCTRL(c & 0x7F);
815 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
819 while (/* CONSTCOND */ 1) {
822 shf_puts("EOS", shf);
825 shf_puts("ADELIM=", shf);
828 shf_puts("CHAR=", shf);
829 dumpchar(shf, *wp++);
832 shf_puts("QCHAR<", shf);
834 if (quotelevel == 0 ||
835 (c == '"' || c == '`' || c == '$' || c == '\\'))
840 shf_puts("COMSUB<", shf);
842 while ((c = *wp++) != 0)
848 shf_puts("FUNSUB<", shf);
851 shf_puts("VALSUB<", shf);
854 shf_puts("EXPRSUB<", shf);
857 shf_fprintf(shf, "OQUOTE{%d", ++quotelevel);
860 shf_fprintf(shf, "%d}CQUOTE", quotelevel);
864 shf_puts("(err)", shf);
867 shf_puts("OSUBST(", shf);
868 dumpchar(shf, *wp++);
870 while ((c = *wp++) != 0)
873 wp = dumpwdvar_i(shf, wp, 0);
876 shf_puts("]CSUBST(", shf);
877 dumpchar(shf, *wp++);
881 shf_puts("OPAT=", shf);
882 dumpchar(shf, *wp++);
885 shf_puts("SPAT", shf);
888 shf_puts("CPAT", shf);
891 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
898 dumpwdvar(struct shf *shf, const char *wp)
900 dumpwdvar_i(shf, wp, 0);
904 dumpioact(struct shf *shf, struct op *t)
906 struct ioword **ioact, *iop;
908 if ((ioact = t->ioact) == NULL)
911 shf_puts("{IOACT", shf);
912 while ((iop = *ioact++) != NULL) {
913 unsigned short type = iop->ioflag & IOTYPE;
914 #define DT(x) case x: shf_puts(#x, shf); break;
915 #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
926 shf_fprintf(shf, "unk%d", type);
936 shf_fprintf(shf, ",unit=%d", (int)iop->unit);
938 shf_puts(",delim<", shf);
939 dumpwdvar(shf, iop->delim);
943 if (iop->ioflag & IONAMEXP) {
944 shf_puts(",name=", shf);
945 print_value_quoted(shf, iop->name);
947 shf_puts(",name<", shf);
948 dumpwdvar(shf, iop->name);
953 shf_puts(",heredoc=", shf);
954 print_value_quoted(shf, iop->heredoc);
963 dumptree(struct shf *shf, struct op *t)
966 const char **w, *name;
970 for (i = 0; i < nesting; ++i)
973 shf_puts("{tree:" /*}*/, shf);
980 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
985 w = (const char **)t->vars;
988 for (j = 0; j < nesting; ++j)
990 shf_fprintf(shf, " var%d<", i++);
991 dumpwdvar(shf, *w++);
995 shf_puts(" #no-vars#", shf);
1000 shf_putc('\n', shf);
1001 for (j = 0; j < nesting; ++j)
1002 shf_putc('\t', shf);
1003 shf_fprintf(shf, " arg%d<", i++);
1004 dumpwdvar(shf, *w++);
1008 shf_puts(" #no-args#", shf);
1014 shf_putc('\n', shf);
1018 goto dumpleftandout;
1020 dumpleftmidrightandout:
1021 shf_putc('\n', shf);
1022 dumptree(shf, t->left);
1023 /* middumprightandout: (unused) */
1024 shf_fprintf(shf, "/%s:", name);
1029 goto dumpleftmidrightandout;
1031 goto dumpleftmidrightandout;
1033 goto dumpleftmidrightandout;
1035 goto dumprightandout;
1040 shf_putc('\n', shf);
1041 for (j = 0; j < nesting; ++j)
1042 shf_putc('\t', shf);
1043 shf_fprintf(shf, " arg%d<", i++);
1044 dumpwdvar(shf, *w++);
1050 shf_fprintf(shf, " str<%s>", t->str);
1051 if (t->vars != NULL) {
1053 w = (const char **)t->vars;
1055 shf_putc('\n', shf);
1056 for (j = 0; j < nesting; ++j)
1057 shf_putc('\t', shf);
1058 shf_fprintf(shf, " var%d<", i++);
1059 dumpwdvar(shf, *w++);
1063 goto dumpleftandout;
1067 shf_fprintf(shf, " str<%s>", t->str);
1069 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1070 shf_putc('\n', shf);
1071 for (j = 0; j < nesting; ++j)
1072 shf_putc('\t', shf);
1073 shf_fprintf(shf, " sub%d[(", i);
1074 w = (const char **)t1->vars;
1083 shf_putc('\n', shf);
1084 dumptree(shf, t1->left);
1085 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
1089 goto dumpleftmidrightandout;
1091 goto dumpleftmidrightandout;
1093 goto dumpleftandout;
1095 goto dumpleftandout;
1097 goto dumpleftandout;
1099 shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
1100 t->u.ksh_func ? "yes" : "no");
1101 goto dumpleftandout;
1103 goto dumpleftandout;
1106 shf_putc('\n', shf);
1107 dumptree(shf, t->left);
1110 if (t->left != NULL) {
1111 shf_puts(" /TTHEN:\n", shf);
1112 dumptree(shf, t->left);
1114 if (t->right && t->right->type == TELIF) {
1115 shf_puts(" /TELIF:", shf);
1120 if (t->right != NULL) {
1121 shf_puts(" /TELSE:\n", shf);
1122 dumptree(shf, t->right);
1127 shf_puts("unexpected", shf);
1130 goto dumpunexpected;
1132 goto dumpunexpected;
1135 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
1136 goto dumpunexpected;
1141 shf_fprintf(shf, /*{*/ " /%s}\n", name);