#include "sh.h"
RCSID("$Id: sh.dol.c,v 1.1.1.2 2001/06/28 23:10:50 bbraun Exp $")
static int Dpeekc, Dpeekrd;
static Char *Dcp, **Dvp;
#define DEOF -1
#define unDgetC(c) Dpeekc = c
#define QUOTES (_QF|_QB|_ESC)
#define MAXWLEN (BUFSIZE - 4)
#ifndef COMPAT
#define MAXMOD MAXWLEN
#endif
static Char *dolp;
static Char **dolnxt;
static int dolcnt;
#ifdef COMPAT
static Char dolmod;
#else
static Char dolmod[MAXMOD];
static int dolnmod;
#endif
static int dolmcnt;
static int dolwcnt;
static void Dfix2 __P((Char **));
static Char *Dpack __P((Char *, Char *));
static int Dword __P((void));
static void dolerror __P((Char *));
static int DgetC __P((int));
static void Dgetdol __P((void));
static void fixDolMod __P((void));
static void setDolp __P((Char *));
static void unDredc __P((int));
static int Dredc __P((void));
static void Dtestq __P((int));
void
Dfix(t)
register struct command *t;
{
register Char **pp;
register Char *p;
if (noexec)
return;
for (pp = t->t_dcom; (p = *pp++) != NULL;) {
for (; *p; p++) {
#ifdef DSPMBYTE
if (Ismbyte1(*p) && *(p + 1))
p ++;
else
#endif DSPMBYTE
if (cmap(*p, _DOL | QUOTES)) {
Dfix2(t->t_dcom);
blkfree(t->t_dcom);
t->t_dcom = gargv;
gargv = 0;
return;
}
}
}
}
Char *
Dfix1(cp)
register Char *cp;
{
Char *Dv[2];
if (noexec)
return (0);
Dv[0] = cp;
Dv[1] = NULL;
Dfix2(Dv);
if (gargc != 1) {
setname(short2str(cp));
stderror(ERR_NAME | ERR_AMBIG);
}
cp = Strsave(gargv[0]);
blkfree(gargv), gargv = 0;
return (cp);
}
static void
Dfix2(v)
Char **v;
{
ginit();
Dvp = v;
Dcp = STRNULL;
unDgetC(0);
unDredc(0);
dolp = 0;
dolcnt = 0;
while (Dword())
continue;
}
static Char *
Dpack(wbuf, wp)
Char *wbuf, *wp;
{
register int c;
register int i = MAXWLEN - (int) (wp - wbuf);
#if defined(DSPMBYTE)
int mbytepos = 1;
#endif
for (;;) {
c = DgetC(DODOL);
#if defined(DSPMBYTE)
if (mbytepos == 1 && Ismbyte1(c)) {
mbytepos = 2;
}
else {
if (mbytepos == 2 && Ismbyte2(c)) {
mbytepos = 1;
goto mbyteskip;
}
mbytepos = 1;
}
#endif
if (c == '\\') {
c = DgetC(0);
if (c == DEOF) {
unDredc(c);
*wp = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
if (c == '\n')
c = ' ';
else
c |= QUOTE;
}
if (c == DEOF) {
unDredc(c);
*wp = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
if (cmap(c, _SP | _NL | _QF | _QB)) {
unDgetC(c);
if (cmap(c, QUOTES))
return (wp);
*wp++ = 0;
Gcat(STRNULL, wbuf);
return (NULL);
}
#if defined(DSPMBYTE)
mbyteskip:
#endif
if (--i <= 0)
stderror(ERR_WTOOLONG);
*wp++ = (Char) c;
}
}
static int
Dword()
{
register int c, c1;
Char wbuf[BUFSIZE];
register Char *wp = wbuf;
register int i = MAXWLEN;
register bool dolflg;
bool sofar = 0, done = 0;
while (!done) {
done = 1;
c = DgetC(DODOL);
switch (c) {
case DEOF:
if (sofar == 0)
return (0);
unDredc(c);
case '\n':
*wp = 0;
Gcat(STRNULL, wbuf);
return (1);
case ' ':
case '\t':
done = 0;
break;
case '`':
*wp++ = (Char) c, --i;
case '\'':
case '"':
c1 = c;
dolflg = c1 == '"' ? DODOL : 0;
for (;;) {
c = DgetC(dolflg);
if (c == c1)
break;
if (c == '\n' || c == DEOF)
stderror(ERR_UNMATCHED, c1);
if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE)) {
if ((wp[-1] & TRIM) == '\\')
--wp;
++i;
}
if (--i <= 0)
stderror(ERR_WTOOLONG);
switch (c1) {
case '"':
*wp++ = c == '`' ? '`' : c | QUOTE;
break;
case '\'':
*wp++ = c | QUOTE;
break;
case '`':
*wp++ = (Char) c;
break;
default:
break;
}
}
if (c1 == '`')
*wp++ = '`' ;
sofar = 1;
if ((wp = Dpack(wbuf, wp)) == NULL)
return (1);
else {
#ifdef masscomp
i = MAXWLEN;
i -= (int) (wp - wbuf);
#else
i = MAXWLEN - (int) (wp - wbuf);
#endif
done = 0;
}
break;
case '\\':
c = DgetC(0);
if (c == '\n' || c == DEOF) {
done = 0;
break;
}
c |= QUOTE;
break;
default:
break;
}
if (done) {
unDgetC(c);
sofar = 1;
if ((wp = Dpack(wbuf, wp)) == NULL)
return (1);
else {
#ifdef masscomp
i = MAXWLEN;
i -= (int) (wp - wbuf);
#else
i = MAXWLEN - (int) (wp - wbuf);
#endif
done = 0;
}
}
}
return (0);
}
static int
DgetC(flag)
register int flag;
{
register int c;
top:
if ((c = Dpeekc) != 0) {
Dpeekc = 0;
return (c);
}
if (lap) {
c = *lap++ & (QUOTE | TRIM);
if (c == 0) {
lap = 0;
goto top;
}
quotspec:
if (cmap(c, QUOTES))
return (c | QUOTE);
return (c);
}
if (dolp) {
if ((c = *dolp++ & (QUOTE | TRIM)) != 0)
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);
}
static Char *nulvec[] = { NULL };
static struct varent nulargv = {nulvec, STRargv, VAR_READWRITE,
{ NULL, NULL, NULL }, 0 };
static void
dolerror(s)
Char *s;
{
setname(short2str(s));
stderror(ERR_NAME | ERR_RANGE);
}
static void
Dgetdol()
{
register Char *np;
register struct varent *vp = NULL;
Char name[4 * MAXVARLEN + 1];
int c, sc;
int subscr = 0, lwb = 1, upb = 0;
bool dimen = 0, bitset = 0, length = 0;
char tnp;
Char wbuf[BUFSIZE];
static Char *dolbang = NULL;
#ifdef COMPAT
dolmod = dolmcnt = dolwcnt = 0;
#else
dolnmod = dolmcnt = dolwcnt = 0;
#endif
c = sc = DgetC(0);
if (c == '{')
c = DgetC(0);
if ((c & TRIM) == '#')
dimen++, c = DgetC(0);
else if (c == '?')
bitset++, c = DgetC(0);
else if (c == '%')
length++, c = DgetC(0);
switch (c) {
case '!':
if (dimen || bitset || length)
stderror(ERR_SYNTAX);
if (backpid != 0) {
if (dolbang)
xfree((ptr_t) dolbang);
setDolp(dolbang = putn(backpid));
}
goto eatbrac;
case '$':
if (dimen || bitset || length)
stderror(ERR_SYNTAX);
setDolp(doldol);
goto eatbrac;
#ifdef COHERENT
#ifdef SHORT_STRINGS
case 0100074:
#else
case 0274:
#endif
#else
case '<'|QUOTE:
#endif
if (bitset)
stderror(ERR_NOTALLOWED, "$?<");
if (dimen)
stderror(ERR_NOTALLOWED, "$#<");
if (length)
stderror(ERR_NOTALLOWED, "$%<");
{
#ifdef BSDSIGS
sigmask_t omask = sigsetmask(sigblock(0) & ~sigmask(SIGINT));
#else
(void) sigrelse(SIGINT);
#endif
for (np = wbuf; force_read(OLDSTD, &tnp, 1) == 1; np++) {
*np = (unsigned char) tnp;
if (np >= &wbuf[BUFSIZE - 1])
stderror(ERR_LTOOLONG);
if (tnp == '\n')
break;
}
*np = 0;
#ifdef BSDSIGS
(void) sigsetmask(omask);
#else
(void) sighold(SIGINT);
#endif
}
#ifdef COMPAT
dolmod = 'q';
dolmod[dolnmod++] = 'q';
dolmcnt = 10000;
#endif
fixDolMod();
setDolp(wbuf);
goto eatbrac;
case '*':
(void) Strcpy(name, STRargv);
vp = adrof(STRargv);
subscr = -1;
break;
case DEOF:
case '\n':
np = dimen ? STRargv : (bitset ? STRstatus : NULL);
if (np) {
bitset = 0;
(void) Strcpy(name, np);
vp = adrof(np);
subscr = -1;
unDredc(c);
break;
}
else
stderror(ERR_SYNTAX);
default:
np = name;
if (Isdigit(c)) {
if (dimen)
stderror(ERR_NOTALLOWED, "$#<num>");
subscr = 0;
do {
subscr = subscr * 10 + c - '0';
c = DgetC(0);
} while (Isdigit(c));
unDredc(c);
if (subscr < 0) {
dolerror(vp->v_name);
return;
}
if (subscr == 0) {
if (bitset) {
dolp = dolzero ? STR1 : STR0;
goto eatbrac;
}
if (ffile == 0)
stderror(ERR_DOLZERO);
if (length) {
Char *cp;
length = Strlen(ffile);
cp = putn(length);
addla(cp);
xfree((ptr_t) cp);
}
else {
fixDolMod();
setDolp(ffile);
}
goto eatbrac;
}
#if 0
if (bitset)
stderror(ERR_NOTALLOWED, "$?<num>");
if (length)
stderror(ERR_NOTALLOWED, "$%<num>");
#endif
vp = adrof(STRargv);
if (vp == 0) {
vp = &nulargv;
goto eatmod;
}
break;
}
if (!alnum(c)) {
np = dimen ? STRargv : (bitset ? STRstatus : NULL);
if (np) {
bitset = 0;
(void) Strcpy(name, np);
vp = adrof(np);
subscr = -1;
unDredc(c);
break;
}
else
stderror(ERR_VARALNUM);
}
for (;;) {
*np++ = (Char) c;
c = DgetC(0);
if (!alnum(c))
break;
if (np >= &name[MAXVARLEN])
stderror(ERR_VARTOOLONG);
}
*np++ = 0;
unDredc(c);
vp = adrof(name);
}
if (bitset) {
dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
goto eatbrac;
}
if (vp == 0) {
np = str2short(getenv(short2str(name)));
if (np) {
fixDolMod();
setDolp(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)
stderror(ERR_INCBR);
if (np >= &name[sizeof(name) / sizeof(Char) - 2])
stderror(ERR_VARTOOLONG);
*np++ = (Char) c;
}
*np = 0, np = name;
if (dolp || dolcnt)
stderror(ERR_EXPORD);
if (!*np)
stderror(ERR_SYNTAX);
if (Isdigit(*np)) {
int i;
for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
continue;
if ((i < 0 || i > upb) && !any("-*", *np)) {
dolerror(vp->v_name);
return;
}
lwb = i;
if (!*np)
upb = lwb, np = STRstar;
}
if (*np == '*')
np++;
else if (*np != '-')
stderror(ERR_MISSING, '-');
else {
register int i = upb;
np++;
if (Isdigit(*np)) {
i = 0;
while (Isdigit(*np))
i = i * 10 + *np++ - '0';
if (i < 0 || i > upb) {
dolerror(vp->v_name);
return;
}
}
if (i < lwb)
upb = lwb - 1;
else
upb = i;
}
if (lwb == 0) {
if (upb != 0) {
dolerror(vp->v_name);
return;
}
upb = -1;
}
if (*np)
stderror(ERR_SYNTAX);
}
else {
if (subscr > 0) {
if (subscr > upb)
lwb = 1, upb = 0;
else
lwb = upb = subscr;
}
unDredc(c);
}
if (dimen) {
Char *cp = putn(upb - lwb + 1);
if (sc == '{') {
c = Dredc();
if (c != '}')
{
xfree((ptr_t) cp);
stderror(ERR_MISSING, '}');
return;
}
unDredc(c);
}
addla(cp);
xfree((ptr_t) cp);
}
else if (length) {
int i;
Char *cp;
for (i = lwb - 1, length = 0; i < upb; i++)
length += Strlen(vp->vec[i]);
#ifdef notdef
length += i - 1;
#endif
cp = putn(length);
addla(cp);
xfree((ptr_t) cp);
}
else {
eatmod:
fixDolMod();
dolnxt = &vp->vec[lwb - 1];
dolcnt = upb - lwb + 1;
}
eatbrac:
if (sc == '{') {
c = Dredc();
if (c != '}')
stderror(ERR_MISSING, '}');
}
}
static void
fixDolMod()
{
register int c;
c = DgetC(0);
if (c == ':') {
#ifndef COMPAT
do {
#endif
c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
if (c == 'g' || c == 'a') {
if (c == 'g')
dolmcnt = 10000;
else
dolwcnt = 10000;
c = DgetC(0);
}
if ((c == 'g' && dolmcnt != 10000) ||
(c == 'a' && dolwcnt != 10000)) {
if (c == 'g')
dolmcnt = 10000;
else
dolwcnt = 10000;
c = DgetC(0);
}
if (c == 's') {
int delimcnt = 2;
int delim = DgetC(0);
dolmod[dolnmod++] = (Char) c;
dolmod[dolnmod++] = (Char) delim;
if (!delim || letter(delim)
|| Isdigit(delim) || any(" \t\n", delim)) {
seterror(ERR_BADSUBST);
break;
}
while ((c = DgetC(0)) != (-1)) {
dolmod[dolnmod++] = (Char) c;
if(c == delim) delimcnt--;
if(!delimcnt) break;
}
if(delimcnt) {
seterror(ERR_BADSUBST);
break;
}
continue;
}
if (!any("luhtrqxes", c))
stderror(ERR_BADMOD, c);
#ifndef COMPAT
dolmod[dolnmod++] = (Char) c;
#else
dolmod = (Char) c;
#endif
if (c == 'q')
dolmcnt = 10000;
#ifndef COMPAT
}
while ((c = DgetC(0)) == ':');
unDredc(c);
#endif
}
else
unDredc(c);
}
static void
setDolp(cp)
register Char *cp;
{
register Char *dp;
#ifndef COMPAT
int i;
#endif
#ifdef COMPAT
if (dolmod == 0 || dolmcnt == 0) {
#else
if (dolnmod == 0 || dolmcnt == 0) {
#endif
dolp = cp;
return;
}
#ifdef COMPAT
dp = domod(cp, dolmod);
#else
dp = cp = Strsave(cp);
for (i = 0; i < dolnmod; i++) {
if(dolmod[i] == 's') {
int delim;
Char *lhsub, *rhsub, *np;
size_t lhlen = 0, rhlen = 0;
int didmod = 0;
delim = dolmod[++i];
if (!delim || letter(delim)
|| Isdigit(delim) || any(" \t\n", delim)) {
seterror(ERR_BADSUBST);
break;
}
lhsub = &dolmod[++i];
while(dolmod[i] != delim && dolmod[++i]) {
lhlen++;
}
dolmod[i] = 0;
rhsub = &dolmod[++i];
while(dolmod[i] != delim && dolmod[++i]) {
rhlen++;
}
dolmod[i] = 0;
do {
strip(lhsub);
strip(cp);
dp = Strstr(cp, lhsub);
if (dp) {
np = (Char *) xmalloc((size_t)
((Strlen(cp) + 1 - lhlen + rhlen) *
sizeof(Char)));
(void) Strncpy(np, cp, (size_t) (dp - cp));
(void) Strcpy(np + (dp - cp), rhsub);
(void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
xfree((ptr_t) cp);
dp = cp = np;
didmod = 1;
} else {
break;
}
}
while (dolwcnt == 10000);
dolmod[i] = rhsub[-1] = (Char) delim;
if (didmod)
dolmcnt--;
#ifdef notdef
else
break;
#endif
} else {
int didmod = 0;
do {
if ((dp = domod(cp, dolmod[i])) != NULL) {
didmod = 1;
if (Strcmp(cp, dp) == 0) {
xfree((ptr_t) cp);
cp = dp;
break;
}
else {
xfree((ptr_t) cp);
cp = dp;
}
}
else
break;
}
while (dolwcnt == 10000);
dp = cp;
if (didmod)
dolmcnt--;
#ifdef notdef
else
break;
#endif
}
}
#endif
if (dp) {
#ifdef COMPAT
dolmcnt--;
#endif
addla(dp);
xfree((ptr_t) dp);
}
#ifndef COMPAT
else
addla(cp);
#endif
dolp = STRNULL;
if (seterr)
stderror(ERR_OLD);
}
static void
unDredc(c)
int c;
{
Dpeekrd = c;
}
static int
Dredc()
{
register int c;
if ((c = Dpeekrd) != 0) {
Dpeekrd = 0;
return (c);
}
if (Dcp && (c = *Dcp++))
return (c & (QUOTE | TRIM));
if (*Dvp == 0) {
Dcp = 0;
return (DEOF);
}
Dcp = *Dvp++;
return (' ');
}
static void
Dtestq(c)
register int c;
{
if (cmap(c, QUOTES))
gflag = 1;
}
void
heredoc(term)
Char *term;
{
int c;
Char *Dv[2];
Char obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
int ocnt, lcnt, mcnt;
register Char *lbp, *obp, *mbp;
Char **vp;
bool quoted;
char *tmp;
#ifndef WINNT_NATIVE
struct timeval tv;
again:
#endif
tmp = short2str(shtemp);
#ifndef O_CREAT
# define O_CREAT 0
if (creat(tmp, 0600) < 0)
stderror(ERR_SYSTEM, tmp, strerror(errno));
#endif
(void) close(0);
#ifndef O_TEMPORARY
# define O_TEMPORARY 0
#endif
#ifndef O_EXCL
# define O_EXCL 0
#endif
if (open(tmp, O_RDWR|O_CREAT|O_EXCL|O_TEMPORARY) == -1) {
int oerrno = errno;
#ifndef WINNT_NATIVE
if (errno == EEXIST) {
if (unlink(tmp) == -1) {
(void) gettimeofday(&tv, NULL);
shtemp = Strspl(STRtmpsh, putn((((int)tv.tv_sec) ^
((int)tv.tv_usec) ^ ((int)getpid())) & 0x00ffffff));
}
goto again;
}
#endif
(void) unlink(tmp);
errno = oerrno;
stderror(ERR_SYSTEM, tmp, strerror(errno));
}
(void) unlink(tmp);
Dv[0] = term;
Dv[1] = NULL;
gflag = 0;
trim(Dv);
rscan(Dv, Dtestq);
quoted = gflag;
ocnt = BUFSIZE;
obp = obuf;
inheredoc = 1;
#ifdef WINNT_NATIVE
__dup_stdin = 1;
#endif
for (;;) {
lbp = lbuf;
lcnt = BUFSIZE - 4;
for (;;) {
c = readc(1);
if (c < 0 || c == '\n')
break;
if ((c &= TRIM) != 0) {
*lbp++ = (Char) c;
if (--lcnt < 0) {
setname("<<");
stderror(ERR_NAME | ERR_OVERFLOW);
}
}
}
*lbp = 0;
if (c < 0 || eq(lbuf, term)) {
(void) write(0, short2str(obuf), (size_t) (BUFSIZE - ocnt));
(void) lseek(0, (off_t) 0, L_SET);
inheredoc = 0;
return;
}
if (quoted || noexec) {
*lbp++ = '\n';
*lbp = 0;
for (lbp = lbuf; (c = *lbp++) != 0;) {
*obp++ = (Char) c;
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZE);
obp = obuf;
ocnt = BUFSIZE;
}
}
continue;
}
Dcp = lbuf;
Dvp = Dv + 1;
mbp = mbuf;
mcnt = BUFSIZE - 4;
for (;;) {
c = DgetC(DODOL);
if (c == DEOF)
break;
if ((c &= TRIM) == 0)
continue;
if (c == '\\') {
c = DgetC(0);
if (!any("$\\`", c))
unDgetC(c | QUOTE), c = '\\';
else
c |= QUOTE;
}
*mbp++ = (Char) c;
if (--mcnt == 0) {
setname("<<");
stderror(ERR_NAME | ERR_OVERFLOW);
}
}
*mbp++ = 0;
mbp = mbuf;
if (Strchr(mbp, '`') != NULL) {
vp = dobackp(mbuf, 1);
}
else
Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
for (; *vp; vp++) {
for (mbp = *vp; *mbp; mbp++) {
*obp++ = *mbp & TRIM;
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZE);
obp = obuf;
ocnt = BUFSIZE;
}
}
*obp++ = '\n';
if (--ocnt == 0) {
(void) write(0, short2str(obuf), BUFSIZE);
obp = obuf;
ocnt = BUFSIZE;
}
}
if (pargv)
blkfree(pargv), pargv = 0;
}
}