1*1767ce60Schristos /* $NetBSD: dol.c,v 1.31 2019/01/05 16:54:00 christos Exp $ */
249f0ad86Scgd
361f28255Scgd /*-
4cee2bad8Smycroft * Copyright (c) 1980, 1991, 1993
5cee2bad8Smycroft * The Regents of the University of California. All rights reserved.
661f28255Scgd *
761f28255Scgd * Redistribution and use in source and binary forms, with or without
861f28255Scgd * modification, are permitted provided that the following conditions
961f28255Scgd * are met:
1061f28255Scgd * 1. Redistributions of source code must retain the above copyright
1161f28255Scgd * notice, this list of conditions and the following disclaimer.
1261f28255Scgd * 2. Redistributions in binary form must reproduce the above copyright
1361f28255Scgd * notice, this list of conditions and the following disclaimer in the
1461f28255Scgd * documentation and/or other materials provided with the distribution.
15b5b29542Sagc * 3. Neither the name of the University nor the names of its contributors
1661f28255Scgd * may be used to endorse or promote products derived from this software
1761f28255Scgd * without specific prior written permission.
1861f28255Scgd *
1961f28255Scgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2061f28255Scgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2161f28255Scgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2261f28255Scgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2361f28255Scgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2461f28255Scgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2561f28255Scgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2661f28255Scgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2761f28255Scgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2861f28255Scgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2961f28255Scgd * SUCH DAMAGE.
3061f28255Scgd */
3161f28255Scgd
328ea378c6Schristos #include <sys/cdefs.h>
3361f28255Scgd #ifndef lint
3449f0ad86Scgd #if 0
3549f0ad86Scgd static char sccsid[] = "@(#)dol.c 8.1 (Berkeley) 5/31/93";
3649f0ad86Scgd #else
37*1767ce60Schristos __RCSID("$NetBSD: dol.c,v 1.31 2019/01/05 16:54:00 christos Exp $");
3849f0ad86Scgd #endif
3961f28255Scgd #endif /* not lint */
4061f28255Scgd
4161f28255Scgd #include <sys/types.h>
42b771e65bSwiz
4361f28255Scgd #include <errno.h>
44b771e65bSwiz #include <fcntl.h>
4518158540Swiz #include <stdarg.h>
4637e39248Schristos #include <stddef.h>
4761f28255Scgd #include <stdlib.h>
4861f28255Scgd #include <string.h>
4961f28255Scgd #include <unistd.h>
50b771e65bSwiz
5161f28255Scgd #include "csh.h"
5261f28255Scgd #include "extern.h"
5361f28255Scgd
5461f28255Scgd /*
5561f28255Scgd * These routines perform variable substitution and quoting via ' and ".
5661f28255Scgd * To this point these constructs have been preserved in the divided
5761f28255Scgd * input words. Here we expand variables and turn quoting via ' and " into
5861f28255Scgd * QUOTE bits on characters (which prevent further interpretation).
5961f28255Scgd * If the `:q' modifier was applied during history expansion, then
6061f28255Scgd * some QUOTEing may have occurred already, so we dont "trim()" here.
6161f28255Scgd */
6261f28255Scgd
6361f28255Scgd static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
6461f28255Scgd static Char *Dcp, **Dvp; /* Input vector for Dreadc */
6561f28255Scgd
6661f28255Scgd #define DEOF -1
6761f28255Scgd #define unDgetC(c) Dpeekc = c
68cee2bad8Smycroft #define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
6961f28255Scgd
7061f28255Scgd /*
7161f28255Scgd * The following variables give the information about the current
7261f28255Scgd * $ expansion, recording the current word position, the remaining
7361f28255Scgd * words within this expansion, the count of remaining words, and the
7461f28255Scgd * information about any : modifier which is being applied.
7561f28255Scgd */
760bf6fd0cSchristos #define MAXWLEN (BUFSIZE - 4)
77cee2bad8Smycroft #define MAXMOD MAXWLEN /* This cannot overflow */
78b771e65bSwiz static Char dolmod[MAXMOD]; /* : modifier character */
7961f28255Scgd static Char *dolp; /* Remaining chars from this word */
8061f28255Scgd static Char **dolnxt; /* Further words */
8161f28255Scgd static int dolcnt; /* Count of further words */
82cee2bad8Smycroft static int dolnmod; /* Number of modifiers */
8361f28255Scgd static int dolmcnt; /* :gx -> 10000, else 1 */
84cee2bad8Smycroft static int dolwcnt; /* :wx -> 10000, else 1 */
8561f28255Scgd
86b771e65bSwiz static void Dfix2(Char **);
87b771e65bSwiz static Char *Dpack(Char *, Char *);
88b771e65bSwiz static int Dword(void);
895bb1ddccSjoerg __dead static void dolerror(Char *);
90b771e65bSwiz static int DgetC(int);
91b771e65bSwiz static void Dgetdol(void);
92b771e65bSwiz static void fixDolMod(void);
93b771e65bSwiz static void setDolp(Char *);
94b771e65bSwiz static void unDredc(int);
95b771e65bSwiz static int Dredc(void);
96b771e65bSwiz static void Dtestq(int);
9761f28255Scgd
9861f28255Scgd
9961f28255Scgd /*
10061f28255Scgd * Fix up the $ expansions and quotations in the
10161f28255Scgd * argument list to command t.
10261f28255Scgd */
10361f28255Scgd void
Dfix(struct command * t)104b771e65bSwiz Dfix(struct command *t)
10561f28255Scgd {
106b771e65bSwiz Char *p, **pp;
10761f28255Scgd
10861f28255Scgd if (noexec)
10961f28255Scgd return;
11061f28255Scgd /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
111cee2bad8Smycroft for (pp = t->t_dcom; (p = *pp++) != NULL;)
11261f28255Scgd for (; *p; p++) {
11361f28255Scgd if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */
11461f28255Scgd Dfix2(t->t_dcom); /* found one */
11561f28255Scgd blkfree(t->t_dcom);
11661f28255Scgd t->t_dcom = gargv;
11761f28255Scgd gargv = 0;
11861f28255Scgd return;
11961f28255Scgd }
12061f28255Scgd }
12161f28255Scgd }
12261f28255Scgd
12361f28255Scgd /*
12461f28255Scgd * $ substitute one word, for i/o redirection
12561f28255Scgd */
12661f28255Scgd Char *
Dfix1(Char * cp)127b771e65bSwiz Dfix1(Char *cp)
12861f28255Scgd {
12961f28255Scgd Char *Dv[2];
13061f28255Scgd
13161f28255Scgd if (noexec)
13261f28255Scgd return (0);
13361f28255Scgd Dv[0] = cp;
13461f28255Scgd Dv[1] = NULL;
13561f28255Scgd Dfix2(Dv);
13661f28255Scgd if (gargc != 1) {
137cee2bad8Smycroft setname(vis_str(cp));
13861f28255Scgd stderror(ERR_NAME | ERR_AMBIG);
13961f28255Scgd }
14061f28255Scgd cp = Strsave(gargv[0]);
14161f28255Scgd blkfree(gargv), gargv = 0;
14261f28255Scgd return (cp);
14361f28255Scgd }
14461f28255Scgd
14561f28255Scgd /*
14661f28255Scgd * Subroutine to do actual fixing after state initialization.
14761f28255Scgd */
14861f28255Scgd static void
Dfix2(Char ** v)149b771e65bSwiz Dfix2(Char **v)
15061f28255Scgd {
15161f28255Scgd ginit(); /* Initialize glob's area pointers */
15261f28255Scgd Dvp = v;
15361f28255Scgd Dcp = STRNULL; /* Setup input vector for Dreadc */
15461f28255Scgd unDgetC(0);
15561f28255Scgd unDredc(0); /* Clear out any old peeks (at error) */
15661f28255Scgd dolp = 0;
15761f28255Scgd dolcnt = 0; /* Clear out residual $ expands (...) */
15861f28255Scgd while (Dword())
15961f28255Scgd continue;
16061f28255Scgd }
16161f28255Scgd
16261f28255Scgd /*
16361f28255Scgd * Pack up more characters in this word
16461f28255Scgd */
16561f28255Scgd static Char *
Dpack(Char * wbuf,Char * wp)166b771e65bSwiz Dpack(Char *wbuf, Char *wp)
16761f28255Scgd {
16837e39248Schristos int c;
16937e39248Schristos ptrdiff_t i;
17061f28255Scgd
171b771e65bSwiz i = MAXWLEN - (wp - wbuf);
17261f28255Scgd for (;;) {
17361f28255Scgd c = DgetC(DODOL);
17461f28255Scgd if (c == '\\') {
17561f28255Scgd c = DgetC(0);
17661f28255Scgd if (c == DEOF) {
17761f28255Scgd unDredc(c);
17861f28255Scgd *wp = 0;
17961f28255Scgd Gcat(STRNULL, wbuf);
18061f28255Scgd return (NULL);
18161f28255Scgd }
18261f28255Scgd if (c == '\n')
18361f28255Scgd c = ' ';
18461f28255Scgd else
18561f28255Scgd c |= QUOTE;
18661f28255Scgd }
18761f28255Scgd if (c == DEOF) {
18861f28255Scgd unDredc(c);
18961f28255Scgd *wp = 0;
19061f28255Scgd Gcat(STRNULL, wbuf);
19161f28255Scgd return (NULL);
19261f28255Scgd }
193cee2bad8Smycroft if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */
19461f28255Scgd unDgetC(c);
19561f28255Scgd if (cmap(c, QUOTES))
19661f28255Scgd return (wp);
19761f28255Scgd *wp++ = 0;
19861f28255Scgd Gcat(STRNULL, wbuf);
19961f28255Scgd return (NULL);
20061f28255Scgd }
201ee9e50eaSmycroft if (--i <= 0)
20261f28255Scgd stderror(ERR_WTOOLONG);
20337e39248Schristos *wp++ = (Char)c;
20461f28255Scgd }
20561f28255Scgd }
20661f28255Scgd
20761f28255Scgd /*
20861f28255Scgd * Get a word. This routine is analogous to the routine
20961f28255Scgd * word() in sh.lex.c for the main lexical input. One difference
21061f28255Scgd * here is that we don't get a newline to terminate our expansion.
21161f28255Scgd * Rather, DgetC will return a DEOF when we hit the end-of-input.
21261f28255Scgd */
21361f28255Scgd static int
Dword(void)214b771e65bSwiz Dword(void)
21561f28255Scgd {
216b771e65bSwiz Char wbuf[BUFSIZE], *wp;
21737e39248Schristos int c, c1;
21837e39248Schristos ptrdiff_t i;
219b79c2ef2Schristos int dolflg, done, sofar;
220b771e65bSwiz
221b771e65bSwiz done = 0;
222b771e65bSwiz i = MAXWLEN;
223b771e65bSwiz sofar = 0;
224b771e65bSwiz wp = wbuf;
22561f28255Scgd
22661f28255Scgd while (!done) {
22761f28255Scgd done = 1;
22861f28255Scgd c = DgetC(DODOL);
22961f28255Scgd switch (c) {
23061f28255Scgd case DEOF:
23161f28255Scgd if (sofar == 0)
23261f28255Scgd return (0);
23361f28255Scgd /* finish this word and catch the code above the next time */
23461f28255Scgd unDredc(c);
235cdbd74daSmycroft /* FALLTHROUGH */
23661f28255Scgd case '\n':
23761f28255Scgd *wp = 0;
23861f28255Scgd Gcat(STRNULL, wbuf);
23961f28255Scgd return (1);
24061f28255Scgd case ' ':
24161f28255Scgd case '\t':
24261f28255Scgd done = 0;
24361f28255Scgd break;
24461f28255Scgd case '`':
24561f28255Scgd /* We preserve ` quotations which are done yet later */
24637e39248Schristos *wp++ = (Char)c, --i;
247cdbd74daSmycroft /* FALLTHROUGH */
24861f28255Scgd case '\'':
24961f28255Scgd case '"':
25061f28255Scgd /*
25161f28255Scgd * Note that DgetC never returns a QUOTES character from an
25261f28255Scgd * expansion, so only true input quotes will get us here or out.
25361f28255Scgd */
25461f28255Scgd c1 = c;
25561f28255Scgd dolflg = c1 == '"' ? DODOL : 0;
25661f28255Scgd for (;;) {
25761f28255Scgd c = DgetC(dolflg);
25861f28255Scgd if (c == c1)
25961f28255Scgd break;
260ee9e50eaSmycroft if (c == '\n' || c == DEOF)
26161f28255Scgd stderror(ERR_UNMATCHED, c1);
26261f28255Scgd if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
26361f28255Scgd --wp, ++i;
264ee9e50eaSmycroft if (--i <= 0)
26561f28255Scgd stderror(ERR_WTOOLONG);
26661f28255Scgd switch (c1) {
26761f28255Scgd case '"':
26861f28255Scgd /*
26961f28255Scgd * Leave any `s alone for later. Other chars are all
27061f28255Scgd * quoted, thus `...` can tell it was within "...".
27161f28255Scgd */
27237e39248Schristos *wp++ = (Char)(c == '`' ? '`' : (c | QUOTE));
27361f28255Scgd break;
27461f28255Scgd case '\'':
27561f28255Scgd /* Prevent all further interpretation */
27637e39248Schristos *wp++ = (Char)(c | QUOTE);
27761f28255Scgd break;
27861f28255Scgd case '`':
27961f28255Scgd /* Leave all text alone for later */
28037e39248Schristos *wp++ = (Char)c;
28161f28255Scgd break;
282cee2bad8Smycroft default:
283cee2bad8Smycroft break;
28461f28255Scgd }
28561f28255Scgd }
28661f28255Scgd if (c1 == '`')
287cee2bad8Smycroft *wp++ = '`' /* i--; eliminated */;
28861f28255Scgd sofar = 1;
28961f28255Scgd if ((wp = Dpack(wbuf, wp)) == NULL)
29061f28255Scgd return (1);
29161f28255Scgd else {
29261f28255Scgd i = MAXWLEN - (wp - wbuf);
29361f28255Scgd done = 0;
29461f28255Scgd }
29561f28255Scgd break;
29661f28255Scgd case '\\':
29761f28255Scgd c = DgetC(0); /* No $ subst! */
29861f28255Scgd if (c == '\n' || c == DEOF) {
29961f28255Scgd done = 0;
30061f28255Scgd break;
30161f28255Scgd }
30261f28255Scgd c |= QUOTE;
30361f28255Scgd break;
304cee2bad8Smycroft default:
305cee2bad8Smycroft break;
30661f28255Scgd }
30761f28255Scgd if (done) {
30861f28255Scgd unDgetC(c);
30961f28255Scgd sofar = 1;
31061f28255Scgd if ((wp = Dpack(wbuf, wp)) == NULL)
31161f28255Scgd return (1);
31261f28255Scgd else {
31361f28255Scgd i = MAXWLEN - (wp - wbuf);
31461f28255Scgd done = 0;
31561f28255Scgd }
31661f28255Scgd }
31761f28255Scgd }
31861f28255Scgd /* Really NOTREACHED */
31961f28255Scgd return (0);
32061f28255Scgd }
32161f28255Scgd
32261f28255Scgd
32361f28255Scgd /*
32461f28255Scgd * Get a character, performing $ substitution unless flag is 0.
32561f28255Scgd * Any QUOTES character which is returned from a $ expansion is
32661f28255Scgd * QUOTEd so that it will not be recognized above.
32761f28255Scgd */
32861f28255Scgd static int
DgetC(int flag)329b771e65bSwiz DgetC(int flag)
33061f28255Scgd {
33176adbe2bStls int c;
33261f28255Scgd top:
333cee2bad8Smycroft if ((c = Dpeekc) != '\0') {
33461f28255Scgd Dpeekc = 0;
33561f28255Scgd return (c);
33661f28255Scgd }
33761f28255Scgd if (lap) {
33861f28255Scgd c = *lap++ & (QUOTE | TRIM);
33961f28255Scgd if (c == 0) {
34061f28255Scgd lap = 0;
34161f28255Scgd goto top;
34261f28255Scgd }
34361f28255Scgd quotspec:
34461f28255Scgd if (cmap(c, QUOTES))
34561f28255Scgd return (c | QUOTE);
34661f28255Scgd return (c);
34761f28255Scgd }
34861f28255Scgd if (dolp) {
349cee2bad8Smycroft if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
35061f28255Scgd goto quotspec;
35161f28255Scgd if (dolcnt > 0) {
35261f28255Scgd setDolp(*dolnxt++);
35361f28255Scgd --dolcnt;
35461f28255Scgd return (' ');
35561f28255Scgd }
35661f28255Scgd dolp = 0;
35761f28255Scgd }
35861f28255Scgd if (dolcnt > 0) {
35961f28255Scgd setDolp(*dolnxt++);
36061f28255Scgd --dolcnt;
36161f28255Scgd goto top;
36261f28255Scgd }
36361f28255Scgd c = Dredc();
36461f28255Scgd if (c == '$' && flag) {
36561f28255Scgd Dgetdol();
36661f28255Scgd goto top;
36761f28255Scgd }
36861f28255Scgd return (c);
36961f28255Scgd }
37061f28255Scgd
37161f28255Scgd static Char *nulvec[] = {0};
372cee2bad8Smycroft static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
37361f28255Scgd
37461f28255Scgd static void
dolerror(Char * s)375b771e65bSwiz dolerror(Char *s)
37661f28255Scgd {
377cee2bad8Smycroft setname(vis_str(s));
37861f28255Scgd stderror(ERR_NAME | ERR_RANGE);
379cdbd74daSmycroft /* NOTREACHED */
38061f28255Scgd }
38161f28255Scgd
38261f28255Scgd /*
38361f28255Scgd * Handle the multitudinous $ expansion forms.
38461f28255Scgd * Ugh.
38561f28255Scgd */
38661f28255Scgd static void
Dgetdol(void)387b771e65bSwiz Dgetdol(void)
38861f28255Scgd {
389cee2bad8Smycroft static Char *dolbang = NULL;
390b771e65bSwiz Char name[4*MAXVARLEN+1];
391b771e65bSwiz Char wbuf[BUFSIZE];
392b771e65bSwiz struct varent *vp;
393b771e65bSwiz Char *np;
394b771e65bSwiz int c, lwb, sc, subscr, upb;
395b79c2ef2Schristos int dimen, bitset;
396b771e65bSwiz char tnp;
397b771e65bSwiz
398b771e65bSwiz bitset = 0;
399b771e65bSwiz dimen = 0;
400b771e65bSwiz lwb = 1;
401b771e65bSwiz upb = 0;
402b771e65bSwiz subscr = 0;
403b771e65bSwiz vp = NULL;
40461f28255Scgd
405cee2bad8Smycroft dolnmod = dolmcnt = dolwcnt = 0;
40661f28255Scgd c = sc = DgetC(0);
40761f28255Scgd if (c == '{')
40861f28255Scgd c = DgetC(0); /* sc is { to take } later */
40961f28255Scgd if ((c & TRIM) == '#')
41061f28255Scgd dimen++, c = DgetC(0); /* $# takes dimension */
41161f28255Scgd else if (c == '?')
41261f28255Scgd bitset++, c = DgetC(0); /* $? tests existence */
41361f28255Scgd switch (c) {
414cee2bad8Smycroft case '!':
415ee9e50eaSmycroft if (dimen || bitset)
416cee2bad8Smycroft stderror(ERR_SYNTAX);
417cee2bad8Smycroft if (backpid != 0) {
418cee2bad8Smycroft if (dolbang)
419*1767ce60Schristos free(dolbang);
420cee2bad8Smycroft setDolp(dolbang = putn(backpid));
421cee2bad8Smycroft }
422cee2bad8Smycroft goto eatbrac;
42361f28255Scgd case '$':
424ee9e50eaSmycroft if (dimen || bitset)
42561f28255Scgd stderror(ERR_SYNTAX);
42661f28255Scgd setDolp(doldol);
42761f28255Scgd goto eatbrac;
42861f28255Scgd case '<' | QUOTE:
429ee9e50eaSmycroft if (bitset)
43061f28255Scgd stderror(ERR_NOTALLOWED, "$?<");
431ee9e50eaSmycroft if (dimen)
43261f28255Scgd stderror(ERR_NOTALLOWED, "$?#");
43361f28255Scgd for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
434cee2bad8Smycroft *np = (unsigned char)tnp;
4350bf6fd0cSchristos if (np >= &wbuf[BUFSIZE - 1])
43661f28255Scgd stderror(ERR_LTOOLONG);
437cee2bad8Smycroft if (tnp == '\n')
43861f28255Scgd break;
43961f28255Scgd }
44061f28255Scgd *np = 0;
44161f28255Scgd /*
44261f28255Scgd * KLUDGE: dolmod is set here because it will cause setDolp to call
44361f28255Scgd * domod and thus to copy wbuf. Otherwise setDolp would use it
44461f28255Scgd * directly. If we saved it ourselves, no one would know when to free
44561f28255Scgd * it. The actual function of the 'q' causes filename expansion not to
44661f28255Scgd * be done on the interpolated value.
44761f28255Scgd */
448cee2bad8Smycroft dolmod[dolnmod++] = 'q';
44961f28255Scgd dolmcnt = 10000;
45061f28255Scgd setDolp(wbuf);
45161f28255Scgd goto eatbrac;
45261f28255Scgd case DEOF:
45361f28255Scgd case '\n':
45461f28255Scgd stderror(ERR_SYNTAX);
45561f28255Scgd /* NOTREACHED */
45661f28255Scgd case '*':
45761f28255Scgd (void) Strcpy(name, STRargv);
45861f28255Scgd vp = adrof(STRargv);
45961f28255Scgd subscr = -1; /* Prevent eating [...] */
46061f28255Scgd break;
46161f28255Scgd default:
46261f28255Scgd np = name;
46361f28255Scgd if (Isdigit(c)) {
464ee9e50eaSmycroft if (dimen)
46561f28255Scgd stderror(ERR_NOTALLOWED, "$#<num>");
46661f28255Scgd subscr = 0;
46761f28255Scgd do {
46861f28255Scgd subscr = subscr * 10 + c - '0';
46961f28255Scgd c = DgetC(0);
47061f28255Scgd } while (Isdigit(c));
47161f28255Scgd unDredc(c);
472d1fe293aSchristos if (subscr < 0)
4736ba4cdcfSitohy stderror(ERR_RANGE);
47461f28255Scgd if (subscr == 0) {
47561f28255Scgd if (bitset) {
47661f28255Scgd dolp = ffile ? STR1 : STR0;
47761f28255Scgd goto eatbrac;
47861f28255Scgd }
479ee9e50eaSmycroft if (ffile == 0)
48061f28255Scgd stderror(ERR_DOLZERO);
48161f28255Scgd fixDolMod();
48261f28255Scgd setDolp(ffile);
48361f28255Scgd goto eatbrac;
48461f28255Scgd }
485ee9e50eaSmycroft if (bitset)
48661f28255Scgd stderror(ERR_DOLQUEST);
48761f28255Scgd vp = adrof(STRargv);
48861f28255Scgd if (vp == 0) {
48961f28255Scgd vp = &nulargv;
49061f28255Scgd goto eatmod;
49161f28255Scgd }
49261f28255Scgd break;
49361f28255Scgd }
494ee9e50eaSmycroft if (!alnum(c))
49561f28255Scgd stderror(ERR_VARALNUM);
49661f28255Scgd for (;;) {
49737e39248Schristos *np++ = (Char)c;
49861f28255Scgd c = DgetC(0);
49961f28255Scgd if (!alnum(c))
50061f28255Scgd break;
501ee9e50eaSmycroft if (np >= &name[MAXVARLEN])
50261f28255Scgd stderror(ERR_VARTOOLONG);
50361f28255Scgd }
50461f28255Scgd *np++ = 0;
50561f28255Scgd unDredc(c);
50661f28255Scgd vp = adrof(name);
50761f28255Scgd }
50861f28255Scgd if (bitset) {
50961f28255Scgd dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
51061f28255Scgd goto eatbrac;
51161f28255Scgd }
51261f28255Scgd if (vp == 0) {
51361f28255Scgd np = str2short(getenv(short2str(name)));
51461f28255Scgd if (np) {
51561f28255Scgd fixDolMod();
51661f28255Scgd setDolp(np);
51761f28255Scgd goto eatbrac;
51861f28255Scgd }
51961f28255Scgd udvar(name);
52061f28255Scgd }
52161f28255Scgd c = DgetC(0);
52261f28255Scgd upb = blklen(vp->vec);
52361f28255Scgd if (dimen == 0 && subscr == 0 && c == '[') {
52461f28255Scgd np = name;
52561f28255Scgd for (;;) {
52661f28255Scgd c = DgetC(DODOL); /* Allow $ expand within [ ] */
52761f28255Scgd if (c == ']')
52861f28255Scgd break;
529ee9e50eaSmycroft if (c == '\n' || c == DEOF)
53061f28255Scgd stderror(ERR_INCBR);
531ee9e50eaSmycroft if (np >= &name[sizeof(name) / sizeof(Char) - 2])
53261f28255Scgd stderror(ERR_VARTOOLONG);
53337e39248Schristos *np++ = (Char)c;
53461f28255Scgd }
53561f28255Scgd *np = 0, np = name;
536ee9e50eaSmycroft if (dolp || dolcnt) /* $ exp must end before ] */
53761f28255Scgd stderror(ERR_EXPORD);
538ee9e50eaSmycroft if (!*np)
53961f28255Scgd stderror(ERR_SYNTAX);
54061f28255Scgd if (Isdigit(*np)) {
54161f28255Scgd int i;
54261f28255Scgd
543cee2bad8Smycroft for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
544cee2bad8Smycroft continue;
54561f28255Scgd if ((i < 0 || i > upb) && !any("-*", *np)) {
54661f28255Scgd dolerror(vp->v_name);
54761f28255Scgd return;
54861f28255Scgd }
54961f28255Scgd lwb = i;
55061f28255Scgd if (!*np)
55161f28255Scgd upb = lwb, np = STRstar;
55261f28255Scgd }
55361f28255Scgd if (*np == '*')
55461f28255Scgd np++;
555ee9e50eaSmycroft else if (*np != '-')
55661f28255Scgd stderror(ERR_MISSING, '-');
557ee9e50eaSmycroft else {
55876adbe2bStls int i = upb;
55961f28255Scgd
56061f28255Scgd np++;
56161f28255Scgd if (Isdigit(*np)) {
56261f28255Scgd i = 0;
56361f28255Scgd while (Isdigit(*np))
56461f28255Scgd i = i * 10 + *np++ - '0';
56561f28255Scgd if (i < 0 || i > upb) {
56661f28255Scgd dolerror(vp->v_name);
56761f28255Scgd return;
56861f28255Scgd }
56961f28255Scgd }
57061f28255Scgd if (i < lwb)
57161f28255Scgd upb = lwb - 1;
57261f28255Scgd else
57361f28255Scgd upb = i;
57461f28255Scgd }
57561f28255Scgd if (lwb == 0) {
57661f28255Scgd if (upb != 0) {
57761f28255Scgd dolerror(vp->v_name);
57861f28255Scgd return;
57961f28255Scgd }
58061f28255Scgd upb = -1;
58161f28255Scgd }
582ee9e50eaSmycroft if (*np)
58361f28255Scgd stderror(ERR_SYNTAX);
58461f28255Scgd }
58561f28255Scgd else {
586341bd18bSthorpej if (subscr > 0) {
58761f28255Scgd if (subscr > upb)
58861f28255Scgd lwb = 1, upb = 0;
58961f28255Scgd else
59061f28255Scgd lwb = upb = subscr;
591341bd18bSthorpej }
59261f28255Scgd unDredc(c);
59361f28255Scgd }
59461f28255Scgd if (dimen) {
59561f28255Scgd Char *cp = putn(upb - lwb + 1);
59661f28255Scgd
59761f28255Scgd addla(cp);
598*1767ce60Schristos free(cp);
59961f28255Scgd }
60061f28255Scgd else {
60161f28255Scgd eatmod:
60261f28255Scgd fixDolMod();
60361f28255Scgd dolnxt = &vp->vec[lwb - 1];
60461f28255Scgd dolcnt = upb - lwb + 1;
60561f28255Scgd }
60661f28255Scgd eatbrac:
60761f28255Scgd if (sc == '{') {
60861f28255Scgd c = Dredc();
609ee9e50eaSmycroft if (c != '}')
61061f28255Scgd stderror(ERR_MISSING, '}');
61161f28255Scgd }
61261f28255Scgd }
61361f28255Scgd
61461f28255Scgd static void
fixDolMod(void)615b771e65bSwiz fixDolMod(void)
61661f28255Scgd {
61776adbe2bStls int c;
61861f28255Scgd
61961f28255Scgd c = DgetC(0);
62061f28255Scgd if (c == ':') {
621cee2bad8Smycroft do {
622cee2bad8Smycroft c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
623cee2bad8Smycroft if (c == 'g' || c == 'a') {
62461f28255Scgd if (c == 'g')
625cee2bad8Smycroft dolmcnt = 10000;
626cee2bad8Smycroft else
627cee2bad8Smycroft dolwcnt = 10000;
628cee2bad8Smycroft c = DgetC(0);
629cee2bad8Smycroft }
630cee2bad8Smycroft if ((c == 'g' && dolmcnt != 10000) ||
631cee2bad8Smycroft (c == 'a' && dolwcnt != 10000)) {
632cee2bad8Smycroft if (c == 'g')
633cee2bad8Smycroft dolmcnt = 10000;
634cee2bad8Smycroft else
635cee2bad8Smycroft dolwcnt = 10000;
636cee2bad8Smycroft c = DgetC(0);
637cee2bad8Smycroft }
638cee2bad8Smycroft
639cee2bad8Smycroft if (c == 's') { /* [eichin:19910926.0755EST] */
640cee2bad8Smycroft int delimcnt = 2;
641cee2bad8Smycroft int delim = DgetC(0);
64237e39248Schristos dolmod[dolnmod++] = (Char)c;
64337e39248Schristos dolmod[dolnmod++] = (Char)delim;
644cee2bad8Smycroft
645cee2bad8Smycroft if (!delim || letter(delim)
646cee2bad8Smycroft || Isdigit(delim) || any(" \t\n", delim)) {
647cee2bad8Smycroft seterror(ERR_BADSUBST);
648cee2bad8Smycroft break;
649cee2bad8Smycroft }
650cee2bad8Smycroft while ((c = DgetC(0)) != (-1)) {
65137e39248Schristos dolmod[dolnmod++] = (Char)c;
652cee2bad8Smycroft if(c == delim) delimcnt--;
653cee2bad8Smycroft if(!delimcnt) break;
654cee2bad8Smycroft }
655cee2bad8Smycroft if(delimcnt) {
656cee2bad8Smycroft seterror(ERR_BADSUBST);
657cee2bad8Smycroft break;
658cee2bad8Smycroft }
659cee2bad8Smycroft continue;
660cee2bad8Smycroft }
661ee9e50eaSmycroft if (!any("htrqxes", c))
66261f28255Scgd stderror(ERR_BADMOD, c);
66337e39248Schristos dolmod[dolnmod++] = (Char)c;
66461f28255Scgd if (c == 'q')
66561f28255Scgd dolmcnt = 10000;
66661f28255Scgd }
667cee2bad8Smycroft while ((c = DgetC(0)) == ':');
668cee2bad8Smycroft unDredc(c);
669cee2bad8Smycroft }
67061f28255Scgd else
67161f28255Scgd unDredc(c);
67261f28255Scgd }
67361f28255Scgd
67461f28255Scgd static void
setDolp(Char * cp)675b771e65bSwiz setDolp(Char *cp)
67661f28255Scgd {
67776adbe2bStls Char *dp;
678cee2bad8Smycroft int i;
67961f28255Scgd
680cee2bad8Smycroft if (dolnmod == 0 || dolmcnt == 0) {
68161f28255Scgd dolp = cp;
68261f28255Scgd return;
68361f28255Scgd }
684cee2bad8Smycroft dp = cp = Strsave(cp);
685cee2bad8Smycroft for (i = 0; i < dolnmod; i++) {
686cee2bad8Smycroft /* handle s// [eichin:19910926.0510EST] */
687cee2bad8Smycroft if(dolmod[i] == 's') {
688cee2bad8Smycroft int delim;
689cee2bad8Smycroft Char *lhsub, *rhsub, *np;
690cee2bad8Smycroft size_t lhlen = 0, rhlen = 0;
691cee2bad8Smycroft int didmod = 0;
692cee2bad8Smycroft
693cee2bad8Smycroft delim = dolmod[++i];
694cee2bad8Smycroft if (!delim || letter(delim)
695cee2bad8Smycroft || Isdigit(delim) || any(" \t\n", delim)) {
696cee2bad8Smycroft seterror(ERR_BADSUBST);
697cee2bad8Smycroft break;
698cee2bad8Smycroft }
699cee2bad8Smycroft lhsub = &dolmod[++i];
700cee2bad8Smycroft while(dolmod[i] != delim && dolmod[++i]) {
701cee2bad8Smycroft lhlen++;
702cee2bad8Smycroft }
703cee2bad8Smycroft dolmod[i] = 0;
704cee2bad8Smycroft rhsub = &dolmod[++i];
705cee2bad8Smycroft while(dolmod[i] != delim && dolmod[++i]) {
706cee2bad8Smycroft rhlen++;
707cee2bad8Smycroft }
708cee2bad8Smycroft dolmod[i] = 0;
709cee2bad8Smycroft
710cee2bad8Smycroft do {
711cee2bad8Smycroft dp = Strstr(cp, lhsub);
71261f28255Scgd if (dp) {
71337e39248Schristos np = xmalloc(
714b771e65bSwiz (size_t)((Strlen(cp) + 1 - lhlen + rhlen) *
71537e39248Schristos sizeof(*np)));
71637e39248Schristos (void)Strncpy(np, cp, (size_t)(dp - cp));
717cee2bad8Smycroft (void)Strcpy(np + (dp - cp), rhsub);
718cee2bad8Smycroft (void)Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
719cee2bad8Smycroft
720*1767ce60Schristos free(cp);
721cee2bad8Smycroft dp = cp = np;
722cee2bad8Smycroft didmod = 1;
723cee2bad8Smycroft } else {
724cee2bad8Smycroft /* should this do a seterror? */
725cee2bad8Smycroft break;
726cee2bad8Smycroft }
727cee2bad8Smycroft }
728cee2bad8Smycroft while (dolwcnt == 10000);
729cee2bad8Smycroft /*
730cee2bad8Smycroft * restore dolmod for additional words
731cee2bad8Smycroft */
73237e39248Schristos dolmod[i] = rhsub[-1] = (Char)delim;
733cee2bad8Smycroft if (didmod)
73461f28255Scgd dolmcnt--;
735cee2bad8Smycroft else
736cee2bad8Smycroft break;
737cee2bad8Smycroft } else {
738cee2bad8Smycroft int didmod = 0;
739cee2bad8Smycroft
740cee2bad8Smycroft do {
741cee2bad8Smycroft if ((dp = domod(cp, dolmod[i]))) {
742cee2bad8Smycroft didmod = 1;
743cee2bad8Smycroft if (Strcmp(cp, dp) == 0) {
744*1767ce60Schristos free(cp);
745cee2bad8Smycroft cp = dp;
746cee2bad8Smycroft break;
747cee2bad8Smycroft }
748cee2bad8Smycroft else {
749*1767ce60Schristos free(cp);
750cee2bad8Smycroft cp = dp;
751cee2bad8Smycroft }
752cee2bad8Smycroft }
753cee2bad8Smycroft else
754cee2bad8Smycroft break;
755cee2bad8Smycroft }
756cee2bad8Smycroft while (dolwcnt == 10000);
757cee2bad8Smycroft dp = cp;
758cee2bad8Smycroft if (didmod)
759cee2bad8Smycroft dolmcnt--;
760cee2bad8Smycroft else
761cee2bad8Smycroft break;
762cee2bad8Smycroft }
763cee2bad8Smycroft }
764cee2bad8Smycroft
765cee2bad8Smycroft if (dp) {
76661f28255Scgd addla(dp);
767*1767ce60Schristos free(dp);
76861f28255Scgd }
7693cf8c179Schristos else {
77061f28255Scgd addla(cp);
771*1767ce60Schristos free(cp);
7723cf8c179Schristos }
773cee2bad8Smycroft
77461f28255Scgd dolp = STRNULL;
775ee9e50eaSmycroft if (seterr)
77661f28255Scgd stderror(ERR_OLD);
77761f28255Scgd }
77861f28255Scgd
77961f28255Scgd static void
unDredc(int c)780b771e65bSwiz unDredc(int c)
78161f28255Scgd {
78261f28255Scgd Dpeekrd = c;
78361f28255Scgd }
78461f28255Scgd
78561f28255Scgd static int
Dredc(void)786b771e65bSwiz Dredc(void)
78761f28255Scgd {
78876adbe2bStls int c;
78961f28255Scgd
790cee2bad8Smycroft if ((c = Dpeekrd) != '\0') {
79161f28255Scgd Dpeekrd = 0;
79261f28255Scgd return (c);
79361f28255Scgd }
79461f28255Scgd if (Dcp && (c = *Dcp++))
79561f28255Scgd return (c & (QUOTE | TRIM));
79661f28255Scgd if (*Dvp == 0) {
79761f28255Scgd Dcp = 0;
79861f28255Scgd return (DEOF);
79961f28255Scgd }
80061f28255Scgd Dcp = *Dvp++;
80161f28255Scgd return (' ');
80261f28255Scgd }
80361f28255Scgd
80461f28255Scgd static void
Dtestq(int c)805b771e65bSwiz Dtestq(int c)
80661f28255Scgd {
80761f28255Scgd if (cmap(c, QUOTES))
80861f28255Scgd gflag = 1;
80961f28255Scgd }
81061f28255Scgd
81161f28255Scgd /*
81261f28255Scgd * Form a shell temporary file (in unit 0) from the words
81361f28255Scgd * of the shell input up to EOF or a line the same as "term".
81461f28255Scgd * Unit 0 should have been closed before this call.
81561f28255Scgd */
81661f28255Scgd void
817cee2bad8Smycroft /*ARGSUSED*/
heredoc(Char * term)818b771e65bSwiz heredoc(Char *term)
81961f28255Scgd {
8200bf6fd0cSchristos Char obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
821c4753f0fSchristos struct timespec tv;
822b771e65bSwiz Char *Dv[2], *lbp, *obp, *mbp, **vp;
823b771e65bSwiz char *tmp;
824b771e65bSwiz int c, ocnt, lcnt, mcnt;
825b79c2ef2Schristos int quoted;
82661f28255Scgd
827e5dfea2fSchristos again:
828baccf0fbSmycroft tmp = short2str(shtemp);
829e5dfea2fSchristos if (open(tmp, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600) < 0) {
830e5dfea2fSchristos if (errno == EEXIST) {
831e5dfea2fSchristos if (unlink(tmp) == -1) {
832c4753f0fSchristos (void)clock_gettime(CLOCK_MONOTONIC, &tv);
833e889898cSchristos mbp = putn((((int)tv.tv_sec) ^
834c4753f0fSchristos ((int)tv.tv_nsec) ^ ((int)getpid())) & 0x00ffffff);
835e889898cSchristos shtemp = Strspl(STRtmpsh, mbp);
836*1767ce60Schristos free(mbp);
837e5dfea2fSchristos }
838e5dfea2fSchristos goto again;
839e5dfea2fSchristos }
84061f28255Scgd stderror(ERR_SYSTEM, tmp, strerror(errno));
841e5dfea2fSchristos }
84261f28255Scgd (void)unlink(tmp); /* 0 0 inode! */
84361f28255Scgd Dv[0] = term;
84461f28255Scgd Dv[1] = NULL;
84561f28255Scgd gflag = 0;
84661f28255Scgd trim(Dv);
84761f28255Scgd rscan(Dv, Dtestq);
84861f28255Scgd quoted = gflag;
8490bf6fd0cSchristos ocnt = BUFSIZE;
85061f28255Scgd obp = obuf;
85161f28255Scgd for (;;) {
85261f28255Scgd /*
85361f28255Scgd * Read up a line
85461f28255Scgd */
85561f28255Scgd lbp = lbuf;
8560bf6fd0cSchristos lcnt = BUFSIZE - 4;
85761f28255Scgd for (;;) {
85861f28255Scgd c = readc(1); /* 1 -> Want EOF returns */
85961f28255Scgd if (c < 0 || c == '\n')
86061f28255Scgd break;
861cee2bad8Smycroft if ((c &= TRIM) != '\0') {
86237e39248Schristos *lbp++ = (Char)c;
86361f28255Scgd if (--lcnt < 0) {
86461f28255Scgd setname("<<");
86561f28255Scgd stderror(ERR_NAME | ERR_OVERFLOW);
86661f28255Scgd }
86761f28255Scgd }
86861f28255Scgd }
86961f28255Scgd *lbp = 0;
87061f28255Scgd
87161f28255Scgd /*
87261f28255Scgd * Check for EOF or compare to terminator -- before expansion
87361f28255Scgd */
87461f28255Scgd if (c < 0 || eq(lbuf, term)) {
8750bf6fd0cSchristos (void)write(0, short2str(obuf), (size_t)(BUFSIZE - ocnt));
8760ab192c9Sjtc (void)lseek(0, (off_t)0, SEEK_SET);
87761f28255Scgd return;
87861f28255Scgd }
87961f28255Scgd
88061f28255Scgd /*
88161f28255Scgd * If term was quoted or -n just pass it on
88261f28255Scgd */
88361f28255Scgd if (quoted || noexec) {
88461f28255Scgd *lbp++ = '\n';
88561f28255Scgd *lbp = 0;
886cee2bad8Smycroft for (lbp = lbuf; (c = *lbp++) != '\0';) {
88737e39248Schristos *obp++ = (Char)c;
88861f28255Scgd if (--ocnt == 0) {
8890bf6fd0cSchristos (void) write(0, short2str(obuf), BUFSIZE);
89061f28255Scgd obp = obuf;
8910bf6fd0cSchristos ocnt = BUFSIZE;
89261f28255Scgd }
89361f28255Scgd }
89461f28255Scgd continue;
89561f28255Scgd }
89661f28255Scgd
89761f28255Scgd /*
89861f28255Scgd * Term wasn't quoted so variable and then command expand the input
89961f28255Scgd * line
90061f28255Scgd */
90161f28255Scgd Dcp = lbuf;
90261f28255Scgd Dvp = Dv + 1;
90361f28255Scgd mbp = mbuf;
9040bf6fd0cSchristos mcnt = BUFSIZE - 4;
90561f28255Scgd for (;;) {
90661f28255Scgd c = DgetC(DODOL);
90761f28255Scgd if (c == DEOF)
90861f28255Scgd break;
90961f28255Scgd if ((c &= TRIM) == 0)
91061f28255Scgd continue;
91161f28255Scgd /* \ quotes \ $ ` here */
91261f28255Scgd if (c == '\\') {
91361f28255Scgd c = DgetC(0);
91461f28255Scgd if (!any("$\\`", c))
91561f28255Scgd unDgetC(c | QUOTE), c = '\\';
91661f28255Scgd else
91761f28255Scgd c |= QUOTE;
91861f28255Scgd }
91937e39248Schristos *mbp++ = (Char)c;
92061f28255Scgd if (--mcnt == 0) {
92161f28255Scgd setname("<<");
92261f28255Scgd stderror(ERR_NAME | ERR_OVERFLOW);
92361f28255Scgd }
92461f28255Scgd }
92561f28255Scgd *mbp++ = 0;
92661f28255Scgd
92761f28255Scgd /*
92861f28255Scgd * If any ` in line do command substitution
92961f28255Scgd */
93061f28255Scgd mbp = mbuf;
93161f28255Scgd if (any(short2str(mbp), '`')) {
93261f28255Scgd /*
93361f28255Scgd * 1 arg to dobackp causes substitution to be literal. Words are
93461f28255Scgd * broken only at newlines so that all blanks and tabs are
93561f28255Scgd * preserved. Blank lines (null words) are not discarded.
93661f28255Scgd */
93761f28255Scgd vp = dobackp(mbuf, 1);
93861f28255Scgd }
93961f28255Scgd else
94061f28255Scgd /* Setup trivial vector similar to return of dobackp */
94161f28255Scgd Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
94261f28255Scgd
94361f28255Scgd /*
94461f28255Scgd * Resurrect the words from the command substitution each separated by
94561f28255Scgd * a newline. Note that the last newline of a command substitution
94661f28255Scgd * will have been discarded, but we put a newline after the last word
94761f28255Scgd * because this represents the newline after the last input line!
94861f28255Scgd */
94961f28255Scgd for (; *vp; vp++) {
95061f28255Scgd for (mbp = *vp; *mbp; mbp++) {
95161f28255Scgd *obp++ = *mbp & TRIM;
95261f28255Scgd if (--ocnt == 0) {
9530bf6fd0cSchristos (void)write(0, short2str(obuf), BUFSIZE);
95461f28255Scgd obp = obuf;
9550bf6fd0cSchristos ocnt = BUFSIZE;
95661f28255Scgd }
95761f28255Scgd }
95861f28255Scgd *obp++ = '\n';
95961f28255Scgd if (--ocnt == 0) {
9600bf6fd0cSchristos (void)write(0, short2str(obuf), BUFSIZE);
96161f28255Scgd obp = obuf;
9620bf6fd0cSchristos ocnt = BUFSIZE;
96361f28255Scgd }
96461f28255Scgd }
96561f28255Scgd if (pargv)
96661f28255Scgd blkfree(pargv), pargv = 0;
96761f28255Scgd }
96861f28255Scgd }
969