-/* $OpenBSD: tree.c,v 1.19 2008/08/11 21:50:35 jaredy Exp $ */
+/* $OpenBSD: tree.c,v 1.20 2012/06/27 07:17:19 otto Exp $ */
/*-
- * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
+ * Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
+ * 2011, 2012, 2013, 2015
* Thorsten Glaser <tg@mirbsd.org>
*
* Provided that these terms and disclaimer and all copyright notices
#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.51 2011/09/07 15:24:21 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.73 2015/04/11 22:03:32 tg Exp $");
#define INDENT 8
static void ptree(struct op *, int, struct shf *);
-static void pioact(struct shf *, int, struct ioword *);
+static void pioact(struct shf *, struct ioword *);
static const char *wdvarput(struct shf *, const char *, int, int);
static void vfptreef(struct shf *, int, const char *, va_list);
static struct ioword **iocopy(struct ioword **, Area *);
/* "foo& ; bar" and "foo |& ; bar" are invalid */
static bool prevent_semicolon;
+static const char Telif_pT[] = "elif %T";
+
/*
* print a command tree
*/
return;
switch (t->type) {
case TCOM:
+ prevent_semicolon = false;
+ /*
+ * special-case 'var=<<EOF' (rough; see
+ * exec.c:execute() for full code)
+ */
+ if (
+ /* we have zero arguments, i.e. no programme to run */
+ t->args[0] == NULL &&
+ /* we have exactly one variable assignment */
+ t->vars[0] != NULL && t->vars[1] == NULL &&
+ /* we have exactly one I/O redirection */
+ t->ioact != NULL && t->ioact[0] != NULL &&
+ t->ioact[1] == NULL &&
+ /* of type "here document" (or "here string") */
+ (t->ioact[0]->ioflag & IOTYPE) == IOHERE) {
+ fptreef(shf, indent, "%S", t->vars[0]);
+ break;
+ }
+
if (t->vars) {
w = (const char **)t->vars;
while (*w)
fptreef(shf, indent, "%S ", *w++);
} else
shf_puts("#no-args# ", shf);
- prevent_semicolon = false;
break;
case TEXEC:
t = t->left;
}
fptreef(shf, indent, "%Nesac ");
break;
-#ifndef MKSH_NO_DEPRECATED_WARNING
+#ifdef DEBUG
case TELIF:
internal_errorf("TELIF in tree.c:ptree() unexpected");
/* FALLTHROUGH */
#endif
case TIF:
i = 2;
+ t1 = t;
goto process_TIF;
do {
- t = t->right;
+ t1 = t1->right;
i = 0;
fptreef(shf, indent, "%;");
process_TIF:
/* 5 == strlen("elif ") */
- fptreef(shf, indent + 5 - i, "elif %T" + i, t->left);
- t = t->right;
- if (t->left != NULL) {
+ fptreef(shf, indent + 5 - i, Telif_pT + i, t1->left);
+ t1 = t1->right;
+ if (t1->left != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "%s%N%T",
- "then", t->left);
+ "then", t1->left);
}
- } while (t->right && t->right->type == TELIF);
- if (t->right != NULL) {
+ } while (t1->right && t1->right->type == TELIF);
+ if (t1->right != NULL) {
fptreef(shf, indent, "%;");
fptreef(shf, indent + INDENT, "%s%N%T",
- "else", t->right);
+ "else", t1->right);
}
fptreef(shf, indent, "%;fi ");
break;
case TWHILE:
case TUNTIL:
- /* 6 == strlen("while"/"until") */
+ /* 6 == strlen("while "/"until ") */
fptreef(shf, indent + 6, "%s %T",
(t->type == TWHILE) ? "while" : "until",
t->left);
bool need_nl = false;
while (*ioact != NULL)
- pioact(shf, indent, *ioact++);
+ pioact(shf, *ioact++);
/* Print here documents after everything else... */
ioact = t->ioact;
while (*ioact != NULL) {
struct ioword *iop = *ioact++;
/* heredoc is NULL when tracing (set -x) */
- if ((iop->flag & (IOTYPE | IOHERESTR)) == IOHERE &&
+ if ((iop->ioflag & (IOTYPE | IOHERESTR)) == IOHERE &&
iop->heredoc) {
shf_putc('\n', shf);
shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s",
- iop->flag & IONDELIM ? "<<" :
+ iop->ioflag & IONDELIM ? "<<" :
evalstr(iop->delim, 0));
need_nl = true;
}
* often leads to an extra blank line, but it's not
* worth worrying about)
*/
- if (need_nl)
+ if (need_nl) {
shf_putc('\n', shf);
+ prevent_semicolon = true;
+ }
}
}
static void
-pioact(struct shf *shf, int indent, struct ioword *iop)
+pioact(struct shf *shf, struct ioword *iop)
{
- int flag = iop->flag;
- int type = flag & IOTYPE;
- int expected;
+ unsigned short flag = iop->ioflag;
+ unsigned short type = flag & IOTYPE;
+ short expected;
expected = (type == IOREAD || type == IORDWR || type == IOHERE) ? 0 :
(type == IOCAT || type == IOWRITE) ? 1 :
(type == IODUP && (iop->unit == !(flag & IORDUP))) ? iop->unit :
iop->unit + 1;
if (iop->unit != expected)
- shf_fprintf(shf, "%d", iop->unit);
+ shf_fprintf(shf, "%d", (int)iop->unit);
switch (type) {
case IOREAD:
- shf_puts("<", shf);
+ shf_putc('<', shf);
break;
case IOHERE:
- shf_puts(flag & IOSKIP ? "<<-" : "<<", shf);
+ shf_puts("<<", shf);
+ if (flag & IOSKIP)
+ shf_putc('-', shf);
break;
case IOCAT:
shf_puts(">>", shf);
break;
case IOWRITE:
- shf_puts(flag & IOCLOB ? ">|" : ">", shf);
+ shf_putc('>', shf);
+ if (flag & IOCLOB)
+ shf_putc('|', shf);
break;
case IORDWR:
shf_puts("<>", shf);
/* name/delim are NULL when printing syntax errors */
if (type == IOHERE) {
if (iop->delim)
- fptreef(shf, indent, "%S ", iop->delim);
- else
+ wdvarput(shf, iop->delim, 0, WDS_TPUTS);
+ if (flag & IOHERESTR)
shf_putc(' ', shf);
- } else if (iop->name)
- fptreef(shf, indent, (iop->flag & IONAMEXP) ? "%s " : "%S ",
- iop->name);
+ } else if (iop->name) {
+ if (flag & IONAMEXP)
+ print_value_quoted(shf, iop->name);
+ else
+ wdvarput(shf, iop->name, 0, WDS_TPUTS);
+ shf_putc(' ', shf);
+ }
prevent_semicolon = false;
}
wdvarput(struct shf *shf, const char *wp, int quotelevel, int opmode)
{
int c;
+ const char *cs;
/*-
* problems:
case CHAR:
c = *wp++;
if ((opmode & WDS_MAGIC) &&
- (ISMAGIC(c) || c == '[' || c == NOT ||
+ (ISMAGIC(c) || c == '[' || c == '!' ||
c == '-' || c == ']' || c == '*' || c == '?'))
shf_putc(MAGIC, shf);
shf_putc(c, shf);
}
case COMSUB:
shf_puts("$(", shf);
+ cs = ")";
+ pSUB:
while ((c = *wp++) != 0)
shf_putc(c, shf);
- shf_putc(')', shf);
+ shf_puts(cs, shf);
break;
+ case FUNSUB:
+ c = ' ';
+ if (0)
+ /* FALLTHROUGH */
+ case VALSUB:
+ c = '|';
+ shf_putc('$', shf);
+ shf_putc('{', shf);
+ shf_putc(c, shf);
+ cs = ";}";
+ goto pSUB;
case EXPRSUB:
shf_puts("$((", shf);
- while ((c = *wp++) != 0)
- shf_putc(c, shf);
- shf_puts("))", shf);
- break;
+ cs = "))";
+ goto pSUB;
case OQUOTE:
if (opmode & WDS_TPUTS) {
quotelevel++;
break;
case 'R':
/* I/O redirection */
- pioact(shf, indent, va_arg(va, struct ioword *));
+ pioact(shf, va_arg(va, struct ioword *));
break;
default:
shf_putc(c, shf);
wp++;
break;
case COMSUB:
+ case FUNSUB:
+ case VALSUB:
case EXPRSUB:
while (*wp++ != 0)
;
void
vistree(char *dst, size_t sz, struct op *t)
{
- int c;
+ unsigned int c;
char *cp, *buf;
+ size_t n;
- buf = alloc(sz, ATEMP);
- snptreef(buf, sz, "%T", t);
+ buf = alloc(sz + 16, ATEMP);
+ snptreef(buf, sz + 16, "%T", t);
cp = buf;
- while ((c = *cp++)) {
- if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) {
- /* C0 or C1 control character or DEL */
- if (!--sz)
- break;
- *dst++ = (c & 0x80) ? '$' : '^';
- c = (c & 0x7F) ^ 0x40;
- }
- if (!--sz)
- break;
- *dst++ = c;
+ vist_loop:
+ if (UTFMODE && (n = utf_mbtowc(&c, cp)) != (size_t)-1) {
+ if (c == 0 || n >= sz)
+ /* NUL or not enough free space */
+ goto vist_out;
+ /* copy multibyte char */
+ sz -= n;
+ while (n--)
+ *dst++ = *cp++;
+ goto vist_loop;
}
+ if (--sz == 0 || (c = (unsigned char)(*cp++)) == 0)
+ /* NUL or not enough free space */
+ goto vist_out;
+ if (ISCTRL(c & 0x7F)) {
+ /* C0 or C1 control character or DEL */
+ if (--sz == 0)
+ /* not enough free space for two chars */
+ goto vist_out;
+ *dst++ = (c & 0x80) ? '$' : '^';
+ c = UNCTRL(c & 0x7F);
+ } else if (UTFMODE && c > 0x7F) {
+ /* better not try to display broken multibyte chars */
+ /* also go easy on the Unicode: no U+FFFD here */
+ c = '?';
+ }
+ *dst++ = c;
+ goto vist_loop;
+
+ vist_out:
*dst = '\0';
afree(buf, ATEMP);
}
void
dumpchar(struct shf *shf, int c)
{
- if (((c & 0x60) == 0) || ((c & 0x7F) == 0x7F)) {
+ if (ISCTRL(c & 0x7F)) {
/* C0 or C1 control character or DEL */
shf_putc((c & 0x80) ? '$' : '^', shf);
- c = (c & 0x7F) ^ 0x40;
+ c = UNCTRL(c & 0x7F);
}
shf_putc(c, shf);
}
/* see: wdvarput */
static const char *
-dumpwdvar_(struct shf *shf, const char *wp, int quotelevel)
+dumpwdvar_i(struct shf *shf, const char *wp, int quotelevel)
{
int c;
closeandout:
shf_putc('>', shf);
break;
+ case FUNSUB:
+ shf_puts("FUNSUB<", shf);
+ goto dumpsub;
+ case VALSUB:
+ shf_puts("VALSUB<", shf);
+ goto dumpsub;
case EXPRSUB:
shf_puts("EXPRSUB<", shf);
goto dumpsub;
while ((c = *wp++) != 0)
dumpchar(shf, c);
shf_putc('|', shf);
- wp = dumpwdvar_(shf, wp, 0);
+ wp = dumpwdvar_i(shf, wp, 0);
break;
case CSUBST:
shf_puts("]CSUBST(", shf);
void
dumpwdvar(struct shf *shf, const char *wp)
{
- dumpwdvar_(shf, wp, 0);
+ dumpwdvar_i(shf, wp, 0);
+}
+
+void
+dumpioact(struct shf *shf, struct op *t)
+{
+ struct ioword **ioact, *iop;
+
+ if ((ioact = t->ioact) == NULL)
+ return;
+
+ shf_puts("{IOACT", shf);
+ while ((iop = *ioact++) != NULL) {
+ unsigned short type = iop->ioflag & IOTYPE;
+#define DT(x) case x: shf_puts(#x, shf); break;
+#define DB(x) if (iop->ioflag & x) shf_puts("|" #x, shf);
+
+ shf_putc(';', shf);
+ switch (type) {
+ DT(IOREAD)
+ DT(IOWRITE)
+ DT(IORDWR)
+ DT(IOHERE)
+ DT(IOCAT)
+ DT(IODUP)
+ default:
+ shf_fprintf(shf, "unk%d", type);
+ }
+ DB(IOEVAL)
+ DB(IOSKIP)
+ DB(IOCLOB)
+ DB(IORDUP)
+ DB(IONAMEXP)
+ DB(IOBASH)
+ DB(IOHERESTR)
+ DB(IONDELIM)
+ shf_fprintf(shf, ",unit=%d", (int)iop->unit);
+ if (iop->delim) {
+ shf_puts(",delim<", shf);
+ dumpwdvar(shf, iop->delim);
+ shf_putc('>', shf);
+ }
+ if (iop->name) {
+ if (iop->ioflag & IONAMEXP) {
+ shf_puts(",name=", shf);
+ print_value_quoted(shf, iop->name);
+ } else {
+ shf_puts(",name<", shf);
+ dumpwdvar(shf, iop->name);
+ shf_putc('>', shf);
+ }
+ }
+ if (iop->heredoc) {
+ shf_puts(",heredoc=", shf);
+ print_value_quoted(shf, iop->heredoc);
+ }
+#undef DT
+#undef DB
+ }
+ shf_putc('}', shf);
}
void
dumptree(struct shf *shf, struct op *t)
{
- int i;
+ int i, j;
const char **w, *name;
struct op *t1;
- static int nesting = 0;
+ static int nesting;
for (i = 0; i < nesting; ++i)
shf_putc('\t', shf);
name = "(null)";
goto out;
}
+ dumpioact(shf, t);
switch (t->type) {
#define OPEN(x) case x: name = #x; shf_puts(" {" #x ":", shf); /*}*/
w = (const char **)t->vars;
while (*w) {
shf_putc('\n', shf);
- for (int j = 0; j < nesting; ++j)
+ for (j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " var%d<", i++);
dumpwdvar(shf, *w++);
w = t->args;
while (*w) {
shf_putc('\n', shf);
- for (int j = 0; j < nesting; ++j)
+ for (j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " arg%d<", i++);
dumpwdvar(shf, *w++);
w = t->args;
while (*w) {
shf_putc('\n', shf);
- for (int j = 0; j < nesting; ++j)
+ for (j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " arg%d<", i++);
dumpwdvar(shf, *w++);
w = (const char **)t->vars;
while (*w) {
shf_putc('\n', shf);
- for (int j = 0; j < nesting; ++j)
+ for (j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " var%d<", i++);
dumpwdvar(shf, *w++);
i = 0;
for (t1 = t->left; t1 != NULL; t1 = t1->right) {
shf_putc('\n', shf);
- for (int j = 0; j < nesting; ++j)
+ for (j = 0; j < nesting; ++j)
shf_putc('\t', shf);
shf_fprintf(shf, " sub%d[(", i);
w = (const char **)t1->vars;
++w;
}
shf_putc(')', shf);
+ dumpioact(shf, t);
shf_putc('\n', shf);
dumptree(shf, t1->left);
shf_fprintf(shf, " ;%c/%d]", t1->u.charflag, i++);
shf_putc('\n', shf);
dumptree(shf, t->left);
t = t->right;
+ dumpioact(shf, t);
if (t->left != NULL) {
shf_puts(" /TTHEN:\n", shf);
dumptree(shf, t->left);
if (t->right && t->right->type == TELIF) {
shf_puts(" /TELIF:", shf);
t = t->right;
+ dumpioact(shf, t);
goto dumpif;
}
if (t->right != NULL) {