zsh/Src/text.c

527 lines
9.9 KiB
C
Raw Normal View History

1999-04-15 20:05:38 +02:00
/*
* 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--;
}