1*5b133f3fSguenther /* $OpenBSD: dol.c,v 1.27 2023/03/08 04:43:04 guenther Exp $ */
2df930be7Sderaadt /* $NetBSD: dol.c,v 1.8 1995/09/27 00:38:38 jtc Exp $ */
3df930be7Sderaadt
4df930be7Sderaadt /*-
5df930be7Sderaadt * Copyright (c) 1980, 1991, 1993
6df930be7Sderaadt * The Regents of the University of California. All rights reserved.
7df930be7Sderaadt *
8df930be7Sderaadt * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt * modification, are permitted provided that the following conditions
10df930be7Sderaadt * are met:
11df930be7Sderaadt * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt * notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt * notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt * documentation and/or other materials provided with the distribution.
1629295d1cSmillert * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt * may be used to endorse or promote products derived from this software
18df930be7Sderaadt * without specific prior written permission.
19df930be7Sderaadt *
20df930be7Sderaadt * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt * SUCH DAMAGE.
31df930be7Sderaadt */
32df930be7Sderaadt
33df930be7Sderaadt #include <sys/types.h>
34df930be7Sderaadt #include <fcntl.h>
35df930be7Sderaadt #include <errno.h>
36df930be7Sderaadt #include <stdlib.h>
37df930be7Sderaadt #include <string.h>
38df930be7Sderaadt #include <unistd.h>
39df930be7Sderaadt #include <stdarg.h>
40df930be7Sderaadt
41df930be7Sderaadt #include "csh.h"
42df930be7Sderaadt #include "extern.h"
43df930be7Sderaadt
44df930be7Sderaadt /*
45df930be7Sderaadt * These routines perform variable substitution and quoting via ' and ".
46df930be7Sderaadt * To this point these constructs have been preserved in the divided
47df930be7Sderaadt * input words. Here we expand variables and turn quoting via ' and " into
48df930be7Sderaadt * QUOTE bits on characters (which prevent further interpretation).
49df930be7Sderaadt * If the `:q' modifier was applied during history expansion, then
50df930be7Sderaadt * some QUOTEing may have occurred already, so we dont "trim()" here.
51df930be7Sderaadt */
52df930be7Sderaadt
53df930be7Sderaadt static int Dpeekc, Dpeekrd; /* Peeks for DgetC and Dreadc */
54df930be7Sderaadt static Char *Dcp, **Dvp; /* Input vector for Dreadc */
55df930be7Sderaadt
56df930be7Sderaadt #define DEOF -1
57df930be7Sderaadt
58df930be7Sderaadt #define unDgetC(c) Dpeekc = c
59df930be7Sderaadt
60df930be7Sderaadt #define QUOTES (_QF|_QB|_ESC) /* \ ' " ` */
61df930be7Sderaadt
62df930be7Sderaadt /*
63df930be7Sderaadt * The following variables give the information about the current
64df930be7Sderaadt * $ expansion, recording the current word position, the remaining
65df930be7Sderaadt * words within this expansion, the count of remaining words, and the
66df930be7Sderaadt * information about any : modifier which is being applied.
67df930be7Sderaadt */
68df930be7Sderaadt #define MAXWLEN (BUFSIZ - 4)
69df930be7Sderaadt #define MAXMOD MAXWLEN /* This cannot overflow */
70df930be7Sderaadt static Char *dolp; /* Remaining chars from this word */
71df930be7Sderaadt static Char **dolnxt; /* Further words */
72df930be7Sderaadt static int dolcnt; /* Count of further words */
73df930be7Sderaadt static Char dolmod[MAXMOD]; /* : modifier character */
74df930be7Sderaadt static int dolnmod; /* Number of modifiers */
75df930be7Sderaadt static int dolmcnt; /* :gx -> 10000, else 1 */
76df930be7Sderaadt static int dolwcnt; /* :wx -> 10000, else 1 */
77df930be7Sderaadt
78c72b5b24Smillert static void Dfix2(Char **);
79c72b5b24Smillert static Char *Dpack(Char *, Char *);
80c72b5b24Smillert static int Dword(void);
81c72b5b24Smillert static void dolerror(Char *);
82c72b5b24Smillert static int DgetC(int);
83c72b5b24Smillert static void Dgetdol(void);
84c72b5b24Smillert static void fixDolMod(void);
85c72b5b24Smillert static void setDolp(Char *);
86c72b5b24Smillert static void unDredc(int);
87c72b5b24Smillert static int Dredc(void);
88c72b5b24Smillert static void Dtestq(int);
89df930be7Sderaadt
90df930be7Sderaadt
91df930be7Sderaadt /*
92df930be7Sderaadt * Fix up the $ expansions and quotations in the
93df930be7Sderaadt * argument list to command t.
94df930be7Sderaadt */
95df930be7Sderaadt void
Dfix(struct command * t)96e757c91eSderaadt Dfix(struct command *t)
97df930be7Sderaadt {
98e757c91eSderaadt Char **pp;
99e757c91eSderaadt Char *p;
100df930be7Sderaadt
101df930be7Sderaadt if (noexec)
102df930be7Sderaadt return;
103df930be7Sderaadt /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
104df930be7Sderaadt for (pp = t->t_dcom; (p = *pp++) != NULL;)
105df930be7Sderaadt for (; *p; p++) {
106df930be7Sderaadt if (cmap(*p, _DOL | QUOTES)) { /* $, \, ', ", ` */
107df930be7Sderaadt Dfix2(t->t_dcom); /* found one */
108df930be7Sderaadt blkfree(t->t_dcom);
109df930be7Sderaadt t->t_dcom = gargv;
110df930be7Sderaadt gargv = 0;
111df930be7Sderaadt return;
112df930be7Sderaadt }
113df930be7Sderaadt }
114df930be7Sderaadt }
115df930be7Sderaadt
116df930be7Sderaadt /*
117df930be7Sderaadt * $ substitute one word, for i/o redirection
118df930be7Sderaadt */
119df930be7Sderaadt Char *
Dfix1(Char * cp)120e757c91eSderaadt Dfix1(Char *cp)
121df930be7Sderaadt {
122df930be7Sderaadt Char *Dv[2];
123df930be7Sderaadt
124df930be7Sderaadt if (noexec)
125df930be7Sderaadt return (0);
126df930be7Sderaadt Dv[0] = cp;
127df930be7Sderaadt Dv[1] = NULL;
128df930be7Sderaadt Dfix2(Dv);
129df930be7Sderaadt if (gargc != 1) {
130df930be7Sderaadt setname(vis_str(cp));
131df930be7Sderaadt stderror(ERR_NAME | ERR_AMBIG);
132df930be7Sderaadt }
133df930be7Sderaadt cp = Strsave(gargv[0]);
134df930be7Sderaadt blkfree(gargv), gargv = 0;
135df930be7Sderaadt return (cp);
136df930be7Sderaadt }
137df930be7Sderaadt
138df930be7Sderaadt /*
139df930be7Sderaadt * Subroutine to do actual fixing after state initialization.
140df930be7Sderaadt */
141df930be7Sderaadt static void
Dfix2(Char ** v)142e757c91eSderaadt Dfix2(Char **v)
143df930be7Sderaadt {
144df930be7Sderaadt ginit(); /* Initialize glob's area pointers */
145df930be7Sderaadt Dvp = v;
146df930be7Sderaadt Dcp = STRNULL; /* Setup input vector for Dreadc */
147df930be7Sderaadt unDgetC(0);
148df930be7Sderaadt unDredc(0); /* Clear out any old peeks (at error) */
149df930be7Sderaadt dolp = 0;
150df930be7Sderaadt dolcnt = 0; /* Clear out residual $ expands (...) */
151df930be7Sderaadt while (Dword())
152df930be7Sderaadt continue;
153df930be7Sderaadt }
154df930be7Sderaadt
155df930be7Sderaadt /*
156df930be7Sderaadt * Pack up more characters in this word
157df930be7Sderaadt */
158df930be7Sderaadt static Char *
Dpack(Char * wbuf,Char * wp)159e757c91eSderaadt Dpack(Char *wbuf, Char *wp)
160df930be7Sderaadt {
161e757c91eSderaadt int c;
162e757c91eSderaadt int i = MAXWLEN - (wp - wbuf);
163df930be7Sderaadt
164df930be7Sderaadt for (;;) {
165df930be7Sderaadt c = DgetC(DODOL);
166df930be7Sderaadt if (c == '\\') {
167df930be7Sderaadt c = DgetC(0);
168df930be7Sderaadt if (c == DEOF) {
169df930be7Sderaadt unDredc(c);
170df930be7Sderaadt *wp = 0;
171df930be7Sderaadt Gcat(STRNULL, wbuf);
172df930be7Sderaadt return (NULL);
173df930be7Sderaadt }
174df930be7Sderaadt if (c == '\n')
175df930be7Sderaadt c = ' ';
176df930be7Sderaadt else
177df930be7Sderaadt c |= QUOTE;
178df930be7Sderaadt }
179df930be7Sderaadt if (c == DEOF) {
180df930be7Sderaadt unDredc(c);
181df930be7Sderaadt *wp = 0;
182df930be7Sderaadt Gcat(STRNULL, wbuf);
183df930be7Sderaadt return (NULL);
184df930be7Sderaadt }
185df930be7Sderaadt if (cmap(c, _SP | _NL | _QF | _QB)) { /* sp \t\n'"` */
186df930be7Sderaadt unDgetC(c);
187df930be7Sderaadt if (cmap(c, QUOTES))
188df930be7Sderaadt return (wp);
189df930be7Sderaadt *wp++ = 0;
190df930be7Sderaadt Gcat(STRNULL, wbuf);
191df930be7Sderaadt return (NULL);
192df930be7Sderaadt }
193df930be7Sderaadt if (--i <= 0)
194df930be7Sderaadt stderror(ERR_WTOOLONG);
195df930be7Sderaadt *wp++ = c;
196df930be7Sderaadt }
197df930be7Sderaadt }
198df930be7Sderaadt
199df930be7Sderaadt /*
200df930be7Sderaadt * Get a word. This routine is analogous to the routine
201df930be7Sderaadt * word() in sh.lex.c for the main lexical input. One difference
202df930be7Sderaadt * here is that we don't get a newline to terminate our expansion.
203df930be7Sderaadt * Rather, DgetC will return a DEOF when we hit the end-of-input.
204df930be7Sderaadt */
205df930be7Sderaadt static int
Dword(void)206e757c91eSderaadt Dword(void)
207df930be7Sderaadt {
208e757c91eSderaadt int c, c1;
209df930be7Sderaadt Char wbuf[BUFSIZ];
210e757c91eSderaadt Char *wp = wbuf;
211e757c91eSderaadt int i = MAXWLEN;
212e757c91eSderaadt bool dolflg;
213df930be7Sderaadt bool sofar = 0, done = 0;
214df930be7Sderaadt
215df930be7Sderaadt while (!done) {
216df930be7Sderaadt done = 1;
217df930be7Sderaadt c = DgetC(DODOL);
218df930be7Sderaadt switch (c) {
219df930be7Sderaadt
220df930be7Sderaadt case DEOF:
221df930be7Sderaadt if (sofar == 0)
222df930be7Sderaadt return (0);
223df930be7Sderaadt /* finish this word and catch the code above the next time */
224df930be7Sderaadt unDredc(c);
225df930be7Sderaadt /* fall into ... */
226df930be7Sderaadt
227df930be7Sderaadt case '\n':
228df930be7Sderaadt *wp = 0;
229df930be7Sderaadt Gcat(STRNULL, wbuf);
230df930be7Sderaadt return (1);
231df930be7Sderaadt
232df930be7Sderaadt case ' ':
233df930be7Sderaadt case '\t':
234df930be7Sderaadt done = 0;
235df930be7Sderaadt break;
236df930be7Sderaadt
237df930be7Sderaadt case '`':
238df930be7Sderaadt /* We preserve ` quotations which are done yet later */
239df930be7Sderaadt *wp++ = c, --i;
240df930be7Sderaadt case '\'':
241df930be7Sderaadt case '"':
242df930be7Sderaadt /*
243df930be7Sderaadt * Note that DgetC never returns a QUOTES character from an
244df930be7Sderaadt * expansion, so only true input quotes will get us here or out.
245df930be7Sderaadt */
246df930be7Sderaadt c1 = c;
247df930be7Sderaadt dolflg = c1 == '"' ? DODOL : 0;
248df930be7Sderaadt for (;;) {
249df930be7Sderaadt c = DgetC(dolflg);
250df930be7Sderaadt if (c == c1)
251df930be7Sderaadt break;
252df930be7Sderaadt if (c == '\n' || c == DEOF)
253df930be7Sderaadt stderror(ERR_UNMATCHED, c1);
254df930be7Sderaadt if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
255df930be7Sderaadt --wp, ++i;
256df930be7Sderaadt if (--i <= 0)
257df930be7Sderaadt stderror(ERR_WTOOLONG);
258df930be7Sderaadt switch (c1) {
259df930be7Sderaadt
260df930be7Sderaadt case '"':
261df930be7Sderaadt /*
262df930be7Sderaadt * Leave any `s alone for later. Other chars are all
263df930be7Sderaadt * quoted, thus `...` can tell it was within "...".
264df930be7Sderaadt */
265df930be7Sderaadt *wp++ = c == '`' ? '`' : c | QUOTE;
266df930be7Sderaadt break;
267df930be7Sderaadt
268df930be7Sderaadt case '\'':
269df930be7Sderaadt /* Prevent all further interpretation */
270df930be7Sderaadt *wp++ = c | QUOTE;
271df930be7Sderaadt break;
272df930be7Sderaadt
273df930be7Sderaadt case '`':
274df930be7Sderaadt /* Leave all text alone for later */
275df930be7Sderaadt *wp++ = c;
276df930be7Sderaadt break;
277df930be7Sderaadt
278df930be7Sderaadt default:
279df930be7Sderaadt break;
280df930be7Sderaadt }
281df930be7Sderaadt }
282df930be7Sderaadt if (c1 == '`')
283df930be7Sderaadt *wp++ = '`' /* i--; eliminated */;
284df930be7Sderaadt sofar = 1;
285df930be7Sderaadt if ((wp = Dpack(wbuf, wp)) == NULL)
286df930be7Sderaadt return (1);
287df930be7Sderaadt else {
288df930be7Sderaadt i = MAXWLEN - (wp - wbuf);
289df930be7Sderaadt done = 0;
290df930be7Sderaadt }
291df930be7Sderaadt break;
292df930be7Sderaadt
293df930be7Sderaadt case '\\':
294df930be7Sderaadt c = DgetC(0); /* No $ subst! */
295df930be7Sderaadt if (c == '\n' || c == DEOF) {
296df930be7Sderaadt done = 0;
297df930be7Sderaadt break;
298df930be7Sderaadt }
299df930be7Sderaadt c |= QUOTE;
300df930be7Sderaadt break;
301df930be7Sderaadt
302df930be7Sderaadt default:
303df930be7Sderaadt break;
304df930be7Sderaadt }
305df930be7Sderaadt if (done) {
306df930be7Sderaadt unDgetC(c);
307df930be7Sderaadt sofar = 1;
308df930be7Sderaadt if ((wp = Dpack(wbuf, wp)) == NULL)
309df930be7Sderaadt return (1);
310df930be7Sderaadt else {
311df930be7Sderaadt i = MAXWLEN - (wp - wbuf);
312df930be7Sderaadt done = 0;
313df930be7Sderaadt }
314df930be7Sderaadt }
315df930be7Sderaadt }
316df930be7Sderaadt /* Really NOTREACHED */
317df930be7Sderaadt return (0);
318df930be7Sderaadt }
319df930be7Sderaadt
320df930be7Sderaadt
321df930be7Sderaadt /*
322df930be7Sderaadt * Get a character, performing $ substitution unless flag is 0.
323df930be7Sderaadt * Any QUOTES character which is returned from a $ expansion is
324df930be7Sderaadt * QUOTEd so that it will not be recognized above.
325df930be7Sderaadt */
326df930be7Sderaadt static int
DgetC(int flag)327e757c91eSderaadt DgetC(int flag)
328df930be7Sderaadt {
329e757c91eSderaadt int c;
330df930be7Sderaadt
331df930be7Sderaadt top:
332df930be7Sderaadt if ((c = Dpeekc) != '\0') {
333df930be7Sderaadt Dpeekc = 0;
334df930be7Sderaadt return (c);
335df930be7Sderaadt }
336df930be7Sderaadt if (lap) {
337df930be7Sderaadt c = *lap++ & (QUOTE | TRIM);
338df930be7Sderaadt if (c == 0) {
339df930be7Sderaadt lap = 0;
340df930be7Sderaadt goto top;
341df930be7Sderaadt }
342df930be7Sderaadt quotspec:
343df930be7Sderaadt if (cmap(c, QUOTES))
344df930be7Sderaadt return (c | QUOTE);
345df930be7Sderaadt return (c);
346df930be7Sderaadt }
347df930be7Sderaadt if (dolp) {
348df930be7Sderaadt if ((c = *dolp++ & (QUOTE | TRIM)) != '\0')
349df930be7Sderaadt goto quotspec;
350df930be7Sderaadt if (dolcnt > 0) {
351df930be7Sderaadt setDolp(*dolnxt++);
352df930be7Sderaadt --dolcnt;
353df930be7Sderaadt return (' ');
354df930be7Sderaadt }
355df930be7Sderaadt dolp = 0;
356df930be7Sderaadt }
357df930be7Sderaadt if (dolcnt > 0) {
358df930be7Sderaadt setDolp(*dolnxt++);
359df930be7Sderaadt --dolcnt;
360df930be7Sderaadt goto top;
361df930be7Sderaadt }
362df930be7Sderaadt c = Dredc();
363df930be7Sderaadt if (c == '$' && flag) {
364df930be7Sderaadt Dgetdol();
365df930be7Sderaadt goto top;
366df930be7Sderaadt }
367df930be7Sderaadt return (c);
368df930be7Sderaadt }
369df930be7Sderaadt
370df930be7Sderaadt static Char *nulvec[] = {0};
371df930be7Sderaadt static struct varent nulargv = {nulvec, STRargv, { NULL, NULL, NULL }, 0};
372df930be7Sderaadt
373df930be7Sderaadt static void
dolerror(Char * s)374e757c91eSderaadt dolerror(Char *s)
375df930be7Sderaadt {
376df930be7Sderaadt setname(vis_str(s));
377df930be7Sderaadt stderror(ERR_NAME | ERR_RANGE);
378df930be7Sderaadt }
379df930be7Sderaadt
380df930be7Sderaadt /*
381df930be7Sderaadt * Handle the multitudinous $ expansion forms.
382df930be7Sderaadt * Ugh.
383df930be7Sderaadt */
384df930be7Sderaadt static void
Dgetdol(void)385e757c91eSderaadt Dgetdol(void)
386df930be7Sderaadt {
387e757c91eSderaadt Char *np;
388e757c91eSderaadt struct varent *vp = NULL;
389df930be7Sderaadt Char name[4 * MAXVARLEN + 1];
390df930be7Sderaadt int c, sc;
391df930be7Sderaadt int subscr = 0, lwb = 1, upb = 0;
392df930be7Sderaadt bool dimen = 0, bitset = 0;
393df930be7Sderaadt char tnp;
394df930be7Sderaadt Char wbuf[BUFSIZ];
395df930be7Sderaadt static Char *dolbang = NULL;
396df930be7Sderaadt
397df930be7Sderaadt dolnmod = dolmcnt = dolwcnt = 0;
398df930be7Sderaadt c = sc = DgetC(0);
399df930be7Sderaadt if (c == '{')
400df930be7Sderaadt c = DgetC(0); /* sc is { to take } later */
401df930be7Sderaadt if ((c & TRIM) == '#')
402df930be7Sderaadt dimen++, c = DgetC(0); /* $# takes dimension */
403df930be7Sderaadt else if (c == '?')
404df930be7Sderaadt bitset++, c = DgetC(0); /* $? tests existence */
405df930be7Sderaadt switch (c) {
406df930be7Sderaadt
407df930be7Sderaadt case '!':
408df930be7Sderaadt if (dimen || bitset)
409df930be7Sderaadt stderror(ERR_SYNTAX);
410df930be7Sderaadt if (backpid != 0) {
411acdb3202Smestre free(dolbang);
412df930be7Sderaadt setDolp(dolbang = putn(backpid));
413df930be7Sderaadt }
414df930be7Sderaadt goto eatbrac;
415df930be7Sderaadt
416df930be7Sderaadt case '$':
417df930be7Sderaadt if (dimen || bitset)
418df930be7Sderaadt stderror(ERR_SYNTAX);
419df930be7Sderaadt setDolp(doldol);
420df930be7Sderaadt goto eatbrac;
421df930be7Sderaadt
422df930be7Sderaadt case '<' | QUOTE:
423df930be7Sderaadt if (bitset)
424df930be7Sderaadt stderror(ERR_NOTALLOWED, "$?<");
425df930be7Sderaadt if (dimen)
426df930be7Sderaadt stderror(ERR_NOTALLOWED, "$?#");
427df930be7Sderaadt for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
428df930be7Sderaadt *np = (unsigned char) tnp;
429df930be7Sderaadt if (np >= &wbuf[BUFSIZ - 1])
430df930be7Sderaadt stderror(ERR_LTOOLONG);
431df930be7Sderaadt if (tnp == '\n')
432df930be7Sderaadt break;
433df930be7Sderaadt }
434df930be7Sderaadt *np = 0;
435df930be7Sderaadt /*
436df930be7Sderaadt * KLUDGE: dolmod is set here because it will cause setDolp to call
437df930be7Sderaadt * domod and thus to copy wbuf. Otherwise setDolp would use it
438df930be7Sderaadt * directly. If we saved it ourselves, no one would know when to free
439df930be7Sderaadt * it. The actual function of the 'q' causes filename expansion not to
440df930be7Sderaadt * be done on the interpolated value.
441df930be7Sderaadt */
442df930be7Sderaadt dolmod[dolnmod++] = 'q';
443df930be7Sderaadt dolmcnt = 10000;
444df930be7Sderaadt setDolp(wbuf);
445df930be7Sderaadt goto eatbrac;
446df930be7Sderaadt
447df930be7Sderaadt case DEOF:
448df930be7Sderaadt case '\n':
449df930be7Sderaadt stderror(ERR_SYNTAX);
450df930be7Sderaadt /* NOTREACHED */
451df930be7Sderaadt break;
452df930be7Sderaadt
453df930be7Sderaadt case '*':
4546a01f4acSderaadt (void) Strlcpy(name, STRargv, sizeof name/sizeof(Char));
455df930be7Sderaadt vp = adrof(STRargv);
456df930be7Sderaadt subscr = -1; /* Prevent eating [...] */
457df930be7Sderaadt break;
458df930be7Sderaadt
459df930be7Sderaadt default:
460df930be7Sderaadt np = name;
461df930be7Sderaadt if (Isdigit(c)) {
462df930be7Sderaadt if (dimen)
463df930be7Sderaadt stderror(ERR_NOTALLOWED, "$#<num>");
464df930be7Sderaadt subscr = 0;
465df930be7Sderaadt do {
466df930be7Sderaadt subscr = subscr * 10 + c - '0';
467df930be7Sderaadt c = DgetC(0);
468df930be7Sderaadt } while (Isdigit(c));
469df930be7Sderaadt unDredc(c);
470d9c0df3bSitojun if (subscr < 0)
471d9c0df3bSitojun stderror(ERR_RANGE);
472df930be7Sderaadt if (subscr == 0) {
473df930be7Sderaadt if (bitset) {
474df930be7Sderaadt dolp = ffile ? STR1 : STR0;
475df930be7Sderaadt goto eatbrac;
476df930be7Sderaadt }
477df930be7Sderaadt if (ffile == 0)
478df930be7Sderaadt stderror(ERR_DOLZERO);
479df930be7Sderaadt fixDolMod();
480df930be7Sderaadt setDolp(ffile);
481df930be7Sderaadt goto eatbrac;
482df930be7Sderaadt }
483df930be7Sderaadt if (bitset)
484df930be7Sderaadt stderror(ERR_DOLQUEST);
485df930be7Sderaadt vp = adrof(STRargv);
486df930be7Sderaadt if (vp == 0) {
487df930be7Sderaadt vp = &nulargv;
488df930be7Sderaadt goto eatmod;
489df930be7Sderaadt }
490df930be7Sderaadt break;
491df930be7Sderaadt }
492df930be7Sderaadt if (!alnum(c))
493df930be7Sderaadt stderror(ERR_VARALNUM);
494df930be7Sderaadt for (;;) {
495df930be7Sderaadt *np++ = c;
496df930be7Sderaadt c = DgetC(0);
497df930be7Sderaadt if (!alnum(c))
498df930be7Sderaadt break;
499df930be7Sderaadt if (np >= &name[MAXVARLEN])
500df930be7Sderaadt stderror(ERR_VARTOOLONG);
501df930be7Sderaadt }
502df930be7Sderaadt *np++ = 0;
503df930be7Sderaadt unDredc(c);
504df930be7Sderaadt vp = adrof(name);
505df930be7Sderaadt }
506df930be7Sderaadt if (bitset) {
507df930be7Sderaadt dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
508df930be7Sderaadt goto eatbrac;
509df930be7Sderaadt }
510df930be7Sderaadt if (vp == 0) {
511df930be7Sderaadt np = str2short(getenv(short2str(name)));
512df930be7Sderaadt if (np) {
513df930be7Sderaadt fixDolMod();
514df930be7Sderaadt setDolp(np);
515df930be7Sderaadt goto eatbrac;
516df930be7Sderaadt }
517df930be7Sderaadt udvar(name);
518df930be7Sderaadt /* NOTREACHED */
519df930be7Sderaadt }
520df930be7Sderaadt c = DgetC(0);
521df930be7Sderaadt upb = blklen(vp->vec);
522df930be7Sderaadt if (dimen == 0 && subscr == 0 && c == '[') {
523df930be7Sderaadt np = name;
524df930be7Sderaadt for (;;) {
525df930be7Sderaadt c = DgetC(DODOL); /* Allow $ expand within [ ] */
526df930be7Sderaadt if (c == ']')
527df930be7Sderaadt break;
528df930be7Sderaadt if (c == '\n' || c == DEOF)
529df930be7Sderaadt stderror(ERR_INCBR);
530df930be7Sderaadt if (np >= &name[sizeof(name) / sizeof(Char) - 2])
531df930be7Sderaadt stderror(ERR_VARTOOLONG);
532df930be7Sderaadt *np++ = c;
533df930be7Sderaadt }
534df930be7Sderaadt *np = 0, np = name;
535df930be7Sderaadt if (dolp || dolcnt) /* $ exp must end before ] */
536df930be7Sderaadt stderror(ERR_EXPORD);
537df930be7Sderaadt if (!*np)
538df930be7Sderaadt stderror(ERR_SYNTAX);
539df930be7Sderaadt if (Isdigit(*np)) {
540df930be7Sderaadt int i;
541df930be7Sderaadt
542df930be7Sderaadt for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
543df930be7Sderaadt continue;
5445f867525Sderaadt if ((i < 0 || i > upb) && !any("-*", *np)) {
545df930be7Sderaadt dolerror(vp->v_name);
546df930be7Sderaadt return;
547df930be7Sderaadt }
548df930be7Sderaadt lwb = i;
549df930be7Sderaadt if (!*np)
550df930be7Sderaadt upb = lwb, np = STRstar;
551df930be7Sderaadt }
552df930be7Sderaadt if (*np == '*')
553df930be7Sderaadt np++;
554df930be7Sderaadt else if (*np != '-')
555df930be7Sderaadt stderror(ERR_MISSING, '-');
556df930be7Sderaadt else {
557e757c91eSderaadt int i = upb;
558df930be7Sderaadt
559df930be7Sderaadt np++;
560df930be7Sderaadt if (Isdigit(*np)) {
561df930be7Sderaadt i = 0;
562df930be7Sderaadt while (Isdigit(*np))
563df930be7Sderaadt i = i * 10 + *np++ - '0';
564df930be7Sderaadt if (i < 0 || i > upb) {
565df930be7Sderaadt dolerror(vp->v_name);
566df930be7Sderaadt return;
567df930be7Sderaadt }
568df930be7Sderaadt }
569df930be7Sderaadt if (i < lwb)
570df930be7Sderaadt upb = lwb - 1;
571df930be7Sderaadt else
572df930be7Sderaadt upb = i;
573df930be7Sderaadt }
574df930be7Sderaadt if (lwb == 0) {
575df930be7Sderaadt if (upb != 0) {
576df930be7Sderaadt dolerror(vp->v_name);
577df930be7Sderaadt return;
578df930be7Sderaadt }
579df930be7Sderaadt upb = -1;
580df930be7Sderaadt }
581df930be7Sderaadt if (*np)
582df930be7Sderaadt stderror(ERR_SYNTAX);
583df930be7Sderaadt }
584df930be7Sderaadt else {
585927fd51fSart if (subscr > 0) {
586df930be7Sderaadt if (subscr > upb)
587df930be7Sderaadt lwb = 1, upb = 0;
588df930be7Sderaadt else
589df930be7Sderaadt lwb = upb = subscr;
590927fd51fSart }
591df930be7Sderaadt unDredc(c);
592df930be7Sderaadt }
593df930be7Sderaadt if (dimen) {
594df930be7Sderaadt Char *cp = putn(upb - lwb + 1);
595df930be7Sderaadt
596df930be7Sderaadt addla(cp);
597acdb3202Smestre free(cp);
598df930be7Sderaadt }
599df930be7Sderaadt else {
600df930be7Sderaadt eatmod:
601df930be7Sderaadt fixDolMod();
602df930be7Sderaadt dolnxt = &vp->vec[lwb - 1];
603df930be7Sderaadt dolcnt = upb - lwb + 1;
604df930be7Sderaadt }
605df930be7Sderaadt eatbrac:
606df930be7Sderaadt if (sc == '{') {
607df930be7Sderaadt c = Dredc();
608df930be7Sderaadt if (c != '}')
609df930be7Sderaadt stderror(ERR_MISSING, '}');
610df930be7Sderaadt }
611df930be7Sderaadt }
612df930be7Sderaadt
613df930be7Sderaadt static void
fixDolMod(void)614e757c91eSderaadt fixDolMod(void)
615df930be7Sderaadt {
616e757c91eSderaadt int c;
617df930be7Sderaadt
618df930be7Sderaadt c = DgetC(0);
619df930be7Sderaadt if (c == ':') {
620df930be7Sderaadt do {
621df930be7Sderaadt c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
622df930be7Sderaadt if (c == 'g' || c == 'a') {
623df930be7Sderaadt if (c == 'g')
624df930be7Sderaadt dolmcnt = 10000;
625df930be7Sderaadt else
626df930be7Sderaadt dolwcnt = 10000;
627df930be7Sderaadt c = DgetC(0);
628df930be7Sderaadt }
629df930be7Sderaadt if ((c == 'g' && dolmcnt != 10000) ||
630df930be7Sderaadt (c == 'a' && dolwcnt != 10000)) {
631df930be7Sderaadt if (c == 'g')
632df930be7Sderaadt dolmcnt = 10000;
633df930be7Sderaadt else
634df930be7Sderaadt dolwcnt = 10000;
635df930be7Sderaadt c = DgetC(0);
636df930be7Sderaadt }
637df930be7Sderaadt
638df930be7Sderaadt if (c == 's') { /* [eichin:19910926.0755EST] */
639df930be7Sderaadt int delimcnt = 2;
640df930be7Sderaadt int delim = DgetC(0);
641df930be7Sderaadt dolmod[dolnmod++] = c;
642df930be7Sderaadt dolmod[dolnmod++] = delim;
643df930be7Sderaadt
644df930be7Sderaadt if (!delim || letter(delim)
6455f867525Sderaadt || Isdigit(delim) || any(" \t\n", delim)) {
646df930be7Sderaadt seterror(ERR_BADSUBST);
647df930be7Sderaadt break;
648df930be7Sderaadt }
649df930be7Sderaadt while ((c = DgetC(0)) != (-1)) {
650df930be7Sderaadt dolmod[dolnmod++] = c;
651df930be7Sderaadt if(c == delim) delimcnt--;
652df930be7Sderaadt if(!delimcnt) break;
653df930be7Sderaadt }
654df930be7Sderaadt if(delimcnt) {
655df930be7Sderaadt seterror(ERR_BADSUBST);
656df930be7Sderaadt break;
657df930be7Sderaadt }
658df930be7Sderaadt continue;
659df930be7Sderaadt }
6605f867525Sderaadt if (!any("htrqxes", c))
661df930be7Sderaadt stderror(ERR_BADMOD, c);
662df930be7Sderaadt dolmod[dolnmod++] = c;
663df930be7Sderaadt if (c == 'q')
664df930be7Sderaadt dolmcnt = 10000;
665df930be7Sderaadt }
666df930be7Sderaadt while ((c = DgetC(0)) == ':');
667df930be7Sderaadt unDredc(c);
668df930be7Sderaadt }
669df930be7Sderaadt else
670df930be7Sderaadt unDredc(c);
671df930be7Sderaadt }
672df930be7Sderaadt
673df930be7Sderaadt static void
setDolp(Char * cp)674e757c91eSderaadt setDolp(Char *cp)
675df930be7Sderaadt {
676e757c91eSderaadt Char *dp;
677df930be7Sderaadt int i;
678df930be7Sderaadt
679df930be7Sderaadt if (dolnmod == 0 || dolmcnt == 0) {
680df930be7Sderaadt dolp = cp;
681df930be7Sderaadt return;
682df930be7Sderaadt }
683df930be7Sderaadt dp = cp = Strsave(cp);
684df930be7Sderaadt for (i = 0; i < dolnmod; i++) {
685df930be7Sderaadt /* handle s// [eichin:19910926.0510EST] */
686df930be7Sderaadt if(dolmod[i] == 's') {
687df930be7Sderaadt int delim;
688df930be7Sderaadt Char *lhsub, *rhsub, *np;
689df930be7Sderaadt size_t lhlen = 0, rhlen = 0;
690df930be7Sderaadt int didmod = 0;
691df930be7Sderaadt
692df930be7Sderaadt delim = dolmod[++i];
693df930be7Sderaadt if (!delim || letter(delim)
6945f867525Sderaadt || Isdigit(delim) || any(" \t\n", delim)) {
695df930be7Sderaadt seterror(ERR_BADSUBST);
696df930be7Sderaadt break;
697df930be7Sderaadt }
698df930be7Sderaadt lhsub = &dolmod[++i];
699df930be7Sderaadt while(dolmod[i] != delim && dolmod[++i]) {
700df930be7Sderaadt lhlen++;
701df930be7Sderaadt }
702df930be7Sderaadt dolmod[i] = 0;
703df930be7Sderaadt rhsub = &dolmod[++i];
704df930be7Sderaadt while(dolmod[i] != delim && dolmod[++i]) {
705df930be7Sderaadt rhlen++;
706df930be7Sderaadt }
707df930be7Sderaadt dolmod[i] = 0;
708df930be7Sderaadt
709df930be7Sderaadt do {
710df930be7Sderaadt dp = Strstr(cp, lhsub);
711df930be7Sderaadt if (dp) {
7126a01f4acSderaadt size_t len = Strlen(cp) + 1 - lhlen + rhlen;
7136a01f4acSderaadt
714a8627d2cSderaadt np = xreallocarray(NULL, len, sizeof(Char));
7155128fc07Smillert *dp = 0;
7166a01f4acSderaadt (void) Strlcpy(np, cp, len);
7176a01f4acSderaadt (void) Strlcat(np, rhsub, len);
7186a01f4acSderaadt (void) Strlcat(np, dp + lhlen, len);
719df930be7Sderaadt
720acdb3202Smestre free(cp);
721df930be7Sderaadt dp = cp = np;
722df930be7Sderaadt didmod = 1;
723df930be7Sderaadt } else {
724df930be7Sderaadt /* should this do a seterror? */
725df930be7Sderaadt break;
726df930be7Sderaadt }
727df930be7Sderaadt }
728df930be7Sderaadt while (dolwcnt == 10000);
729df930be7Sderaadt /*
730df930be7Sderaadt * restore dolmod for additional words
731df930be7Sderaadt */
732df930be7Sderaadt dolmod[i] = rhsub[-1] = delim;
733df930be7Sderaadt if (didmod)
734df930be7Sderaadt dolmcnt--;
735df930be7Sderaadt else
736df930be7Sderaadt break;
737df930be7Sderaadt } else {
738df930be7Sderaadt int didmod = 0;
739df930be7Sderaadt
740df930be7Sderaadt do {
741df930be7Sderaadt if ((dp = domod(cp, dolmod[i]))) {
742df930be7Sderaadt didmod = 1;
743df930be7Sderaadt if (Strcmp(cp, dp) == 0) {
744acdb3202Smestre free(cp);
745df930be7Sderaadt cp = dp;
746df930be7Sderaadt break;
747df930be7Sderaadt }
748df930be7Sderaadt else {
749acdb3202Smestre free(cp);
750df930be7Sderaadt cp = dp;
751df930be7Sderaadt }
752df930be7Sderaadt }
753df930be7Sderaadt else
754df930be7Sderaadt break;
755df930be7Sderaadt }
756df930be7Sderaadt while (dolwcnt == 10000);
757df930be7Sderaadt dp = cp;
758df930be7Sderaadt if (didmod)
759df930be7Sderaadt dolmcnt--;
760df930be7Sderaadt else
761df930be7Sderaadt break;
762df930be7Sderaadt }
763df930be7Sderaadt }
764df930be7Sderaadt
765df930be7Sderaadt addla(cp);
7663daa59e0Smiko free(cp);
767df930be7Sderaadt
768df930be7Sderaadt dolp = STRNULL;
769df930be7Sderaadt if (seterr)
770df930be7Sderaadt stderror(ERR_OLD);
771df930be7Sderaadt }
772df930be7Sderaadt
773df930be7Sderaadt static void
unDredc(int c)774e757c91eSderaadt unDredc(int c)
775df930be7Sderaadt {
776df930be7Sderaadt
777df930be7Sderaadt Dpeekrd = c;
778df930be7Sderaadt }
779df930be7Sderaadt
780df930be7Sderaadt static int
Dredc(void)781e757c91eSderaadt Dredc(void)
782df930be7Sderaadt {
783e757c91eSderaadt int c;
784df930be7Sderaadt
785df930be7Sderaadt if ((c = Dpeekrd) != '\0') {
786df930be7Sderaadt Dpeekrd = 0;
787df930be7Sderaadt return (c);
788df930be7Sderaadt }
789df930be7Sderaadt if (Dcp && (c = *Dcp++))
790df930be7Sderaadt return (c & (QUOTE | TRIM));
791df930be7Sderaadt if (*Dvp == 0) {
792df930be7Sderaadt Dcp = 0;
793df930be7Sderaadt return (DEOF);
794df930be7Sderaadt }
795df930be7Sderaadt Dcp = *Dvp++;
796df930be7Sderaadt return (' ');
797df930be7Sderaadt }
798df930be7Sderaadt
799df930be7Sderaadt static void
Dtestq(int c)800e757c91eSderaadt Dtestq(int c)
801df930be7Sderaadt {
802df930be7Sderaadt
803df930be7Sderaadt if (cmap(c, QUOTES))
804df930be7Sderaadt gflag = 1;
805df930be7Sderaadt }
806df930be7Sderaadt
807df930be7Sderaadt /*
808df930be7Sderaadt * Form a shell temporary file (in unit 0) from the words
809df930be7Sderaadt * of the shell input up to EOF or a line the same as "term".
810df930be7Sderaadt * Unit 0 should have been closed before this call.
811df930be7Sderaadt */
812df930be7Sderaadt void
heredoc(Char * term)813e757c91eSderaadt heredoc(Char *term)
814df930be7Sderaadt {
815e757c91eSderaadt int c;
816df930be7Sderaadt Char *Dv[2];
817df930be7Sderaadt Char obuf[BUFSIZ], lbuf[BUFSIZ], mbuf[BUFSIZ];
818df930be7Sderaadt int ocnt, lcnt, mcnt;
819e757c91eSderaadt Char *lbp, *obp, *mbp;
820df930be7Sderaadt Char **vp;
821df930be7Sderaadt bool quoted;
822c23026eaSmillert char tmp[] = "/tmp/sh.XXXXXXXX";
823df930be7Sderaadt
824c2d43ecaSderaadt if (mkstemp(tmp) == -1)
825df930be7Sderaadt stderror(ERR_SYSTEM, tmp, strerror(errno));
826df930be7Sderaadt (void) unlink(tmp); /* 0 0 inode! */
827df930be7Sderaadt Dv[0] = term;
828df930be7Sderaadt Dv[1] = NULL;
829df930be7Sderaadt gflag = 0;
830df930be7Sderaadt trim(Dv);
831df930be7Sderaadt rscan(Dv, Dtestq);
832df930be7Sderaadt quoted = gflag;
833df930be7Sderaadt ocnt = BUFSIZ;
834df930be7Sderaadt obp = obuf;
835df930be7Sderaadt for (;;) {
836df930be7Sderaadt /*
837df930be7Sderaadt * Read up a line
838df930be7Sderaadt */
839df930be7Sderaadt lbp = lbuf;
840df930be7Sderaadt lcnt = BUFSIZ - 4;
841df930be7Sderaadt for (;;) {
842df930be7Sderaadt c = readc(1); /* 1 -> Want EOF returns */
843df930be7Sderaadt if (c < 0 || c == '\n')
844df930be7Sderaadt break;
845df930be7Sderaadt if ((c &= TRIM) != '\0') {
846df930be7Sderaadt *lbp++ = c;
847df930be7Sderaadt if (--lcnt < 0) {
848df930be7Sderaadt setname("<<");
849df930be7Sderaadt stderror(ERR_NAME | ERR_OVERFLOW);
850df930be7Sderaadt }
851df930be7Sderaadt }
852df930be7Sderaadt }
853df930be7Sderaadt *lbp = 0;
854df930be7Sderaadt
855df930be7Sderaadt /*
856df930be7Sderaadt * Check for EOF or compare to terminator -- before expansion
857df930be7Sderaadt */
858df930be7Sderaadt if (c < 0 || eq(lbuf, term)) {
8598af2993fSkevlo (void) write(STDIN_FILENO, short2str(obuf),
8608af2993fSkevlo (size_t) (BUFSIZ - ocnt));
8618af2993fSkevlo (void) lseek(STDIN_FILENO, (off_t) 0, SEEK_SET);
862df930be7Sderaadt return;
863df930be7Sderaadt }
864df930be7Sderaadt
865df930be7Sderaadt /*
866df930be7Sderaadt * If term was quoted or -n just pass it on
867df930be7Sderaadt */
868df930be7Sderaadt if (quoted || noexec) {
869df930be7Sderaadt *lbp++ = '\n';
870df930be7Sderaadt *lbp = 0;
871df930be7Sderaadt for (lbp = lbuf; (c = *lbp++) != '\0';) {
872df930be7Sderaadt *obp++ = c;
873df930be7Sderaadt if (--ocnt == 0) {
8748af2993fSkevlo (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
875df930be7Sderaadt obp = obuf;
876df930be7Sderaadt ocnt = BUFSIZ;
877df930be7Sderaadt }
878df930be7Sderaadt }
879df930be7Sderaadt continue;
880df930be7Sderaadt }
881df930be7Sderaadt
882df930be7Sderaadt /*
883df930be7Sderaadt * Term wasn't quoted so variable and then command expand the input
884df930be7Sderaadt * line
885df930be7Sderaadt */
886df930be7Sderaadt Dcp = lbuf;
887df930be7Sderaadt Dvp = Dv + 1;
888df930be7Sderaadt mbp = mbuf;
889df930be7Sderaadt mcnt = BUFSIZ - 4;
890df930be7Sderaadt for (;;) {
891df930be7Sderaadt c = DgetC(DODOL);
892df930be7Sderaadt if (c == DEOF)
893df930be7Sderaadt break;
894df930be7Sderaadt if ((c &= TRIM) == 0)
895df930be7Sderaadt continue;
896df930be7Sderaadt /* \ quotes \ $ ` here */
897df930be7Sderaadt if (c == '\\') {
898df930be7Sderaadt c = DgetC(0);
8995f867525Sderaadt if (!any("$\\`", c))
900df930be7Sderaadt unDgetC(c | QUOTE), c = '\\';
901df930be7Sderaadt else
902df930be7Sderaadt c |= QUOTE;
903df930be7Sderaadt }
904df930be7Sderaadt *mbp++ = c;
905df930be7Sderaadt if (--mcnt == 0) {
906df930be7Sderaadt setname("<<");
907df930be7Sderaadt stderror(ERR_NAME | ERR_OVERFLOW);
908df930be7Sderaadt }
909df930be7Sderaadt }
910df930be7Sderaadt *mbp++ = 0;
911df930be7Sderaadt
912df930be7Sderaadt /*
913df930be7Sderaadt * If any ` in line do command substitution
914df930be7Sderaadt */
915df930be7Sderaadt mbp = mbuf;
9165f867525Sderaadt if (any(short2str(mbp), '`')) {
917df930be7Sderaadt /*
918df930be7Sderaadt * 1 arg to dobackp causes substitution to be literal. Words are
919df930be7Sderaadt * broken only at newlines so that all blanks and tabs are
920df930be7Sderaadt * preserved. Blank lines (null words) are not discarded.
921df930be7Sderaadt */
922df930be7Sderaadt vp = dobackp(mbuf, 1);
923df930be7Sderaadt }
924df930be7Sderaadt else
925df930be7Sderaadt /* Setup trivial vector similar to return of dobackp */
926df930be7Sderaadt Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
927df930be7Sderaadt
928df930be7Sderaadt /*
929df930be7Sderaadt * Resurrect the words from the command substitution each separated by
930df930be7Sderaadt * a newline. Note that the last newline of a command substitution
931df930be7Sderaadt * will have been discarded, but we put a newline after the last word
932df930be7Sderaadt * because this represents the newline after the last input line!
933df930be7Sderaadt */
934df930be7Sderaadt for (; *vp; vp++) {
935df930be7Sderaadt for (mbp = *vp; *mbp; mbp++) {
936df930be7Sderaadt *obp++ = *mbp & TRIM;
937df930be7Sderaadt if (--ocnt == 0) {
9388af2993fSkevlo (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
939df930be7Sderaadt obp = obuf;
940df930be7Sderaadt ocnt = BUFSIZ;
941df930be7Sderaadt }
942df930be7Sderaadt }
943df930be7Sderaadt *obp++ = '\n';
944df930be7Sderaadt if (--ocnt == 0) {
9458af2993fSkevlo (void) write(STDIN_FILENO, short2str(obuf), BUFSIZ);
946df930be7Sderaadt obp = obuf;
947df930be7Sderaadt ocnt = BUFSIZ;
948df930be7Sderaadt }
949df930be7Sderaadt }
950bcb7da30Smiko blkfree(pargv);
951bcb7da30Smiko pargv = NULL;
952df930be7Sderaadt }
953df930be7Sderaadt }
954