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