summaryrefslogtreecommitdiffstats
path: root/contrib/tcsh/sh.dol.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/tcsh/sh.dol.c')
-rw-r--r--contrib/tcsh/sh.dol.c1150
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;
+ }
+}
OpenPOWER on IntegriCloud