summaryrefslogtreecommitdiff
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--;
+}