summary refs log tree commit diff
path: root/Src/text.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:49:47 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2000-04-01 20:49:47 +0000
commit48525452555a24b9d41748f26b4b77f160f01220 (patch)
treed814ca2f017d9d843fec7d286fefbca78244beb5 /Src/text.c
parente025336f2f6d9f107ee1e03b9900f04af0544ba9 (diff)
downloadzsh-48525452555a24b9d41748f26b4b77f160f01220.tar.gz
zsh-48525452555a24b9d41748f26b4b77f160f01220.tar.xz
zsh-48525452555a24b9d41748f26b4b77f160f01220.zip
Updated from list as far as 10376
Diffstat (limited to 'Src/text.c')
-rw-r--r--Src/text.c858
1 files changed, 550 insertions, 308 deletions
diff --git a/Src/text.c b/Src/text.c
index b7df8012f..ab6ca5eb9 100644
--- a/Src/text.c
+++ b/Src/text.c
@@ -31,7 +31,7 @@
 #include "text.pro"
 
 static char *tptr, *tbuf, *tlim;
-static int tsiz, tindent, tnewlins;
+static int tsiz, tindent, tnewlins, tjob;
 
 /* add a character to the text buffer */
 
@@ -72,19 +72,18 @@ taddstr(char *s)
     tptr += sl;
 }
 
-#if 0
-/* add an integer to the text buffer */
-
 /**/
-void
-taddint(int x)
+static void
+taddlist(Estate state, int num)
 {
-    char buf[DIGBUFSIZE];
-
-    sprintf(buf, "%d", x);
-    taddstr(buf);
+    if (num) {
+	while (num--) {
+	    taddstr(ecgetstr(state, EC_NODUP, NULL));
+	    taddchr(' ');
+	}
+	tptr--;
+    }
 }
-#endif
 
 /* add a newline, or something equivalent, to the text buffer */
 
@@ -105,15 +104,26 @@ taddnl(void)
 /* get a permanent textual representation of n */
 
 /**/
-char *
-getpermtext(struct node *n)
+mod_export char *
+getpermtext(Eprog prog, Wordcode c)
 {
+    struct estate s;
+
+    if (!c)
+	c = prog->prog;
+
+    s.prog = prog;
+    s.pc = c;
+    s.strs = prog->strs;
+
     tnewlins = 1;
     tbuf = (char *)zalloc(tsiz = 32);
     tptr = tbuf;
     tlim = tbuf + tsiz;
     tindent = 1;
-    gettext2(n);
+    tjob = 0;
+    if (prog->len)
+	gettext2(&s);
     *tptr = '\0';
     untokenize(tbuf);
     return tbuf;
@@ -123,344 +133,587 @@ getpermtext(struct node *n)
 
 /**/
 char *
-getjobtext(struct node *n)
+getjobtext(Eprog prog, Wordcode c)
 {
     static char jbuf[JOBTEXTSIZE];
 
+    struct estate s;
+
+    if (!c)
+	c = prog->prog;
+
+    s.prog = prog;
+    s.pc = c;
+    s.strs = prog->strs;
+
     tnewlins = 0;
     tbuf = NULL;
     tptr = jbuf;
     tlim = tptr + JOBTEXTSIZE - 1;
     tindent = 1;
-    gettext2(n);
+    tjob = 1;
+    gettext2(&s);
     *tptr = '\0';
     untokenize(jbuf);
     return jbuf;
 }
 
-#define gt2(X) gettext2((struct node *) (X))
-
 /*
-	"gettext2" or "type checking and how to avoid it"
-	an epic function by Paul Falstad
-*/
-
-#define _Cond(X) ((Cond) (X))
-#define _Cmd(X) ((Cmd) (X))
-#define _Pline(X) ((Pline) (X))
-#define _Sublist(X) ((Sublist) (X))
-#define _List(X) ((List) (X))
-#define _casecmd(X) ((struct casecmd *) (X))
-#define _ifcmd(X) ((struct ifcmd *) (X))
-#define _whilecmd(X) ((struct whilecmd *) (X))
+ * gettext2() shows one way to walk through the word code without
+ * recursion. We start by reading a word code and executing the
+ * action for it. Some codes have sub-structures (like, e.g. WC_FOR)
+ * and require something to be done after the sub-structure has been
+ * handled. For these codes a tstack structure which describes what
+ * has to be done is pushed onto a stack. Codes without sub-structures
+ * arrange for the next structure being taken from the stack so that
+ * the action for it is executed instead of the one for the next
+ * word code. If the stack is empty at this point, we have handled
+ * the whole structure we were called for.
+ */
+
+typedef struct tstack *Tstack;
+
+struct tstack {
+    Tstack prev;
+    wordcode code;
+    int pop;
+    union {
+	struct {
+	    LinkList list;
+	} _redir;
+	struct {
+	    char *strs;
+	    Wordcode end;
+	} _funcdef;
+	struct {
+	    Wordcode end;
+	} _case;
+	struct {
+	    int cond;
+	    Wordcode end;
+	} _if;
+	struct {
+	    int par;
+	} _cond;
+	struct {
+	    Wordcode end;
+	} _subsh;
+    } u;
+};
+
+static Tstack tstack, tfree;
+
+static Tstack
+tpush(wordcode code, int pop)
+{
+    Tstack s;
+
+    if ((s = tfree))
+	tfree = s->prev;
+    else
+	s = (Tstack) zalloc(sizeof(*s));
+
+    s->prev = tstack;
+    tstack = s;
+    s->code = code;
+    s->pop = pop;
+
+    return s;
+}
 
 /**/
 static void
-gettext2(struct node *n)
+gettext2(Estate state)
 {
-    Cmd nn;
-
-    if (!n || ((List) n) == &dummy_list)
-	return;
-    switch (NT_TYPE(n->ntype)) {
-    case N_LIST:
-	gt2(_List(n)->left);
-	if (_List(n)->type & Z_ASYNC) {
-	    taddstr(" &");
-	    if (_List(n)->type & Z_DISOWN)
-		taddstr("|");
-	}
-	simplifyright(_List(n));
-	if (_List(n)->right) {
-	    if (tnewlins)
-		taddnl();
-	    else
-		taddstr((_List(n)->type & Z_ASYNC) ? " " : "; ");
-	    gt2(_List(n)->right);
-	}
-	break;
-    case N_SUBLIST:
-	if (_Sublist(n)->flags & PFLAG_NOT)
-	    taddstr("! ");
-	if (_Sublist(n)->flags & PFLAG_COPROC)
-	    taddstr("coproc ");
-	gt2(_Sublist(n)->left);
-	if (_Sublist(n)->right) {
-	    taddstr((_Sublist(n)->type == ORNEXT) ? " || " : " && ");
-	    gt2(_Sublist(n)->right);
-	}
-	break;
-    case N_PLINE:
-	gt2(_Pline(n)->left);
-	if (_Pline(n)->type == PIPE) {
-	    taddstr(" | ");
-	    gt2(_Pline(n)->right);
+    Tstack s, n;
+    int stack = 0;
+    wordcode code;
+
+    while (1) {
+	if (stack) {
+	    if (!(s = tstack))
+		return;
+	    if (s->pop) {
+		tstack = s->prev;
+		s->prev = tfree;
+		tfree = s;
+	    }
+	    code = s->code;
+	    stack = 0;
+	} else {
+	    s = NULL;
+	    code = *state->pc++;
 	}
-	break;
-    case N_CMD:
-	nn = _Cmd(n);
-	switch (nn->type) {
-	case SIMPLE:
-	    getsimptext(nn);
+	switch (wc_code(code)) {
+	case WC_LIST:
+	    if (!s) {
+		s = tpush(code, (WC_LIST_TYPE(code) & Z_END));
+		stack = 0;
+	    } else {
+		if (WC_LIST_TYPE(code) & Z_ASYNC) {
+		    taddstr(" &");
+		    if (WC_LIST_TYPE(code) & Z_DISOWN)
+			taddstr("|");
+		}
+		if (!(stack = (WC_LIST_TYPE(code) & Z_END))) {
+		    if (tnewlins)
+			taddnl();
+		    else
+			taddstr((WC_LIST_TYPE(code) & Z_ASYNC) ? " " : "; ");
+		    s->code = *state->pc++;
+		    s->pop = (WC_LIST_TYPE(s->code) & Z_END);
+		}
+	    }
+	    if (!stack && (WC_LIST_TYPE(s->code) & Z_SIMPLE))
+		state->pc++;
+	    break;
+	case WC_SUBLIST:
+	    if (!s) {
+		if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
+		    taddstr("! ");
+		if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC)
+		    taddstr("coproc ");
+		s = tpush(code, (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END));
+	    } else {
+		if (!(stack = (WC_SUBLIST_TYPE(code) == WC_SUBLIST_END))) {
+		    taddstr((WC_SUBLIST_TYPE(code) == WC_SUBLIST_OR) ?
+			    " || " : " && ");
+		    s->code = *state->pc++;
+		    s->pop = (WC_SUBLIST_TYPE(s->code) == WC_SUBLIST_END);
+		    if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_NOT)
+			taddstr("! ");
+		    if (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_COPROC)
+			taddstr("coproc ");
+		}
+	    }
+	    if (!stack && (WC_SUBLIST_FLAGS(s->code) & WC_SUBLIST_SIMPLE))
+		state->pc++;
+	    break;
+	case WC_PIPE:
+	    if (!s) {
+		tpush(code, (WC_PIPE_TYPE(code) == WC_PIPE_END));
+		if (WC_PIPE_TYPE(code) == WC_PIPE_MID)
+		    state->pc++;
+	    } else {
+		if (!(stack = (WC_PIPE_TYPE(code) == WC_PIPE_END))) {
+		    taddstr(" | ");
+		    s->code = *state->pc++;
+		    if (!(s->pop = (WC_PIPE_TYPE(s->code) == WC_PIPE_END)))
+			state->pc++;
+		}
+	    }
 	    break;
-	case SUBSH:
-	    taddstr("( ");
-	    tindent++;
-	    gt2(nn->u.list);
-	    tindent--;
-	    taddstr(" )");
+	case WC_REDIR:
+	    if (!s) {
+		state->pc--;
+		n = tpush(code, 1);
+		n->u._redir.list = ecgetredirs(state);
+	    } else {
+		getredirs(s->u._redir.list);
+		stack = 1;
+	    }
 	    break;
-	case ZCTIME:
-	    taddstr("time ");
-	    tindent++;
-	    gt2(nn->u.pline);
-	    tindent--;
+	case WC_ASSIGN:
+	    taddstr(ecgetstr(state, EC_NODUP, NULL));
+	    taddchr('=');
+	    if (WC_ASSIGN_TYPE(code) == WC_ASSIGN_ARRAY) {
+		taddchr('(');
+		taddlist(state, WC_ASSIGN_NUM(code));
+		taddstr(") ");
+	    } else {
+		taddstr(ecgetstr(state, EC_NODUP, NULL));
+		taddchr(' ');
+	    }
 	    break;
-	case FUNCDEF:
-	    taddlist(nn->args);
-	    taddstr(" () {");
-	    tindent++;
-	    taddnl();
-	    gt2(nn->u.list);
-	    tindent--;
-	    taddnl();
-	    taddstr("}");
+	case WC_SIMPLE:
+	    taddlist(state, WC_SIMPLE_ARGC(code));
+	    stack = 1;
 	    break;
-	case CURSH:
-	    taddstr("{ ");
-	    tindent++;
-	    gt2(nn->u.list);
-	    tindent--;
-	    taddstr(" }");
+	case WC_SUBSH:
+	    if (!s) {
+		taddstr("( ");
+		tindent++;
+		n = tpush(code, 1);
+		n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
+	    } else {
+		state->pc = s->u._subsh.end;
+		tindent--;
+		taddstr(" )");
+		stack = 1;
+	    }
 	    break;
-	case CFOR:
-	case CSELECT:
-	    taddstr((nn->type == CFOR) ? "for " : "select ");
-	    if (nn->u.forcmd->condition) {
-		taddstr("((");
-		taddstr(nn->u.forcmd->name);
-		taddstr("; ");
-		taddstr(nn->u.forcmd->condition);
-		taddstr("; ");
-		taddstr(nn->u.forcmd->advance);
-		taddstr(")) do");
+	case WC_CURSH:
+	    if (!s) {
+		taddstr("{ ");
+		tindent++;
+		n = tpush(code, 1);
+		n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
 	    } else {
-		taddstr(nn->u.forcmd->name);
-		if (nn->u.forcmd->inflag) {
-		    taddstr(" in ");
-		    taddlist(nn->args);
-		}
-		taddnl();
-		taddstr("do");
+		state->pc = s->u._subsh.end;
+		tindent--;
+		taddstr(" }");
+		stack = 1;
 	    }
-	    tindent++;
-	    taddnl();
-	    gt2(nn->u.forcmd->list);
-	    tindent--;
-	    taddnl();
-	    taddstr("done");
 	    break;
-	case CIF:
-	    gt2(nn->u.ifcmd);
-	    taddstr("fi");
+	case WC_TIMED:
+	    if (!s) {
+		taddstr("time");
+		if (WC_TIMED_TYPE(code) == WC_TIMED_PIPE) {
+		    taddchr(' ');
+		    tindent++;
+		    tpush(code, 1);
+		} else
+		    stack = 1;
+	    } else {
+		tindent--;
+		stack = 1;
+	    }
 	    break;
-	case CCASE:
-	    gt2(nn->u.casecmd);
+	case WC_FUNCDEF:
+	    if (!s) {
+		Wordcode p = state->pc;
+		Wordcode end = p + WC_FUNCDEF_SKIP(code);
+
+		taddlist(state, *state->pc++);
+		if (tjob) {
+		    taddstr(" () { ... }");
+		    state->pc = end;
+		    stack = 1;
+		} else {
+		    taddstr(" () {");
+		    tindent++;
+		    taddnl();
+		    n = tpush(code, 1);
+		    n->u._funcdef.strs = state->strs;
+		    n->u._funcdef.end = end;
+		    state->strs += *state->pc;
+		    state->pc += 3;
+		}
+	    } else {
+		state->strs = s->u._funcdef.strs;
+		state->pc = s->u._funcdef.end;
+		tindent--;
+		taddnl();
+		taddstr("}");
+		stack = 1;
+	    }
 	    break;
-	case COND:
-	    taddstr("[[ ");
-	    gt2(nn->u.cond);
-	    taddstr(" ]]");
+	case WC_FOR:
+	    if (!s) {
+		taddstr("for ");
+		if (WC_FOR_TYPE(code) == WC_FOR_COND) {
+		    taddstr("((");
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    taddstr("; ");
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    taddstr("; ");
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    taddstr(")) do");
+		} else {
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    if (WC_FOR_TYPE(code) == WC_FOR_LIST) {
+			taddstr(" in ");
+			taddlist(state, *state->pc++);
+		    }
+		    taddnl();
+		    taddstr("do");
+		}
+		tindent++;
+		taddnl();
+		tpush(code, 1);
+	    } else {
+		tindent--;
+		taddnl();
+		taddstr("done");
+		stack = 1;
+	    }
 	    break;
-	case CARITH:
-	    taddstr("((");
-	    taddlist(nn->args);
-	    taddstr("))");
+	case WC_SELECT:
+	    if (!s) {
+		taddstr("select ");
+		taddstr(ecgetstr(state, EC_NODUP, NULL));
+		if (WC_SELECT_TYPE(code) == WC_SELECT_LIST) {
+		    taddstr(" in ");
+		    taddlist(state, *state->pc++);
+		}
+		tindent++;
+		taddnl();
+		tpush(code, 1);
+	    } else {
+		tindent--;
+		taddnl();
+		taddstr("done");
+		stack = 1;
+	    }
 	    break;
-	case CREPEAT:
-	    taddstr("repeat ");
-	    taddlist(nn->args);
-	    taddnl();
-	    taddstr("do");
-	    tindent++;
-	    taddnl();
-	    gt2(nn->u.list);
-	    tindent--;
-	    taddnl();
-	    taddstr("done");
+	case WC_WHILE:
+	    if (!s) {
+		taddstr(WC_WHILE_TYPE(code) == WC_WHILE_UNTIL ?
+			"until " : "while ");
+		tindent++;
+		tpush(code, 0);
+	    } else if (!s->pop) {
+		tindent--;
+		taddnl();
+		taddstr("do");
+		tindent++;
+		taddnl();
+		s->pop = 1;
+	    } else {
+		tindent--;
+		taddnl();
+		taddstr("done");
+		stack = 1;
+	    }
 	    break;
-	case CWHILE:
-	    gt2(nn->u.whilecmd);
+	case WC_REPEAT:
+	    if (!s) {
+		taddstr("repeat ");
+		taddstr(ecgetstr(state, EC_NODUP, NULL));
+		taddnl();
+		taddstr("do");
+		tindent++;
+		taddnl();
+		tpush(code, 1);
+	    } else {
+		tindent--;
+		taddnl();
+		taddstr("done");
+		stack = 1;
+	    }
 	    break;
-	}
-	getredirs(nn);
-	break;
-    case N_COND:
-	getcond(_Cond(n), 0);
-	break;
-    case N_CASE:
-	{
-	    List *l;
-	    char **p;
-
-	    l = _casecmd(n)->lists;
-	    p = _casecmd(n)->pats;
-
-	    taddstr("case ");
-	    taddstr(*p++);
-	    taddstr(" in");
-	    tindent++;
-	    for (; *l; p++, l++) {
+	case WC_CASE:
+	    if (!s) {
+		Wordcode end = state->pc + WC_CASE_SKIP(code);
+
+		taddstr("case ");
+		taddstr(ecgetstr(state, EC_NODUP, NULL));
+		taddstr(" in");
+
+		if (state->pc >= end) {
+		    if (tnewlins)
+			taddnl();
+		    else
+			taddchr(' ');
+		    taddstr("esac");
+		    stack = 1;
+		} else {
+		    tindent++;
+		    if (tnewlins)
+			taddnl();
+		    else
+			taddchr(' ');
+		    code = *state->pc++;
+		    taddstr(ecgetstr(state, EC_NODUP, NULL));
+		    state->pc++;
+		    taddstr(") ");
+		    tindent++;
+		    n = tpush(code, 0);
+		    n->u._case.end = end;
+		    n->pop = (state->pc - 2 + WC_CASE_SKIP(code) >= end);
+		}
+	    } else if (state->pc < s->u._case.end) {
+		tindent--;
+		taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
 		if (tnewlins)
 		    taddnl();
 		else
 		    taddchr(' ');
-		taddstr(*p + 1);
+		code = *state->pc++;
+		taddstr(ecgetstr(state, EC_NODUP, NULL));
+		state->pc++;
 		taddstr(") ");
 		tindent++;
-		gt2(*l);
+		s->code = code;
+		s->pop = ((state->pc - 2 + WC_CASE_SKIP(code)) >=
+			  s->u._case.end);
+	    } else {
+		tindent--;
+		taddstr(WC_CASE_TYPE(code) == WC_CASE_OR ? " ;;" : ";&");
 		tindent--;
-		taddstr(" ;");
-		taddchr(**p);
+		if (tnewlins)
+		    taddnl();
+		else
+		    taddchr(' ');
+		taddstr("esac");
+		stack = 1;
 	    }
-	    tindent--;
-	    if (tnewlins)
-		taddnl();
-	    else
-		taddchr(' ');
-	    taddstr("esac");
 	    break;
-	}
-    case N_IF:
-	{
-	    List *i, *t;
+	case WC_IF:
+	    if (!s) {
+		Wordcode end = state->pc + WC_IF_SKIP(code);
 
-	    taddstr("if ");
-	    for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) {
+		taddstr("if ");
 		tindent++;
-		gt2(*i);
+		state->pc++;
+
+		n = tpush(code, 0);
+		n->u._if.end = end;
+		n->u._if.cond = 1;
+	    } else if (s->pop) {
+		stack = 1;
+	    } else if (s->u._if.cond) {
 		tindent--;
 		taddnl();
 		taddstr("then");
 		tindent++;
 		taddnl();
-		gt2(*t);
+		s->u._if.cond = 0;
+	    } else if (state->pc < s->u._if.end) {
 		tindent--;
 		taddnl();
-		if (i[1]) {
+		code = *state->pc++;
+		if (WC_IF_TYPE(code) == WC_IF_ELIF) {
 		    taddstr("elif ");
+		    tindent++;
+		    s->u._if.cond = 1;
+		} else {
+		    taddstr("else");
+		    tindent++;
+		    taddnl();
 		}
-	    }
-	    if (*t) {
-		taddstr("else");
-		tindent++;
-		taddnl();
-		gt2(*t);
+	    } else {
+		s->pop = 1;
 		tindent--;
 		taddnl();
+		taddstr("fi");
+		stack = 1;
 	    }
 	    break;
-	}
-    case N_WHILE:
-	taddstr((_whilecmd(n)->cond) ? "until " : "while ");
-	tindent++;
-	gt2(_whilecmd(n)->cont);
-	tindent--;
-	taddnl();
-	taddstr("do");
-	tindent++;
-	taddnl();
-	gt2(_whilecmd(n)->loop);
-	tindent--;
-	taddnl();
-	taddstr("done");
-	break;
-    }
-}
-
-/* Print a condition bracketed by [[ ... ]].             *
- * With addpar non-zero, parenthesise the subexpression. */
-
-/**/
-static void
-getcond(Cond nm, int addpar)
-{
-    static char *c1[] =
-    {
-	"=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
-	"-ne", "-lt", "-gt", "-le", "-ge"
-    };
-
-    if (addpar)
-	taddstr("( ");
-    switch (nm->type) {
-    case COND_NOT:
-	taddstr("! ");
-	getcond(nm->left, _Cond(nm->left)->type <= COND_OR);
-	break;
-    case COND_AND:
-	getcond(nm->left, _Cond(nm->left)->type == COND_OR);
-	taddstr(" && ");
-	getcond(nm->right, _Cond(nm->right)->type == COND_OR);
-	break;
-    case COND_OR:
-	/* This is deliberately over-generous with parentheses: *
-	 * in fact omitting them gives correct precedence.      */
-	getcond(nm->left, _Cond(nm->left)->type == COND_AND);
-	taddstr(" || ");
-	getcond(nm->right, _Cond(nm->right)->type == COND_AND);
-	break;
-    default:
-	if (nm->type <= COND_GE) {
-	    /* Binary test: `a = b' etc. */
-	    taddstr(nm->left);
-	    taddstr(" ");
-	    taddstr(c1[nm->type - COND_STREQ]);
-	    taddstr(" ");
-	    taddstr(nm->right);
-	} else {
-	    /* Unary test: `-f foo' etc. */ 
-	    char c2[4];
-
-	    c2[0] = '-';
-	    c2[1] = nm->type;
-	    c2[2] = ' ';
-	    c2[3] = '\0';
-	    taddstr(c2);
-	    taddstr(nm->left);
-	}
-	break;
-    }
-    if (addpar)
-	taddstr(" )");
-}
-
-/**/
-static void
-getsimptext(Cmd cmd)
-{
-    LinkNode n;
-
-    for (n = firstnode(cmd->vars); n; incnode(n)) {
-	struct varasg *v = (struct varasg *)getdata(n);
-
-	taddstr(v->name);
-	taddchr('=');
-	if (PM_TYPE(v->type) == PM_ARRAY) {
-	    taddchr('(');
-	    taddlist(v->arr);
-	    taddstr(") ");
-	} else {
-	    taddstr(v->str);
-	    taddchr(' ');
+	case WC_COND:
+	    {
+		static char *c1[] = {
+		    "=", "!=", "<", ">", "-nt", "-ot", "-ef", "-eq",
+		    "-ne", "-lt", "-gt", "-le", "-ge"
+		};
+
+		int ctype;
+
+		if (!s) {
+		    taddstr("[[ ");
+		    n = tpush(code, 1);
+		    n->u._cond.par = 2;
+		} else if (s->u._cond.par == 2) {
+		    taddstr(" ]]");
+		    stack = 1;
+		    break;
+		} else if (s->u._cond.par == 1) {
+		    taddstr(" )");
+		    stack = 1;
+		    break;
+		} else if (WC_COND_TYPE(s->code) == COND_AND) {
+		    taddstr(" && ");
+		    code = *state->pc++;
+		    if (WC_COND_TYPE(code) == COND_OR) {
+			taddstr("( ");
+			n = tpush(code, 1);
+			n->u._cond.par = 1;
+		    }
+		} else if (WC_COND_TYPE(s->code) == COND_OR) {
+		    taddstr(" || ");
+		    code = *state->pc++;
+		    if (WC_COND_TYPE(code) == COND_AND) {
+			taddstr("( ");
+			n = tpush(code, 1);
+			n->u._cond.par = 1;
+		    }
+		}
+		while (!stack) {
+		    switch ((ctype = WC_COND_TYPE(code))) {
+		    case COND_NOT:
+			taddstr("! ");
+			code = *state->pc++;
+			if (WC_COND_TYPE(code) <= COND_OR) {
+			    taddstr("( ");
+			    n = tpush(code, 1);
+			    n->u._cond.par = 1;
+			}
+			break;
+		    case COND_AND:
+			n = tpush(code, 1);
+			n->u._cond.par = 0;
+			code = *state->pc++;
+			if (WC_COND_TYPE(code) == COND_OR) {
+			    taddstr("( ");
+			    n = tpush(code, 1);
+			    n->u._cond.par = 1;
+			}
+			break;
+		    case COND_OR:
+			n = tpush(code, 1);
+			n->u._cond.par = 0;
+			code = *state->pc++;
+			if (WC_COND_TYPE(code) == COND_AND) {
+			    taddstr("( ");
+			    n = tpush(code, 1);
+			    n->u._cond.par = 1;
+			}
+			break;
+		    case COND_MOD:
+			taddstr(ecgetstr(state, EC_NODUP, NULL));
+			taddchr(' ');
+			taddlist(state, WC_COND_SKIP(code));
+			stack = 1;
+			break;
+		    case COND_MODI:
+			{
+			    char *name = ecgetstr(state, EC_NODUP, NULL);
+
+			    taddstr(ecgetstr(state, EC_NODUP, NULL));
+			    taddchr(' ');
+			    taddstr(name);
+			    taddchr(' ');
+			    taddstr(ecgetstr(state, EC_NODUP, NULL));
+			    stack = 1;
+			}
+			break;
+		    default:
+			if (ctype <= COND_GE) {
+			    /* Binary test: `a = b' etc. */
+			    taddstr(ecgetstr(state, EC_NODUP, NULL));
+			    taddstr(" ");
+			    taddstr(c1[ctype - COND_STREQ]);
+			    taddstr(" ");
+			    taddstr(ecgetstr(state, EC_NODUP, NULL));
+			    if (ctype == COND_STREQ ||
+				ctype == COND_STRNEQ)
+				state->pc++;
+			} else {
+			    /* Unary test: `-f foo' etc. */ 
+			    char c2[4];
+
+			    c2[0] = '-';
+			    c2[1] = ctype;
+			    c2[2] = ' ';
+			    c2[3] = '\0';
+			    taddstr(c2);
+			    taddstr(ecgetstr(state, EC_NODUP, NULL));
+			}
+			stack = 1;
+			break;
+		    }
+		}
+	    }
+	    break;
+	case WC_ARITH:
+	    taddstr("((");
+	    taddstr(ecgetstr(state, EC_NODUP, NULL));
+	    taddstr("))");
+	    stack = 1;
+	    break;
+	case WC_END:
+	    stack = 1;
+	    break;
+	default:
+	    DPUTS(1, "unknown word code in gettext2()");
+	    return;
 	}
     }
-    taddlist(cmd->args);
 }
 
 /**/
 void
-getredirs(Cmd cmd)
+getredirs(LinkList redirs)
 {
     LinkNode n;
     static char *fstr[] =
@@ -468,10 +721,9 @@ getredirs(Cmd cmd)
 	">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
 	"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
     };
-
     taddchr(' ');
-    for (n = firstnode(cmd->redir); n; incnode(n)) {
-	struct redir *f = (struct redir *)getdata(n);
+    for (n = firstnode(redirs); n; incnode(n)) {
+	Redir f = (Redir) getdata(n);
 
 	switch (f->type) {
 	case WRITE:
@@ -493,7 +745,12 @@ getredirs(Cmd cmd)
 		taddchr('0' + f->fd1);
 	    taddstr(fstr[f->type]);
 	    taddchr(' ');
-	    taddstr(f->name);
+	    if (f->type == HERESTR) {
+		taddchr('\'');
+		taddstr(bslashquote(f->name, NULL, 1));
+		taddchr('\'');
+	    } else
+		taddstr(f->name);
 	    taddchr(' ');
 	    break;
 #ifdef DEBUG
@@ -509,18 +766,3 @@ getredirs(Cmd cmd)
     }
     tptr--;
 }
-
-/**/
-static void
-taddlist(LinkList l)
-{
-    LinkNode n;
-
-    if (!(n = firstnode(l)))
-	return;
-    for (; n; incnode(n)) {
-	taddstr(getdata(n));
-	taddchr(' ');
-    }
-    tptr--;
-}