145e5710bSMark Peek /*
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.
16c80476e4SDavid E. O'Brien * 3. Neither the name of the University nor the names of its contributors
1729301572SMark Peek * 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"
34c80476e4SDavid E. O'Brien #include "tw.h"
3545e5710bSMark Peek
36c80476e4SDavid E. O'Brien #include "glob.h"
37c80476e4SDavid E. O'Brien
3829301572SMark Peek /*
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 */
63c80476e4SDavid E. O'Brien static Char *globtilde (Char *);
64c80476e4SDavid E. O'Brien static Char *handleone (Char *, Char **, int);
65c80476e4SDavid E. O'Brien static Char **libglob (Char **);
66c80476e4SDavid E. O'Brien 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);
7245e5710bSMark Peek static Char *
globtilde(Char * s)7345e5710bSMark Peek globtilde(Char *s)
7445e5710bSMark Peek {
7545e5710bSMark Peek Char *name, *u, *home, *res;
76c80476e4SDavid E. O'Brien
7745e5710bSMark Peek u = s;
78c80476e4SDavid E. O'Brien
7945e5710bSMark Peek if (s[1] == '~')
80c80476e4SDavid E. O'Brien return Strsave(s);
81c80476e4SDavid E. O'Brien
8245e5710bSMark Peek for (s++; *s && *s != '/' && *s != ':'; s++)
83c80476e4SDavid E. O'Brien continue;
8445e5710bSMark Peek
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)
94c80476e4SDavid E. O'Brien stderror(ERR_UNKUSER, short2str(name));
95c80476e4SDavid E. O'Brien else
96c80476e4SDavid E. O'Brien stderror(ERR_NOHOME);
9745e5710bSMark Peek }
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);
105c80476e4SDavid E. O'Brien return res;
106c80476e4SDavid E. O'Brien }
10745e5710bSMark Peek
108c80476e4SDavid E. O'Brien /* Returns a newly allocated string, old or NULL */
10945e5710bSMark Peek Char *
globequal(Char * old)110c80476e4SDavid E. O'Brien globequal(Char *old)
111c80476e4SDavid E. O'Brien {
11245e5710bSMark Peek int dig;
11345e5710bSMark Peek const Char *dir;
114c80476e4SDavid E. O'Brien 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] == '/')) {
12145e5710bSMark Peek /* =- */
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)
126c80476e4SDavid E. O'Brien 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;
14245e5710bSMark Peek
14345e5710bSMark Peek dir = getstakd(dig);
144c80476e4SDavid E. O'Brien if (dir == NULL)
14545e5710bSMark Peek return NULL;
146c80476e4SDavid E. O'Brien return Strspl(dir, b);
147c80476e4SDavid E. O'Brien }
148c80476e4SDavid E. O'Brien
14945e5710bSMark Peek static int
globbrace(const Char * s,Char *** bl)150c80476e4SDavid E. O'Brien globbrace(const Char *s, Char ***bl)
15145e5710bSMark Peek {
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;
156c80476e4SDavid E. O'Brien size_t prefix_len;
157c80476e4SDavid E. O'Brien
15845e5710bSMark Peek /* copy part up to the brace */
15945e5710bSMark Peek for (p = s; *p != LBRC; p++)
16045e5710bSMark Peek ;
161c80476e4SDavid E. O'Brien 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++)
16845e5710bSMark Peek continue;
169c80476e4SDavid E. O'Brien 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 }
17945e5710bSMark Peek
180c80476e4SDavid E. O'Brien if (i != 0 || *pe == '\0')
18145e5710bSMark Peek return (-RBRC);
18245e5710bSMark Peek
183c80476e4SDavid E. O'Brien 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;
19045e5710bSMark Peek if (*pm == EOS) {
19145e5710bSMark Peek bb_cleanup(&bb);
192c80476e4SDavid E. O'Brien 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;
20845e5710bSMark Peek 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);
213c80476e4SDavid E. O'Brien 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;
21945e5710bSMark Peek }
22045e5710bSMark Peek *bl = bb_finish(&bb);
22145e5710bSMark Peek xfree(gbuf.s);
222c80476e4SDavid E. O'Brien return bb.len;
223c80476e4SDavid E. O'Brien }
224c80476e4SDavid E. O'Brien
225c80476e4SDavid E. O'Brien
22645e5710bSMark Peek static void
expbrace(Char *** nvp,Char *** elp,int size)227c80476e4SDavid E. O'Brien 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;
23445e5710bSMark Peek else
235c80476e4SDavid E. O'Brien 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')))
24245e5710bSMark Peek continue;
24345e5710bSMark Peek if (Strchr(s, '{') != NULL) {
244c80476e4SDavid E. O'Brien Char **bl = NULL;
245c80476e4SDavid E. O'Brien int len;
24645e5710bSMark Peek
247c80476e4SDavid E. O'Brien if ((len = globbrace(s, &bl)) < 0)
24845e5710bSMark Peek stderror(ERR_MISSING, -len);
249c80476e4SDavid E. O'Brien xfree(s);
250c80476e4SDavid E. O'Brien if (len == 1) {
25145e5710bSMark Peek *vl-- = *bl;
252c80476e4SDavid E. O'Brien xfree(bl);
253c80476e4SDavid E. O'Brien continue;
254c80476e4SDavid E. O'Brien }
25545e5710bSMark Peek if (&el[len] >= &nv[size]) {
25645e5710bSMark Peek size_t l, e;
257c80476e4SDavid E. O'Brien l = &el[len] - &nv[size];
25845e5710bSMark Peek size += GLOBSPACE > l ? GLOBSPACE : l;
25945e5710bSMark Peek l = vl - nv;
26045e5710bSMark Peek e = el - nv;
26145e5710bSMark Peek nv = xrealloc(nv, size * sizeof(Char *));
262c80476e4SDavid E. O'Brien *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++)
28645e5710bSMark Peek continue;
287c80476e4SDavid E. O'Brien 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
29545e5710bSMark Peek static Char **
globexpand(Char ** v,int noglob)296c80476e4SDavid E. O'Brien globexpand(Char **v, int noglob)
297c80476e4SDavid E. O'Brien {
29845e5710bSMark Peek Char *s;
299c80476e4SDavid E. O'Brien Char ***fnv, **vl, **el;
300c80476e4SDavid E. O'Brien int size = GLOBSPACE;
301c80476e4SDavid E. O'Brien
30245e5710bSMark Peek
30345e5710bSMark Peek fnv = xmalloc(sizeof(Char ***));
304c80476e4SDavid E. O'Brien *fnv = vl = xmalloc(sizeof(Char *) * size);
30545e5710bSMark Peek *vl = NULL;
306c80476e4SDavid E. O'Brien 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 */
311c80476e4SDavid E. O'Brien while ((s = *v++) != NULL) {
312c80476e4SDavid E. O'Brien if (Strchr(s, '`')) {
31345e5710bSMark Peek int i;
314c80476e4SDavid E. O'Brien Char **expanded;
31545e5710bSMark Peek
31645e5710bSMark Peek expanded = dobackp(s, 0);
31745e5710bSMark Peek for (i = 0; expanded[i] != NULL; i++) {
31845e5710bSMark Peek *vl++ = expanded[i];
319c80476e4SDavid E. O'Brien if (vl == &(*fnv)[size]) {
32045e5710bSMark Peek size += GLOBSPACE;
32145e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *));
322c80476e4SDavid E. O'Brien vl = &(*fnv)[size - GLOBSPACE];
323c80476e4SDavid E. O'Brien }
32445e5710bSMark Peek }
325c80476e4SDavid E. O'Brien xfree(expanded);
326c80476e4SDavid E. O'Brien }
327c80476e4SDavid E. O'Brien else {
32845e5710bSMark Peek *vl++ = Strsave(s);
329c80476e4SDavid E. O'Brien if (vl == &(*fnv)[size]) {
33045e5710bSMark Peek size += GLOBSPACE;
33145e5710bSMark Peek *fnv = xrealloc(*fnv, size * sizeof(Char *));
332c80476e4SDavid E. O'Brien vl = &(*fnv)[size - GLOBSPACE];
333c80476e4SDavid E. O'Brien }
334c80476e4SDavid E. O'Brien }
33545e5710bSMark Peek *vl = NULL;
336c80476e4SDavid E. O'Brien }
337c80476e4SDavid E. O'Brien
33845e5710bSMark Peek if (noglob)
339c80476e4SDavid E. O'Brien goto done;
340c80476e4SDavid E. O'Brien
341c80476e4SDavid E. O'Brien /*
342c80476e4SDavid E. O'Brien * Step 2: expand braces
343c80476e4SDavid E. O'Brien */
34445e5710bSMark Peek el = vl;
345c80476e4SDavid E. O'Brien expbrace(fnv, &el, size);
346c80476e4SDavid E. O'Brien
347c80476e4SDavid E. O'Brien
348c80476e4SDavid E. O'Brien /*
349c80476e4SDavid E. O'Brien * Step 3: expand ~ =
35045e5710bSMark Peek */
351c80476e4SDavid E. O'Brien vl = *fnv;
352c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl)
35345e5710bSMark Peek switch (*s) {
354c80476e4SDavid E. O'Brien Char *ns;
35545e5710bSMark Peek case '~':
356c80476e4SDavid E. O'Brien *vl = globtilde(s);
357c80476e4SDavid E. O'Brien break;
35845e5710bSMark Peek case '=':
35945e5710bSMark Peek if ((ns = globequal(s)) == NULL) {
36045e5710bSMark Peek if (!adrof(STRnonomatch))
361c80476e4SDavid E. O'Brien stderror(ERR_DEEP); /* Error */
362c80476e4SDavid E. O'Brien }
363c80476e4SDavid E. O'Brien if (ns && ns != s) {
36445e5710bSMark Peek /* Expansion succeeded */
36545e5710bSMark Peek xfree(s);
366c80476e4SDavid E. O'Brien *vl = ns;
367c80476e4SDavid E. O'Brien }
368c80476e4SDavid E. O'Brien break;
369c80476e4SDavid E. O'Brien default:
370c80476e4SDavid E. O'Brien break;
37145e5710bSMark Peek }
372c80476e4SDavid E. O'Brien vl = *fnv;
373c80476e4SDavid E. O'Brien
374c80476e4SDavid E. O'Brien /*
375c80476e4SDavid E. O'Brien * Step 4: expand .. if the variable symlinks==expand is set
3766767bd61SMark Peek */
377c80476e4SDavid E. O'Brien if (symlinks == SYM_EXPAND) {
378c80476e4SDavid E. O'Brien for (s = *vl; s; s = *++vl) {
37945e5710bSMark Peek *vl = dnormalize(s, 1);
380c80476e4SDavid E. O'Brien xfree(s);
3813b6eaa7bSAndrey A. Chernov }
382c80476e4SDavid E. O'Brien }
38345e5710bSMark Peek
38445e5710bSMark Peek done:
38545e5710bSMark Peek cleanup_ignore(fnv);
38645e5710bSMark Peek cleanup_until(fnv);
38745e5710bSMark Peek vl = *fnv;
38845e5710bSMark Peek xfree(fnv);
389c80476e4SDavid E. O'Brien return vl;
390c80476e4SDavid E. O'Brien }
391c80476e4SDavid E. O'Brien
39245e5710bSMark Peek static Char *
handleone(Char * str,Char ** vl,int action)393c80476e4SDavid E. O'Brien handleone(Char *str, Char **vl, int action)
39445e5710bSMark Peek {
395c80476e4SDavid E. O'Brien 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:
40545e5710bSMark Peek chars = 0;
40645e5710bSMark Peek for (t = vl; (p = *t++) != NULL; chars++)
40745e5710bSMark Peek chars += Strlen(p);
40845e5710bSMark Peek str = xmalloc(chars * sizeof(Char));
409c80476e4SDavid E. O'Brien 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;
41745e5710bSMark Peek case G_IGNORE:
418c80476e4SDavid E. O'Brien 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
42745e5710bSMark Peek static Char **
libglob(Char ** vl)428c80476e4SDavid E. O'Brien 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
435c80476e4SDavid E. O'Brien if (adrof(STRglobdot))
436c80476e4SDavid E. O'Brien gflgs |= GLOB_DOT;
437c80476e4SDavid E. O'Brien
438c80476e4SDavid E. O'Brien if (adrof(STRglobstar))
439c80476e4SDavid E. O'Brien gflgs |= GLOB_STAR;
440c80476e4SDavid E. O'Brien
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);
47345e5710bSMark Peek vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
474c80476e4SDavid E. O'Brien NULL : blk2short(globv.gl_pathv);
475c80476e4SDavid E. O'Brien globfree(&globv);
47645e5710bSMark Peek return (vl);
477c80476e4SDavid E. O'Brien }
478c80476e4SDavid E. O'Brien
479c80476e4SDavid E. O'Brien Char *
globone(Char * str,int action)480c80476e4SDavid E. O'Brien globone(Char *str, int action)
48145e5710bSMark Peek {
482c80476e4SDavid E. O'Brien Char *v[2], **vl, **vo;
483c80476e4SDavid E. O'Brien 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;
488c80476e4SDavid E. O'Brien gflg = tglob(v);
48945e5710bSMark Peek if (gflg == G_NONE)
490c80476e4SDavid E. O'Brien return (strip(Strsave(str)));
49145e5710bSMark Peek
49245e5710bSMark Peek if (gflg & G_CSH) {
493c80476e4SDavid E. O'Brien /*
49445e5710bSMark Peek * Expand back-quote, tilde and brace
495c80476e4SDavid E. O'Brien */
496c80476e4SDavid E. O'Brien vo = globexpand(v, noglob);
497c80476e4SDavid E. O'Brien if (noglob || (gflg & G_GLOB) == 0) {
498c80476e4SDavid E. O'Brien vl = vo;
499c80476e4SDavid E. O'Brien goto result;
500c80476e4SDavid E. O'Brien }
501c80476e4SDavid E. O'Brien cleanup_push(vo, blk_cleanup);
50245e5710bSMark Peek }
50345e5710bSMark Peek else if (noglob || (gflg & G_GLOB) == 0)
50445e5710bSMark Peek return (strip(Strsave(str)));
50545e5710bSMark Peek else
50645e5710bSMark Peek vo = v;
50745e5710bSMark Peek
508c80476e4SDavid E. O'Brien vl = libglob(vo);
509c80476e4SDavid E. O'Brien if (gflg & G_CSH) {
510c80476e4SDavid E. O'Brien if (vl != vo)
511c80476e4SDavid E. O'Brien cleanup_until(vo);
51245e5710bSMark Peek else
513c80476e4SDavid E. O'Brien 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 }
519c80476e4SDavid E. O'Brien result:
520c80476e4SDavid E. O'Brien if (vl && vl[0] == NULL) {
52145e5710bSMark Peek if (vl != v)
522c80476e4SDavid E. O'Brien xfree(vl);
523c80476e4SDavid E. O'Brien return (Strsave(STRNULL));
524c80476e4SDavid E. O'Brien }
525c80476e4SDavid E. O'Brien if (vl && vl[1])
526c80476e4SDavid E. O'Brien return (handleone(str, vl, action));
52745e5710bSMark Peek else {
528c80476e4SDavid E. O'Brien str = strip(*vl);
529c80476e4SDavid E. O'Brien if (vl != v)
53045e5710bSMark Peek xfree(vl);
531c80476e4SDavid E. O'Brien return (str);
53245e5710bSMark Peek }
53345e5710bSMark Peek }
534c80476e4SDavid E. O'Brien
535c80476e4SDavid E. O'Brien Char **
globall(Char ** v,int gflg)536c80476e4SDavid E. O'Brien globall(Char **v, int gflg)
537c80476e4SDavid E. O'Brien {
538c80476e4SDavid E. O'Brien Char **vl, **vo;
539c80476e4SDavid E. O'Brien int noglob;
540c80476e4SDavid E. O'Brien
54145e5710bSMark Peek if (!v || !v[0])
542c80476e4SDavid E. O'Brien return saveblk(v);
543c80476e4SDavid E. O'Brien
544c80476e4SDavid E. O'Brien noglob = adrof(STRnoglob) != 0;
545c80476e4SDavid E. O'Brien
54645e5710bSMark Peek if (gflg & G_CSH)
547c80476e4SDavid E. O'Brien /*
54845e5710bSMark Peek * Expand back-quote, tilde and brace
54945e5710bSMark Peek */
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);
557c80476e4SDavid E. O'Brien if (vl == vo)
55845e5710bSMark Peek cleanup_ignore(vo);
55945e5710bSMark Peek cleanup_until(vo);
560c80476e4SDavid E. O'Brien }
56145e5710bSMark Peek else
56245e5710bSMark Peek trim(vl);
56345e5710bSMark Peek
56445e5710bSMark Peek return vl;
56545e5710bSMark Peek }
56645e5710bSMark Peek
56745e5710bSMark Peek Char **
glob_all_or_error(Char ** v)56845e5710bSMark Peek glob_all_or_error(Char **v)
56945e5710bSMark Peek {
57045e5710bSMark Peek int gflag;
57145e5710bSMark Peek
57245e5710bSMark Peek gflag = tglob(v);
573c80476e4SDavid E. O'Brien if (gflag) {
574c80476e4SDavid E. O'Brien v = globall(v, gflag);
575c80476e4SDavid E. O'Brien if (v == NULL)
57645e5710bSMark Peek stderror(ERR_NAME | ERR_NOMATCH);
577c80476e4SDavid E. O'Brien } else {
57823338178SMark Peek v = saveblk(v);
579c80476e4SDavid E. O'Brien trim(v);
580c80476e4SDavid E. O'Brien }
581c80476e4SDavid E. O'Brien return v;
582c80476e4SDavid E. O'Brien }
583c80476e4SDavid E. O'Brien
584c80476e4SDavid E. O'Brien void
rscan(Char ** t,void (* f)(Char))585c80476e4SDavid E. O'Brien rscan(Char **t, void (*f) (Char))
58645e5710bSMark Peek {
587c80476e4SDavid E. O'Brien Char *p;
58823338178SMark Peek
589c80476e4SDavid E. O'Brien 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)
59645e5710bSMark Peek {
597c80476e4SDavid E. O'Brien Char *p;
59845e5710bSMark Peek
59945e5710bSMark Peek while ((p = *t++) != NULL)
600c80476e4SDavid E. O'Brien while (*p) {
60145e5710bSMark Peek #if INVALID_BYTE != 0
602c80476e4SDavid E. O'Brien if ((*p & INVALID_BYTE) != INVALID_BYTE) /* *p < INVALID_BYTE */
603c80476e4SDavid E. O'Brien #endif
604c80476e4SDavid E. O'Brien *p &= TRIM;
605c80476e4SDavid E. O'Brien p++;
606c80476e4SDavid E. O'Brien }
607c80476e4SDavid E. O'Brien }
60845e5710bSMark Peek
60945e5710bSMark Peek int
tglob(Char ** t)610c80476e4SDavid E. O'Brien tglob(Char **t)
611c80476e4SDavid E. O'Brien {
612c80476e4SDavid E. O'Brien int gflag;
613c80476e4SDavid E. O'Brien const Char *p;
614c80476e4SDavid E. O'Brien
615c80476e4SDavid E. O'Brien gflag = 0;
61645e5710bSMark Peek 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;
622c80476e4SDavid E. O'Brien while (*p != '\0') {
623c80476e4SDavid E. O'Brien if (*p == '`') {
62445e5710bSMark Peek 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\
62845e5710bSMark Peek * 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++ == '\\') {
63345e5710bSMark Peek if (*p) /* Quoted chars */
634c80476e4SDavid E. O'Brien p++;
63545e5710bSMark Peek 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 }
642c80476e4SDavid E. O'Brien else if (*p == '{')
643c80476e4SDavid E. O'Brien gflag |= G_CSH;
644c80476e4SDavid E. O'Brien 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++;
65045e5710bSMark Peek }
65145e5710bSMark Peek }
652c80476e4SDavid E. O'Brien return gflag;
65345e5710bSMark Peek }
65445e5710bSMark Peek
655c80476e4SDavid E. O'Brien /*
65645e5710bSMark Peek * Command substitute cp. If literal, then this is a substitution from a
65745e5710bSMark Peek * << redirection, and so we should not crunch blanks and tabs, separating
65845e5710bSMark Peek * words only at newlines.
65945e5710bSMark Peek */
66045e5710bSMark Peek Char **
dobackp(Char * cp,int literal)661c80476e4SDavid E. O'Brien dobackp(Char *cp, int literal)
662c80476e4SDavid E. O'Brien {
663c80476e4SDavid E. O'Brien struct Strbuf word = Strbuf_INIT;
664c80476e4SDavid E. O'Brien struct blk_buf bb = BLK_BUF_INIT;
665c80476e4SDavid E. O'Brien Char *lp, *rp, *ep;
666c80476e4SDavid E. O'Brien
667c80476e4SDavid E. O'Brien cleanup_push(&bb, bb_cleanup);
66845e5710bSMark Peek cleanup_push(&word, Strbuf_cleanup);
66945e5710bSMark Peek 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;
67545e5710bSMark Peek lp++;
676c80476e4SDavid E. O'Brien for (rp = lp; *rp && *rp != '`'; rp++)
677c80476e4SDavid E. O'Brien if (*rp == '\\') {
67845e5710bSMark Peek rp++;
67945e5710bSMark Peek if (!*rp)
68045e5710bSMark Peek goto oops;
68145e5710bSMark Peek }
68245e5710bSMark Peek if (!*rp) {
683c80476e4SDavid E. O'Brien oops:
684c80476e4SDavid E. O'Brien cleanup_until(&bb);
685c80476e4SDavid E. O'Brien stderror(ERR_UNMATCHED, '`');
686c80476e4SDavid E. O'Brien }
68745e5710bSMark Peek ep = Strnsave(lp, rp - lp);
688c80476e4SDavid E. O'Brien cleanup_push(ep, xfree);
68923338178SMark Peek backeval(&bb, &word, ep, literal);
69023338178SMark Peek cleanup_until(ep);
691c80476e4SDavid E. O'Brien cp = rp + 1;
69223338178SMark Peek }
693c80476e4SDavid E. O'Brien if (word.len != 0)
694c80476e4SDavid E. O'Brien pword(&bb, &word);
695c80476e4SDavid E. O'Brien cleanup_ignore(&bb);
696c80476e4SDavid E. O'Brien cleanup_until(&bb);
697c80476e4SDavid E. O'Brien 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)702c80476e4SDavid E. O'Brien backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
703c80476e4SDavid E. O'Brien {
704c80476e4SDavid E. O'Brien ssize_t icnt;
705c80476e4SDavid E. O'Brien Char c, *ip;
706c80476e4SDavid E. O'Brien struct command faket;
707c80476e4SDavid E. O'Brien 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;
713c80476e4SDavid E. O'Brien if (!literal) {
714c80476e4SDavid E. O'Brien for (ip = cp; (*ip & QUOTE) != 0; ip++)
715c80476e4SDavid E. O'Brien continue;
716c80476e4SDavid E. O'Brien quoted = *ip == '\0';
71745e5710bSMark Peek } else
718c80476e4SDavid E. O'Brien 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;
72545e5710bSMark Peek fakecom[0] = STRfakecom1;
72645e5710bSMark Peek fakecom[1] = 0;
727c80476e4SDavid E. O'Brien
72823338178SMark Peek /*
72945e5710bSMark Peek * We do the psave job to temporarily change the current job so that the
73045e5710bSMark Peek * 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
73245e5710bSMark Peek * 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();
73629301572SMark Peek cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
737c80476e4SDavid E. O'Brien
73829301572SMark Peek /*
73929301572SMark Peek * It would be nicer if we could integrate this redirection more with the
74023338178SMark Peek * routines in sh.sem.c by doing a fake execute on a builtin function that
74129301572SMark Peek * was piped out.
74229301572SMark Peek */
743c80476e4SDavid E. O'Brien mypipe(pvec);
744c80476e4SDavid E. O'Brien cleanup_push(&pvec[0], open_cleanup);
745c80476e4SDavid E. O'Brien cleanup_push(&pvec[1], open_cleanup);
746c80476e4SDavid E. O'Brien if (pfork(&faket, -1) == 0) {
747c80476e4SDavid E. O'Brien jmp_buf_t osetexit;
748c80476e4SDavid E. O'Brien struct command *t;
749c80476e4SDavid E. O'Brien size_t omark;
750c80476e4SDavid E. O'Brien
751c80476e4SDavid E. O'Brien xclose(pvec[0]);
75223338178SMark Peek (void) dmove(pvec[1], 1);
75345e5710bSMark Peek (void) dmove(SHDIAG, 2);
75423338178SMark Peek initdesc();
75523338178SMark Peek closem();
75623338178SMark Peek arginp = cp;
75723338178SMark Peek for (arginp = cp; *cp; cp++) {
75823338178SMark Peek *cp &= TRIM;
75923338178SMark Peek if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
76023338178SMark Peek *cp = ' ';
76123338178SMark Peek }
76245e5710bSMark Peek
76323338178SMark Peek /*
76423338178SMark Peek * In the child ``forget'' everything about current aliases or
76523338178SMark Peek * eval vectors.
76623338178SMark Peek */
76745e5710bSMark Peek alvec = NULL;
76823338178SMark Peek evalvec = NULL;
76923338178SMark Peek alvecp = NULL;
77023338178SMark Peek evalp = NULL;
771c80476e4SDavid E. O'Brien
77245e5710bSMark Peek omark = cleanup_push_mark();
773c80476e4SDavid E. O'Brien getexit(osetexit);
774c80476e4SDavid E. O'Brien for (;;) {
775c80476e4SDavid E. O'Brien struct wordent paraml1;
776c80476e4SDavid E. O'Brien initlex(¶ml1);
77745e5710bSMark Peek
778c80476e4SDavid E. O'Brien (void) setexit();
779c80476e4SDavid E. O'Brien justpr = 0;
780c80476e4SDavid E. O'Brien
78145e5710bSMark Peek if (haderr) {
782c80476e4SDavid E. O'Brien /* unwind */
783c80476e4SDavid E. O'Brien doneinp = 0;
78445e5710bSMark Peek cleanup_pop_mark(omark);
785c80476e4SDavid E. O'Brien resexit(osetexit);
786c80476e4SDavid E. O'Brien reset();
78745e5710bSMark Peek }
788c80476e4SDavid E. O'Brien if (seterr) {
78929301572SMark Peek xfree(seterr);
79023338178SMark Peek seterr = NULL;
79145e5710bSMark Peek }
79223338178SMark Peek
793c80476e4SDavid E. O'Brien freelex(¶ml1);
79445e5710bSMark Peek (void) lex(¶ml1);
795c80476e4SDavid E. O'Brien cleanup_push(¶ml1, lex_cleanup);
796c80476e4SDavid E. O'Brien if (seterr)
797c80476e4SDavid E. O'Brien stderror(ERR_OLD);
798c80476e4SDavid E. O'Brien alias(¶ml1);
79923338178SMark Peek t = syntax(paraml1.next, ¶ml1, 0);
800c80476e4SDavid E. O'Brien cleanup_push(t, syntax_cleanup);
80123338178SMark Peek /* The F_BACKQ flag must set so the job output is correct if
802c80476e4SDavid E. O'Brien * printexitvalue is set. If it's not set, the job output
80323338178SMark Peek * will have "Exit N" appended where N is the exit status. */
80423338178SMark Peek if (t)
805c80476e4SDavid E. O'Brien t->t_dflg = F_BACKQ|F_NOFORK;
806c80476e4SDavid E. O'Brien if (seterr)
80745e5710bSMark Peek stderror(ERR_OLD);
80823338178SMark Peek #ifdef SIGTSTP
809c80476e4SDavid E. O'Brien signal(SIGTSTP, SIG_IGN);
81023338178SMark Peek #endif
81123338178SMark Peek #ifdef SIGTTIN
81223338178SMark Peek signal(SIGTTIN, SIG_IGN);
81323338178SMark Peek #endif
814c80476e4SDavid E. O'Brien #ifdef SIGTTOU
81523338178SMark Peek signal(SIGTTOU, SIG_IGN);
81623338178SMark Peek #endif
81723338178SMark Peek execute(t, -1, NULL, NULL, TRUE);
81823338178SMark Peek
81923338178SMark Peek cleanup_until(¶ml1);
82023338178SMark Peek }
82123338178SMark Peek }
82223338178SMark Peek cleanup_until(&pvec[1]);
82323338178SMark Peek c = 0;
82423338178SMark Peek ip = NULL;
82523338178SMark Peek do {
82623338178SMark Peek ssize_t cnt = 0;
82723338178SMark Peek
82823338178SMark Peek for (;;) {
82923338178SMark Peek if (icnt == 0) {
83023338178SMark Peek ip = ibuf;
83123338178SMark Peek icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
83223338178SMark Peek if (icnt <= 0)
83323338178SMark Peek goto eof;
83423338178SMark Peek }
83523338178SMark Peek if (hadnl)
83623338178SMark Peek break;
83723338178SMark Peek --icnt;
838c80476e4SDavid E. O'Brien c = (*ip++ & TRIM);
839c80476e4SDavid E. O'Brien if (c == 0)
840c80476e4SDavid E. O'Brien break;
841c80476e4SDavid E. O'Brien #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
842c80476e4SDavid E. O'Brien if (c == '\r')
843c80476e4SDavid E. O'Brien c = ' ';
844c80476e4SDavid E. O'Brien #endif /* WINNT_NATIVE || __CYGWIN__ */
8453b6eaa7bSAndrey A. Chernov if (c == '\n') {
846c80476e4SDavid E. O'Brien /*
847c80476e4SDavid E. O'Brien * Continue around the loop one more time, so that we can eat
8483b6eaa7bSAndrey A. Chernov * 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++;
856c80476e4SDavid E. O'Brien if (c == '\\' || quoted)
857c80476e4SDavid E. O'Brien c |= QUOTE;
858c80476e4SDavid E. O'Brien Strbuf_append1(word, c);
859c80476e4SDavid E. O'Brien }
86045e5710bSMark Peek /*
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 */
866c80476e4SDavid E. O'Brien if (c != 0 && (cnt || literal))
867c80476e4SDavid E. O'Brien pword(bb, word);
86823338178SMark Peek hadnl = 0;
86945e5710bSMark Peek } while (c > 0);
870c80476e4SDavid E. O'Brien eof:
87123338178SMark Peek cleanup_until(&pvec[0]);
87223338178SMark Peek pwait();
87345e5710bSMark Peek cleanup_until(&faket); /* psavejob_cleanup(); */
874c80476e4SDavid E. O'Brien }
87545e5710bSMark Peek
876c80476e4SDavid E. O'Brien static void
pword(struct blk_buf * bb,struct Strbuf * word)877c80476e4SDavid E. O'Brien 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);
882c80476e4SDavid E. O'Brien bb_append(bb, s);
88345e5710bSMark Peek *word = Strbuf_init;
88445e5710bSMark Peek }
88545e5710bSMark Peek
886c80476e4SDavid E. O'Brien int
Gmatch(const Char * string,const Char * pattern)887c80476e4SDavid E. O'Brien Gmatch(const Char *string, const Char *pattern)
888c80476e4SDavid E. O'Brien {
88945e5710bSMark Peek 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)893c80476e4SDavid E. O'Brien Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
894c80476e4SDavid E. O'Brien {
89545e5710bSMark Peek Char ***fblk, **p;
896c80476e4SDavid E. O'Brien const Char *tstring = string;
89745e5710bSMark Peek int gpol = 1, gres = 0;
89845e5710bSMark Peek
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
904c80476e4SDavid E. O'Brien fblk = xmalloc(sizeof(Char ***));
905c80476e4SDavid E. O'Brien *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
90645e5710bSMark Peek (*fblk)[0] = Strsave(pattern);
90745e5710bSMark Peek (*fblk)[1] = NULL;
90845e5710bSMark Peek
90945e5710bSMark Peek cleanup_push(fblk, blk_indirect_cleanup);
910c80476e4SDavid E. O'Brien expbrace(fblk, NULL, GLOBSPACE);
91145e5710bSMark Peek
91245e5710bSMark Peek if (endstr == NULL)
913c80476e4SDavid E. O'Brien /* Exact matches only */
914c80476e4SDavid E. O'Brien for (p = *fblk; *p; p++)
915c80476e4SDavid E. O'Brien gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
91645e5710bSMark Peek else {
91723338178SMark Peek const Char *end;
918c80476e4SDavid E. O'Brien
91945e5710bSMark Peek /* partial matches */
92045e5710bSMark Peek end = Strend(string);
921c80476e4SDavid E. O'Brien for (p = *fblk; *p; p++)
92245e5710bSMark Peek if (t_pmatch(string, *p, &tstring, 1) != 0) {
92345e5710bSMark Peek gres |= 1;
92423338178SMark Peek if (end > tstring)
925c80476e4SDavid E. O'Brien end = tstring;
92645e5710bSMark Peek }
92745e5710bSMark Peek *endstr = end;
928c80476e4SDavid E. O'Brien }
92945e5710bSMark Peek
930c80476e4SDavid E. O'Brien cleanup_until(fblk);
931c80476e4SDavid E. O'Brien return(gres == gpol);
93245e5710bSMark Peek }
933c80476e4SDavid E. O'Brien
934c80476e4SDavid E. O'Brien /* t_pmatch():
935c80476e4SDavid E. O'Brien * Return 2 on exact match,
936b2d5d167SMark Peek * 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 */
940c80476e4SDavid E. O'Brien int
t_pmatch(const Char * string,const Char * pattern,const Char ** estr,int cs)941c80476e4SDavid E. O'Brien t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
942b2d5d167SMark Peek {
94345e5710bSMark Peek Char stringc, patternc, rangec;
944c80476e4SDavid E. O'Brien int match, negate_range;
94545e5710bSMark Peek const Char *pestr, *nstring;
946c80476e4SDavid E. O'Brien
94745e5710bSMark Peek for (nstring = string;; string = nstring) {
948c80476e4SDavid E. O'Brien stringc = *nstring++ & TRIM;
94923338178SMark Peek patternc = *pattern++ & TRIM;
95045e5710bSMark Peek switch (patternc) {
95145e5710bSMark Peek case '\0':
952c80476e4SDavid E. O'Brien *estr = string;
95323338178SMark Peek return (stringc == '\0' ? 2 : 1);
954c80476e4SDavid E. O'Brien case '?':
95523338178SMark Peek 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) {
960c80476e4SDavid E. O'Brien *estr = Strend(string);
961c80476e4SDavid E. O'Brien return (2);
96245e5710bSMark Peek }
963c80476e4SDavid E. O'Brien pestr = NULL;
964c80476e4SDavid E. O'Brien
965c80476e4SDavid E. O'Brien for (;;) {
966c80476e4SDavid E. O'Brien switch(t_pmatch(string, pattern, estr, cs)) {
96723338178SMark Peek case 0:
968b2d5d167SMark Peek break;
969c80476e4SDavid E. O'Brien case 1:
970c80476e4SDavid E. O'Brien pestr = *estr;/*FIXME: does not guarantee longest match */
971c80476e4SDavid E. O'Brien break;
97245e5710bSMark Peek case 2:
973c80476e4SDavid E. O'Brien return 2;
974c80476e4SDavid E. O'Brien default:
975c80476e4SDavid E. O'Brien abort(); /* Cannot happen */
976c80476e4SDavid E. O'Brien }
977c80476e4SDavid E. O'Brien stringc = *string++ & TRIM;
978c80476e4SDavid E. O'Brien if (!stringc)
97945e5710bSMark Peek break;
98023338178SMark Peek }
98123338178SMark Peek
982c80476e4SDavid E. O'Brien if (pestr) {
983c80476e4SDavid E. O'Brien *estr = pestr;
984c80476e4SDavid E. O'Brien return 1;
985c80476e4SDavid E. O'Brien }
986c80476e4SDavid E. O'Brien else
987c80476e4SDavid E. O'Brien return 0;
98845e5710bSMark Peek
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++;
993c80476e4SDavid E. O'Brien while ((rangec = *pattern++ & TRIM) != '\0') {
994c80476e4SDavid E. O'Brien if (rangec == ']')
99545e5710bSMark Peek break;
996c80476e4SDavid E. O'Brien if (match)
997c80476e4SDavid E. O'Brien continue;
998c80476e4SDavid E. O'Brien if (*pattern == '-' && pattern[1] != ']') {
999c80476e4SDavid E. O'Brien Char rangec2;
100023338178SMark Peek pattern++;
100145e5710bSMark Peek rangec2 = *pattern++ & TRIM;
1002c80476e4SDavid E. O'Brien match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
100345e5710bSMark Peek globcharcoll(rangec, stringc, 0) <= 0);
100423338178SMark Peek }
100523338178SMark Peek else
1006c80476e4SDavid E. O'Brien 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'))
1011c80476e4SDavid E. O'Brien return (0);
101223338178SMark Peek if (match == negate_range)
101323338178SMark Peek return (0);
1014c80476e4SDavid E. O'Brien break;
1015c80476e4SDavid E. O'Brien default:
1016c80476e4SDavid E. O'Brien if (cs ? patternc != stringc
1017c80476e4SDavid E. O'Brien : Tolower(patternc) != Tolower(stringc))
101823338178SMark Peek return (0);
101923338178SMark Peek break;
1020c80476e4SDavid E. O'Brien }
1021c80476e4SDavid E. O'Brien }
1022c80476e4SDavid E. O'Brien }
1023c80476e4SDavid E. O'Brien