xref: /freebsd/contrib/tcsh/sh.glob.c (revision a0b9e2e854027e6ff61fb075a1309dbc71c42b54)
1 /*
2  * sh.glob.c: Regular expression expansion
3  */
4 /*-
5  * Copyright (c) 1980, 1991 The Regents of the University of California.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 #include "sh.h"
33 #include "tc.h"
34 #include "tw.h"
35 
36 #include "glob.h"
37 
38 /*
39  * Values for gflag
40  */
41 #define	G_NONE	0		/* No globbing needed			*/
42 #define	G_GLOB	1		/* string contains *?[] characters	*/
43 #define	G_CSH	2		/* string contains ~`{ characters	*/
44 
45 #define	GLOBSPACE	100	/* Alloc increment			*/
46 
47 
48 #define LBRC '{'
49 #define RBRC '}'
50 #define LBRK '['
51 #define RBRK ']'
52 #define EOS '\0'
53 
54 /*
55  * globbing is now done in two stages. In the first pass we expand
56  * csh globbing idioms ~`{ and then we proceed doing the normal
57  * globbing if needed ?*[
58  *
59  * Csh type globbing is handled in globexpand() and the rest is
60  * handled in glob() which is part of the 4.4BSD libc.
61  *
62  */
63 static	Char	 *globtilde	(Char *);
64 static	Char     *handleone	(Char *, Char **, int);
65 static	Char	**libglob	(Char **);
66 static	Char	**globexpand	(Char **, int);
67 static	int	  globbrace	(const Char *, Char ***);
68 static  void	  expbrace	(Char ***, Char ***, int);
69 static	void	  pword		(struct blk_buf *, struct Strbuf *);
70 static	void	  backeval	(struct blk_buf *, struct Strbuf *, Char *,
71 				 int);
72 static Char *
73 globtilde(Char *s)
74 {
75     Char *name, *u, *home, *res;
76 
77     u = s;
78     for (s++; *s && *s != '/' && *s != ':'; s++)
79 	continue;
80     name = Strnsave(u + 1, s - (u + 1));
81     cleanup_push(name, xfree);
82     home = gethdir(name);
83     if (home == NULL) {
84 	if (adrof(STRnonomatch)) {
85 	    cleanup_until(name);
86 	    return u;
87 	}
88 	if (*name)
89 	    stderror(ERR_UNKUSER, short2str(name));
90 	else
91 	    stderror(ERR_NOHOME);
92     }
93     cleanup_until(name);
94     if (home[0] == '/' && home[1] == '\0' && s[0] == '/')
95 	res = Strsave(s);
96     else
97 	res = Strspl(home, s);
98     xfree(home);
99     xfree(u);
100     return res;
101 }
102 
103 /* Returns a newly allocated string, old or NULL */
104 Char *
105 globequal(Char *old)
106 {
107     int     dig;
108     const Char *dir;
109     Char    *b;
110 
111     /*
112      * kfk - 17 Jan 1984 - stack hack allows user to get at arbitrary dir names
113      * in stack. PWP: let =foobar pass through (for X windows)
114      */
115     if (old[1] == '-' && (old[2] == '\0' || old[2] == '/')) {
116 	/* =- */
117 	const Char *olddir = varval (STRowd);
118 
119 	if (olddir && *olddir &&
120 	    !dcwd->di_next->di_name && !dcwd->di_prev->di_name)
121 	    return Strspl(olddir, &old[2]);
122 	dig = -1;
123 	b = &old[2];
124     }
125     else if (Isdigit(old[1])) {
126 	/* =<number> */
127 	dig = old[1] - '0';
128 	for (b = &old[2]; Isdigit(*b); b++)
129 	    dig = dig * 10 + (*b - '0');
130 	if (*b != '\0' && *b != '/')
131 	    /* =<number>foobar */
132 	    return old;
133     }
134     else
135 	/* =foobar */
136 	return old;
137 
138     dir = getstakd(dig);
139     if (dir == NULL)
140 	return NULL;
141     return Strspl(dir, b);
142 }
143 
144 static int
145 globbrace(const Char *s, Char ***bl)
146 {
147     struct Strbuf gbuf = Strbuf_INIT;
148     struct blk_buf bb = BLK_BUF_INIT;
149     int     i;
150     const Char *p, *pm, *pe, *pl;
151     size_t prefix_len;
152 
153     /* copy part up to the brace */
154     for (p = s; *p != LBRC; p++)
155 	;
156     prefix_len = p - s;
157 
158     /* check for balanced braces */
159     for (i = 0, pe = ++p; *pe; pe++)
160 	if (*pe == LBRK) {
161 	    /* Ignore everything between [] */
162 	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
163 		continue;
164 	    if (*pe == EOS)
165 		return (-RBRK);
166 	}
167 	else if (*pe == LBRC)
168 	    i++;
169 	else if (*pe == RBRC) {
170 	    if (i == 0)
171 		break;
172 	    i--;
173 	}
174 
175     if (i != 0 || *pe == '\0')
176 	return (-RBRC);
177 
178     Strbuf_appendn(&gbuf, s, prefix_len);
179 
180     for (i = 0, pl = pm = p; pm <= pe; pm++)
181 	switch (*pm) {
182 	case LBRK:
183 	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
184 		continue;
185 	    if (*pm == EOS) {
186 		bb_cleanup(&bb);
187 		xfree(gbuf.s);
188 		return (-RBRK);
189 	    }
190 	    break;
191 	case LBRC:
192 	    i++;
193 	    break;
194 	case RBRC:
195 	    if (i) {
196 		i--;
197 		break;
198 	    }
199 	    /* FALLTHROUGH */
200 	case ',':
201 	    if (i && *pm == ',')
202 		break;
203 	    else {
204 		gbuf.len = prefix_len;
205 		Strbuf_appendn(&gbuf, pl, pm - pl);
206 		Strbuf_append(&gbuf, pe + 1);
207 		Strbuf_terminate(&gbuf);
208 		bb_append(&bb, Strsave(gbuf.s));
209 		pl = pm + 1;
210 	    }
211 	    break;
212 	default:
213 	    break;
214 	}
215     *bl = bb_finish(&bb);
216     xfree(gbuf.s);
217     return bb.len;
218 }
219 
220 
221 static void
222 expbrace(Char ***nvp, Char ***elp, int size)
223 {
224     Char **vl, **el, **nv, *s;
225 
226     vl = nv = *nvp;
227     if (elp != NULL)
228 	el = *elp;
229     else
230 	el = vl + blklen(vl);
231 
232     for (s = *vl; s; s = *++vl) {
233 	Char  **vp, **bp;
234 
235 	/* leave {} untouched for find */
236 	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
237 	    continue;
238 	if (Strchr(s, '{') != NULL) {
239 	    Char  **bl = NULL;
240 	    int     len;
241 
242 	    if ((len = globbrace(s, &bl)) < 0)
243 		stderror(ERR_MISSING, -len);
244 	    xfree(s);
245 	    if (len == 1) {
246 		*vl-- = *bl;
247 		xfree(bl);
248 		continue;
249 	    }
250 	    if (&el[len] >= &nv[size]) {
251 		size_t l, e;
252 		l = &el[len] - &nv[size];
253 		size += GLOBSPACE > l ? GLOBSPACE : l;
254 		l = vl - nv;
255 		e = el - nv;
256 		nv = xrealloc(nv, size * sizeof(Char *));
257 		*nvp = nv; /* To keep cleanups working */
258 		vl = nv + l;
259 		el = nv + e;
260 	    }
261 	    /* nv vl   el     bl
262 	     * |  |    |      |
263 	     * -.--..--	      x--
264 	     *   |            len
265 	     *   vp
266 	     */
267 	    vp = vl--;
268 	    *vp = *bl;
269 	    len--;
270 	    for (bp = el; bp != vp; bp--)
271 		bp[len] = *bp;
272 	    el += len;
273 	    /* nv vl    el bl
274 	     * |  |     |  |
275 	     * -.-x  ---    --
276 	     *   |len
277 	     *   vp
278 	     */
279 	    vp++;
280 	    for (bp = bl + 1; *bp; *vp++ = *bp++)
281 		continue;
282 	    xfree(bl);
283 	}
284 
285     }
286     if (elp != NULL)
287 	*elp = el;
288 }
289 
290 static Char **
291 globexpand(Char **v, int noglob)
292 {
293     Char   *s;
294     Char  ***fnv, **vl, **el;
295     int     size = GLOBSPACE;
296 
297 
298     fnv = xmalloc(sizeof(Char ***));
299     *fnv = vl = xmalloc(sizeof(Char *) * size);
300     *vl = NULL;
301     cleanup_push(fnv, blk_indirect_cleanup);
302 
303     /*
304      * Step 1: expand backquotes.
305      */
306     while ((s = *v++) != NULL) {
307 	if (Strchr(s, '`')) {
308 	    int     i;
309 	    Char **expanded;
310 
311 	    expanded = dobackp(s, 0);
312 	    for (i = 0; expanded[i] != NULL; i++) {
313 		*vl++ = expanded[i];
314 		if (vl == &(*fnv)[size]) {
315 		    size += GLOBSPACE;
316 		    *fnv = xrealloc(*fnv, size * sizeof(Char *));
317 		    vl = &(*fnv)[size - GLOBSPACE];
318 		}
319 	    }
320 	    xfree(expanded);
321 	}
322 	else {
323 	    *vl++ = Strsave(s);
324 	    if (vl == &(*fnv)[size]) {
325 		size += GLOBSPACE;
326 		*fnv = xrealloc(*fnv, size * sizeof(Char *));
327 		vl = &(*fnv)[size - GLOBSPACE];
328 	    }
329 	}
330 	*vl = NULL;
331     }
332 
333     if (noglob)
334 	goto done;
335 
336     /*
337      * Step 2: expand braces
338      */
339     el = vl;
340     expbrace(fnv, &el, size);
341 
342 
343     /*
344      * Step 3: expand ~ =
345      */
346     vl = *fnv;
347     for (s = *vl; s; s = *++vl)
348 	switch (*s) {
349 	    Char *ns;
350 	case '~':
351 	    *vl = globtilde(s);
352 	    break;
353 	case '=':
354 	    if ((ns = globequal(s)) == NULL) {
355 		if (!adrof(STRnonomatch))
356 		    stderror(ERR_DEEP); /* Error */
357 	    }
358 	    if (ns && ns != s) {
359 		/* Expansion succeeded */
360 		xfree(s);
361 		*vl = ns;
362 	    }
363 	    break;
364 	default:
365 	    break;
366 	}
367     vl = *fnv;
368 
369     /*
370      * Step 4: expand .. if the variable symlinks==expand is set
371      */
372     if (symlinks == SYM_EXPAND) {
373 	for (s = *vl; s; s = *++vl) {
374 	    *vl = dnormalize(s, 1);
375 	    xfree(s);
376 	}
377     }
378 
379  done:
380     cleanup_ignore(fnv);
381     cleanup_until(fnv);
382     vl = *fnv;
383     xfree(fnv);
384     return vl;
385 }
386 
387 static Char *
388 handleone(Char *str, Char **vl, int action)
389 {
390     size_t chars;
391     Char **t, *p, *strp;
392 
393     switch (action) {
394     case G_ERROR:
395 	setname(short2str(str));
396 	blkfree(vl);
397 	stderror(ERR_NAME | ERR_AMBIG);
398 	break;
399     case G_APPEND:
400 	chars = 0;
401 	for (t = vl; (p = *t++) != NULL; chars++)
402 	    chars += Strlen(p);
403 	str = xmalloc(chars * sizeof(Char));
404 	for (t = vl, strp = str; (p = *t++) != NULL; chars++) {
405 	    while (*p)
406 		 *strp++ = *p++ & TRIM;
407 	    *strp++ = ' ';
408 	}
409 	*--strp = '\0';
410 	blkfree(vl);
411 	break;
412     case G_IGNORE:
413 	str = Strsave(strip(*vl));
414 	blkfree(vl);
415 	break;
416     default:
417 	break;
418     }
419     return (str);
420 }
421 
422 static Char **
423 libglob(Char **vl)
424 {
425     int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
426     glob_t  globv;
427     char   *ptr;
428     int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
429 
430     if (adrof(STRglobdot))
431        gflgs |= GLOB_DOT;
432 
433     if (adrof(STRglobstar))
434        gflgs |= GLOB_STAR;
435 
436     if (!vl || !vl[0])
437 	return(vl);
438 
439     globv.gl_offs = 0;
440     globv.gl_pathv = 0;
441     globv.gl_pathc = 0;
442 
443     if (nonomatch)
444 	gflgs |= GLOB_NOCHECK;
445 
446     do {
447 	ptr = short2qstr(*vl);
448 	switch (glob(ptr, gflgs, 0, &globv)) {
449 	case GLOB_ABEND:
450 	    globfree(&globv);
451 	    setname(ptr);
452 	    stderror(ERR_NAME | ERR_GLOB);
453 	    /* NOTREACHED */
454 	case GLOB_NOSPACE:
455 	    globfree(&globv);
456 	    stderror(ERR_NOMEM);
457 	    /* NOTREACHED */
458 	default:
459 	    break;
460 	}
461 	if (globv.gl_flags & GLOB_MAGCHAR) {
462 	    match |= (globv.gl_matchc != 0);
463 	    magic = 1;
464 	}
465 	gflgs |= GLOB_APPEND;
466     }
467     while (*++vl);
468     vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
469 	NULL : blk2short(globv.gl_pathv);
470     globfree(&globv);
471     return (vl);
472 }
473 
474 Char   *
475 globone(Char *str, int action)
476 {
477     Char   *v[2], **vl, **vo;
478     int gflg, noglob;
479 
480     noglob = adrof(STRnoglob) != 0;
481     v[0] = str;
482     v[1] = 0;
483     gflg = tglob(v);
484     if (gflg == G_NONE)
485 	return (strip(Strsave(str)));
486 
487     if (gflg & G_CSH) {
488 	/*
489 	 * Expand back-quote, tilde and brace
490 	 */
491 	vo = globexpand(v, noglob);
492 	if (noglob || (gflg & G_GLOB) == 0) {
493 	    vl = vo;
494 	    goto result;
495 	}
496 	cleanup_push(vo, blk_cleanup);
497     }
498     else if (noglob || (gflg & G_GLOB) == 0)
499 	return (strip(Strsave(str)));
500     else
501 	vo = v;
502 
503     vl = libglob(vo);
504     if (gflg & G_CSH) {
505     	if (vl != vo)
506 	    cleanup_until(vo);
507 	else
508 	    cleanup_ignore(vo);
509     }
510     if (vl == NULL) {
511 	setname(short2str(str));
512 	stderror(ERR_NAME | ERR_NOMATCH);
513     }
514  result:
515     if (vl && vl[0] == NULL) {
516 	xfree(vl);
517 	return (Strsave(STRNULL));
518     }
519     if (vl && vl[1])
520 	return (handleone(str, vl, action));
521     else {
522 	str = strip(*vl);
523 	xfree(vl);
524 	return (str);
525     }
526 }
527 
528 Char  **
529 globall(Char **v, int gflg)
530 {
531     Char  **vl, **vo;
532     int noglob;
533 
534     if (!v || !v[0])
535 	return saveblk(v);
536 
537     noglob = adrof(STRnoglob) != 0;
538 
539     if (gflg & G_CSH)
540 	/*
541 	 * Expand back-quote, tilde and brace
542 	 */
543 	vl = vo = globexpand(v, noglob);
544     else
545 	vl = vo = saveblk(v);
546 
547     if (!noglob && (gflg & G_GLOB)) {
548 	cleanup_push(vo, blk_cleanup);
549 	vl = libglob(vo);
550 	if (vl == vo)
551 	    cleanup_ignore(vo);
552 	cleanup_until(vo);
553     }
554     else
555 	trim(vl);
556 
557     return vl;
558 }
559 
560 Char **
561 glob_all_or_error(Char **v)
562 {
563     int gflag;
564 
565     gflag = tglob(v);
566     if (gflag) {
567 	v = globall(v, gflag);
568 	if (v == NULL)
569 	    stderror(ERR_NAME | ERR_NOMATCH);
570     } else {
571 	v = saveblk(v);
572 	trim(v);
573     }
574     return v;
575 }
576 
577 void
578 rscan(Char **t, void (*f) (Char))
579 {
580     Char *p;
581 
582     while ((p = *t++) != NULL)
583 	while (*p)
584 	    (*f) (*p++);
585 }
586 
587 void
588 trim(Char **t)
589 {
590     Char *p;
591 
592     while ((p = *t++) != NULL)
593 	while (*p) {
594 #if INVALID_BYTE != 0
595 	    if ((*p & INVALID_BYTE) != INVALID_BYTE)	/* *p < INVALID_BYTE */
596 #endif
597 		*p &= TRIM;
598 	    p++;
599 	}
600 }
601 
602 int
603 tglob(Char **t)
604 {
605     int gflag;
606     const Char *p;
607 
608     gflag = 0;
609     while ((p = *t++) != NULL) {
610 	if (*p == '~' || *p == '=')
611 	    gflag |= G_CSH;
612 	else if (*p == '{' &&
613 		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
614 	    continue;
615 	while (*p != '\0') {
616 	    if (*p == '`') {
617 		gflag |= G_CSH;
618 #ifdef notdef
619 		/*
620 		 * We do want to expand echo `echo '*'`, so we don't\
621 		 * use this piece of code anymore.
622 		 */
623 		p++;
624 		while (*p && *p != '`')
625 		    if (*p++ == '\\') {
626 			if (*p)		/* Quoted chars */
627 			    p++;
628 			else
629 			    break;
630 		    }
631 		if (!*p)		/* The matching ` */
632 		    break;
633 #endif
634 	    }
635 	    else if (*p == '{')
636 		gflag |= G_CSH;
637 	    else if (isglob(*p))
638 		gflag |= G_GLOB;
639 	    else if (symlinks == SYM_EXPAND &&
640 		p[1] && ISDOTDOT(p) && (p == *(t-1) || *(p-1) == '/') )
641 	    	gflag |= G_CSH;
642 	    p++;
643 	}
644     }
645     return gflag;
646 }
647 
648 /*
649  * Command substitute cp.  If literal, then this is a substitution from a
650  * << redirection, and so we should not crunch blanks and tabs, separating
651  * words only at newlines.
652  */
653 Char  **
654 dobackp(Char *cp, int literal)
655 {
656     struct Strbuf word = Strbuf_INIT;
657     struct blk_buf bb = BLK_BUF_INIT;
658     Char *lp, *rp, *ep;
659 
660     cleanup_push(&bb, bb_cleanup);
661     cleanup_push(&word, Strbuf_cleanup);
662     for (;;) {
663 	for (lp = cp; *lp != '\0' && *lp != '`'; lp++)
664 	    ;
665 	Strbuf_appendn(&word, cp, lp - cp);
666 	if (*lp == 0)
667 	    break;
668 	lp++;
669 	for (rp = lp; *rp && *rp != '`'; rp++)
670 	    if (*rp == '\\') {
671 		rp++;
672 		if (!*rp)
673 		    goto oops;
674 	    }
675 	if (!*rp) {
676 	oops:
677 	    cleanup_until(&bb);
678 	    stderror(ERR_UNMATCHED, '`');
679 	}
680 	ep = Strnsave(lp, rp - lp);
681 	cleanup_push(ep, xfree);
682 	backeval(&bb, &word, ep, literal);
683 	cleanup_until(ep);
684 	cp = rp + 1;
685     }
686     if (word.len != 0)
687 	pword(&bb, &word);
688     cleanup_ignore(&bb);
689     cleanup_until(&bb);
690     return bb_finish(&bb);
691 }
692 
693 
694 static void
695 backeval(struct blk_buf *bb, struct Strbuf *word, Char *cp, int literal)
696 {
697     ssize_t icnt;
698     Char c, *ip;
699     struct command faket;
700     int    hadnl;
701     int     pvec[2], quoted;
702     Char   *fakecom[2], ibuf[BUFSIZE];
703 
704     hadnl = 0;
705     icnt = 0;
706     if (!literal) {
707 	for (ip = cp; (*ip & QUOTE) != 0; ip++)
708 		continue;
709 	quoted = *ip == '\0';
710     } else
711 	quoted = literal;
712     faket.t_dtyp = NODE_COMMAND;
713     faket.t_dflg = F_BACKQ;
714     faket.t_dlef = 0;
715     faket.t_drit = 0;
716     faket.t_dspr = 0;
717     faket.t_dcom = fakecom;
718     fakecom[0] = STRfakecom1;
719     fakecom[1] = 0;
720 
721     /*
722      * We do the psave job to temporarily change the current job so that the
723      * following fork is considered a separate job.  This is so that when
724      * backquotes are used in a builtin function that calls glob the "current
725      * job" is not corrupted.  We only need one level of pushed jobs as long as
726      * we are sure to fork here.
727      */
728     psavejob();
729     cleanup_push(&faket, psavejob_cleanup); /* faket is only a marker */
730 
731     /*
732      * It would be nicer if we could integrate this redirection more with the
733      * routines in sh.sem.c by doing a fake execute on a builtin function that
734      * was piped out.
735      */
736     mypipe(pvec);
737     cleanup_push(&pvec[0], open_cleanup);
738     cleanup_push(&pvec[1], open_cleanup);
739     if (pfork(&faket, -1) == 0) {
740 	jmp_buf_t osetexit;
741 	struct command *t;
742 	size_t omark;
743 
744 	xclose(pvec[0]);
745 	(void) dmove(pvec[1], 1);
746 	(void) dmove(SHDIAG,  2);
747 	initdesc();
748 	closem();
749 	arginp = cp;
750 	for (arginp = cp; *cp; cp++) {
751 	    *cp &= TRIM;
752 	    if (is_set(STRcsubstnonl) && (*cp == '\n' || *cp == '\r'))
753 		*cp = ' ';
754 	}
755 
756         /*
757 	 * In the child ``forget'' everything about current aliases or
758 	 * eval vectors.
759 	 */
760 	alvec = NULL;
761 	evalvec = NULL;
762 	alvecp = NULL;
763 	evalp = NULL;
764 
765 	omark = cleanup_push_mark();
766 	getexit(osetexit);
767 	for (;;) {
768 	    struct wordent paraml1;
769 	    initlex(&paraml1);
770 
771 	    (void) setexit();
772 	    justpr = 0;
773 
774 	    if (haderr) {
775 		/* unwind */
776 		doneinp = 0;
777 		cleanup_pop_mark(omark);
778 		resexit(osetexit);
779 		reset();
780 	    }
781 	    if (seterr) {
782 		xfree(seterr);
783 		seterr = NULL;
784 	    }
785 
786 	    freelex(&paraml1);
787 	    (void) lex(&paraml1);
788 	    cleanup_push(&paraml1, lex_cleanup);
789 	    if (seterr)
790 		stderror(ERR_OLD);
791 	    alias(&paraml1);
792 	    t = syntax(paraml1.next, &paraml1, 0);
793 	    cleanup_push(t, syntax_cleanup);
794 	    /* The F_BACKQ flag must set so the job output is correct if
795 	     * printexitvalue is set.  If it's not set, the job output
796 	     * will have "Exit N" appended where N is the exit status. */
797 	    if (t)
798 		    t->t_dflg = F_BACKQ|F_NOFORK;
799 	    if (seterr)
800 		stderror(ERR_OLD);
801 #ifdef SIGTSTP
802 	    signal(SIGTSTP, SIG_IGN);
803 #endif
804 #ifdef SIGTTIN
805 	    signal(SIGTTIN, SIG_IGN);
806 #endif
807 #ifdef SIGTTOU
808 	    signal(SIGTTOU, SIG_IGN);
809 #endif
810 	    execute(t, -1, NULL, NULL, TRUE);
811 
812 	    cleanup_until(&paraml1);
813 	}
814     }
815     cleanup_until(&pvec[1]);
816     c = 0;
817     ip = NULL;
818     do {
819 	ssize_t     cnt = 0;
820 
821 	for (;;) {
822 	    if (icnt == 0) {
823 		ip = ibuf;
824 		icnt = wide_read(pvec[0], ibuf, BUFSIZE, 0);
825 		if (icnt <= 0)
826 		    goto eof;
827 	    }
828 	    if (hadnl)
829 		break;
830 	    --icnt;
831 	    c = (*ip++ & TRIM);
832 	    if (c == 0)
833 		break;
834 #if defined(WINNT_NATIVE) || defined(__CYGWIN__)
835 	    if (c == '\r')
836 	    	c = ' ';
837 #endif /* WINNT_NATIVE || __CYGWIN__ */
838 	    if (c == '\n') {
839 		/*
840 		 * Continue around the loop one more time, so that we can eat
841 		 * the last newline without terminating this word.
842 		 */
843 		hadnl = 1;
844 		continue;
845 	    }
846 	    if (!quoted && (c == ' ' || c == '\t'))
847 		break;
848 	    cnt++;
849 	    if (c == '\\' || quoted)
850 		c |= QUOTE;
851 	    Strbuf_append1(word, c);
852 	}
853 	/*
854 	 * Unless at end-of-file, we will form a new word here if there were
855 	 * characters in the word, or in any case when we take text literally.
856 	 * If we didn't make empty words here when literal was set then we
857 	 * would lose blank lines.
858 	 */
859 	if (c != 0 && (cnt || literal))
860 	    pword(bb, word);
861 	hadnl = 0;
862     } while (c > 0);
863  eof:
864     cleanup_until(&pvec[0]);
865     pwait();
866     cleanup_until(&faket); /* psavejob_cleanup(); */
867 }
868 
869 static void
870 pword(struct blk_buf *bb, struct Strbuf *word)
871 {
872     Char *s;
873 
874     s = Strbuf_finish(word);
875     bb_append(bb, s);
876     *word = Strbuf_init;
877 }
878 
879 int
880 Gmatch(const Char *string, const Char *pattern)
881 {
882     return Gnmatch(string, pattern, NULL);
883 }
884 
885 int
886 Gnmatch(const Char *string, const Char *pattern, const Char **endstr)
887 {
888     Char ***fblk, **p;
889     const Char *tstring = string;
890     int	   gpol = 1, gres = 0;
891 
892     if (*pattern == '^') {
893 	gpol = 0;
894 	pattern++;
895     }
896 
897     fblk = xmalloc(sizeof(Char ***));
898     *fblk = xmalloc(GLOBSPACE * sizeof(Char *));
899     (*fblk)[0] = Strsave(pattern);
900     (*fblk)[1] = NULL;
901 
902     cleanup_push(fblk, blk_indirect_cleanup);
903     expbrace(fblk, NULL, GLOBSPACE);
904 
905     if (endstr == NULL)
906 	/* Exact matches only */
907 	for (p = *fblk; *p; p++)
908 	    gres |= t_pmatch(string, *p, &tstring, 1) == 2 ? 1 : 0;
909     else {
910 	const Char *end;
911 
912 	/* partial matches */
913         end = Strend(string);
914 	for (p = *fblk; *p; p++)
915 	    if (t_pmatch(string, *p, &tstring, 1) != 0) {
916 		gres |= 1;
917 		if (end > tstring)
918 		    end = tstring;
919 	    }
920 	*endstr = end;
921     }
922 
923     cleanup_until(fblk);
924     return(gres == gpol);
925 }
926 
927 /* t_pmatch():
928  *	Return 2 on exact match,
929  *	Return 1 on substring match.
930  *	Return 0 on no match.
931  *	*estr will point to the end of the longest exact or substring match.
932  */
933 int
934 t_pmatch(const Char *string, const Char *pattern, const Char **estr, int cs)
935 {
936     Char stringc, patternc, rangec;
937     int     match, negate_range;
938     const Char *pestr, *nstring;
939 
940     for (nstring = string;; string = nstring) {
941 	stringc = *nstring++ & TRIM;
942 	patternc = *pattern++ & TRIM;
943 	switch (patternc) {
944 	case '\0':
945 	    *estr = string;
946 	    return (stringc == '\0' ? 2 : 1);
947 	case '?':
948 	    if (stringc == 0)
949 		return (0);
950 	    break;
951 	case '*':
952 	    if (!*pattern) {
953 		*estr = Strend(string);
954 		return (2);
955 	    }
956 	    pestr = NULL;
957 
958 	    for (;;) {
959 		switch(t_pmatch(string, pattern, estr, cs)) {
960 		case 0:
961 		    break;
962 		case 1:
963 		    pestr = *estr;/*FIXME: does not guarantee longest match */
964 		    break;
965 		case 2:
966 		    return 2;
967 		default:
968 		    abort();	/* Cannot happen */
969 		}
970 		stringc = *string++ & TRIM;
971 		if (!stringc)
972 		    break;
973 	    }
974 
975 	    if (pestr) {
976 		*estr = pestr;
977 		return 1;
978 	    }
979 	    else
980 		return 0;
981 
982 	case '[':
983 	    match = 0;
984 	    if ((negate_range = (*pattern == '^')) != 0)
985 		pattern++;
986 	    while ((rangec = *pattern++ & TRIM) != '\0') {
987 		if (rangec == ']')
988 		    break;
989 		if (match)
990 		    continue;
991 		if (*pattern == '-' && pattern[1] != ']') {
992 		    Char rangec2;
993 		    pattern++;
994 		    rangec2 = *pattern++ & TRIM;
995 		    match = (globcharcoll(stringc, rangec2, 0) <= 0 &&
996 			globcharcoll(rangec, stringc, 0) <= 0);
997 		}
998 		else
999 		    match = (stringc == rangec);
1000 	    }
1001 	    if (rangec == '\0')
1002 		stderror(ERR_NAME | ERR_MISSING, ']');
1003 	    if ((!match) && (stringc == '\0'))
1004 		return (0);
1005 	    if (match == negate_range)
1006 		return (0);
1007 	    break;
1008 	default:
1009 	    if (cs ? patternc  != stringc
1010 		: Tolower(patternc) != Tolower(stringc))
1011 		return (0);
1012 	    break;
1013 	}
1014     }
1015 }
1016