summary refs log tree commit diff
path: root/Src/text.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/text.c')
-rw-r--r--Src/text.c526
1 files changed, 526 insertions, 0 deletions
diff --git a/Src/text.c b/Src/text.c
new file mode 100644
index 000000000..b7df8012f
--- /dev/null
+++ b/Src/text.c
@@ -0,0 +1,526 @@
+/*
+ * 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;
+
+/* 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);
+
+    while (tptr + sl >= tlim) {
+	int x = tptr - tbuf;
+
+	if (!tbuf)
+	    return;
+	tbuf = realloc(tbuf, tsiz *= 2);
+	tlim = tbuf + tsiz;
+	tptr = tbuf + x;
+    }
+    strcpy(tptr, s);
+    tptr += sl;
+}
+
+#if 0
+/* add an integer to the text buffer */
+
+/**/
+void
+taddint(int x)
+{
+    char buf[DIGBUFSIZE];
+
+    sprintf(buf, "%d", x);
+    taddstr(buf);
+}
+#endif
+
+/* 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 */
+
+/**/
+char *
+getpermtext(struct node *n)
+{
+    tnewlins = 1;
+    tbuf = (char *)zalloc(tsiz = 32);
+    tptr = tbuf;
+    tlim = tbuf + tsiz;
+    tindent = 1;
+    gettext2(n);
+    *tptr = '\0';
+    untokenize(tbuf);
+    return tbuf;
+}
+
+/* get a representation of n in a job text buffer */
+
+/**/
+char *
+getjobtext(struct node *n)
+{
+    static char jbuf[JOBTEXTSIZE];
+
+    tnewlins = 0;
+    tbuf = NULL;
+    tptr = jbuf;
+    tlim = tptr + JOBTEXTSIZE - 1;
+    tindent = 1;
+    gettext2(n);
+    *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))
+
+/**/
+static void
+gettext2(struct node *n)
+{
+    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);
+	}
+	break;
+    case N_CMD:
+	nn = _Cmd(n);
+	switch (nn->type) {
+	case SIMPLE:
+	    getsimptext(nn);
+	    break;
+	case SUBSH:
+	    taddstr("( ");
+	    tindent++;
+	    gt2(nn->u.list);
+	    tindent--;
+	    taddstr(" )");
+	    break;
+	case ZCTIME:
+	    taddstr("time ");
+	    tindent++;
+	    gt2(nn->u.pline);
+	    tindent--;
+	    break;
+	case FUNCDEF:
+	    taddlist(nn->args);
+	    taddstr(" () {");
+	    tindent++;
+	    taddnl();
+	    gt2(nn->u.list);
+	    tindent--;
+	    taddnl();
+	    taddstr("}");
+	    break;
+	case CURSH:
+	    taddstr("{ ");
+	    tindent++;
+	    gt2(nn->u.list);
+	    tindent--;
+	    taddstr(" }");
+	    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");
+	    } else {
+		taddstr(nn->u.forcmd->name);
+		if (nn->u.forcmd->inflag) {
+		    taddstr(" in ");
+		    taddlist(nn->args);
+		}
+		taddnl();
+		taddstr("do");
+	    }
+	    tindent++;
+	    taddnl();
+	    gt2(nn->u.forcmd->list);
+	    tindent--;
+	    taddnl();
+	    taddstr("done");
+	    break;
+	case CIF:
+	    gt2(nn->u.ifcmd);
+	    taddstr("fi");
+	    break;
+	case CCASE:
+	    gt2(nn->u.casecmd);
+	    break;
+	case COND:
+	    taddstr("[[ ");
+	    gt2(nn->u.cond);
+	    taddstr(" ]]");
+	    break;
+	case CARITH:
+	    taddstr("((");
+	    taddlist(nn->args);
+	    taddstr("))");
+	    break;
+	case CREPEAT:
+	    taddstr("repeat ");
+	    taddlist(nn->args);
+	    taddnl();
+	    taddstr("do");
+	    tindent++;
+	    taddnl();
+	    gt2(nn->u.list);
+	    tindent--;
+	    taddnl();
+	    taddstr("done");
+	    break;
+	case CWHILE:
+	    gt2(nn->u.whilecmd);
+	    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++) {
+		if (tnewlins)
+		    taddnl();
+		else
+		    taddchr(' ');
+		taddstr(*p + 1);
+		taddstr(") ");
+		tindent++;
+		gt2(*l);
+		tindent--;
+		taddstr(" ;");
+		taddchr(**p);
+	    }
+	    tindent--;
+	    if (tnewlins)
+		taddnl();
+	    else
+		taddchr(' ');
+	    taddstr("esac");
+	    break;
+	}
+    case N_IF:
+	{
+	    List *i, *t;
+
+	    taddstr("if ");
+	    for (i = _ifcmd(n)->ifls, t = _ifcmd(n)->thenls; *i; i++, t++) {
+		tindent++;
+		gt2(*i);
+		tindent--;
+		taddnl();
+		taddstr("then");
+		tindent++;
+		taddnl();
+		gt2(*t);
+		tindent--;
+		taddnl();
+		if (i[1]) {
+		    taddstr("elif ");
+		}
+	    }
+	    if (*t) {
+		taddstr("else");
+		tindent++;
+		taddnl();
+		gt2(*t);
+		tindent--;
+		taddnl();
+	    }
+	    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(' ');
+	}
+    }
+    taddlist(cmd->args);
+}
+
+/**/
+void
+getredirs(Cmd cmd)
+{
+    LinkNode n;
+    static char *fstr[] =
+    {
+	">", ">|", ">>", ">>|", "&>", "&>|", "&>>", "&>>|", "<>", "<",
+	"<<", "<<-", "<<<", "<&", ">&", NULL /* >&- */, "<", ">"
+    };
+
+    taddchr(' ');
+    for (n = firstnode(cmd->redir); n; incnode(n)) {
+	struct redir *f = (struct redir *)getdata(n);
+
+	switch (f->type) {
+	case WRITE:
+	case WRITENOW:
+	case APP:
+	case APPNOW:
+	case ERRWRITE:
+	case ERRWRITENOW:
+	case ERRAPP:
+	case ERRAPPNOW:
+	case READ:
+	case READWRITE:
+	case HERESTR:
+	case MERGEIN:
+	case MERGEOUT:
+	case INPIPE:
+	case OUTPIPE:
+	    if (f->fd1 != (IS_READFD(f->type) ? 0 : 1))
+		taddchr('0' + f->fd1);
+	    taddstr(fstr[f->type]);
+	    taddchr(' ');
+	    taddstr(f->name);
+	    taddchr(' ');
+	    break;
+#ifdef DEBUG
+	case CLOSE:
+	    DPUTS(1, "BUG: CLOSE in getredirs()");
+	    taddchr(f->fd1 + '0');
+	    taddstr(">&- ");
+	    break;
+	default:
+	    DPUTS(1, "BUG: unknown redirection in getredirs()");
+#endif
+	}
+    }
+    tptr--;
+}
+
+/**/
+static void
+taddlist(LinkList l)
+{
+    LinkNode n;
+
+    if (!(n = firstnode(l)))
+	return;
+    for (; n; incnode(n)) {
+	taddstr(getdata(n));
+	taddchr(' ');
+    }
+    tptr--;
+}