147823Sbostic /*-
260765Sbostic * Copyright (c) 1980, 1991, 1993
360765Sbostic * The Regents of the University of California. All rights reserved.
447823Sbostic *
547823Sbostic * %sccs.include.redist.c%
621928Sdist */
721928Sdist
817515Sedward #ifndef lint
9*69126Schristos static char sccsid[] = "@(#)dol.c 8.2 (Berkeley) 04/29/95";
1047410Sbostic #endif /* not lint */
111290Sbill
1250028Sbostic #include <sys/types.h>
1350028Sbostic #include <fcntl.h>
1450028Sbostic #include <errno.h>
1550028Sbostic #include <stdlib.h>
1650028Sbostic #include <string.h>
1750028Sbostic #include <unistd.h>
1850033Schristos #if __STDC__
1950033Schristos # include <stdarg.h>
2050033Schristos #else
2150033Schristos # include <varargs.h>
2250033Schristos #endif
2350033Schristos
2450023Sbostic #include "csh.h"
2550023Sbostic #include "extern.h"
261290Sbill
271290Sbill /*
281290Sbill * These routines perform variable substitution and quoting via ' and ".
291290Sbill * To this point these constructs have been preserved in the divided
301290Sbill * input words. Here we expand variables and turn quoting via ' and " into
311290Sbill * QUOTE bits on characters (which prevent further interpretation).
321290Sbill * If the `:q' modifier was applied during history expansion, then
3317515Sedward * some QUOTEing may have occurred already, so we dont "trim()" here.
341290Sbill */
351290Sbill
3649992Sbostic static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
3749992Sbostic static Char *Dcp, **Dvp; /* Input vector for Dreadc */
381290Sbill
391290Sbill #define DEOF -1
401290Sbill
411290Sbill #define unDgetC(c) Dpeekc = c
421290Sbill
4360488Schristos #define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
441290Sbill
451290Sbill /*
461290Sbill * The following variables give the information about the current
471290Sbill * $ expansion, recording the current word position, the remaining
481290Sbill * words within this expansion, the count of remaining words, and the
491290Sbill * information about any : modifier which is being applied.
501290Sbill */
5150462Schristos #define MAXWLEN (BUFSIZ - 4)
5250462Schristos #define MAXMOD MAXWLEN /* This cannot overflow */
5349992Sbostic static Char *dolp; /* Remaining chars from this word */
5449992Sbostic static Char **dolnxt; /* Further words */
5549992Sbostic static int dolcnt; /* Count of further words */
5650462Schristos static Char dolmod[MAXMOD]; /* : modifier character */
5750462Schristos static int dolnmod; /* Number of modifiers */
5849992Sbostic static int dolmcnt; /* :gx -> 10000, else 1 */
5951526Schristos static int dolwcnt; /* :wx -> 10000, else 1 */
601290Sbill
6150024Schristos static void Dfix2 __P((Char **));
6251437Sleres static Char *Dpack __P((Char *, Char *));
6350024Schristos static int Dword __P((void));
6450024Schristos static void dolerror __P((Char *));
6550024Schristos static int DgetC __P((int));
6650024Schristos static void Dgetdol __P((void));
6750024Schristos static void fixDolMod __P((void));
6850024Schristos static void setDolp __P((Char *));
6950024Schristos static void unDredc __P((int));
7050024Schristos static int Dredc __P((void));
7150024Schristos static void Dtestq __P((int));
7249992Sbostic
7349992Sbostic
741290Sbill /*
751290Sbill * Fix up the $ expansions and quotations in the
761290Sbill * argument list to command t.
771290Sbill */
7849992Sbostic void
Dfix(t)791290Sbill Dfix(t)
8049992Sbostic register struct command *t;
811290Sbill {
8249992Sbostic register Char **pp;
8349992Sbostic register Char *p;
841290Sbill
8549992Sbostic if (noexec)
8649992Sbostic return;
8749992Sbostic /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
8860237Schristos for (pp = t->t_dcom; (p = *pp++) != NULL;)
8949992Sbostic for (; *p; p++) {
9049992Sbostic if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */
9149992Sbostic Dfix2(t->t_dcom); /* found one */
9249992Sbostic blkfree(t->t_dcom);
9349992Sbostic t->t_dcom = gargv;
9449992Sbostic gargv = 0;
951290Sbill return;
9649992Sbostic }
9749992Sbostic }
981290Sbill }
991290Sbill
1001290Sbill /*
1011290Sbill * $ substitute one word, for i/o redirection
1021290Sbill */
10349992Sbostic Char *
Dfix1(cp)1041290Sbill Dfix1(cp)
10549992Sbostic register Char *cp;
1061290Sbill {
10749992Sbostic Char *Dv[2];
1081290Sbill
10949992Sbostic if (noexec)
11049992Sbostic return (0);
11149992Sbostic Dv[0] = cp;
11249992Sbostic Dv[1] = NULL;
11349992Sbostic Dfix2(Dv);
11449992Sbostic if (gargc != 1) {
11551589Schristos setname(vis_str(cp));
11649992Sbostic stderror(ERR_NAME | ERR_AMBIG);
11749992Sbostic }
11849992Sbostic cp = Strsave(gargv[0]);
11949992Sbostic blkfree(gargv), gargv = 0;
12049992Sbostic return (cp);
1211290Sbill }
1221290Sbill
1231290Sbill /*
1241290Sbill * Subroutine to do actual fixing after state initialization.
1251290Sbill */
12649992Sbostic static void
Dfix2(v)1271290Sbill Dfix2(v)
12849992Sbostic Char **v;
1291290Sbill {
13049992Sbostic ginit(); /* Initialize glob's area pointers */
13149992Sbostic Dvp = v;
13249992Sbostic Dcp = STRNULL; /* Setup input vector for Dreadc */
13349992Sbostic unDgetC(0);
13449992Sbostic unDredc(0); /* Clear out any old peeks (at error) */
13549992Sbostic dolp = 0;
13649992Sbostic dolcnt = 0; /* Clear out residual $ expands (...) */
13749992Sbostic while (Dword())
13849992Sbostic continue;
1391290Sbill }
1401290Sbill
1411290Sbill /*
14249992Sbostic * Pack up more characters in this word
14349992Sbostic */
14449992Sbostic static Char *
Dpack(wbuf,wp)14549992Sbostic Dpack(wbuf, wp)
14649992Sbostic Char *wbuf, *wp;
14749992Sbostic {
14849992Sbostic register int c;
14949992Sbostic register int i = MAXWLEN - (wp - wbuf);
15049992Sbostic
15149992Sbostic for (;;) {
15249992Sbostic c = DgetC(DODOL);
15349992Sbostic if (c == '\\') {
15449992Sbostic c = DgetC(0);
15549992Sbostic if (c == DEOF) {
15649992Sbostic unDredc(c);
15749992Sbostic *wp = 0;
15849992Sbostic Gcat(STRNULL, wbuf);
15949992Sbostic return (NULL);
16049992Sbostic }
16149992Sbostic if (c == '\n')
16249992Sbostic c = ' ';
16349992Sbostic else
16449992Sbostic c |= QUOTE;
16549992Sbostic }
16649992Sbostic if (c == DEOF) {
16749992Sbostic unDredc(c);
16849992Sbostic *wp = 0;
16949992Sbostic Gcat(STRNULL, wbuf);
17049992Sbostic return (NULL);
17149992Sbostic }
17260488Schristos if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */
17349992Sbostic unDgetC(c);
17449992Sbostic if (cmap(c, QUOTES))
17549992Sbostic return (wp);
17649992Sbostic *wp++ = 0;
17749992Sbostic Gcat(STRNULL, wbuf);
17849992Sbostic return (NULL);
17949992Sbostic }
18049992Sbostic if (--i <= 0)
18149992Sbostic stderror(ERR_WTOOLONG);
18249992Sbostic *wp++ = c;
18349992Sbostic }
18449992Sbostic }
18549992Sbostic
18649992Sbostic /*
1871290Sbill * Get a word. This routine is analogous to the routine
1881290Sbill * word() in sh.lex.c for the main lexical input. One difference
1891290Sbill * here is that we don't get a newline to terminate our expansion.
1901290Sbill * Rather, DgetC will return a DEOF when we hit the end-of-input.
1911290Sbill */
19249992Sbostic static int
Dword()1931290Sbill Dword()
1941290Sbill {
19549992Sbostic register int c, c1;
19649992Sbostic Char wbuf[BUFSIZ];
19749992Sbostic register Char *wp = wbuf;
19849992Sbostic register int i = MAXWLEN;
19949992Sbostic register bool dolflg;
20049992Sbostic bool sofar = 0, done = 0;
2011290Sbill
20249992Sbostic while (!done) {
20349992Sbostic done = 1;
2041290Sbill c = DgetC(DODOL);
2051290Sbill switch (c) {
2061290Sbill
2071290Sbill case DEOF:
20849992Sbostic if (sofar == 0)
20949992Sbostic return (0);
21049992Sbostic /* finish this word and catch the code above the next time */
21149992Sbostic unDredc(c);
21249992Sbostic /* fall into ... */
2131290Sbill
2141290Sbill case '\n':
21549992Sbostic *wp = 0;
21649992Sbostic Gcat(STRNULL, wbuf);
21749992Sbostic return (1);
2181290Sbill
2191290Sbill case ' ':
2201290Sbill case '\t':
22149992Sbostic done = 0;
22249992Sbostic break;
2231290Sbill
2241290Sbill case '`':
22549992Sbostic /* We preserve ` quotations which are done yet later */
22649992Sbostic *wp++ = c, --i;
2271290Sbill case '\'':
2281290Sbill case '"':
22949992Sbostic /*
23049992Sbostic * Note that DgetC never returns a QUOTES character from an
23149992Sbostic * expansion, so only true input quotes will get us here or out.
23249992Sbostic */
23349992Sbostic c1 = c;
23449992Sbostic dolflg = c1 == '"' ? DODOL : 0;
23549992Sbostic for (;;) {
23649992Sbostic c = DgetC(dolflg);
23749992Sbostic if (c == c1)
23849992Sbostic break;
23949992Sbostic if (c == '\n' || c == DEOF)
24049992Sbostic stderror(ERR_UNMATCHED, c1);
24149992Sbostic if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
24249992Sbostic --wp, ++i;
24349992Sbostic if (--i <= 0)
24449992Sbostic stderror(ERR_WTOOLONG);
24549992Sbostic switch (c1) {
2461290Sbill
24749992Sbostic case '"':
24849992Sbostic /*
24949992Sbostic * Leave any `s alone for later. Other chars are all
25049992Sbostic * quoted, thus `...` can tell it was within "...".
25149992Sbostic */
25249992Sbostic *wp++ = c == '`' ? '`' : c | QUOTE;
25349992Sbostic break;
2541290Sbill
25549992Sbostic case '\'':
25649992Sbostic /* Prevent all further interpretation */
25749992Sbostic *wp++ = c | QUOTE;
25849992Sbostic break;
2591290Sbill
26049992Sbostic case '`':
26149992Sbostic /* Leave all text alone for later */
26249992Sbostic *wp++ = c;
26349992Sbostic break;
26451526Schristos
26551526Schristos default:
26651526Schristos break;
2671290Sbill }
26849992Sbostic }
26949992Sbostic if (c1 == '`')
27051526Schristos *wp++ = '`' /* i--; eliminated */;
27149992Sbostic sofar = 1;
27249992Sbostic if ((wp = Dpack(wbuf, wp)) == NULL)
27349992Sbostic return (1);
27449992Sbostic else {
27549992Sbostic i = MAXWLEN - (wp - wbuf);
27649992Sbostic done = 0;
27749992Sbostic }
27849992Sbostic break;
2791290Sbill
2801290Sbill case '\\':
28149992Sbostic c = DgetC(0); /* No $ subst! */
28249992Sbostic if (c == '\n' || c == DEOF) {
28349992Sbostic done = 0;
2841290Sbill break;
28549992Sbostic }
28649992Sbostic c |= QUOTE;
28749992Sbostic break;
28851526Schristos
28951526Schristos default:
29051526Schristos break;
2911290Sbill }
29249992Sbostic if (done) {
29349992Sbostic unDgetC(c);
29449992Sbostic sofar = 1;
29549992Sbostic if ((wp = Dpack(wbuf, wp)) == NULL)
29649992Sbostic return (1);
29749992Sbostic else {
29849992Sbostic i = MAXWLEN - (wp - wbuf);
29949992Sbostic done = 0;
30049992Sbostic }
3011290Sbill }
30249992Sbostic }
30349992Sbostic /* Really NOTREACHED */
30449992Sbostic return (0);
3051290Sbill }
3061290Sbill
30749992Sbostic
3081290Sbill /*
3091290Sbill * Get a character, performing $ substitution unless flag is 0.
31012210Ssam * Any QUOTES character which is returned from a $ expansion is
31112210Ssam * QUOTEd so that it will not be recognized above.
3121290Sbill */
31349992Sbostic static int
DgetC(flag)3141290Sbill DgetC(flag)
31549992Sbostic register int flag;
3161290Sbill {
31749992Sbostic register int c;
3181290Sbill
3191290Sbill top:
32060237Schristos if ((c = Dpeekc) != '\0') {
32149992Sbostic Dpeekc = 0;
32249992Sbostic return (c);
32349992Sbostic }
32449992Sbostic if (lap) {
32549992Sbostic c = *lap++ & (QUOTE | TRIM);
32649992Sbostic if (c == 0) {
32749992Sbostic lap = 0;
32849992Sbostic goto top;
3291290Sbill }
3301290Sbill quotspec:
33149992Sbostic if (cmap(c, QUOTES))
33249992Sbostic return (c | QUOTE);
33349992Sbostic return (c);
33449992Sbostic }
33549992Sbostic if (dolp) {
33660237Schristos if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
33749992Sbostic goto quotspec;
3381290Sbill if (dolcnt > 0) {
33949992Sbostic setDolp(*dolnxt++);
34049992Sbostic --dolcnt;
34149992Sbostic return (' ');
3421290Sbill }
34349992Sbostic dolp = 0;
34449992Sbostic }
34549992Sbostic if (dolcnt > 0) {
34649992Sbostic setDolp(*dolnxt++);
34749992Sbostic --dolcnt;
34849992Sbostic goto top;
34949992Sbostic }
35049992Sbostic c = Dredc();
35149992Sbostic if (c == '$' && flag) {
35249992Sbostic Dgetdol();
35349992Sbostic goto top;
35449992Sbostic }
35549992Sbostic return (c);
3561290Sbill }
3571290Sbill
35849992Sbostic static Char *nulvec[] = {0};
35960237Schristos static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
3601290Sbill
36149992Sbostic static void
dolerror(s)36249992Sbostic dolerror(s)
36349992Sbostic Char *s;
36449992Sbostic {
36551589Schristos setname(vis_str(s));
36649992Sbostic stderror(ERR_NAME | ERR_RANGE);
36749992Sbostic }
36849992Sbostic
3691290Sbill /*
3701290Sbill * Handle the multitudinous $ expansion forms.
3711290Sbill * Ugh.
3721290Sbill */
37349992Sbostic static void
Dgetdol()3741290Sbill Dgetdol()
3751290Sbill {
37649992Sbostic register Char *np;
37749992Sbostic register struct varent *vp = NULL;
37849992Sbostic Char name[4 * MAXVARLEN + 1];
37949992Sbostic int c, sc;
38049992Sbostic int subscr = 0, lwb = 1, upb = 0;
38149992Sbostic bool dimen = 0, bitset = 0;
38249992Sbostic char tnp;
38349992Sbostic Char wbuf[BUFSIZ];
38451526Schristos static Char *dolbang = NULL;
3851290Sbill
38651526Schristos dolnmod = dolmcnt = dolwcnt = 0;
38749992Sbostic c = sc = DgetC(0);
38849992Sbostic if (c == '{')
38949992Sbostic c = DgetC(0); /* sc is { to take } later */
39049992Sbostic if ((c & TRIM) == '#')
39149992Sbostic dimen++, c = DgetC(0); /* $# takes dimension */
39249992Sbostic else if (c == '?')
39349992Sbostic bitset++, c = DgetC(0); /* $? tests existence */
39449992Sbostic switch (c) {
3951290Sbill
39651526Schristos case '!':
39751526Schristos if (dimen || bitset)
39851526Schristos stderror(ERR_SYNTAX);
39951526Schristos if (backpid != 0) {
40051526Schristos if (dolbang)
40151526Schristos xfree((ptr_t) dolbang);
40251526Schristos setDolp(dolbang = putn(backpid));
40351526Schristos }
40451526Schristos goto eatbrac;
40551526Schristos
40649992Sbostic case '$':
40749992Sbostic if (dimen || bitset)
40849992Sbostic stderror(ERR_SYNTAX);
40949992Sbostic setDolp(doldol);
41049992Sbostic goto eatbrac;
4111290Sbill
41249992Sbostic case '<' | QUOTE:
41349992Sbostic if (bitset)
41449992Sbostic stderror(ERR_NOTALLOWED, "$?<");
41549992Sbostic if (dimen)
41649992Sbostic stderror(ERR_NOTALLOWED, "$?#");
41749992Sbostic for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
41853569Schristos *np = (unsigned char) tnp;
41949992Sbostic if (np >= &wbuf[BUFSIZ - 1])
42049992Sbostic stderror(ERR_LTOOLONG);
42153569Schristos if (tnp == '\n')
4221290Sbill break;
42349992Sbostic }
42449992Sbostic *np = 0;
42549992Sbostic /*
42649992Sbostic * KLUDGE: dolmod is set here because it will cause setDolp to call
42749992Sbostic * domod and thus to copy wbuf. Otherwise setDolp would use it
42849992Sbostic * directly. If we saved it ourselves, no one would know when to free
42949992Sbostic * it. The actual function of the 'q' causes filename expansion not to
43049992Sbostic * be done on the interpolated value.
43149992Sbostic */
43250462Schristos dolmod[dolnmod++] = 'q';
43349992Sbostic dolmcnt = 10000;
43449992Sbostic setDolp(wbuf);
43549992Sbostic goto eatbrac;
4361290Sbill
43749992Sbostic case DEOF:
43849992Sbostic case '\n':
43949992Sbostic stderror(ERR_SYNTAX);
44049992Sbostic /* NOTREACHED */
44149992Sbostic break;
44249992Sbostic
44349992Sbostic case '*':
44449992Sbostic (void) Strcpy(name, STRargv);
44549992Sbostic vp = adrof(STRargv);
44649992Sbostic subscr = -1; /* Prevent eating [...] */
44749992Sbostic break;
44849992Sbostic
44949992Sbostic default:
45049992Sbostic np = name;
45149992Sbostic if (Isdigit(c)) {
45249992Sbostic if (dimen)
45349992Sbostic stderror(ERR_NOTALLOWED, "$#<num>");
45449992Sbostic subscr = 0;
45549992Sbostic do {
45649992Sbostic subscr = subscr * 10 + c - '0';
45749992Sbostic c = DgetC(0);
45849992Sbostic } while (Isdigit(c));
45949992Sbostic unDredc(c);
46049992Sbostic if (subscr < 0) {
46149992Sbostic dolerror(vp->v_name);
46249992Sbostic return;
46349992Sbostic }
46449992Sbostic if (subscr == 0) {
46549992Sbostic if (bitset) {
46649992Sbostic dolp = ffile ? STR1 : STR0;
46749992Sbostic goto eatbrac;
4681290Sbill }
46949992Sbostic if (ffile == 0)
47049992Sbostic stderror(ERR_DOLZERO);
47149992Sbostic fixDolMod();
47249992Sbostic setDolp(ffile);
4731290Sbill goto eatbrac;
47449992Sbostic }
47549992Sbostic if (bitset)
47649992Sbostic stderror(ERR_DOLQUEST);
47749992Sbostic vp = adrof(STRargv);
47849992Sbostic if (vp == 0) {
47949992Sbostic vp = &nulargv;
48049992Sbostic goto eatmod;
48149992Sbostic }
48249992Sbostic break;
4831290Sbill }
48449992Sbostic if (!alnum(c))
48549992Sbostic stderror(ERR_VARALNUM);
48649992Sbostic for (;;) {
48749992Sbostic *np++ = c;
48849992Sbostic c = DgetC(0);
48949992Sbostic if (!alnum(c))
49049992Sbostic break;
49149992Sbostic if (np >= &name[MAXVARLEN])
49249992Sbostic stderror(ERR_VARTOOLONG);
4931290Sbill }
49449992Sbostic *np++ = 0;
49549992Sbostic unDredc(c);
49649992Sbostic vp = adrof(name);
49749992Sbostic }
49849992Sbostic if (bitset) {
49949992Sbostic dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
50049992Sbostic goto eatbrac;
50149992Sbostic }
50249992Sbostic if (vp == 0) {
50349992Sbostic np = str2short(getenv(short2str(name)));
50449992Sbostic if (np) {
50549992Sbostic fixDolMod();
50649992Sbostic setDolp(np);
50749992Sbostic goto eatbrac;
50849992Sbostic }
50949992Sbostic udvar(name);
51049992Sbostic /* NOTREACHED */
51149992Sbostic }
51249992Sbostic c = DgetC(0);
51349992Sbostic upb = blklen(vp->vec);
51449992Sbostic if (dimen == 0 && subscr == 0 && c == '[') {
51549992Sbostic np = name;
51649992Sbostic for (;;) {
51749992Sbostic c = DgetC(DODOL); /* Allow $ expand within [ ] */
51849992Sbostic if (c == ']')
51949992Sbostic break;
52049992Sbostic if (c == '\n' || c == DEOF)
52149992Sbostic stderror(ERR_INCBR);
52249992Sbostic if (np >= &name[sizeof(name) / sizeof(Char) - 2])
52349992Sbostic stderror(ERR_VARTOOLONG);
52449992Sbostic *np++ = c;
52549992Sbostic }
52649992Sbostic *np = 0, np = name;
52749992Sbostic if (dolp || dolcnt) /* $ exp must end before ] */
52849992Sbostic stderror(ERR_EXPORD);
52949992Sbostic if (!*np)
53049992Sbostic stderror(ERR_SYNTAX);
53149992Sbostic if (Isdigit(*np)) {
53249992Sbostic int i;
5331290Sbill
53451437Sleres for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
53551437Sleres continue;
53649992Sbostic if ((i < 0 || i > upb) && !any("-*", *np)) {
53749992Sbostic dolerror(vp->v_name);
53849992Sbostic return;
53949992Sbostic }
54049992Sbostic lwb = i;
54149992Sbostic if (!*np)
54249992Sbostic upb = lwb, np = STRstar;
54349992Sbostic }
54449992Sbostic if (*np == '*')
54549992Sbostic np++;
54649992Sbostic else if (*np != '-')
54749992Sbostic stderror(ERR_MISSING, '-');
54849992Sbostic else {
54949992Sbostic register int i = upb;
5501290Sbill
55149992Sbostic np++;
55249992Sbostic if (Isdigit(*np)) {
55349992Sbostic i = 0;
55449992Sbostic while (Isdigit(*np))
55549992Sbostic i = i * 10 + *np++ - '0';
55649992Sbostic if (i < 0 || i > upb) {
55749992Sbostic dolerror(vp->v_name);
55849992Sbostic return;
5591290Sbill }
56049992Sbostic }
56149992Sbostic if (i < lwb)
56249992Sbostic upb = lwb - 1;
56349992Sbostic else
56449992Sbostic upb = i;
5651290Sbill }
56649992Sbostic if (lwb == 0) {
56749992Sbostic if (upb != 0) {
56849992Sbostic dolerror(vp->v_name);
56949992Sbostic return;
57049992Sbostic }
57149992Sbostic upb = -1;
57249992Sbostic }
57349992Sbostic if (*np)
57449992Sbostic stderror(ERR_SYNTAX);
57549992Sbostic }
57649992Sbostic else {
57749992Sbostic if (subscr > 0)
57849992Sbostic if (subscr > upb)
57949992Sbostic lwb = 1, upb = 0;
58049992Sbostic else
58149992Sbostic lwb = upb = subscr;
58249992Sbostic unDredc(c);
58349992Sbostic }
58449992Sbostic if (dimen) {
58549992Sbostic Char *cp = putn(upb - lwb + 1);
5861290Sbill
58749992Sbostic addla(cp);
58849992Sbostic xfree((ptr_t) cp);
58949992Sbostic }
59049992Sbostic else {
5911290Sbill eatmod:
59249992Sbostic fixDolMod();
59349992Sbostic dolnxt = &vp->vec[lwb - 1];
59449992Sbostic dolcnt = upb - lwb + 1;
59549992Sbostic }
5961290Sbill eatbrac:
59749992Sbostic if (sc == '{') {
59849992Sbostic c = Dredc();
59949992Sbostic if (c != '}')
60049992Sbostic stderror(ERR_MISSING, '}');
60149992Sbostic }
6021290Sbill }
6031290Sbill
60449992Sbostic static void
fixDolMod()60549992Sbostic fixDolMod()
60649992Sbostic {
60749992Sbostic register int c;
60849992Sbostic
60949992Sbostic c = DgetC(0);
61049992Sbostic if (c == ':') {
61150462Schristos do {
61251526Schristos c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
61351526Schristos if (c == 'g' || c == 'a') {
61451526Schristos if (c == 'g')
61551526Schristos dolmcnt = 10000;
61651526Schristos else
61751526Schristos dolwcnt = 10000;
61851526Schristos c = DgetC(0);
61951526Schristos }
62051526Schristos if ((c == 'g' && dolmcnt != 10000) ||
62151526Schristos (c == 'a' && dolwcnt != 10000)) {
62251526Schristos if (c == 'g')
62351526Schristos dolmcnt = 10000;
62451526Schristos else
62551526Schristos dolwcnt = 10000;
62651526Schristos c = DgetC(0);
62751526Schristos }
62851526Schristos
62951526Schristos if (c == 's') { /* [eichin:19910926.0755EST] */
63051526Schristos int delimcnt = 2;
63151526Schristos int delim = DgetC(0);
63251526Schristos dolmod[dolnmod++] = c;
63351526Schristos dolmod[dolnmod++] = delim;
63451526Schristos
63551526Schristos if (!delim || letter(delim)
63651526Schristos || Isdigit(delim) || any(" \t\n", delim)) {
63751526Schristos seterror(ERR_BADSUBST);
63851526Schristos break;
63951526Schristos }
64051526Schristos while ((c = DgetC(0)) != (-1)) {
64151526Schristos dolmod[dolnmod++] = c;
64251526Schristos if(c == delim) delimcnt--;
64351526Schristos if(!delimcnt) break;
64451526Schristos }
64551526Schristos if(delimcnt) {
64651526Schristos seterror(ERR_BADSUBST);
64751526Schristos break;
64851526Schristos }
64951526Schristos continue;
65051526Schristos }
65151526Schristos if (!any("htrqxes", c))
65250462Schristos stderror(ERR_BADMOD, c);
65350462Schristos dolmod[dolnmod++] = c;
65450462Schristos if (c == 'q')
65550462Schristos dolmcnt = 10000;
65650462Schristos }
65750462Schristos while ((c = DgetC(0)) == ':');
65850462Schristos unDredc(c);
65949992Sbostic }
66049992Sbostic else
66149992Sbostic unDredc(c);
66249992Sbostic }
66349992Sbostic
66449992Sbostic static void
setDolp(cp)6651290Sbill setDolp(cp)
66649992Sbostic register Char *cp;
6671290Sbill {
66849992Sbostic register Char *dp;
66950462Schristos int i;
6701290Sbill
67150462Schristos if (dolnmod == 0 || dolmcnt == 0) {
67249992Sbostic dolp = cp;
67349992Sbostic return;
67449992Sbostic }
67550462Schristos dp = cp = Strsave(cp);
67651526Schristos for (i = 0; i < dolnmod; i++) {
67751526Schristos /* handle s// [eichin:19910926.0510EST] */
67851526Schristos if(dolmod[i] == 's') {
67951526Schristos int delim;
68051526Schristos Char *lhsub, *rhsub, *np;
68151526Schristos size_t lhlen = 0, rhlen = 0;
68251526Schristos int didmod = 0;
68351526Schristos
68451526Schristos delim = dolmod[++i];
68551526Schristos if (!delim || letter(delim)
68651526Schristos || Isdigit(delim) || any(" \t\n", delim)) {
68751526Schristos seterror(ERR_BADSUBST);
68851526Schristos break;
68951526Schristos }
69051526Schristos lhsub = &dolmod[++i];
69151526Schristos while(dolmod[i] != delim && dolmod[++i]) {
69251526Schristos lhlen++;
69351526Schristos }
69451526Schristos dolmod[i] = 0;
69551526Schristos rhsub = &dolmod[++i];
69651526Schristos while(dolmod[i] != delim && dolmod[++i]) {
69751526Schristos rhlen++;
69851526Schristos }
69951526Schristos dolmod[i] = 0;
70051526Schristos
70151526Schristos do {
70251526Schristos dp = Strstr(cp, lhsub);
70351526Schristos if (dp) {
70451526Schristos np = (Char *) xmalloc((size_t)
70551526Schristos ((Strlen(cp) + 1 - lhlen + rhlen) *
70651526Schristos sizeof(Char)));
70751526Schristos (void) Strncpy(np, cp, dp - cp);
70851526Schristos (void) Strcpy(np + (dp - cp), rhsub);
70951526Schristos (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
71051526Schristos
71151526Schristos xfree((ptr_t) cp);
71251526Schristos dp = cp = np;
71351526Schristos didmod = 1;
71451526Schristos } else {
71551526Schristos /* should this do a seterror? */
71651526Schristos break;
71751526Schristos }
71851526Schristos }
71951526Schristos while (dolwcnt == 10000);
72051526Schristos /*
72151526Schristos * restore dolmod for additional words
72251526Schristos */
72351526Schristos dolmod[i] = rhsub[-1] = delim;
72451526Schristos if (didmod)
72551526Schristos dolmcnt--;
72651526Schristos else
72751526Schristos break;
72851526Schristos } else {
72951526Schristos int didmod = 0;
73051526Schristos
73151526Schristos do {
73251526Schristos if ((dp = domod(cp, dolmod[i]))) {
73351526Schristos didmod = 1;
73451526Schristos if (Strcmp(cp, dp) == 0) {
73551526Schristos xfree((ptr_t) cp);
73651526Schristos cp = dp;
73751526Schristos break;
73851526Schristos }
73951526Schristos else {
74051526Schristos xfree((ptr_t) cp);
74151526Schristos cp = dp;
74251526Schristos }
74351526Schristos }
74451526Schristos else
74551526Schristos break;
74651526Schristos }
74751526Schristos while (dolwcnt == 10000);
74850462Schristos dp = cp;
74951526Schristos if (didmod)
75051526Schristos dolmcnt--;
75151526Schristos else
75251526Schristos break;
75350462Schristos }
75451526Schristos }
75550462Schristos
75649992Sbostic if (dp) {
75749992Sbostic addla(dp);
75849992Sbostic xfree((ptr_t) dp);
75949992Sbostic }
76051526Schristos else
76151526Schristos addla(cp);
76251526Schristos
76349992Sbostic dolp = STRNULL;
76449992Sbostic if (seterr)
76549992Sbostic stderror(ERR_OLD);
7661290Sbill }
7671290Sbill
76849992Sbostic static void
unDredc(c)7691290Sbill unDredc(c)
77049992Sbostic int c;
7711290Sbill {
7721290Sbill
77349992Sbostic Dpeekrd = c;
7741290Sbill }
7751290Sbill
77649992Sbostic static int
Dredc()7771290Sbill Dredc()
7781290Sbill {
77949992Sbostic register int c;
7801290Sbill
78160237Schristos if ((c = Dpeekrd) != '\0') {
78249992Sbostic Dpeekrd = 0;
78349992Sbostic return (c);
78449992Sbostic }
78549992Sbostic if (Dcp && (c = *Dcp++))
78649992Sbostic return (c & (QUOTE | TRIM));
78749992Sbostic if (*Dvp == 0) {
78849992Sbostic Dcp = 0;
78949992Sbostic return (DEOF);
79049992Sbostic }
79149992Sbostic Dcp = *Dvp++;
79249992Sbostic return (' ');
7931290Sbill }
7941290Sbill
79549992Sbostic static void
Dtestq(c)7961290Sbill Dtestq(c)
79749992Sbostic register int c;
7981290Sbill {
7991290Sbill
80049992Sbostic if (cmap(c, QUOTES))
80149992Sbostic gflag = 1;
8021290Sbill }
8031290Sbill
8041290Sbill /*
8051290Sbill * Form a shell temporary file (in unit 0) from the words
80630306Sbostic * of the shell input up to EOF or a line the same as "term".
8071290Sbill * Unit 0 should have been closed before this call.
8081290Sbill */
80949992Sbostic void
81050439Schristos /*ARGSUSED*/
heredoc(term)8111290Sbill heredoc(term)
81250439Schristos Char *term;
8131290Sbill {
81449992Sbostic register int c;
81549992Sbostic Char *Dv[2];
81649992Sbostic Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
81749992Sbostic int ocnt, lcnt, mcnt;
81849992Sbostic register Char *lbp, *obp, *mbp;
81949992Sbostic Char **vp;
82049992Sbostic bool quoted;
82149992Sbostic char *tmp;
8221290Sbill
823*69126Schristos tmp = short2str(shtemp);
824*69126Schristos if (open(tmp, O_RDWR | O_CREAT | O_TRUNC, 0600) < 0)
82549992Sbostic stderror(ERR_SYSTEM, tmp, strerror(errno));
82649992Sbostic (void) unlink(tmp); /* 0 0 inode! */
82749992Sbostic Dv[0] = term;
82849992Sbostic Dv[1] = NULL;
82949992Sbostic gflag = 0;
83049992Sbostic trim(Dv);
83149992Sbostic rscan(Dv, Dtestq);
83249992Sbostic quoted = gflag;
83349992Sbostic ocnt = BUFSIZ;
83449992Sbostic obp = obuf;
83549992Sbostic for (;;) {
83649992Sbostic /*
83749992Sbostic * Read up a line
83849992Sbostic */
83949992Sbostic lbp = lbuf;
84049992Sbostic lcnt = BUFSIZ - 4;
8411290Sbill for (;;) {
84249992Sbostic c = readc(1); /* 1 -> Want EOF returns */
84349992Sbostic if (c < 0 || c == '\n')
84449992Sbostic break;
84560237Schristos if ((c &= TRIM) != '\0') {
84649992Sbostic *lbp++ = c;
84749992Sbostic if (--lcnt < 0) {
84849992Sbostic setname("<<");
84949992Sbostic stderror(ERR_NAME | ERR_OVERFLOW);
8501290Sbill }
85149992Sbostic }
85249992Sbostic }
85349992Sbostic *lbp = 0;
8541290Sbill
85549992Sbostic /*
85649992Sbostic * Check for EOF or compare to terminator -- before expansion
85749992Sbostic */
85849992Sbostic if (c < 0 || eq(lbuf, term)) {
85949992Sbostic (void) write(0, short2str(obuf), (size_t) (BUFSIZ - ocnt));
86049992Sbostic (void) lseek(0, 0l, L_SET);
86149992Sbostic return;
86249992Sbostic }
8631290Sbill
86449992Sbostic /*
86549992Sbostic * If term was quoted or -n just pass it on
86649992Sbostic */
86749992Sbostic if (quoted || noexec) {
86849992Sbostic *lbp++ = '\n';
86949992Sbostic *lbp = 0;
87060237Schristos for (lbp = lbuf; (c = *lbp++) != '\0';) {
87149992Sbostic *obp++ = c;
87249992Sbostic if (--ocnt == 0) {
87349992Sbostic (void) write(0, short2str(obuf), BUFSIZ);
87449992Sbostic obp = obuf;
87549992Sbostic ocnt = BUFSIZ;
8761290Sbill }
87749992Sbostic }
87849992Sbostic continue;
87949992Sbostic }
8801290Sbill
88149992Sbostic /*
88249992Sbostic * Term wasn't quoted so variable and then command expand the input
88349992Sbostic * line
88449992Sbostic */
88549992Sbostic Dcp = lbuf;
88649992Sbostic Dvp = Dv + 1;
88749992Sbostic mbp = mbuf;
88849992Sbostic mcnt = BUFSIZ - 4;
88949992Sbostic for (;;) {
89049992Sbostic c = DgetC(DODOL);
89149992Sbostic if (c == DEOF)
89249992Sbostic break;
89349992Sbostic if ((c &= TRIM) == 0)
89449992Sbostic continue;
89549992Sbostic /* \ quotes \ $ ` here */
89649992Sbostic if (c == '\\') {
89749992Sbostic c = DgetC(0);
89849992Sbostic if (!any("$\\`", c))
89949992Sbostic unDgetC(c | QUOTE), c = '\\';
90049992Sbostic else
90149992Sbostic c |= QUOTE;
90249992Sbostic }
90349992Sbostic *mbp++ = c;
90449992Sbostic if (--mcnt == 0) {
90549992Sbostic setname("<<");
90649992Sbostic stderror(ERR_NAME | ERR_OVERFLOW);
90749992Sbostic }
90849992Sbostic }
90949992Sbostic *mbp++ = 0;
9101290Sbill
91149992Sbostic /*
91249992Sbostic * If any ` in line do command substitution
91349992Sbostic */
91449992Sbostic mbp = mbuf;
91549992Sbostic if (any(short2str(mbp), '`')) {
91649992Sbostic /*
91749992Sbostic * 1 arg to dobackp causes substitution to be literal. Words are
91849992Sbostic * broken only at newlines so that all blanks and tabs are
91949992Sbostic * preserved. Blank lines (null words) are not discarded.
92049992Sbostic */
92149992Sbostic vp = dobackp(mbuf, 1);
92249992Sbostic }
92349992Sbostic else
92449992Sbostic /* Setup trivial vector similar to return of dobackp */
92549992Sbostic Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
9261290Sbill
92749992Sbostic /*
92849992Sbostic * Resurrect the words from the command substitution each separated by
92949992Sbostic * a newline. Note that the last newline of a command substitution
93049992Sbostic * will have been discarded, but we put a newline after the last word
93149992Sbostic * because this represents the newline after the last input line!
93249992Sbostic */
93349992Sbostic for (; *vp; vp++) {
93449992Sbostic for (mbp = *vp; *mbp; mbp++) {
93549992Sbostic *obp++ = *mbp & TRIM;
93649992Sbostic if (--ocnt == 0) {
93749992Sbostic (void) write(0, short2str(obuf), BUFSIZ);
93849992Sbostic obp = obuf;
93949992Sbostic ocnt = BUFSIZ;
9401290Sbill }
94149992Sbostic }
94249992Sbostic *obp++ = '\n';
94349992Sbostic if (--ocnt == 0) {
94449992Sbostic (void) write(0, short2str(obuf), BUFSIZ);
94549992Sbostic obp = obuf;
94649992Sbostic ocnt = BUFSIZ;
94749992Sbostic }
9481290Sbill }
94949992Sbostic if (pargv)
95049992Sbostic blkfree(pargv), pargv = 0;
95149992Sbostic }
9521290Sbill }
953