#include <unistd.h>
#include "sh.h"
#include "sh.tconst.h"
bool noexec;
long gargc;
short OLDSTD;
short gflag;
tchar *bname;
tchar *file;
tchar **gargv;
tchar *doldol;
tchar *lap;
tchar **pargv;
int Dpeekc, Dpeekrd;
tchar *Dcp, **Dvp;
#define DEOF -1
#define unDgetC(c) Dpeekc = c
#define QUOTES (_Q|_Q1|_ESC)
tchar *dolp;
tchar **dolnxt;
int dolcnt;
tchar dolmod;
int dolmcnt;
void Dfix2(tchar **);
void Dgetdol(void);
void setDolp(tchar *);
void unDredc(int);
void
Dfix(struct command *t)
{
tchar **pp;
tchar *p;
#ifdef TRACE
tprintf("TRACE- Dfix()\n");
#endif
if (noexec)
return;
for (pp = t->t_dcom; p = *pp++; )
while (*p)
if (cmap(*p++, _DOL|QUOTES)) {
Dfix2(t->t_dcom);
blkfree(t->t_dcom);
t->t_dcom = gargv;
gargv = 0;
return;
}
}
tchar *
Dfix1(tchar *cp)
{
tchar *Dv[2];
#ifdef TRACE
tprintf("TRACE- Dfix1()\n");
#endif
if (noexec)
return (0);
Dv[0] = cp; Dv[1] = NOSTR;
Dfix2(Dv);
if (gargc != 1) {
setname(cp);
bferr("Ambiguous");
}
cp = savestr(gargv[0]);
blkfree(gargv), gargv = 0;
return (cp);
}
void
Dfix2(tchar **v)
{
tchar *agargv[GAVSIZ];
#ifdef TRACE
tprintf("TRACE- Dfix2()\n");
#endif
ginit(agargv);
Dvp = v; Dcp = S_ ;
unDgetC(0); unDredc(0);
dolp = 0; dolcnt = 0;
while (Dword())
continue;
gargv = copyblk(gargv);
}
int
Dword(void)
{
int c, c1;
static tchar *wbuf = NULL;
static int wbufsiz = BUFSIZ;
int wp = 0;
bool dolflg;
bool sofar = 0;
#define DYNAMICBUFFER() \
do { \
if (wp >= wbufsiz) { \
wbufsiz += BUFSIZ; \
wbuf = xrealloc(wbuf, (wbufsiz+1) * sizeof (tchar)); \
} \
} while (0)
#ifdef TRACE
tprintf("TRACE- Dword()\n");
#endif
if (wbuf == NULL)
wbuf = xalloc((wbufsiz+1) * sizeof (tchar));
loop:
c = DgetC(DODOL);
switch (c) {
case DEOF:
deof:
if (sofar == 0)
return (0);
unDredc(c);
case '\n':
wbuf[wp] = 0;
goto ret;
case ' ':
case '\t':
goto loop;
case '`':
wbuf[wp++] = c;
case '\'':
case '"':
c1 = c;
dolflg = c1 == '"' ? DODOL : 0;
for (;;) {
c = DgetC(dolflg);
if (c == c1)
break;
if (c == '\n' || c == DEOF)
error("Unmatched %c", (tchar) c1);
if ((c & (QUOTE|TRIM)) == ('\n' | QUOTE))
--wp;
DYNAMICBUFFER();
switch (c1) {
case '"':
wbuf[wp++] = c == '`' ? '`' : c | QUOTE;
break;
case '\'':
wbuf[wp++] = c | QUOTE;
break;
case '`':
wbuf[wp++] = c;
break;
}
}
if (c1 == '`') {
DYNAMICBUFFER();
wbuf[wp++] = '`';
}
goto pack;
case '\\':
c = DgetC(0);
if (c == '\n' || c == DEOF)
goto loop;
c |= QUOTE;
break;
#ifdef MBCHAR
default:
if (isauxsp(c)) goto loop;
#endif
}
unDgetC(c);
pack:
sofar = 1;
for (;;) {
c = DgetC(DODOL);
if (c == '\\') {
c = DgetC(0);
if (c == DEOF)
goto deof;
if (c == '\n')
c = ' ';
else
c |= QUOTE;
}
if (c == DEOF)
goto deof;
if (cmap(c, _SP|_NL|_Q|_Q1) ||
isauxsp(c)) {
unDgetC(c);
if (cmap(c, QUOTES))
goto loop;
DYNAMICBUFFER();
wbuf[wp++] = 0;
goto ret;
}
DYNAMICBUFFER();
wbuf[wp++] = c;
}
ret:
Gcat(S_ , wbuf);
return (1);
}
int
DgetC(int flag)
{
int c;
top:
if (c = Dpeekc) {
Dpeekc = 0;
return (c);
}
if (lap) {
c = *lap++ & (QUOTE|TRIM);
if (c == 0) {
lap = 0;
goto top;
}
quotspec:
if (!err_msg && cmap(c, QUOTES))
return (c | QUOTE);
return (c);
}
if (dolp) {
if (c = *dolp++ & (QUOTE|TRIM))
goto quotspec;
if (dolcnt > 0) {
setDolp(*dolnxt++);
--dolcnt;
return (' ');
}
dolp = 0;
}
if (dolcnt > 0) {
setDolp(*dolnxt++);
--dolcnt;
goto top;
}
c = Dredc();
if (c == '$' && flag) {
Dgetdol();
goto top;
}
return (c);
}
tchar *nulvec[] = { 0 };
struct varent nulargv = { nulvec, S_argv, 0 };
void
Dgetdol(void)
{
tchar *np;
struct varent *vp;
tchar name[MAX_VREF_LEN];
int c, sc;
int subscr = 0, lwb = 1, upb = 0;
bool dimen = 0, bitset = 0;
tchar wbuf[BUFSIZ + MB_LEN_MAX];
#ifdef TRACE
tprintf("TRACE- Dgetdol()\n");
#endif
dolmod = dolmcnt = 0;
c = sc = DgetC(0);
if (c == '{')
c = DgetC(0);
if ((c & TRIM) == '#')
dimen++, c = DgetC(0);
else if (c == '?')
bitset++, c = DgetC(0);
switch (c) {
case '$':
if (dimen || bitset)
syntax:
error("Variable syntax");
setDolp(doldol);
goto eatbrac;
case '<'|QUOTE:
if (dimen || bitset)
goto syntax;
for (np = wbuf; read_(OLDSTD, np, 1) == 1; np++) {
if (np >= &wbuf[BUFSIZ-1])
error("$< line too long");
if (*np <= 0 || *np == '\n')
break;
}
*np = 0;
dolmod = 'q';
dolmcnt = 10000;
setDolp(wbuf);
goto eatbrac;
case DEOF:
case '\n':
goto syntax;
case '*':
(void) strcpy_(name, S_argv);
vp = adrof(S_argv);
subscr = -1;
break;
default:
np = name;
if (digit(c)) {
if (dimen)
goto syntax;
subscr = 0;
do {
subscr = subscr * 10 + c - '0';
c = DgetC(0);
} while (digit(c));
unDredc(c);
if (subscr < 0)
error("Subscript out of range");
if (subscr == 0) {
if (bitset) {
dolp = file ? S_1 : S_0 ;
goto eatbrac;
}
if (file == 0)
error("No file for $0");
setDolp(file);
goto eatbrac;
}
if (bitset)
goto syntax;
vp = adrof(S_argv);
if (vp == 0) {
vp = &nulargv;
goto eatmod;
}
break;
}
if (!alnum(c))
goto syntax;
for (;;) {
*np++ = c;
c = DgetC(0);
if (!alnum(c))
break;
if (np >= &name[MAX_VAR_LEN])
error("Variable name too long");
}
*np++ = 0;
unDredc(c);
vp = adrof(name);
}
if (bitset) {
dolp = (vp || getenv_(name)) ? S_1 : S_0 ;
goto eatbrac;
}
if (vp == 0) {
np = getenv_(name);
if (np) {
addla(np);
goto eatbrac;
}
udvar(name);
}
c = DgetC(0);
upb = blklen(vp->vec);
if (dimen == 0 && subscr == 0 && c == '[') {
np = name;
for (;;) {
c = DgetC(DODOL);
if (c == ']')
break;
if (c == '\n' || c == DEOF)
goto syntax;
if (np >= &name[MAX_VREF_LEN])
error("Variable reference too long");
*np++ = c;
}
*np = 0, np = name;
if (dolp || dolcnt)
goto syntax;
if (!*np)
goto syntax;
if (digit(*np)) {
int i = 0;
while (digit(*np))
i = i * 10 + *np++ - '0';
if ((i < 0 || i > upb) && (*np != '-') && (*np != '*')) {
oob:
setname(vp->v_name);
error("Subscript out of range");
}
lwb = i;
if (!*np)
upb = lwb, np = S_AST ;
}
if (*np == '*')
np++;
else if (*np != '-')
goto syntax;
else {
int i = upb;
np++;
if (digit(*np)) {
i = 0;
while (digit(*np))
i = i * 10 + *np++ - '0';
if (i < 0 || i > upb)
goto oob;
}
if (i < lwb)
upb = lwb - 1;
else
upb = i;
}
if (lwb == 0) {
if (upb != 0)
goto oob;
upb = -1;
}
if (*np)
goto syntax;
} else {
if (subscr > 0)
if (subscr > upb)
lwb = 1, upb = 0;
else
lwb = upb = subscr;
unDredc(c);
}
if (dimen) {
tchar *cp = putn(upb - lwb + 1);
addla(cp);
xfree(cp);
} else {
eatmod:
c = DgetC(0);
if (c == ':') {
c = DgetC(0), dolmcnt = 1;
if (c == 'g')
c = DgetC(0), dolmcnt = 10000;
if (!any(c, S_htrqxe))
error("Bad : mod in $");
dolmod = c;
if (c == 'q')
dolmcnt = 10000;
} else
unDredc(c);
dolnxt = &vp->vec[lwb - 1];
dolcnt = upb - lwb + 1;
}
eatbrac:
if (sc == '{') {
c = Dredc();
if (c != '}')
goto syntax;
}
}
void
setDolp(tchar *cp)
{
tchar *dp;
#ifdef TRACE
tprintf("TRACE- setDolp()\n");
#endif
if (dolmod == 0 || dolmcnt == 0) {
dolp = cp;
return;
}
dp = domod(cp, dolmod);
if (dp) {
dolmcnt--;
addla(dp);
xfree(dp);
} else
addla(cp);
dolp = S_ ;
}
void
unDredc(int c)
{
Dpeekrd = c;
}
int
Dredc()
{
int c;
if (c = Dpeekrd) {
Dpeekrd = 0;
return (c);
}
if (Dcp && (c = *Dcp++))
return (c&(QUOTE|TRIM));
if (*Dvp == 0) {
Dcp = 0;
return (DEOF);
}
Dcp = *Dvp++;
return (' ');
}
void
Dtestq(int c)
{
if (cmap(c, QUOTES))
gflag = 1;
}
void
heredoc(tchar *term)
{
int c;
tchar *Dv[2];
tchar obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
int ocnt, lcnt, mcnt;
tchar *lbp, *obp, *mbp;
tchar **vp;
bool quoted;
tchar shtemp[] = {'/', 't', 'm', 'p', '/', 's', 'h', 'X', 'X', 'X',
'X', 'X', 'X', 0};
int fd1;
#ifdef TRACE
tprintf("TRACE- heredoc()\n");
#endif
if ((fd1 = mkstemp_(shtemp)) < 0)
Perror(shtemp);
(void) unlink_(shtemp);
unsetfd(fd1);
Dv[0] = term; Dv[1] = NOSTR; gflag = 0;
trim(Dv); rscan(Dv, Dtestq); quoted = gflag;
ocnt = BUFSIZ; obp = obuf;
for (;;) {
lbp = lbuf; lcnt = BUFSIZ - 4;
for (;;) {
c = readc(1);
if (c < 0) {
setname(term);
bferr("<< terminator not found");
}
if (c == '\n')
break;
if (c &= TRIM) {
*lbp++ = c;
if (--lcnt < 0) {
setname(S_LESLES );
error("Line overflow");
}
}
}
*lbp = 0;
if (eq(lbuf, term)) {
(void) write_(0, obuf, BUFSIZ - ocnt);
(void) lseek(0, (off_t)0, 0);
return;
}
if (quoted || noexec) {
*lbp++ = '\n'; *lbp = 0;
for (lbp = lbuf; c = *lbp++; ) {
*obp++ = c;
if (--ocnt == 0) {
(void) write_(0, obuf, BUFSIZ);
obp = obuf; ocnt = BUFSIZ;
}
}
continue;
}
Dcp = lbuf; Dvp = Dv + 1; mbp = mbuf; mcnt = BUFSIZ - 4;
for (;;) {
c = DgetC(DODOL);
if (c == DEOF)
break;
if ((c &= TRIM) == 0)
continue;
if (c == '\\') {
c = DgetC(0);
if ((c != '$') && (c != '\\') && (c != '`'))
unDgetC(c | QUOTE), c = '\\';
else
c |= QUOTE;
}
*mbp++ = c;
if (--mcnt == 0) {
setname(S_LESLES );
bferr("Line overflow");
}
}
*mbp++ = 0;
mbp = mbuf;
if (any('`', mbp)) {
vp = dobackp(mbuf, 1);
} else
Dv[0] = mbp, Dv[1] = NOSTR, vp = Dv;
for (; *vp; vp++) {
for (mbp = *vp; *mbp; mbp++) {
*obp++ = *mbp & TRIM;
if (--ocnt == 0) {
(void) write_(0, obuf, BUFSIZ);
obp = obuf; ocnt = BUFSIZ;
}
}
*obp++ = '\n';
if (--ocnt == 0) {
(void) write_(0, obuf, BUFSIZ);
obp = obuf; ocnt = BUFSIZ;
}
}
if (pargv)
blkfree(pargv), pargv = 0;
}
}