1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien * sh.glob.c: Regular expression expansion
3c80476e4SDavid E. O'Brien */
4c80476e4SDavid E. O'Brien /*-
5c80476e4SDavid E. O'Brien * Copyright (c) 1980, 1991 The Regents of the University of California.
6c80476e4SDavid E. O'Brien * All rights reserved.
7c80476e4SDavid E. O'Brien *
8c80476e4SDavid E. O'Brien * Redistribution and use in source and binary forms, with or without
9c80476e4SDavid E. O'Brien * modification, are permitted provided that the following conditions
10c80476e4SDavid E. O'Brien * are met:
11c80476e4SDavid E. O'Brien * 1. Redistributions of source code must retain the above copyright
12c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer.
13c80476e4SDavid E. O'Brien * 2. Redistributions in binary form must reproduce the above copyright
14c80476e4SDavid E. O'Brien * notice, this list of conditions and the following disclaimer in the
15c80476e4SDavid E. O'Brien * documentation and/or other materials provided with the distribution.
1629301572SMark Peek * 3. Neither the name of the University nor the names of its contributors
17c80476e4SDavid E. O'Brien * may be used to endorse or promote products derived from this software
18c80476e4SDavid E. O'Brien * without specific prior written permission.
19c80476e4SDavid E. O'Brien *
20c80476e4SDavid E. O'Brien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21c80476e4SDavid E. O'Brien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22c80476e4SDavid E. O'Brien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23c80476e4SDavid E. O'Brien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24c80476e4SDavid E. O'Brien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25c80476e4SDavid E. O'Brien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26c80476e4SDavid E. O'Brien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27c80476e4SDavid E. O'Brien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28c80476e4SDavid E. O'Brien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29c80476e4SDavid E. O'Brien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30c80476e4SDavid E. O'Brien * SUCH DAMAGE.
31c80476e4SDavid E. O'Brien */
32c80476e4SDavid E. O'Brien #include "sh.h"
33c80476e4SDavid E. O'Brien #include "tc.h"
3429301572SMark Peek #include "tw.h"
35c80476e4SDavid E. O'Brien
36c80476e4SDavid E. O'Brien #include "glob.h"
37c80476e4SDavid E. O'Brien
38c80476e4SDavid E. O'Brien /*
39c80476e4SDavid E. O'Brien * Values for gflag
40c80476e4SDavid E. O'Brien */
41c80476e4SDavid E. O'Brien #define G_NONE 0 /* No globbing needed */
42c80476e4SDavid E. O'Brien #define G_GLOB 1 /* string contains *?[] characters */
43c80476e4SDavid E. O'Brien #define G_CSH 2 /* string contains ~`{ characters */
44c80476e4SDavid E. O'Brien
45c80476e4SDavid E. O'Brien #define GLOBSPACE 100 /* Alloc increment */
46c80476e4SDavid E. O'Brien
47c80476e4SDavid E. O'Brien
48c80476e4SDavid E. O'Brien #define LBRC '{'
49c80476e4SDavid E. O'Brien #define RBRC '}'
50c80476e4SDavid E. O'Brien #define LBRK '['
51c80476e4SDavid E. O'Brien #define RBRK ']'
52c80476e4SDavid E. O'Brien #define EOS '\0'
53c80476e4SDavid E. O'Brien
54c80476e4SDavid E. O'Brien /*
55c80476e4SDavid E. O'Brien * globbing is now done in two stages. In the first pass we expand
56c80476e4SDavid E. O'Brien * csh globbing idioms ~`{ and then we proceed doing the normal
57c80476e4SDavid E. O'Brien * globbing if needed ?*[
58c80476e4SDavid E. O'Brien *
59c80476e4SDavid E. O'Brien * Csh type globbing is handled in globexpand() and the rest is
60c80476e4SDavid E. O'Brien * handled in glob() which is part of the 4.4BSD libc.
61c80476e4SDavid E. O'Brien *
62c80476e4SDavid E. O'Brien */
6345e5710bSMark Peek static Char *globtilde (Char *);
6445e5710bSMark Peek static Char *handleone (Char *, Char **, int);
6545e5710bSMark Peek static Char **libglob (Char **);
6645e5710bSMark Peek static Char **globexpand (Char **, int);
6745e5710bSMark Peek static int globbrace (const Char *, Char ***);
6845e5710bSMark Peek static void expbrace (Char ***, Char ***, int);
6945e5710bSMark Peek static void pword (struct blk_buf *, struct Strbuf *);
7045e5710bSMark Peek static void backeval (struct blk_buf *, struct Strbuf *, Char *,
7145e5710bSMark Peek int);
72c80476e4SDavid E. O'Brien static Char *
globtilde(Char * s)7345e5710bSMark Peek globtilde(Char *s)
74c80476e4SDavid E. O'Brien {
7545e5710bSMark Peek Char *name, *u, *home, *res;
76c80476e4SDavid E. O'Brien
77c80476e4SDavid E. O'Brien u = s;
78*5224c2a3SDmitry Chagin
79*5224c2a3SDmitry Chagin if (s[1] == '~')
80*5224c2a3SDmitry Chagin return Strsave(s);
81*5224c2a3SDmitry Chagin
8245e5710bSMark Peek for (s++; *s && *s != '/' && *s != ':'; s++)
83c80476e4SDavid E. O'Brien continue;
84*5224c2a3SDmitry Chagin
8545e5710bSMark Peek name = Strnsave(u + 1, s - (u + 1));
8645e5710bSMark Peek cleanup_push(name, xfree);
8745e5710bSMark Peek home = gethdir(name);
8845e5710bSMark Peek if (home == NULL) {
8945e5710bSMark Peek if (adrof(STRnonomatch)) {
9045e5710bSMark Peek cleanup_until(name);
9145e5710bSMark Peek return u;
9245e5710bSMark Peek }
9345e5710bSMark Peek if (*name)
9445e5710bSMark Peek stderror(ERR_UNKUSER, short2str(name));
95c80476e4SDavid E. O'Brien else
96c80476e4SDavid E. O'Brien stderror(ERR_NOHOME);
97c80476e4SDavid E. O'Brien }
9845e5710bSMark Peek cleanup_until(name);
9945e5710bSMark Peek if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
10045e5710bSMark Peek res = Strsave(s);
10145e5710bSMark Peek else
10245e5710bSMark Peek res = Strspl(home, s);
10345e5710bSMark Peek xfree(home);
10445e5710bSMark Peek xfree(u);
10545e5710bSMark Peek return res;
106c80476e4SDavid E. O'Brien }
107c80476e4SDavid E. O'Brien
10845e5710bSMark Peek /* Returns a newly allocated string, old or NULL */
109c80476e4SDavid E. O'Brien Char *
globequal(Char * old)11045e5710bSMark Peek globequal(Char *old)
111c80476e4SDavid E. O'Brien {
112c80476e4SDavid E. O'Brien int dig;
11345e5710bSMark Peek const Char *dir;
11445e5710bSMark Peek Char *b;
115c80476e4SDavid E. O'Brien
116c80476e4SDavid E. O'Brien /*
117c80476e4SDavid E. O'Brien * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
118c80476e4SDavid E. O'Brien * in stack. PWP: let =foobar pass through (for X windows)
119c80476e4SDavid E. O'Brien */
120c80476e4SDavid E. O'Brien if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
121c80476e4SDavid E. O'Brien /* =- */
12245e5710bSMark Peek const Char *olddir = varval (STRowd);
12345e5710bSMark Peek
12445e5710bSMark Peek if (olddir && *olddir &&
12545e5710bSMark Peek !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
12645e5710bSMark Peek return Strspl(olddir, &old[2]);
127c80476e4SDavid E. O'Brien dig = -1;
128c80476e4SDavid E. O'Brien b = &old[2];
129c80476e4SDavid E. O'Brien }
130c80476e4SDavid E. O'Brien else if (Isdigit(old[1])) {
131c80476e4SDavid E. O'Brien /* =<number> */
132c80476e4SDavid E. O'Brien dig = old[1] - '0';
133c80476e4SDavid E. O'Brien for (b = &old[2]; Isdigit(*b); b++)
134c80476e4SDavid E. O'Brien dig = dig * 10 + (*b - '0');
135c80476e4SDavid E. O'Brien if (*b != '\0' && *b != '/')
136c80476e4SDavid E. O'Brien /* =<number>foobar */
137c80476e4SDavid E. O'Brien return old;
138c80476e4SDavid E. O'Brien }
139c80476e4SDavid E. O'Brien else
140c80476e4SDavid E. O'Brien /* =foobar */
141c80476e4SDavid E. O'Brien return old;
142c80476e4SDavid E. O'Brien
14345e5710bSMark Peek dir = getstakd(dig);
14445e5710bSMark Peek if (dir == NULL)
145c80476e4SDavid E. O'Brien return NULL;
14645e5710bSMark Peek return Strspl(dir, b);
147c80476e4SDavid E. O'Brien }
148c80476e4SDavid E. O'Brien
149c80476e4SDavid E. O'Brien static int
globbrace(const Char * s,Char *** bl)15045e5710bSMark Peek globbrace(const Char *s, Char ***bl)
151c80476e4SDavid E. O'Brien {
15245e5710bSMark Peek struct Strbuf gbuf = Strbuf_INIT;
15345e5710bSMark Peek struct blk_buf bb = BLK_BUF_INIT;
15445e5710bSMark Peek int i;
15545e5710bSMark Peek const Char *p, *pm, *pe, *pl;
15645e5710bSMark Peek size_t prefix_len;
157c80476e4SDavid E. O'Brien
158c80476e4SDavid E. O'Brien /* copy part up to the brace */
15945e5710bSMark Peek for (p = s; *p != LBRC; p++)
16045e5710bSMark Peek ;
16145e5710bSMark Peek prefix_len = p - s;
162c80476e4SDavid E. O'Brien
163c80476e4SDavid E. O'Brien /* check for balanced braces */
164c80476e4SDavid E. O'Brien for (i = 0, pe = ++p; *pe; pe++)
165c80476e4SDavid E. O'Brien if (*pe == LBRK) {
166c80476e4SDavid E. O'Brien /* Ignore everything between [] */
167c80476e4SDavid E. O'Brien for (++pe; *pe != RBRK && *pe != EOS; pe++)
168c80476e4SDavid E. O'Brien continue;
16945e5710bSMark Peek if (*pe == EOS)
170c80476e4SDavid E. O'Brien return (-RBRK);
171c80476e4SDavid E. O'Brien }
172c80476e4SDavid E. O'Brien else if (*pe == LBRC)
173c80476e4SDavid E. O'Brien i++;
174c80476e4SDavid E. O'Brien else if (*pe == RBRC) {
175c80476e4SDavid E. O'Brien if (i == 0)
176c80476e4SDavid E. O'Brien break;
177c80476e4SDavid E. O'Brien i--;
178c80476e4SDavid E. O'Brien }
179c80476e4SDavid E. O'Brien
18045e5710bSMark Peek if (i != 0 || *pe == '\0')
181c80476e4SDavid E. O'Brien return (-RBRC);
18245e5710bSMark Peek
18345e5710bSMark Peek Strbuf_appendn(&gbuf, s, prefix_len);
184c80476e4SDavid E. O'Brien
185c80476e4SDavid E. O'Brien for (i = 0, pl = pm = p; pm <= pe; pm++)
186c80476e4SDavid E. O'Brien switch (*pm) {
187c80476e4SDavid E. O'Brien case LBRK:
188c80476e4SDavid E. O'Brien for (++pm; *pm != RBRK && *pm != EOS; pm++)
189c80476e4SDavid E. O'Brien continue;
190c80476e4SDavid E. O'Brien if (*pm == EOS) {
19145e5710bSMark Peek bb_cleanup(&bb);
19245e5710bSMark Peek xfree(gbuf.s);
193c80476e4SDavid E. O'Brien return (-RBRK);
194c80476e4SDavid E. O'Brien }
195c80476e4SDavid E. O'Brien break;
196c80476e4SDavid E. O'Brien case LBRC:
197c80476e4SDavid E. O'Brien i++;
198c80476e4SDavid E. O'Brien break;
199c80476e4SDavid E. O'Brien case RBRC:
200c80476e4SDavid E. O'Brien if (i) {
201c80476e4SDavid E. O'Brien i--;
202c80476e4SDavid E. O'Brien break;
203c80476e4SDavid E. O'Brien }
204c80476e4SDavid E. O'Brien /* FALLTHROUGH */
205c80476e4SDavid E. O'Brien case ',':
206c80476e4SDavid E. O'Brien if (i && *pm == ',')
207c80476e4SDavid E. O'Brien break;
208c80476e4SDavid E. O'Brien else {
20945e5710bSMark Peek gbuf.len = prefix_len;
21045e5710bSMark Peek Strbuf_appendn(&gbuf, pl, pm - pl);
21145e5710bSMark Peek Strbuf_append(&gbuf, pe + 1);
21245e5710bSMark Peek Strbuf_terminate(&gbuf);
21345e5710bSMark Peek bb_append(&bb, Strsave(gbuf.s));
214c80476e4SDavid E. O'Brien pl = pm + 1;
215c80476e4SDavid E. O'Brien }
216c80476e4SDavid E. O'Brien break;
217c80476e4SDavid E. O'Brien default:
218c80476e4SDavid E. O'Brien break;
219c80476e4SDavid E. O'Brien }
22045e5710bSMark Peek *bl = bb_finish(&bb);
22145e5710bSMark Peek xfree(gbuf.s);
22245e5710bSMark Peek return bb.len;
223c80476e4SDavid E. O'Brien }
224c80476e4SDavid E. O'Brien
225c80476e4SDavid E. O'Brien
226c80476e4SDavid E. O'Brien static void
expbrace(Char *** nvp,Char *** elp,int size)22745e5710bSMark Peek expbrace(Char ***nvp, Char ***elp, int size)
228c80476e4SDavid E. O'Brien {
229c80476e4SDavid E. O'Brien Char **vl, **el, **nv, *s;
230c80476e4SDavid E. O'Brien
231c80476e4SDavid E. O'Brien vl = nv = *nvp;
232c80476e4SDavid E. O'Brien if (elp != NULL)
233c80476e4SDavid E. O'Brien el = *elp;
234c80476e4SDavid E. O'Brien else
23545e5710bSMark Peek el = vl + blklen(vl);
236c80476e4SDavid E. O'Brien
237c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) {
238c80476e4SDavid E. O'Brien Char **vp, **bp;
239c80476e4SDavid E. O'Brien
240c80476e4SDavid E. O'Brien /* leave {} untouched for find */
241c80476e4SDavid E. O'Brien if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
242c80476e4SDavid E. O'Brien continue;
24345e5710bSMark Peek if (Strchr(s, '{') != NULL) {
24445e5710bSMark Peek Char **bl = NULL;
245c80476e4SDavid E. O'Brien int len;
246c80476e4SDavid E. O'Brien
24745e5710bSMark Peek if ((len = globbrace(s, &bl)) < 0)
248c80476e4SDavid E. O'Brien stderror(ERR_MISSING, -len);
24945e5710bSMark Peek xfree(s);
250c80476e4SDavid E. O'Brien if (len == 1) {
251c80476e4SDavid E. O'Brien *vl-- = *bl;
25245e5710bSMark Peek xfree(bl);
253c80476e4SDavid E. O'Brien continue;
254c80476e4SDavid E. O'Brien }
255c80476e4SDavid E. O'Brien if (&el[len] >= &nv[size]) {
25645e5710bSMark Peek size_t l, e;
25745e5710bSMark Peek l = &el[len] - &nv[size];
258c80476e4SDavid E. O'Brien size += GLOBSPACE > l ? GLOBSPACE : l;
25945e5710bSMark Peek l = vl - nv;
26045e5710bSMark Peek e = el - nv;
26145e5710bSMark Peek nv = xrealloc(nv, size * sizeof(Char *));
26245e5710bSMark Peek *nvp = nv; /* To keep cleanups working */
263c80476e4SDavid E. O'Brien vl = nv + l;
264c80476e4SDavid E. O'Brien el = nv + e;
265c80476e4SDavid E. O'Brien }
266c80476e4SDavid E. O'Brien /* nv vl el bl
267c80476e4SDavid E. O'Brien * | | | |
268c80476e4SDavid E. O'Brien * -.--..-- x--
269c80476e4SDavid E. O'Brien * | len
270c80476e4SDavid E. O'Brien * vp
271c80476e4SDavid E. O'Brien */
272c80476e4SDavid E. O'Brien vp = vl--;
273c80476e4SDavid E. O'Brien *vp = *bl;
274c80476e4SDavid E. O'Brien len--;
275c80476e4SDavid E. O'Brien for (bp = el; bp != vp; bp--)
276c80476e4SDavid E. O'Brien bp[len] = *bp;
277c80476e4SDavid E. O'Brien el += len;
278c80476e4SDavid E. O'Brien /* nv vl el bl
279c80476e4SDavid E. O'Brien * | | | |
280c80476e4SDavid E. O'Brien * -.-x --- --
281c80476e4SDavid E. O'Brien * |len
282c80476e4SDavid E. O'Brien * vp
283c80476e4SDavid E. O'Brien */
284c80476e4SDavid E. O'Brien vp++;
285c80476e4SDavid E. O'Brien for (bp = bl + 1; *bp; *vp++ = *bp++)
286c80476e4SDavid E. O'Brien continue;
28745e5710bSMark Peek xfree(bl);
288c80476e4SDavid E. O'Brien }
289c80476e4SDavid E. O'Brien
290c80476e4SDavid E. O'Brien }
291c80476e4SDavid E. O'Brien if (elp != NULL)
292c80476e4SDavid E. O'Brien *elp = el;
293c80476e4SDavid E. O'Brien }
294c80476e4SDavid E. O'Brien
295c80476e4SDavid E. O'Brien static Char **
globexpand(Char ** v,int noglob)29645e5710bSMark Peek globexpand(Char **v, int noglob)
297c80476e4SDavid E. O'Brien {
298c80476e4SDavid E. O'Brien Char *s;
29945e5710bSMark Peek Char ***fnv, **vl, **el;
300c80476e4SDavid E. O'Brien int size = GLOBSPACE;
301c80476e4SDavid E. O'Brien
302c80476e4SDavid E. O'Brien
30345e5710bSMark Peek fnv = xmalloc(sizeof(Char ***));
30445e5710bSMark Peek *fnv = vl = xmalloc(sizeof(Char *) * size);
305c80476e4SDavid E. O'Brien *vl = NULL;
30645e5710bSMark Peek cleanup_push(fnv, blk_indirect_cleanup);
307c80476e4SDavid E. O'Brien
308c80476e4SDavid E. O'Brien /*
309c80476e4SDavid E. O'Brien * Step 1: expand backquotes.
310c80476e4SDavid E. O'Brien */
311cc698b49SBrooks Davis while ((s = *v++) != NULL) {
312c80476e4SDavid E. O'Brien if (Strchr(s, '`')) {
313c80476e4SDavid E. O'Brien int i;
31445e5710bSMark Peek Char **expanded;
315c80476e4SDavid E. O'Brien
31645e5710bSMark Peek expanded = dobackp(s, 0);
31745e5710bSMark Peek for (i = 0; expanded[i] != NULL; i++) {
31845e5710bSMark Peek *vl++ = expanded[i];
31945e5710bSMark Peek if (vl == &(*fnv)[size]) {
320c80476e4SDavid E. O'Brien size += GLOBSPACE;
32145e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *));
32245e5710bSMark Peek vl = &(*fnv)[size - GLOBSPACE];
323c80476e4SDavid E. O'Brien }
324c80476e4SDavid E. O'Brien }
32545e5710bSMark Peek xfree(expanded);
326c80476e4SDavid E. O'Brien }
327c80476e4SDavid E. O'Brien else {
328c80476e4SDavid E. O'Brien *vl++ = Strsave(s);
32945e5710bSMark Peek if (vl == &(*fnv)[size]) {
330c80476e4SDavid E. O'Brien size += GLOBSPACE;
33145e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *));
33245e5710bSMark Peek vl = &(*fnv)[size - GLOBSPACE];
333c80476e4SDavid E. O'Brien }
334c80476e4SDavid E. O'Brien }
335c80476e4SDavid E. O'Brien *vl = NULL;
33645e5710bSMark Peek }
337c80476e4SDavid E. O'Brien
338c80476e4SDavid E. O'Brien if (noglob)
33945e5710bSMark Peek goto done;
340c80476e4SDavid E. O'Brien
341c80476e4SDavid E. O'Brien /*
342c80476e4SDavid E. O'Brien * Step 2: expand braces
343c80476e4SDavid E. O'Brien */
344c80476e4SDavid E. O'Brien el = vl;
34545e5710bSMark Peek expbrace(fnv, &el, size);
346c80476e4SDavid E. O'Brien
347c80476e4SDavid E. O'Brien
348c80476e4SDavid E. O'Brien /*
349c80476e4SDavid E. O'Brien * Step 3: expand ~ =
350c80476e4SDavid E. O'Brien */
35145e5710bSMark Peek vl = *fnv;
352c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl)
353c80476e4SDavid E. O'Brien switch (*s) {
35445e5710bSMark Peek Char *ns;
355c80476e4SDavid E. O'Brien case '~':
35645e5710bSMark Peek *vl = globtilde(s);
357c80476e4SDavid E. O'Brien break;
358c80476e4SDavid E. O'Brien case '=':
35945e5710bSMark Peek if ((ns = globequal(s)) == NULL) {
36045e5710bSMark Peek if (!adrof(STRnonomatch))
36145e5710bSMark Peek stderror(ERR_DEEP); /* Error */
362c80476e4SDavid E. O'Brien }
363c80476e4SDavid E. O'Brien if (ns && ns != s) {
364c80476e4SDavid E. O'Brien /* Expansion succeeded */
36545e5710bSMark Peek xfree(s);
36645e5710bSMark Peek *vl = ns;
367c80476e4SDavid E. O'Brien }
368c80476e4SDavid E. O'Brien break;
369c80476e4SDavid E. O'Brien default:
370c80476e4SDavid E. O'Brien break;
371c80476e4SDavid E. O'Brien }
37245e5710bSMark Peek vl = *fnv;
373c80476e4SDavid E. O'Brien
374c80476e4SDavid E. O'Brien /*
375c80476e4SDavid E. O'Brien * Step 4: expand .. if the variable symlinks==expand is set
376c80476e4SDavid E. O'Brien */
3776767bd61SMark Peek if (symlinks == SYM_EXPAND) {
378c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) {
379c80476e4SDavid E. O'Brien *vl = dnormalize(s, 1);
38045e5710bSMark Peek xfree(s);
381c80476e4SDavid E. O'Brien }
3823b6eaa7bSAndrey A. Chernov }
383c80476e4SDavid E. O'Brien
38445e5710bSMark Peek done:
38545e5710bSMark Peek cleanup_ignore(fnv);
38645e5710bSMark Peek cleanup_until(fnv);
38745e5710bSMark Peek vl = *fnv;
38845e5710bSMark Peek xfree(fnv);
38945e5710bSMark Peek return vl;
390c80476e4SDavid E. O'Brien }
391c80476e4SDavid E. O'Brien
392c80476e4SDavid E. O'Brien static Char *
handleone(Char * str,Char ** vl,int action)39345e5710bSMark Peek handleone(Char *str, Char **vl, int action)
394c80476e4SDavid E. O'Brien {
39545e5710bSMark Peek size_t chars;
396c80476e4SDavid E. O'Brien Char **t, *p, *strp;
397c80476e4SDavid E. O'Brien
398c80476e4SDavid E. O'Brien switch (action) {
399c80476e4SDavid E. O'Brien case G_ERROR:
400c80476e4SDavid E. O'Brien setname(short2str(str));
401c80476e4SDavid E. O'Brien blkfree(vl);
402c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_AMBIG);
403c80476e4SDavid E. O'Brien break;
404c80476e4SDavid E. O'Brien case G_APPEND:
405c80476e4SDavid E. O'Brien chars = 0;
40645e5710bSMark Peek for (t = vl; (p = *t++) != NULL; chars++)
40745e5710bSMark Peek chars += Strlen(p);
40845e5710bSMark Peek str = xmalloc(chars * sizeof(Char));
409cc698b49SBrooks Davis for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
410c80476e4SDavid E. O'Brien while (*p)
411c80476e4SDavid E. O'Brien *strp++ = *p++ & TRIM;
412c80476e4SDavid E. O'Brien *strp++ = ' ';
413c80476e4SDavid E. O'Brien }
414c80476e4SDavid E. O'Brien *--strp = '\0';
415c80476e4SDavid E. O'Brien blkfree(vl);
416c80476e4SDavid E. O'Brien break;
417c80476e4SDavid E. O'Brien case G_IGNORE:
41845e5710bSMark Peek str = Strsave(strip(*vl));
419c80476e4SDavid E. O'Brien blkfree(vl);
420c80476e4SDavid E. O'Brien break;
421c80476e4SDavid E. O'Brien default:
422c80476e4SDavid E. O'Brien break;
423c80476e4SDavid E. O'Brien }
424c80476e4SDavid E. O'Brien return (str);
425c80476e4SDavid E. O'Brien }
426c80476e4SDavid E. O'Brien
427c80476e4SDavid E. O'Brien static Char **
libglob(Char ** vl)42845e5710bSMark Peek libglob(Char **vl)
429c80476e4SDavid E. O'Brien {
430c80476e4SDavid E. O'Brien int gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
431c80476e4SDavid E. O'Brien glob_t globv;
432c80476e4SDavid E. O'Brien char *ptr;
433c80476e4SDavid E. O'Brien int nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
434c80476e4SDavid E. O'Brien
4359ccc37e3SMark Peek if (adrof(STRglobdot))
4369ccc37e3SMark Peek gflgs |= GLOB_DOT;
4379ccc37e3SMark Peek
4389ccc37e3SMark Peek if (adrof(STRglobstar))
4399ccc37e3SMark Peek gflgs |= GLOB_STAR;
4409ccc37e3SMark Peek
441c80476e4SDavid E. O'Brien if (!vl || !vl[0])
442c80476e4SDavid E. O'Brien return(vl);
443c80476e4SDavid E. O'Brien
444c80476e4SDavid E. O'Brien globv.gl_offs = 0;
445c80476e4SDavid E. O'Brien globv.gl_pathv = 0;
446c80476e4SDavid E. O'Brien globv.gl_pathc = 0;
447c80476e4SDavid E. O'Brien
448c80476e4SDavid E. O'Brien if (nonomatch)
449c80476e4SDavid E. O'Brien gflgs |= GLOB_NOCHECK;
450c80476e4SDavid E. O'Brien
451c80476e4SDavid E. O'Brien do {
452c80476e4SDavid E. O'Brien ptr = short2qstr(*vl);
453c80476e4SDavid E. O'Brien switch (glob(ptr, gflgs, 0, &globv)) {
454c80476e4SDavid E. O'Brien case GLOB_ABEND:
455c80476e4SDavid E. O'Brien globfree(&globv);
456c80476e4SDavid E. O'Brien setname(ptr);
457c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_GLOB);
458c80476e4SDavid E. O'Brien /* NOTREACHED */
459c80476e4SDavid E. O'Brien case GLOB_NOSPACE:
460c80476e4SDavid E. O'Brien globfree(&globv);
461c80476e4SDavid E. O'Brien stderror(ERR_NOMEM);
462c80476e4SDavid E. O'Brien /* NOTREACHED */
463c80476e4SDavid E. O'Brien default:
464c80476e4SDavid E. O'Brien break;
465c80476e4SDavid E. O'Brien }
466c80476e4SDavid E. O'Brien if (globv.gl_flags & GLOB_MAGCHAR) {
467c80476e4SDavid E. O'Brien match |= (globv.gl_matchc != 0);
468c80476e4SDavid E. O'Brien magic = 1;
469c80476e4SDavid E. O'Brien }
470c80476e4SDavid E. O'Brien gflgs |= GLOB_APPEND;
471c80476e4SDavid E. O'Brien }
472c80476e4SDavid E. O'Brien while (*++vl);
473c80476e4SDavid E. O'Brien vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474c80476e4SDavid E. O'Brien NULL : blk2short(globv.gl_pathv);
475c80476e4SDavid E. O'Brien globfree(&globv);
476c80476e4SDavid E. O'Brien return (vl);
477c80476e4SDavid E. O'Brien }
478c80476e4SDavid E. O'Brien
479c80476e4SDavid E. O'Brien Char *
globone(Char * str,int action)48045e5710bSMark Peek globone(Char *str, int action)
481c80476e4SDavid E. O'Brien {
482c80476e4SDavid E. O'Brien Char *v[2], **vl, **vo;
48345e5710bSMark Peek int gflg, noglob;
484c80476e4SDavid E. O'Brien
485c80476e4SDavid E. O'Brien noglob = adrof(STRnoglob) != 0;
486c80476e4SDavid E. O'Brien v[0] = str;
487c80476e4SDavid E. O'Brien v[1] = 0;
48845e5710bSMark Peek gflg = tglob(v);
489c80476e4SDavid E. O'Brien if (gflg == G_NONE)
490c80476e4SDavid E. O'Brien return (strip(Strsave(str)));
491c80476e4SDavid E. O'Brien
492c80476e4SDavid E. O'Brien if (gflg & G_CSH) {
493c80476e4SDavid E. O'Brien /*
494c80476e4SDavid E. O'Brien * Expand back-quote, tilde and brace
495c80476e4SDavid E. O'Brien */
49645e5710bSMark Peek vo = globexpand(v, noglob);
497c80476e4SDavid E. O'Brien if (noglob || (gflg & G_GLOB) == 0) {
49845e5710bSMark Peek vl = vo;
49945e5710bSMark Peek goto result;
500c80476e4SDavid E. O'Brien }
50145e5710bSMark Peek cleanup_push(vo, blk_cleanup);
502c80476e4SDavid E. O'Brien }
503c80476e4SDavid E. O'Brien else if (noglob || (gflg & G_GLOB) == 0)
504c80476e4SDavid E. O'Brien return (strip(Strsave(str)));
505c80476e4SDavid E. O'Brien else
506c80476e4SDavid E. O'Brien vo = v;
507c80476e4SDavid E. O'Brien
508c80476e4SDavid E. O'Brien vl = libglob(vo);
50945e5710bSMark Peek if (gflg & G_CSH) {
51045e5710bSMark Peek if (vl != vo)
51145e5710bSMark Peek cleanup_until(vo);
51245e5710bSMark Peek else
51345e5710bSMark Peek cleanup_ignore(vo);
51445e5710bSMark Peek }
515c80476e4SDavid E. O'Brien if (vl == NULL) {
516c80476e4SDavid E. O'Brien setname(short2str(str));
517c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_NOMATCH);
518c80476e4SDavid E. O'Brien }
51945e5710bSMark Peek result:
5209ccc37e3SMark Peek if (vl && vl[0] == NULL) {
521*5224c2a3SDmitry Chagin if (vl != v)
52245e5710bSMark Peek xfree(vl);
523c80476e4SDavid E. O'Brien return (Strsave(STRNULL));
524c80476e4SDavid E. O'Brien }
5259ccc37e3SMark Peek if (vl && vl[1])
526c80476e4SDavid E. O'Brien return (handleone(str, vl, action));
527c80476e4SDavid E. O'Brien else {
528c80476e4SDavid E. O'Brien str = strip(*vl);
529*5224c2a3SDmitry Chagin if (vl != v)
53045e5710bSMark Peek xfree(vl);
531c80476e4SDavid E. O'Brien return (str);
532c80476e4SDavid E. O'Brien }
533c80476e4SDavid E. O'Brien }
534c80476e4SDavid E. O'Brien
535c80476e4SDavid E. O'Brien Char **
globall(Char ** v,int gflg)53645e5710bSMark Peek globall(Char **v, int gflg)
537c80476e4SDavid E. O'Brien {
538c80476e4SDavid E. O'Brien Char **vl, **vo;
53945e5710bSMark Peek int noglob;
540c80476e4SDavid E. O'Brien
54145e5710bSMark Peek if (!v || !v[0])
54245e5710bSMark Peek return saveblk(v);
543c80476e4SDavid E. O'Brien
544c80476e4SDavid E. O'Brien noglob = adrof(STRnoglob) != 0;
545c80476e4SDavid E. O'Brien
546c80476e4SDavid E. O'Brien if (gflg & G_CSH)
547c80476e4SDavid E. O'Brien /*
548c80476e4SDavid E. O'Brien * Expand back-quote, tilde and brace
549c80476e4SDavid E. O'Brien */
55045e5710bSMark Peek vl = vo = globexpand(v, noglob);
551c80476e4SDavid E. O'Brien else
552c80476e4SDavid E. O'Brien vl = vo = saveblk(v);
553c80476e4SDavid E. O'Brien
554c80476e4SDavid E. O'Brien if (!noglob && (gflg & G_GLOB)) {
55545e5710bSMark Peek cleanup_push(vo, blk_cleanup);
556c80476e4SDavid E. O'Brien vl = libglob(vo);
55745e5710bSMark Peek if (vl == vo)
55845e5710bSMark Peek cleanup_ignore(vo);
55945e5710bSMark Peek cleanup_until(vo);
560c80476e4SDavid E. O'Brien }
561c80476e4SDavid E. O'Brien else
562c80476e4SDavid E. O'Brien trim(vl);
563c80476e4SDavid E. O'Brien
56445e5710bSMark Peek return vl;
565c80476e4SDavid E. O'Brien }
566c80476e4SDavid E. O'Brien
56745e5710bSMark Peek Char **
glob_all_or_error(Char ** v)56845e5710bSMark Peek glob_all_or_error(Char **v)
569c80476e4SDavid E. O'Brien {
57045e5710bSMark Peek int gflag;
57145e5710bSMark Peek
57245e5710bSMark Peek gflag = tglob(v);
57345e5710bSMark Peek if (gflag) {
57445e5710bSMark Peek v = globall(v, gflag);
57545e5710bSMark Peek if (v == NULL)
57645e5710bSMark Peek stderror(ERR_NAME | ERR_NOMATCH);
57745e5710bSMark Peek } else {
57845e5710bSMark Peek v = saveblk(v);
57945e5710bSMark Peek trim(v);
58045e5710bSMark Peek }
58145e5710bSMark Peek return v;
582c80476e4SDavid E. O'Brien }
583c80476e4SDavid E. O'Brien
584c80476e4SDavid E. O'Brien void
rscan(Char ** t,void (* f)(Char))58545e5710bSMark Peek rscan(Char **t, void (*f) (Char))
586c80476e4SDavid E. O'Brien {
58723338178SMark Peek Char *p;
588c80476e4SDavid E. O'Brien
589cc698b49SBrooks Davis while ((p = *t++) != NULL)
590c80476e4SDavid E. O'Brien while (*p)
591c80476e4SDavid E. O'Brien (*f) (*p++);
592c80476e4SDavid E. O'Brien }
593c80476e4SDavid E. O'Brien
594c80476e4SDavid E. O'Brien void
trim(Char ** t)59545e5710bSMark Peek trim(Char **t)
596c80476e4SDavid E. O'Brien {
59723338178SMark Peek Char *p;
598c80476e4SDavid E. O'Brien
599cc698b49SBrooks Davis while ((p = *t++) != NULL)
60019d2e3deSDmitry Chagin while (*p) {
60119d2e3deSDmitry Chagin #if INVALID_BYTE != 0
60219d2e3deSDmitry Chagin if ((*p & INVALID_BYTE) != INVALID_BYTE) /* *p < INVALID_BYTE */
60319d2e3deSDmitry Chagin #endif
60419d2e3deSDmitry Chagin *p &= TRIM;
60519d2e3deSDmitry Chagin p++;
60619d2e3deSDmitry Chagin }
607c80476e4SDavid E. O'Brien }
608c80476e4SDavid E. O'Brien
60945e5710bSMark Peek int
tglob(Char ** t)61045e5710bSMark Peek tglob(Char **t)
611c80476e4SDavid E. O'Brien {
61245e5710bSMark Peek int gflag;
61345e5710bSMark Peek const Char *p;
614c80476e4SDavid E. O'Brien
61545e5710bSMark Peek gflag = 0;
616cc698b49SBrooks Davis while ((p = *t++) != NULL) {
617c80476e4SDavid E. O'Brien if (*p == '~' || *p == '=')
618c80476e4SDavid E. O'Brien gflag |= G_CSH;
619c80476e4SDavid E. O'Brien else if (*p == '{' &&
620c80476e4SDavid E. O'Brien (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
621c80476e4SDavid E. O'Brien continue;
62245e5710bSMark Peek while (*p != '\0') {
62345e5710bSMark Peek if (*p == '`') {
624c80476e4SDavid E. O'Brien gflag |= G_CSH;
625c80476e4SDavid E. O'Brien #ifdef notdef
626c80476e4SDavid E. O'Brien /*
627c80476e4SDavid E. O'Brien * We do want to expand echo `echo '*'`, so we don't\
628c80476e4SDavid E. O'Brien * use this piece of code anymore.
629c80476e4SDavid E. O'Brien */
63045e5710bSMark Peek p++;
631c80476e4SDavid E. O'Brien while (*p && *p != '`')
632c80476e4SDavid E. O'Brien if (*p++ == '\\') {
633c80476e4SDavid E. O'Brien if (*p) /* Quoted chars */
634c80476e4SDavid E. O'Brien p++;
635c80476e4SDavid E. O'Brien else
636c80476e4SDavid E. O'Brien break;
637c80476e4SDavid E. O'Brien }
63845e5710bSMark Peek if (!*p) /* The matching ` */
639c80476e4SDavid E. O'Brien break;
640c80476e4SDavid E. O'Brien #endif
641c80476e4SDavid E. O'Brien }
64245e5710bSMark Peek else if (*p == '{')
643c80476e4SDavid E. O'Brien gflag |= G_CSH;
64445e5710bSMark Peek else if (isglob(*p))
645c80476e4SDavid E. O'Brien gflag |= G_GLOB;
646c80476e4SDavid E. O'Brien else if (symlinks == SYM_EXPAND &&
64745e5710bSMark Peek p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
648c80476e4SDavid E. O'Brien gflag |= G_CSH;
64945e5710bSMark Peek p++;
650c80476e4SDavid E. O'Brien }
651c80476e4SDavid E. O'Brien }
65245e5710bSMark Peek return gflag;
653c80476e4SDavid E. O'Brien }
654c80476e4SDavid E. O'Brien
655c80476e4SDavid E. O'Brien /*
656c80476e4SDavid E. O'Brien * Command substitute cp. If literal, then this is a substitution from a
657c80476e4SDavid E. O'Brien * << redirection, and so we should not crunch blanks and tabs, separating
658c80476e4SDavid E. O'Brien * words only at newlines.
659c80476e4SDavid E. O'Brien */
660c80476e4SDavid E. O'Brien Char **
dobackp(Char * cp,int literal)66145e5710bSMark Peek dobackp(Char *cp, int literal)
662c80476e4SDavid E. O'Brien {
66345e5710bSMark Peek struct Strbuf word = Strbuf_INIT;
66445e5710bSMark Peek struct blk_buf bb = BLK_BUF_INIT;
66545e5710bSMark Peek Char *lp, *rp, *ep;
666c80476e4SDavid E. O'Brien
66745e5710bSMark Peek cleanup_push(&bb, bb_cleanup);
66845e5710bSMark Peek cleanup_push(&word, Strbuf_cleanup);
669c80476e4SDavid E. O'Brien for (;;) {
67045e5710bSMark Peek for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
67145e5710bSMark Peek ;
67245e5710bSMark Peek Strbuf_appendn(&word, cp, lp - cp);
67345e5710bSMark Peek if (*lp == 0)
67445e5710bSMark Peek break;
675c80476e4SDavid E. O'Brien lp++;
676c80476e4SDavid E. O'Brien for (rp = lp; *rp && *rp != '`'; rp++)
677c80476e4SDavid E. O'Brien if (*rp == '\\') {
678c80476e4SDavid E. O'Brien rp++;
679c80476e4SDavid E. O'Brien if (!*rp)
680c80476e4SDavid E. O'Brien goto oops;
681c80476e4SDavid E. O'Brien }
68245e5710bSMark Peek if (!*rp) {
68345e5710bSMark Peek oops:
684a15e6f9aSMark Peek cleanup_until(&bb);
68545e5710bSMark Peek stderror(ERR_UNMATCHED, '`');
68645e5710bSMark Peek }
68745e5710bSMark Peek ep = Strnsave(lp, rp - lp);
68845e5710bSMark Peek cleanup_push(ep, xfree);
68945e5710bSMark Peek backeval(&bb, &word, ep, literal);
69045e5710bSMark Peek cleanup_until(ep);
691c80476e4SDavid E. O'Brien cp = rp + 1;
692c80476e4SDavid E. O'Brien }
69345e5710bSMark Peek if (word.len != 0)
69445e5710bSMark Peek pword(&bb, &word);
69545e5710bSMark Peek cleanup_ignore(&bb);
69645e5710bSMark Peek cleanup_until(&bb);
69745e5710bSMark Peek return bb_finish(&bb);
698c80476e4SDavid E. O'Brien }
699c80476e4SDavid E. O'Brien
700c80476e4SDavid E. O'Brien
701c80476e4SDavid E. O'Brien static void
backeval(struct blk_buf * bb,struct Strbuf * word,Char * cp,int literal)70245e5710bSMark Peek backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
703c80476e4SDavid E. O'Brien {
7049ccc37e3SMark Peek ssize_t icnt;
70523338178SMark Peek Char c, *ip;
706c80476e4SDavid E. O'Brien struct command faket;
70723338178SMark Peek int hadnl;
708c80476e4SDavid E. O'Brien int pvec[2], quoted;
709c80476e4SDavid E. O'Brien Char *fakecom[2], ibuf[BUFSIZE];
710c80476e4SDavid E. O'Brien
711c80476e4SDavid E. O'Brien hadnl = 0;
712c80476e4SDavid E. O'Brien icnt = 0;
71319d2e3deSDmitry Chagin if (!literal) {
71419d2e3deSDmitry Chagin for (ip = cp; (*ip & QUOTE) != 0; ip++)
71519d2e3deSDmitry Chagin continue;
71619d2e3deSDmitry Chagin quoted = *ip == '\0';
71719d2e3deSDmitry Chagin } else
71819d2e3deSDmitry Chagin quoted = literal;
719c80476e4SDavid E. O'Brien faket.t_dtyp = NODE_COMMAND;
720c80476e4SDavid E. O'Brien faket.t_dflg = F_BACKQ;
721c80476e4SDavid E. O'Brien faket.t_dlef = 0;
722c80476e4SDavid E. O'Brien faket.t_drit = 0;
723c80476e4SDavid E. O'Brien faket.t_dspr = 0;
724c80476e4SDavid E. O'Brien faket.t_dcom = fakecom;
725c80476e4SDavid E. O'Brien fakecom[0] = STRfakecom1;
726c80476e4SDavid E. O'Brien fakecom[1] = 0;
727c80476e4SDavid E. O'Brien
728c80476e4SDavid E. O'Brien /*
729c80476e4SDavid E. O'Brien * We do the psave job to temporarily change the current job so that the
730c80476e4SDavid E. O'Brien * following fork is considered a separate job. This is so that when
731c80476e4SDavid E. O'Brien * backquotes are used in a builtin function that calls glob the "current
732c80476e4SDavid E. O'Brien * job" is not corrupted. We only need one level of pushed jobs as long as
733c80476e4SDavid E. O'Brien * we are sure to fork here.
734c80476e4SDavid E. O'Brien */
735c80476e4SDavid E. O'Brien psavejob();
73645e5710bSMark Peek cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
737c80476e4SDavid E. O'Brien
738c80476e4SDavid E. O'Brien /*
739c80476e4SDavid E. O'Brien * It would be nicer if we could integrate this redirection more with the
740c80476e4SDavid E. O'Brien * routines in sh.sem.c by doing a fake execute on a builtin function that
741c80476e4SDavid E. O'Brien * was piped out.
742c80476e4SDavid E. O'Brien */
743c80476e4SDavid E. O'Brien mypipe(pvec);
74445e5710bSMark Peek cleanup_push(&pvec[0], open_cleanup);
74545e5710bSMark Peek cleanup_push(&pvec[1], open_cleanup);
746c80476e4SDavid E. O'Brien if (pfork(&faket, -1) == 0) {
74723338178SMark Peek jmp_buf_t osetexit;
74845e5710bSMark Peek struct command *t;
74945e5710bSMark Peek size_t omark;
750c80476e4SDavid E. O'Brien
75145e5710bSMark Peek xclose(pvec[0]);
752c80476e4SDavid E. O'Brien (void) dmove(pvec[1], 1);
753c80476e4SDavid E. O'Brien (void) dmove(SHDIAG, 2);
754c80476e4SDavid E. O'Brien initdesc();
75529301572SMark Peek closem();
756c80476e4SDavid E. O'Brien arginp = cp;
75729301572SMark Peek for (arginp = cp; *cp; cp++) {
75829301572SMark Peek *cp &= TRIM;
75923338178SMark Peek if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
76029301572SMark Peek *cp = ' ';
76129301572SMark Peek }
762c80476e4SDavid E. O'Brien
763c80476e4SDavid E. O'Brien /*
764c80476e4SDavid E. O'Brien * In the child ``forget'' everything about current aliases or
765c80476e4SDavid E. O'Brien * eval vectors.
766c80476e4SDavid E. O'Brien */
767c80476e4SDavid E. O'Brien alvec = NULL;
768c80476e4SDavid E. O'Brien evalvec = NULL;
769c80476e4SDavid E. O'Brien alvecp = NULL;
770c80476e4SDavid E. O'Brien evalp = NULL;
77123338178SMark Peek
77245e5710bSMark Peek omark = cleanup_push_mark();
77323338178SMark Peek getexit(osetexit);
77423338178SMark Peek for (;;) {
77519d2e3deSDmitry Chagin struct wordent paraml1;
77619d2e3deSDmitry Chagin initlex(¶ml1);
77719d2e3deSDmitry Chagin
77823338178SMark Peek (void) setexit();
77923338178SMark Peek justpr = 0;
78023338178SMark Peek
78123338178SMark Peek if (haderr) {
78223338178SMark Peek /* unwind */
78323338178SMark Peek doneinp = 0;
78445e5710bSMark Peek cleanup_pop_mark(omark);
78523338178SMark Peek resexit(osetexit);
78623338178SMark Peek reset();
78723338178SMark Peek }
78823338178SMark Peek if (seterr) {
78945e5710bSMark Peek xfree(seterr);
79023338178SMark Peek seterr = NULL;
79123338178SMark Peek }
79223338178SMark Peek
79319d2e3deSDmitry Chagin freelex(¶ml1);
79419d2e3deSDmitry Chagin (void) lex(¶ml1);
79519d2e3deSDmitry Chagin cleanup_push(¶ml1, lex_cleanup);
796c80476e4SDavid E. O'Brien if (seterr)
797c80476e4SDavid E. O'Brien stderror(ERR_OLD);
79819d2e3deSDmitry Chagin alias(¶ml1);
79919d2e3deSDmitry Chagin t = syntax(paraml1.next, ¶ml1, 0);
80045e5710bSMark Peek cleanup_push(t, syntax_cleanup);
8019ccc37e3SMark Peek /* The F_BACKQ flag must set so the job output is correct if
8029ccc37e3SMark Peek * printexitvalue is set. If it's not set, the job output
8039ccc37e3SMark Peek * will have "Exit N" appended where N is the exit status. */
80419d2e3deSDmitry Chagin if (t)
8059ccc37e3SMark Peek t->t_dflg = F_BACKQ|F_NOFORK;
806c80476e4SDavid E. O'Brien if (seterr)
807c80476e4SDavid E. O'Brien stderror(ERR_OLD);
808c80476e4SDavid E. O'Brien #ifdef SIGTSTP
80945e5710bSMark Peek signal(SIGTSTP, SIG_IGN);
810c80476e4SDavid E. O'Brien #endif
811c80476e4SDavid E. O'Brien #ifdef SIGTTIN
81245e5710bSMark Peek signal(SIGTTIN, SIG_IGN);
813c80476e4SDavid E. O'Brien #endif
814c80476e4SDavid E. O'Brien #ifdef SIGTTOU
81545e5710bSMark Peek signal(SIGTTOU, SIG_IGN);
816c80476e4SDavid E. O'Brien #endif
81729301572SMark Peek execute(t, -1, NULL, NULL, TRUE);
81823338178SMark Peek
81919d2e3deSDmitry Chagin cleanup_until(¶ml1);
82023338178SMark Peek }
821c80476e4SDavid E. O'Brien }
82245e5710bSMark Peek cleanup_until(&pvec[1]);
823c80476e4SDavid E. O'Brien c = 0;
824c80476e4SDavid E. O'Brien ip = NULL;
825c80476e4SDavid E. O'Brien do {
8269ccc37e3SMark Peek ssize_t cnt = 0;
827c80476e4SDavid E. O'Brien
828c80476e4SDavid E. O'Brien for (;;) {
82919d2e3deSDmitry Chagin if (icnt == 0) {
830c80476e4SDavid E. O'Brien ip = ibuf;
83119d2e3deSDmitry Chagin icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
83219d2e3deSDmitry Chagin if (icnt <= 0)
83323338178SMark Peek goto eof;
834c80476e4SDavid E. O'Brien }
835c80476e4SDavid E. O'Brien if (hadnl)
836c80476e4SDavid E. O'Brien break;
837c80476e4SDavid E. O'Brien --icnt;
838c80476e4SDavid E. O'Brien c = (*ip++ & TRIM);
839c80476e4SDavid E. O'Brien if (c == 0)
840c80476e4SDavid E. O'Brien break;
841a15e6f9aSMark Peek #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842c80476e4SDavid E. O'Brien if (c == '\r')
843c80476e4SDavid E. O'Brien c = ' ';
844a15e6f9aSMark Peek #endif /* WINNT_NATIVE || __CYGWIN__ */
845c80476e4SDavid E. O'Brien if (c == '\n') {
846c80476e4SDavid E. O'Brien /*
847c80476e4SDavid E. O'Brien * Continue around the loop one more time, so that we can eat
848c80476e4SDavid E. O'Brien * the last newline without terminating this word.
849c80476e4SDavid E. O'Brien */
850c80476e4SDavid E. O'Brien hadnl = 1;
851c80476e4SDavid E. O'Brien continue;
852c80476e4SDavid E. O'Brien }
853c80476e4SDavid E. O'Brien if (!quoted && (c == ' ' || c == '\t'))
854c80476e4SDavid E. O'Brien break;
855c80476e4SDavid E. O'Brien cnt++;
85619d2e3deSDmitry Chagin if (c == '\\' || quoted)
85719d2e3deSDmitry Chagin c |= QUOTE;
85819d2e3deSDmitry Chagin Strbuf_append1(word, c);
859c80476e4SDavid E. O'Brien }
860c80476e4SDavid E. O'Brien /*
861c80476e4SDavid E. O'Brien * Unless at end-of-file, we will form a new word here if there were
862c80476e4SDavid E. O'Brien * characters in the word, or in any case when we take text literally.
863c80476e4SDavid E. O'Brien * If we didn't make empty words here when literal was set then we
864c80476e4SDavid E. O'Brien * would lose blank lines.
865c80476e4SDavid E. O'Brien */
86623338178SMark Peek if (c != 0 && (cnt || literal))
86745e5710bSMark Peek pword(bb, word);
868c80476e4SDavid E. O'Brien hadnl = 0;
86923338178SMark Peek } while (c > 0);
87023338178SMark Peek eof:
87145e5710bSMark Peek cleanup_until(&pvec[0]);
872c80476e4SDavid E. O'Brien pwait();
87345e5710bSMark Peek cleanup_until(&faket); /* psavejob_cleanup(); */
874c80476e4SDavid E. O'Brien }
875c80476e4SDavid E. O'Brien
876c80476e4SDavid E. O'Brien static void
pword(struct blk_buf * bb,struct Strbuf * word)87745e5710bSMark Peek pword(struct blk_buf *bb, struct Strbuf *word)
878c80476e4SDavid E. O'Brien {
87945e5710bSMark Peek Char *s;
880c80476e4SDavid E. O'Brien
88145e5710bSMark Peek s = Strbuf_finish(word);
88245e5710bSMark Peek bb_append(bb, s);
88345e5710bSMark Peek *word = Strbuf_init;
884c80476e4SDavid E. O'Brien }
885c80476e4SDavid E. O'Brien
886c80476e4SDavid E. O'Brien int
Gmatch(const Char * string,const Char * pattern)88745e5710bSMark Peek Gmatch(const Char *string, const Char *pattern)
888c80476e4SDavid E. O'Brien {
889c80476e4SDavid E. O'Brien return Gnmatch(string, pattern, NULL);
890c80476e4SDavid E. O'Brien }
891c80476e4SDavid E. O'Brien
892c80476e4SDavid E. O'Brien int
Gnmatch(const Char * string,const Char * pattern,const Char ** endstr)89345e5710bSMark Peek Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
894c80476e4SDavid E. O'Brien {
89545e5710bSMark Peek Char ***fblk, **p;
89645e5710bSMark Peek const Char *tstring = string;
897c80476e4SDavid E. O'Brien int gpol = 1, gres = 0;
898c80476e4SDavid E. O'Brien
899c80476e4SDavid E. O'Brien if (*pattern == '^') {
900c80476e4SDavid E. O'Brien gpol = 0;
901c80476e4SDavid E. O'Brien pattern++;
902c80476e4SDavid E. O'Brien }
903c80476e4SDavid E. O'Brien
90445e5710bSMark Peek fblk = xmalloc(sizeof(Char ***));
90545e5710bSMark Peek *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
90645e5710bSMark Peek (*fblk)[0] = Strsave(pattern);
90745e5710bSMark Peek (*fblk)[1] = NULL;
908c80476e4SDavid E. O'Brien
90945e5710bSMark Peek cleanup_push(fblk, blk_indirect_cleanup);
91045e5710bSMark Peek expbrace(fblk, NULL, GLOBSPACE);
911c80476e4SDavid E. O'Brien
912c80476e4SDavid E. O'Brien if (endstr == NULL)
913c80476e4SDavid E. O'Brien /* Exact matches only */
91445e5710bSMark Peek for (p = *fblk; *p; p++)
91523338178SMark Peek gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
916c80476e4SDavid E. O'Brien else {
91745e5710bSMark Peek const Char *end;
91845e5710bSMark Peek
919c80476e4SDavid E. O'Brien /* partial matches */
92045e5710bSMark Peek end = Strend(string);
92145e5710bSMark Peek for (p = *fblk; *p; p++)
92223338178SMark Peek if (t_pmatch(string, *p, &tstring, 1) != 0) {
923c80476e4SDavid E. O'Brien gres |= 1;
92445e5710bSMark Peek if (end > tstring)
92545e5710bSMark Peek end = tstring;
926c80476e4SDavid E. O'Brien }
92745e5710bSMark Peek *endstr = end;
928c80476e4SDavid E. O'Brien }
929c80476e4SDavid E. O'Brien
93045e5710bSMark Peek cleanup_until(fblk);
931c80476e4SDavid E. O'Brien return(gres == gpol);
932c80476e4SDavid E. O'Brien }
933c80476e4SDavid E. O'Brien
934b2d5d167SMark Peek /* t_pmatch():
935c80476e4SDavid E. O'Brien * Return 2 on exact match,
936c80476e4SDavid E. O'Brien * Return 1 on substring match.
937c80476e4SDavid E. O'Brien * Return 0 on no match.
938c80476e4SDavid E. O'Brien * *estr will point to the end of the longest exact or substring match.
939c80476e4SDavid E. O'Brien */
940b2d5d167SMark Peek int
t_pmatch(const Char * string,const Char * pattern,const Char ** estr,int cs)94145e5710bSMark Peek t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
942c80476e4SDavid E. O'Brien {
94345e5710bSMark Peek Char stringc, patternc, rangec;
944c80476e4SDavid E. O'Brien int match, negate_range;
94545e5710bSMark Peek const Char *pestr, *nstring;
946c80476e4SDavid E. O'Brien
94723338178SMark Peek for (nstring = string;; string = nstring) {
94845e5710bSMark Peek stringc = *nstring++ & TRIM;
94945e5710bSMark Peek patternc = *pattern++ & TRIM;
950c80476e4SDavid E. O'Brien switch (patternc) {
95123338178SMark Peek case '\0':
952c80476e4SDavid E. O'Brien *estr = string;
95323338178SMark Peek return (stringc == '\0' ? 2 : 1);
954c80476e4SDavid E. O'Brien case '?':
955c80476e4SDavid E. O'Brien if (stringc == 0)
956c80476e4SDavid E. O'Brien return (0);
957c80476e4SDavid E. O'Brien break;
958c80476e4SDavid E. O'Brien case '*':
959c80476e4SDavid E. O'Brien if (!*pattern) {
96045e5710bSMark Peek *estr = Strend(string);
961c80476e4SDavid E. O'Brien return (2);
962c80476e4SDavid E. O'Brien }
963c80476e4SDavid E. O'Brien pestr = NULL;
964c80476e4SDavid E. O'Brien
96523338178SMark Peek for (;;) {
966b2d5d167SMark Peek switch(t_pmatch(string, pattern, estr, cs)) {
967c80476e4SDavid E. O'Brien case 0:
968c80476e4SDavid E. O'Brien break;
969c80476e4SDavid E. O'Brien case 1:
97045e5710bSMark Peek pestr = *estr;/*FIXME: does not guarantee longest match */
971c80476e4SDavid E. O'Brien break;
972c80476e4SDavid E. O'Brien case 2:
973c80476e4SDavid E. O'Brien return 2;
974c80476e4SDavid E. O'Brien default:
975c80476e4SDavid E. O'Brien abort(); /* Cannot happen */
976c80476e4SDavid E. O'Brien }
97745e5710bSMark Peek stringc = *string++ & TRIM;
97823338178SMark Peek if (!stringc)
97923338178SMark Peek break;
980c80476e4SDavid E. O'Brien }
981c80476e4SDavid E. O'Brien
982c80476e4SDavid E. O'Brien if (pestr) {
983c80476e4SDavid E. O'Brien *estr = pestr;
984c80476e4SDavid E. O'Brien return 1;
985c80476e4SDavid E. O'Brien }
98645e5710bSMark Peek else
987c80476e4SDavid E. O'Brien return 0;
988c80476e4SDavid E. O'Brien
989c80476e4SDavid E. O'Brien case '[':
990c80476e4SDavid E. O'Brien match = 0;
991c80476e4SDavid E. O'Brien if ((negate_range = (*pattern == '^')) != 0)
992c80476e4SDavid E. O'Brien pattern++;
99345e5710bSMark Peek while ((rangec = *pattern++ & TRIM) != '\0') {
994c80476e4SDavid E. O'Brien if (rangec == ']')
995c80476e4SDavid E. O'Brien break;
996c80476e4SDavid E. O'Brien if (match)
997c80476e4SDavid E. O'Brien continue;
99823338178SMark Peek if (*pattern == '-' && pattern[1] != ']') {
99945e5710bSMark Peek Char rangec2;
1000c80476e4SDavid E. O'Brien pattern++;
100145e5710bSMark Peek rangec2 = *pattern++ & TRIM;
100223338178SMark Peek match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
100323338178SMark Peek globcharcoll(rangec, stringc, 0) <= 0);
1004c80476e4SDavid E. O'Brien }
1005c80476e4SDavid E. O'Brien else
100623338178SMark Peek match = (stringc == rangec);
1007c80476e4SDavid E. O'Brien }
100823338178SMark Peek if (rangec == '\0')
1009c80476e4SDavid E. O'Brien stderror(ERR_NAME | ERR_MISSING, ']');
101023338178SMark Peek if ((!match) && (stringc == '\0'))
101123338178SMark Peek return (0);
1012c80476e4SDavid E. O'Brien if (match == negate_range)
1013c80476e4SDavid E. O'Brien return (0);
1014c80476e4SDavid E. O'Brien break;
1015c80476e4SDavid E. O'Brien default:
101623338178SMark Peek if (cs ? patternc != stringc
101723338178SMark Peek : Tolower(patternc) != Tolower(stringc))
1018c80476e4SDavid E. O'Brien return (0);
1019c80476e4SDavid E. O'Brien break;
1020c80476e4SDavid E. O'Brien }
1021c80476e4SDavid E. O'Brien }
1022c80476e4SDavid E. O'Brien }
1023