1 /* $OpenBSD: tree.c,v 1.21 2015/09/01 13:12:31 tedu Exp $ */
4 * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
5 * 2011, 2012, 2013, 2015, 2016, 2017
6 * mirabilos <m@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.95 2018/01/14 00:03:05 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;
59 prevent_semicolon = false;
60 /* special-case 'var=<<EOF' (cf. exec.c:execute) */
62 /* we have zero arguments, i.e. no program to run */
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]);
82 w = (const char **)t->vars;
84 fptreef(shf, indent, Tf_S_, *w++);
86 shf_puts("#no-vars# ", shf);
89 if (*w && **w == CHAR) {
90 char *cp = wdstrip(*w++, WDS_TPUTS);
92 if (valid_alias_name(cp))
99 fptreef(shf, indent, Tf_S_, *w++);
101 shf_puts("#no-args# ", shf);
107 fptreef(shf, indent + 2, "( %T) ", t->left);
110 fptreef(shf, indent, "%T| ", t->left);
114 fptreef(shf, indent, "%T%;", t->left);
119 fptreef(shf, indent, "%T%s %T",
120 t->left, (t->type == TOR) ? "||" : "&&", t->right);
124 prevent_semicolon = false;
131 fptreef(shf, indent, Tf__S, *w++);
132 shf_puts(" ]] ", shf);
136 fptreef(shf, indent, "%s %s ",
137 (t->type == TFOR) ? "for" : Tselect, t->str);
138 if (t->vars != NULL) {
139 shf_puts("in ", shf);
140 w = (const char **)t->vars;
142 fptreef(shf, indent, Tf_S_, *w++);
143 fptreef(shf, indent, Tft_end);
145 fptreef(shf, indent + INDENT, "do%N%T", t->left);
146 fptreef(shf, indent, "%;done ");
149 fptreef(shf, indent, "case %S in", t->str);
150 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
151 fptreef(shf, indent, "%N(");
152 w = (const char **)t1->vars;
154 fptreef(shf, indent, "%S%c", *w,
155 (w[1] != NULL) ? '|' : ')');
158 fptreef(shf, indent + INDENT, "%N%T%N;%c", t1->left,
161 fptreef(shf, indent, "%Nesac ");
164 internal_errorf(TELIF_unexpected);
173 fptreef(shf, indent, Tft_end);
175 /* 5 == strlen("elif ") */
176 fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
178 if (t1->left != NULL) {
179 fptreef(shf, indent, Tft_end);
180 fptreef(shf, indent + INDENT, "%s%N%T",
183 } while (t1->right && t1->right->type == TELIF);
184 if (t1->right != NULL) {
185 fptreef(shf, indent, Tft_end);
186 fptreef(shf, indent + INDENT, "%s%N%T",
189 fptreef(shf, indent, "%;fi ");
193 /* 6 == strlen("while "/"until ") */
194 fptreef(shf, indent + 6, Tf_s_T,
195 (t->type == TWHILE) ? "while" : "until",
197 fptreef(shf, indent, Tft_end);
198 fptreef(shf, indent + INDENT, "do%N%T", t->right);
199 fptreef(shf, indent, "%;done ");
202 fptreef(shf, indent + INDENT, "{%N%T", t->left);
203 fptreef(shf, indent, "%;} ");
206 fptreef(shf, indent, "%T|& ", t->left);
207 prevent_semicolon = true;
210 fptreef(shf, indent, "%T& ", t->left);
211 prevent_semicolon = true;
214 fpFUNCTf(shf, indent, tobool(t->u.ksh_func), t->str, t->left);
217 fptreef(shf, indent, Tf_s_T, Ttime, t->left);
220 shf_puts("<botch>", shf);
221 prevent_semicolon = false;
224 if ((ioact = t->ioact) != NULL) {
225 bool need_nl = false;
227 while (*ioact != NULL)
228 pioact(shf, *ioact++);
229 /* Print here documents after everything else... */
231 while (*ioact != NULL) {
232 struct ioword *iop = *ioact++;
234 /* heredoc is NULL when tracing (set -x) */
235 if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
238 shf_puts(iop->heredoc, shf);
239 fptreef(shf, indent, Tf_s,
240 evalstr(iop->delim, 0));
245 * Last delimiter must be followed by a newline (this
246 * often leads to an extra blank line, but it's not
247 * worth worrying about)
251 prevent_semicolon = true;
257 pioact(struct shf *shf, struct ioword *iop)
259 unsigned short flag = iop->ioflag;
260 unsigned short type = flag & IOTYPE;
263 expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
264 (type == IOCAT || type == IOWRITE) ? 1 :
265 (type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
267 if (iop->unit != expected)
268 shf_fprintf(shf, Tf_d, (int)iop->unit);
278 else if (flag & IOHERESTR)
293 shf_puts(flag & IORDUP ? "<&" : ">&", shf);
296 /* name/delim are NULL when printing syntax errors */
297 if (type == IOHERE) {
298 if (iop->delim && !(iop->ioflag & IONDELIM))
299 wdvarput(shf, iop->delim, 0, WDS_TPUTS);
300 } else if (iop->ioname) {
302 print_value_quoted(shf, iop->ioname);
304 wdvarput(shf, iop->ioname, 0, WDS_TPUTS);
307 prevent_semicolon = false;
310 /* variant of fputs for ptreef and wdstrip */
312 wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
321 * x${foo:-"hi"} -> x${foo:-hi} unless WDS_TPUTS
322 * x${foo:-'hi'} -> x${foo:-hi}
323 * could change encoding to:
324 * OQUOTE ["'] ... CQUOTE ["']
325 * COMSUB [(`] ...\0 (handle $ ` \ and maybe " in `...` case)
327 while (/* CONSTCOND */ 1)
332 if (ord(*wp) == ORD(/*{*/ '}')) {
334 goto wdvarput_csubst;
343 if (opmode & WDS_TPUTS)
346 if (quotelevel == 0) {
349 shf_putc(ORD('\n'), shf);
359 shf_putc(ORD('\\'), shf);
368 if (ord(*wp) == ORD('(' /*)*/))
371 while ((c = *wp++) != 0)
388 shf_puts("$((", shf);
392 if (opmode & WDS_TPUTS) {
398 if (opmode & WDS_TPUTS) {
406 if (ord(*wp++) == ORD('{'))
408 while ((c = *wp++) != 0)
410 wp = wdvarput(shf, wp, 0, opmode);
413 if (ord(*wp++) == ORD('}')) {
419 shf_putchar(*wp++, shf);
434 * this is the _only_ way to reliably handle
435 * variable args with an ANSI compiler
439 fptreef(struct shf *shf, int indent, const char *fmt, ...)
444 vfptreef(shf, indent, fmt, va);
450 snptreef(char *s, ssize_t n, const char *fmt, ...)
455 shf_sopen(s, n, SHF_WR | (s ? 0 : SHF_DYNAMIC), &shf);
458 vfptreef(&shf, 0, fmt, va);
461 /* shf_sclose NUL terminates */
462 return (shf_sclose(&shf));
466 vfptreef(struct shf *shf, int indent, const char *fmt, va_list va)
470 while ((c = ord(*fmt++))) {
472 switch ((c = ord(*fmt++))) {
474 /* character (octet, probably) */
475 shf_putchar(va_arg(va, int), shf);
479 shf_puts(va_arg(va, char *), shf);
483 wdvarput(shf, va_arg(va, char *), 0, WDS_TPUTS);
487 shf_fprintf(shf, Tf_d, va_arg(va, int));
490 /* unsigned decimal */
491 shf_fprintf(shf, "%u", va_arg(va, unsigned int));
495 ptree(va_arg(va, struct op *), indent, shf);
496 goto dont_trash_prevent_semicolon;
500 /* newline or space */
501 if (shf->flags & SHF_STRING) {
502 if ((unsigned int)c == ORD(';') &&
520 /* I/O redirection */
521 pioact(shf, va_arg(va, struct ioword *));
529 prevent_semicolon = false;
530 dont_trash_prevent_semicolon:
536 * copy tree (for function definition)
539 tcopy(struct op *t, Area *ap)
548 r = alloc(sizeof(struct op), ap);
551 r->u.evalflags = t->u.evalflags;
553 if (t->type == TCASE)
554 r->str = wdcopy(t->str, ap);
556 strdupx(r->str, t->str, ap);
561 tw = (const char **)t->vars;
564 rw = r->vars = alloc2(tw - (const char **)t->vars + 1,
566 tw = (const char **)t->vars;
568 *rw++ = wdcopy(*tw++, ap);
578 r->args = (const char **)(rw = alloc2(tw - t->args + 1,
582 *rw++ = wdcopy(*tw++, ap);
586 r->ioact = (t->ioact == NULL) ? NULL : iocopy(t->ioact, ap);
588 r->left = tcopy(t->left, ap);
589 r->right = tcopy(t->right, ap);
590 r->lineno = t->lineno;
596 wdcopy(const char *wp, Area *ap)
600 len = wdscan(wp, EOS) - wp;
601 return (memcpy(alloc(len, ap), wp, len));
604 /* return the position of prefix c in wp plus 1 */
606 wdscan(const char *wp, int c)
610 while (/* CONSTCOND */ 1)
615 if (c == ADELIM && nest == 0)
617 if (ord(*wp) == ORD(/*{*/ '}'))
638 while (*wp++ != '\0')
644 if (c == CSUBST && nest == 0)
654 if (c == wp[-1] && nest == 0)
661 "wdscan: unknown char 0x%X (carrying on)",
662 (unsigned char)wp[-1]);
667 * return a copy of wp without any of the mark up characters and with
668 * quote characters (" ' \) stripped. (string is allocated from ATEMP)
671 wdstrip(const char *wp, int opmode)
675 shf_sopen(NULL, 32, SHF_WR | SHF_DYNAMIC, &shf);
676 wdvarput(&shf, wp, 0, opmode);
677 /* shf_sclose NUL terminates */
678 return (shf_sclose(&shf));
681 static struct ioword **
682 iocopy(struct ioword **iow, Area *ap)
690 ior = alloc2(ior - iow + 1, sizeof(struct ioword *), ap);
692 for (i = 0; iow[i] != NULL; i++) {
693 struct ioword *p, *q;
696 q = alloc(sizeof(struct ioword), ap);
699 if (p->ioname != NULL)
700 q->ioname = wdcopy(p->ioname, ap);
701 if (p->delim != NULL)
702 q->delim = wdcopy(p->delim, ap);
703 if (p->heredoc != NULL)
704 strdupx(q->heredoc, p->heredoc, ap);
712 * free tree (for function definition)
715 tfree(struct op *t, Area *ap)
724 if (t->vars != NULL) {
725 for (w = t->vars; *w != NULL; w++)
730 if (t->args != NULL) {
731 /*XXX we assume the caller is right */
732 union mksh_ccphack cw;
735 for (w = cw.rw; *w != NULL; w++)
740 if (t->ioact != NULL)
741 iofree(t->ioact, ap);
750 iofree(struct ioword **iow, Area *ap)
756 while ((p = *iop++) != NULL) {
757 afree(p->ioname, ap);
759 afree(p->heredoc, ap);
766 fpFUNCTf(struct shf *shf, int i, bool isksh, const char *k, struct op *v)
769 fptreef(shf, i, "%s %s %T", Tfunction, k, v);
770 else if (ktsearch(&keywords, k, hash(k)))
771 fptreef(shf, i, "%s %s() %T", Tfunction, k, v);
773 fptreef(shf, i, "%s() %T", k, v);
779 vistree(char *dst, size_t sz, struct op *t)
785 buf = alloc(sz + 16, ATEMP);
786 snptreef(buf, sz + 16, Tf_T, t);
789 if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
790 if (c == 0 || n >= sz)
791 /* NUL or not enough free space */
793 /* copy multibyte char */
799 if (--sz == 0 || (c = ord(*cp++)) == 0)
800 /* NUL or not enough free space */
803 /* C0 or C1 control character or DEL */
805 /* not enough free space for two chars */
809 } else if (UTFMODE && rtt2asc(c) > 0x7F) {
810 /* better not try to display broken multibyte chars */
811 /* also go easy on the Unicode: no U+FFFD here */
824 dumpchar(struct shf *shf, int c)
827 /* C0 or C1 control character or DEL */
836 dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
840 while (/* CONSTCOND */ 1) {
843 shf_puts("EOS", shf);
846 if (ord(*wp) == ORD(/*{*/ '}')) {
847 shf_puts(/*{*/ "]ADELIM(})", shf);
850 shf_puts("ADELIM=", shf);
854 shf_puts("CHAR=", shf);
855 dumpchar(shf, *wp++);
858 shf_puts("QCHAR<", shf);
860 if (quotelevel == 0 || c == ORD('"') ||
861 c == ORD('\\') || ctype(c, C_DOLAR | C_GRAVE))
866 shf_puts("COMASUB<", shf);
869 shf_puts("COMSUB<", shf);
871 while ((c = *wp++) != 0)
877 shf_puts("FUNASUB<", shf);
880 shf_puts("FUNSUB<", shf);
883 shf_puts("VALSUB<", shf);
886 shf_puts("EXPRSUB<", shf);
889 shf_fprintf(shf, "OQUOTE{%d" /*}*/, ++quotelevel);
892 shf_fprintf(shf, /*{*/ "%d}CQUOTE", quotelevel);
896 shf_puts("(err)", shf);
899 shf_puts("OSUBST(", shf);
900 dumpchar(shf, *wp++);
902 while ((c = *wp++) != 0)
905 wp = dumpwdvar_i(shf, wp, 0);
908 shf_puts("]CSUBST(", shf);
909 dumpchar(shf, *wp++);
913 shf_puts("OPAT=", shf);
914 dumpchar(shf, *wp++);
917 shf_puts("SPAT", shf);
920 shf_puts("CPAT", shf);
923 shf_fprintf(shf, "INVAL<%u>", (uint8_t)wp[-1]);
930 dumpwdvar(struct shf *shf, const char *wp)
932 dumpwdvar_i(shf, wp, 0);
936 dumpioact(struct shf *shf, struct op *t)
938 struct ioword **ioact, *iop;
940 if ((ioact = t->ioact) == NULL)
943 shf_puts("{IOACT", shf);
944 while ((iop = *ioact++) != NULL) {
945 unsigned short type = iop->ioflag & IOTYPE;
946 #define DT(x) case x: shf_puts(#x, shf); break;
947 #define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
958 shf_fprintf(shf, "unk%d", type);
968 shf_fprintf(shf, ",unit=%d", (int)iop->unit);
969 if (iop->delim && !(iop->ioflag & IONDELIM)) {
970 shf_puts(",delim<", shf);
971 dumpwdvar(shf, iop->delim);
975 if (iop->ioflag & IONAMEXP) {
976 shf_puts(",name=", shf);
977 print_value_quoted(shf, iop->ioname);
979 shf_puts(",name<", shf);
980 dumpwdvar(shf, iop->ioname);
985 shf_puts(",heredoc=", shf);
986 print_value_quoted(shf, iop->heredoc);
995 dumptree(struct shf *shf, struct op *t)
998 const char **w, *name;
1002 for (i = 0; i < nesting; ++i)
1003 shf_putc('\t', shf);
1005 shf_puts("{tree:" /*}*/, shf);
1012 #define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
1017 w = (const char **)t->vars;
1019 shf_putc('\n', shf);
1020 for (j = 0; j < nesting; ++j)
1021 shf_putc('\t', shf);
1022 shf_fprintf(shf, " var%d<", i++);
1023 dumpwdvar(shf, *w++);
1027 shf_puts(" #no-vars#", shf);
1032 shf_putc('\n', shf);
1033 for (j = 0; j < nesting; ++j)
1034 shf_putc('\t', shf);
1035 shf_fprintf(shf, " arg%d<", i++);
1036 dumpwdvar(shf, *w++);
1040 shf_puts(" #no-args#", shf);
1046 shf_putc('\n', shf);
1050 goto dumpleftandout;
1052 dumpleftmidrightandout:
1053 shf_putc('\n', shf);
1054 dumptree(shf, t->left);
1055 /* middumprightandout: (unused) */
1056 shf_fprintf(shf, "/%s:", name);
1061 goto dumpleftmidrightandout;
1063 goto dumpleftmidrightandout;
1065 goto dumpleftmidrightandout;
1067 goto dumprightandout;
1072 shf_putc('\n', shf);
1073 for (j = 0; j < nesting; ++j)
1074 shf_putc('\t', shf);
1075 shf_fprintf(shf, " arg%d<", i++);
1076 dumpwdvar(shf, *w++);
1082 shf_fprintf(shf, " str<%s>", t->str);
1083 if (t->vars != NULL) {
1085 w = (const char **)t->vars;
1087 shf_putc('\n', shf);
1088 for (j = 0; j < nesting; ++j)
1089 shf_putc('\t', shf);
1090 shf_fprintf(shf, " var%d<", i++);
1091 dumpwdvar(shf, *w++);
1095 goto dumpleftandout;
1099 shf_fprintf(shf, " str<%s>", t->str);
1101 for (t1 = t->left; t1 != NULL; t1 = t1->right) {
1102 shf_putc('\n', shf);
1103 for (j = 0; j < nesting; ++j)
1104 shf_putc('\t', shf);
1105 shf_fprintf(shf, " sub%d[(", i);
1106 w = (const char **)t1->vars;
1115 shf_putc('\n', shf);
1116 dumptree(shf, t1->left);
1117 shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
1121 goto dumpleftmidrightandout;
1123 goto dumpleftmidrightandout;
1125 goto dumpleftandout;
1127 goto dumpleftandout;
1129 goto dumpleftandout;
1131 shf_fprintf(shf, " str<%s> ksh<%s>", t->str,
1132 t->u.ksh_func ? Ttrue : Tfalse);
1133 goto dumpleftandout;
1135 goto dumpleftandout;
1138 shf_putc('\n', shf);
1139 dumptree(shf, t->left);
1142 if (t->left != NULL) {
1143 shf_puts(" /TTHEN:\n", shf);
1144 dumptree(shf, t->left);
1146 if (t->right && t->right->type == TELIF) {
1147 shf_puts(" /TELIF:", shf);
1152 if (t->right != NULL) {
1153 shf_puts(" /TELSE:\n", shf);
1154 dumptree(shf, t->right);
1159 shf_puts(Tunexpected, shf);
1162 goto dumpunexpected;
1164 goto dumpunexpected;
1167 shf_fprintf(shf, "{T<%d>:" /*}*/, t->type);
1168 goto dumpunexpected;
1173 shf_fprintf(shf, /*{*/ " /%s}\n", name);