diff options
Diffstat (limited to 'contrib/tcsh/sh.dol.c')
-rw-r--r-- | contrib/tcsh/sh.dol.c | 1150 |
1 files changed, 1150 insertions, 0 deletions
diff --git a/contrib/tcsh/sh.dol.c b/contrib/tcsh/sh.dol.c new file mode 100644 index 0000000..9b14b6f --- /dev/null +++ b/contrib/tcsh/sh.dol.c @@ -0,0 +1,1150 @@ +/* $Header: /src/pub/tcsh/sh.dol.c,v 3.38 1998/10/25 15:10:05 christos Exp $ */ +/* + * sh.dol.c: Variable substitutions + */ +/*- + * Copyright (c) 1980, 1991 The Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#include "sh.h" + +RCSID("$Id: sh.dol.c,v 3.38 1998/10/25 15:10:05 christos Exp $") + +/* + * C shell + */ + +/* + * These routines perform variable substitution and quoting via ' and ". + * To this point these constructs have been preserved in the divided + * input words. Here we expand variables and turn quoting via ' and " into + * QUOTE bits on characters (which prevent further interpretation). + * If the `:q' modifier was applied during history expansion, then + * some QUOTEing may have occurred already, so we dont "trim()" here. + */ + +static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */ +static Char *Dcp, **Dvp; /* Input vector for Dreadc */ + +#define DEOF -1 + +#define unDgetC(c) Dpeekc = c + +#define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */ + +/* + * The following variables give the information about the current + * $ expansion, recording the current word position, the remaining + * words within this expansion, the count of remaining words, and the + * information about any : modifier which is being applied. + */ +#define MAXWLEN (BUFSIZE - 4) +#ifndef COMPAT +#define MAXMOD MAXWLEN /* This cannot overflow */ +#endif /* COMPAT */ +static Char *dolp; /* Remaining chars from this word */ +static Char **dolnxt; /* Further words */ +static int dolcnt; /* Count of further words */ +#ifdef COMPAT +static Char dolmod; /* : modifier character */ +#else +static Char dolmod[MAXMOD]; /* : modifier character */ +static int dolnmod; /* Number of modifiers */ +#endif /* COMPAT */ +static int dolmcnt; /* :gx -> 10000, else 1 */ +static int dolwcnt; /* :ax -> 10000, else 1 */ + +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)); + +/* + * Fix up the $ expansions and quotations in the + * argument list to command t. + */ +void +Dfix(t) + register struct command *t; +{ + register Char **pp; + register Char *p; + + if (noexec) + return; + /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */ + for (pp = t->t_dcom; (p = *pp++) != NULL;) { + for (; *p; p++) { + if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */ + Dfix2(t->t_dcom); /* found one */ + blkfree(t->t_dcom); + t->t_dcom = gargv; + gargv = 0; + return; + } + } + } +} + +/* + * $ substitute one word, for i/o redirection + */ +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); +} + +/* + * Subroutine to do actual fixing after state initialization. + */ +static void +Dfix2(v) + Char **v; +{ + ginit(); /* Initialize glob's area pointers */ + Dvp = v; + Dcp = STRNULL; /* Setup input vector for Dreadc */ + unDgetC(0); + unDredc(0); /* Clear out any old peeks (at error) */ + dolp = 0; + dolcnt = 0; /* Clear out residual $ expands (...) */ + while (Dword()) + continue; +} + +/* + * Pack up more characters in this word + */ +static Char * +Dpack(wbuf, wp) + Char *wbuf, *wp; +{ + register int c; + register int i = MAXWLEN - (int) (wp - wbuf); + + for (;;) { + c = DgetC(DODOL); + 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)) { /* sp \t\n'"` */ + unDgetC(c); + if (cmap(c, QUOTES)) + return (wp); + *wp++ = 0; + Gcat(STRNULL, wbuf); + return (NULL); + } + if (--i <= 0) + stderror(ERR_WTOOLONG); + *wp++ = (Char) c; + } +} + +/* + * Get a word. This routine is analogous to the routine + * word() in sh.lex.c for the main lexical input. One difference + * here is that we don't get a newline to terminate our expansion. + * Rather, DgetC will return a DEOF when we hit the end-of-input. + */ +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); + /* finish this word and catch the code above the next time */ + unDredc(c); + /*FALLTHROUGH*/ + + case '\n': + *wp = 0; + Gcat(STRNULL, wbuf); + return (1); + + case ' ': + case '\t': + done = 0; + break; + + case '`': + /* We preserve ` quotations which are done yet later */ + *wp++ = (Char) c, --i; + /*FALLTHROUGH*/ + case '\'': + case '"': + /* + * Note that DgetC never returns a QUOTES character from an + * expansion, so only true input quotes will get us here or out. + */ + 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 '"': + /* + * Leave any `s alone for later. Other chars are all + * quoted, thus `...` can tell it was within "...". + */ + *wp++ = c == '`' ? '`' : c | QUOTE; + break; + + case '\'': + /* Prevent all further interpretation */ + *wp++ = c | QUOTE; + break; + + case '`': + /* Leave all text alone for later */ + *wp++ = (Char) c; + break; + + default: + break; + } + } + if (c1 == '`') + *wp++ = '`' /* i--; eliminated */; + sofar = 1; + if ((wp = Dpack(wbuf, wp)) == NULL) + return (1); + else { +#ifdef masscomp + /* + * Avoid a nasty message from the RTU 4.1A & RTU 5.0 compiler concerning + * the "overuse of registers". According to the compiler release notes, + * incorrect code may be produced unless the offending expression is + * rewritten. Therefore, we can't just ignore it, DAS DEC-90. + */ + i = MAXWLEN; + i -= (int) (wp - wbuf); +#else /* !masscomp */ + i = MAXWLEN - (int) (wp - wbuf); +#endif /* masscomp */ + done = 0; + } + break; + + case '\\': + c = DgetC(0); /* No $ subst! */ + 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 + /* + * Avoid a nasty message from the RTU 4.1A & RTU 5.0 compiler concerning + * the "overuse of registers". According to the compiler release notes, + * incorrect code may be produced unless the offending expression is + * rewritten. Therefore, we can't just ignore it, DAS DEC-90. + */ + i = MAXWLEN; + i -= (int) (wp - wbuf); +#else /* !masscomp */ + i = MAXWLEN - (int) (wp - wbuf); +#endif /* masscomp */ + done = 0; + } + } + } + /* Really NOTREACHED */ + return (0); +} + + +/* + * Get a character, performing $ substitution unless flag is 0. + * Any QUOTES character which is returned from a $ expansion is + * QUOTEd so that it will not be recognized above. + */ +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); +} + +/* + * Handle the multitudinous $ expansion forms. + * Ugh. + */ +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 /* COMPAT */ + c = sc = DgetC(0); + if (c == '{') + c = DgetC(0); /* sc is { to take } later */ + if ((c & TRIM) == '#') + dimen++, c = DgetC(0); /* $# takes dimension */ + else if (c == '?') + bitset++, c = DgetC(0); /* $? tests existence */ + else if (c == '%') + length++, c = DgetC(0); /* $% returns length in chars */ + 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 + /* Coherent compiler doesn't allow case-labels that are not + constant-expressions */ +#ifdef SHORT_STRINGS + case 0100074: +#else /* !SHORT_STRINGS */ + case 0274: +#endif +#else /* !COHERENT */ + 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 /* !BSDSIGS */ + (void) sigrelse(SIGINT); +#endif /* BSDSIGS */ + 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 /* !BSDSIGS */ + (void) sighold(SIGINT); +#endif /* BSDSIGS */ + } + +#ifdef COMPAT + /* + * KLUDGE: dolmod is set here because it will cause setDolp to call + * domod and thus to copy wbuf. Otherwise setDolp would use it + * directly. If we saved it ourselves, no one would know when to free + * it. The actual function of the 'q' causes filename expansion not to + * be done on the interpolated value. + */ + /* + * If we do that, then other modifiers don't work. + * in addition, let the user specify :q if wanted + * [christos] + */ +/*old*/ dolmod = 'q'; +/*new*/ dolmod[dolnmod++] = 'q'; + dolmcnt = 10000; +#endif /* COMPAT */ + + fixDolMod(); + setDolp(wbuf); + goto eatbrac; + + case '*': + (void) Strcpy(name, STRargv); + vp = adrof(STRargv); + subscr = -1; /* Prevent eating [...] */ + break; + + case DEOF: + case '\n': + np = dimen ? STRargv : (bitset ? STRstatus : NULL); + if (np) { + bitset = 0; + (void) Strcpy(name, np); + vp = adrof(np); + subscr = -1; /* Prevent eating [...] */ + unDredc(c); + break; + } + else + stderror(ERR_SYNTAX); + /*NOTREACHED*/ + + 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; /* Prevent eating [...] */ + 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); + /* NOTREACHED */ + } + c = DgetC(0); + upb = blklen(vp->vec); + if (dimen == 0 && subscr == 0 && c == '[') { + np = name; + for (;;) { + c = DgetC(DODOL); /* Allow $ expand within [ ] */ + 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) /* $ exp must end before ] */ + 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); + + /* this is a kludge. It prevents Dgetdol() from */ + /* pushing erroneous ${#<error> values into the labuf. */ + 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 + /* We don't want that, since we can always compute it by adding $#xxx */ + length += i - 1; /* Add the number of spaces in */ +#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 /* COMPAT */ + 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') { /* [eichin:19910926.0755EST] */ + 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 /* COMPAT */ + if (c == 'q') + dolmcnt = 10000; +#ifndef COMPAT + } + while ((c = DgetC(0)) == ':'); + unDredc(c); +#endif /* COMPAT */ + } + else + unDredc(c); +} + +static void +setDolp(cp) + register Char *cp; +{ + register Char *dp; +#ifndef COMPAT + int i; +#endif /* COMPAT */ + +#ifdef COMPAT + if (dolmod == 0 || dolmcnt == 0) { +#else + if (dolnmod == 0 || dolmcnt == 0) { +#endif /* COMPAT */ + dolp = cp; + return; + } +#ifdef COMPAT + dp = domod(cp, dolmod); +#else + dp = cp = Strsave(cp); + for (i = 0; i < dolnmod; i++) { + /* handle s// [eichin:19910926.0510EST] */ + 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 { + /* should this do a seterror? */ + break; + } + } + while (dolwcnt == 10000); + /* + * restore dolmod for additional words + */ + 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 /* COMPAT */ + + if (dp) { +#ifdef COMPAT + dolmcnt--; +#endif /* COMPAT */ + addla(dp); + xfree((ptr_t) dp); + } +#ifndef COMPAT + else + addla(cp); +#endif /* COMPAT */ + + 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; +} + +/* + * Form a shell temporary file (in unit 0) from the words + * of the shell input up to EOF or a line the same as "term". + * Unit 0 should have been closed before this call. + */ +void +heredoc(term) + Char *term; +{ + register 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; + + 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 + if (open(tmp, O_RDWR|O_CREAT|O_TEMPORARY) < 0) { + int oerrno = errno; + + (void) unlink(tmp); + errno = oerrno; + stderror(ERR_SYSTEM, tmp, strerror(errno)); + } + (void) unlink(tmp); /* 0 0 inode! */ + Dv[0] = term; + Dv[1] = NULL; + gflag = 0; + trim(Dv); + rscan(Dv, Dtestq); + quoted = gflag; + ocnt = BUFSIZE; + obp = obuf; + inheredoc = 1; +#ifdef WINNT + __dup_stdin = 1; +#endif /* WINNT */ + for (;;) { + /* + * Read up a line + */ + lbp = lbuf; + lcnt = BUFSIZE - 4; + for (;;) { + c = readc(1); /* 1 -> Want EOF returns */ + if (c < 0 || c == '\n') + break; + if ((c &= TRIM) != 0) { + *lbp++ = (Char) c; + if (--lcnt < 0) { + setname("<<"); + stderror(ERR_NAME | ERR_OVERFLOW); + } + } + } + *lbp = 0; + + /* + * Check for EOF or compare to terminator -- before expansion + */ + 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 term was quoted or -n just pass it on + */ + 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; + } + + /* + * Term wasn't quoted so variable and then command expand the input + * line + */ + Dcp = lbuf; + Dvp = Dv + 1; + mbp = mbuf; + mcnt = BUFSIZE - 4; + for (;;) { + c = DgetC(DODOL); + if (c == DEOF) + break; + if ((c &= TRIM) == 0) + continue; + /* \ quotes \ $ ` here */ + 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; + + /* + * If any ` in line do command substitution + */ + mbp = mbuf; + if (Strchr(mbp, '`') != NULL) { + /* + * 1 arg to dobackp causes substitution to be literal. Words are + * broken only at newlines so that all blanks and tabs are + * preserved. Blank lines (null words) are not discarded. + */ + vp = dobackp(mbuf, 1); + } + else + /* Setup trivial vector similar to return of dobackp */ + Dv[0] = mbp, Dv[1] = NULL, vp = Dv; + + /* + * Resurrect the words from the command substitution each separated by + * a newline. Note that the last newline of a command substitution + * will have been discarded, but we put a newline after the last word + * because this represents the newline after the last input line! + */ + 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; + } +} |