mirror of
git://git.code.sf.net/p/zsh/code
synced 2024-11-19 13:33:52 +01:00
774 lines
16 KiB
C
774 lines
16 KiB
C
/*
|
|
* 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;
|
|
|
|
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';
|
|
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;
|
|
|
|
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';
|
|
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_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 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));
|
|
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++;
|
|
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 WC_CURSH:
|
|
if (!s) {
|
|
taddstr("{ ");
|
|
tindent++;
|
|
n = tpush(code, 1);
|
|
n->u._subsh.end = state->pc + WC_CURSH_SKIP(code);
|
|
} else {
|
|
state->pc = s->u._subsh.end;
|
|
tindent--;
|
|
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 {
|
|
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 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(' ');
|
|
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(' ');
|
|
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_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) {
|
|
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--;
|
|
}
|