--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/openenvutils/commandshell/shell/src/text.c Tue Feb 02 10:12:00 2010 +0200
@@ -0,0 +1,822 @@
+/*
+ * text.c - textual representations of syntax trees
+ *
+ * This file is part of zsh, the Z shell.
+ *
+ * Copyright (c) 1992-1997 Paul Falstad
+ * All rights reserved.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and to distribute modified versions of this software for any
+ * purpose, provided that the above copyright notice and the following
+ * two paragraphs appear in all copies of this software.
+ *
+ * In no event shall Paul Falstad or the Zsh Development Group be liable
+ * to any party for direct, indirect, special, incidental, or consequential
+ * damages arising out of the use of this software and its documentation,
+ * even if Paul Falstad and the Zsh Development Group have been advised of
+ * the possibility of such damage.
+ *
+ * Paul Falstad and the Zsh Development Group specifically disclaim any
+ * warranties, including, but not limited to, the implied warranties of
+ * merchantability and fitness for a particular purpose. The software
+ * provided hereunder is on an "as is" basis, and Paul Falstad and the
+ * Zsh Development Group have no obligation to provide maintenance,
+ * support, updates, enhancements, or modifications.
+ *
+ */
+
+#include "zsh.mdh"
+#include "text.pro"
+
+static char *tptr, *tbuf, *tlim;
+static int tsiz, tindent, tnewlins, tjob;
+
+/* add a character to the text buffer */
+
+/**/
+static void
+taddchr(int c)
+{
+ *tptr++ = c;
+ if (tptr == tlim) {
+ if (!tbuf) {
+ tptr--;
+ return;
+ }
+ tbuf = realloc(tbuf, tsiz *= 2);
+ tlim = tbuf + tsiz;
+ tptr = tbuf + tsiz / 2;
+ }
+}
+
+/* add a string to the text buffer */
+
+/**/
+static void
+taddstr(char *s)
+{
+ int sl = strlen(s);
+ char c;
+
+ while (tptr + sl >= tlim) {
+ int x = tptr - tbuf;
+
+ if (!tbuf)
+ return;
+ tbuf = realloc(tbuf, tsiz *= 2);
+ tlim = tbuf + tsiz;
+ tptr = tbuf + x;
+ }
+ if (tnewlins) {
+ memcpy(tptr, s, sl);
+ tptr += sl;
+ } else
+ while ((c = *s++))
+ *tptr++ = (c == '\n' ? ' ' : c);
+}
+
+/**/
+static void
+taddlist(Estate state, int num)
+{
+ if (num) {
+ while (num--) {
+ taddstr(ecgetstr(state, EC_NODUP, NULL));
+ taddchr(' ');
+ }
+ tptr--;
+ }
+}
+
+/* add a newline, or something equivalent, to the text buffer */
+
+/**/
+static void
+taddnl(void)
+{
+ int t0;
+
+ if (tnewlins) {
+ taddchr('\n');
+ for (t0 = 0; t0 != tindent; t0++)
+ taddchr('\t');
+ } else
+ taddstr("; ");
+}
+
+/* get a permanent textual representation of n */
+
+/**/
+mod_export char *
+getpermtext(Eprog prog, Wordcode c)
+{
+ struct estate s;
+
+ if (!c)
+ c = prog->prog;
+
+ useeprog(prog); /* mark as used */
+
+ s.prog = prog;
+ s.pc = c;
+ s.strs = prog->strs;
+
+ tnewlins = 1;
+ tbuf = (char *)zalloc(tsiz = 32);
+ tptr = tbuf;
+ tlim = tbuf + tsiz;
+ tindent = 1;
+ tjob = 0;
+ if (prog->len)
+ gettext2(&s);
+ *tptr = '\0';
+ freeeprog(prog); /* mark as unused */
+ untokenize(tbuf);
+ return tbuf;
+}
+
+/* get a representation of n in a job text buffer */
+
+/**/
+char *
+getjobtext(Eprog prog, Wordcode c)
+{
+ static char jbuf[JOBTEXTSIZE];
+
+ struct estate s;
+
+ if (!c)
+ c = prog->prog;
+
+ useeprog(prog); /* mark as used */
+ s.prog = prog;
+ s.pc = c;
+ s.strs = prog->strs;
+
+ tnewlins = 0;
+ tbuf = NULL;
+ tptr = jbuf;
+ tlim = tptr + JOBTEXTSIZE - 1;
+ tindent = 1;
+ tjob = 1;
+ gettext2(&s);
+ *tptr = '\0';
+ freeeprog(prog); /* mark as unused */
+ untokenize(jbuf);
+ return jbuf;
+}
+
+/*
+ * 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(Estate state)
+{
+ 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++;
+ }
+ 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_SIMPLE) &&
+ wc_code(*state->pc) != WC_PIPE)
+ stack = -1;
+ if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_NOT)
+ taddstr(stack ? "!" : "! ");
+ if (WC_SUBLIST_FLAGS(code) & WC_SUBLIST_COPROC)
+ taddstr(stack ? "coproc" : "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 < 1 && (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 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 WC_ASSIGN:
+ taddstr(ecgetstr(state, EC_NODUP, NULL));
+ if (WC_ASSIGN_TYPE2(code) == WC_ASSIGN_INC) taddchr('+');
+ 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 WC_SIMPLE:
+ taddlist(state, WC_SIMPLE_ARGC(code));
+ stack = 1;
+ break;
+ case WC_SUBSH:
+ if (!s) {
+ taddstr("(");
+ tindent++;
+ taddnl();
+ n = tpush(code, 1);
+ n->u._subsh.end = state->pc + WC_SUBSH_SKIP(code);
+ /* skip word only use for try/always */
+ state->pc++;
+ } else {
+ state->pc = s->u._subsh.end;
+ tindent--;
+ taddnl();
+ taddstr(")");
+ stack = 1;
+ }
+ break;
+ case WC_CURSH:
+ if (!s) {
+ taddstr("{");
+ tindent++;
+ taddnl();
+ n = tpush(code, 1);
+ n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
+ /* skip word only use for try/always */
+ state->pc++;
+ } else {
+ state->pc = s->u._subsh.end;
+ tindent--;
+ taddnl();
+ taddstr("}");
+ stack = 1;
+ }
+ break;
+ 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 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 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 {
+ taddlist(state, *state->pc++);
+ 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 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 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 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;
+ 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(' ');
+ taddstr("(");
+ 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("(");
+ code = *state->pc++;
+ taddstr(ecgetstr(state, EC_NODUP, NULL));
+ state->pc++;
+ taddstr(") ");
+ tindent++;
+ 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--;
+ if (tnewlins)
+ taddnl();
+ else
+ taddchr(' ');
+ taddstr("esac");
+ stack = 1;
+ }
+ break;
+ case WC_IF:
+ if (!s) {
+ Wordcode end = state->pc + WC_IF_SKIP(code);
+
+ taddstr("if ");
+ tindent++;
+ 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();
+ s->u._if.cond = 0;
+ } else if (state->pc < s->u._if.end) {
+ tindent--;
+ taddnl();
+ code = *state->pc++;
+ if (WC_IF_TYPE(code) == WC_IF_ELIF) {
+ taddstr("elif ");
+ tindent++;
+ s->u._if.cond = 1;
+ } else {
+ taddstr("else");
+ tindent++;
+ taddnl();
+ }
+ } else {
+ s->pop = 1;
+ tindent--;
+ taddnl();
+ taddstr("fi");
+ stack = 1;
+ }
+ break;
+ 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_TRY:
+ if (!s) {
+ taddstr("{");
+ tindent++;
+ taddnl();
+ n = tpush(code, 0);
+ state->pc++;
+ /* this is the end of the try block alone */
+ n->u._subsh.end = state->pc + WC_CURSH_SKIP(state->pc[-1]);
+ } else if (!s->pop) {
+ state->pc = s->u._subsh.end;
+ tindent--;
+ taddnl();
+ taddstr("} always {");
+ tindent++;
+ taddnl();
+ s->pop = 1;
+ } else {
+ tindent--;
+ taddnl();
+ taddstr("}");
+ stack = 1;
+ }
+ break;
+ case WC_END:
+ stack = 1;
+ break;
+ default:
+ DPUTS(1, "unknown word code in gettext2()");
+ return;
+ }
+ }
+}
+
+/**/
+void
+getredirs(LinkList redirs)
+{
+ LinkNode n;
+ static char *fstr[] =
+ {
+ ">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
+ "<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
+ };
+ taddchr(' ');
+ for (n = firstnode(redirs); n; incnode(n)) {
+ Redir f = (Redir) getdata(n);
+
+ switch (f->type) {
+ case REDIR_WRITE:
+ case REDIR_WRITENOW:
+ case REDIR_APP:
+ case REDIR_APPNOW:
+ case REDIR_ERRWRITE:
+ case REDIR_ERRWRITENOW:
+ case REDIR_ERRAPP:
+ case REDIR_ERRAPPNOW:
+ case REDIR_READ:
+ case REDIR_READWRITE:
+ case REDIR_HERESTR:
+ case REDIR_MERGEIN:
+ case REDIR_MERGEOUT:
+ case REDIR_INPIPE:
+ case REDIR_OUTPIPE:
+ if (f->fd1 != (IS_READFD(f->type) ? 0 : 1))
+ taddchr('0' + f->fd1);
+ taddstr(fstr[f->type]);
+ taddchr(' ');
+ if (f->type == REDIR_HERESTR) {
+ if (has_token(f->name)) {
+ taddchr('\"');
+ taddstr(bslashquote(f->name, NULL, 2));
+ taddchr('\"');
+ } else {
+ taddchr('\'');
+ taddstr(bslashquote(f->name, NULL, 1));
+ taddchr('\'');
+ }
+ } else
+ taddstr(f->name);
+ taddchr(' ');
+ break;
+#ifdef DEBUG
+ case REDIR_CLOSE:
+ DPUTS(1, "BUG: CLOSE in getredirs()");
+ taddchr(f->fd1 + '0');
+ taddstr(">&- ");
+ break;
+ default:
+ DPUTS(1, "BUG: unknown redirection in getredirs()");
+#endif
+ }
+ }
+ tptr--;
+}