sh.glob.c revision 131962
1/* $Header: /src/pub/tcsh/sh.glob.c,v 3.55 2004/03/21 16:48:14 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
35RCSID("$Id: sh.glob.c,v 3.55 2004/03/21 16:48:14 christos Exp $")
36
37#include "tc.h"
38#include "tw.h"
39
40#include "glob.h"
41
42static int noglob;
43static 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
62Char  **gargv = NULL;
63int     gargc = 0;
64Char  **pargv = NULL;
65static 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 */
76static	Char	 *globtilde	__P((Char **, Char *));
77static	Char     *handleone	__P((Char *, Char **, int));
78static	Char	**libglob	__P((Char **));
79static	Char	**globexpand	__P((Char **));
80static	int	  globbrace	__P((Char *, Char *, Char ***));
81static  void	  expbrace	__P((Char ***, Char ***, int));
82static	void	  pword		__P((int));
83static	void	  psave		__P((int));
84static	void	  backeval	__P((Char *, bool));
85
86static Char *
87globtilde(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
128Char *
129globequal(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
169static int
170globbrace(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#ifdef DSPMBYTE
190	if (Ismbyte1(*pe) && *(pe + 1) != EOS)
191	    pe ++;
192	else
193#endif /* DSPMBYTE */
194	if (*pe == LBRK) {
195	    /* Ignore everything between [] */
196	    for (++pe; *pe != RBRK && *pe != EOS; pe++)
197#ifdef DSPMBYTE
198	      if (Ismbyte1(*pe) && *(pe + 1) != EOS)
199		pe ++;
200	      else
201#endif /* DSPMBYTE */
202		continue;
203	    if (*pe == EOS) {
204		blkfree(nv);
205		return (-RBRK);
206	    }
207	}
208	else if (*pe == LBRC)
209	    i++;
210	else if (*pe == RBRC) {
211	    if (i == 0)
212		break;
213	    i--;
214	}
215
216    if (i != 0 || *pe == '\0') {
217	blkfree(nv);
218	return (-RBRC);
219    }
220
221    for (i = 0, pl = pm = p; pm <= pe; pm++)
222#ifdef DSPMBYTE
223	if (Ismbyte1(*pm) && pm + 1 <= pe)
224	    pm ++;
225	else
226#endif /* DSPMBYTE */
227	switch (*pm) {
228	case LBRK:
229	    for (++pm; *pm != RBRK && *pm != EOS; pm++)
230#ifdef DSPMBYTE
231	      if (Ismbyte1(*pm) && *(pm + 1) != EOS)
232		pm ++;
233	      else
234#endif /* DSPMBYTE */
235		continue;
236	    if (*pm == EOS) {
237		*vl = NULL;
238		blkfree(nv);
239		return (-RBRK);
240	    }
241	    break;
242	case LBRC:
243	    i++;
244	    break;
245	case RBRC:
246	    if (i) {
247		i--;
248		break;
249	    }
250	    /* FALLTHROUGH */
251	case ',':
252	    if (i && *pm == ',')
253		break;
254	    else {
255		Char    savec = *pm;
256
257		*pm = EOS;
258		(void) Strcpy(lm, pl);
259		(void) Strcat(gbuf, pe + 1);
260		*pm = savec;
261		*vl++ = Strsave(gbuf);
262		len++;
263		pl = pm + 1;
264		if (vl == &nv[size]) {
265		    size += GLOBSPACE;
266		    nv = (Char **) xrealloc((ptr_t) nv,
267					    (size_t) (size * sizeof(Char *)));
268		    vl = &nv[size - GLOBSPACE];
269		}
270	    }
271	    break;
272	default:
273	    break;
274	}
275    *vl = NULL;
276    *bl = nv;
277    return (len);
278}
279
280
281static void
282expbrace(nvp, elp, size)
283    Char ***nvp, ***elp;
284    int size;
285{
286    Char **vl, **el, **nv, *s;
287
288    vl = nv = *nvp;
289    if (elp != NULL)
290	el = *elp;
291    else
292	for (el = vl; *el; el++)
293	    continue;
294
295    for (s = *vl; s; s = *++vl) {
296	Char   *b;
297	Char  **vp, **bp;
298
299	/* leave {} untouched for find */
300	if (s[0] == '{' && (s[1] == '\0' || (s[1] == '}' && s[2] == '\0')))
301	    continue;
302	if ((b = Strchr(s, '{')) != NULL) {
303	    Char  **bl;
304	    int     len;
305
306#if defined (DSPMBYTE)
307	    if (b != s && Ismbyte2(*b) && Ismbyte1(*(b-1))) {
308		/* The "{" is the 2nd byte of a MB character */
309		continue;
310	    }
311#endif /* DSPMBYTE */
312	    if ((len = globbrace(s, b, &bl)) < 0) {
313		xfree((ptr_t) nv);
314		stderror(ERR_MISSING, -len);
315	    }
316	    xfree((ptr_t) s);
317	    if (len == 1) {
318		*vl-- = *bl;
319		xfree((ptr_t) bl);
320		continue;
321	    }
322	    if (&el[len] >= &nv[size]) {
323		int     l, e;
324		l = (int) (&el[len] - &nv[size]);
325		size += GLOBSPACE > l ? GLOBSPACE : l;
326		l = (int) (vl - nv);
327		e = (int) (el - nv);
328		nv = (Char **) xrealloc((ptr_t) nv,
329					(size_t) (size * sizeof(Char *)));
330		vl = nv + l;
331		el = nv + e;
332	    }
333	    /* nv vl   el     bl
334	     * |  |    |      |
335	     * -.--..--	      x--
336	     *   |            len
337	     *   vp
338	     */
339	    vp = vl--;
340	    *vp = *bl;
341	    len--;
342	    for (bp = el; bp != vp; bp--)
343		bp[len] = *bp;
344	    el += len;
345	    /* nv vl    el bl
346	     * |  |     |  |
347	     * -.-x  ---    --
348	     *   |len
349	     *   vp
350	     */
351	    vp++;
352	    for (bp = bl + 1; *bp; *vp++ = *bp++)
353		continue;
354	    xfree((ptr_t) bl);
355	}
356
357    }
358    if (elp != NULL)
359	*elp = el;
360    *nvp = nv;
361}
362
363static Char **
364globexpand(v)
365    Char  **v;
366{
367    Char   *s;
368    Char  **nv, **vl, **el;
369    int     size = GLOBSPACE;
370
371
372    nv = vl = (Char **) xmalloc((size_t) (sizeof(Char *) * size));
373    *vl = NULL;
374
375    /*
376     * Step 1: expand backquotes.
377     */
378    while ((s = *v++) != '\0') {
379	if (Strchr(s, '`')) {
380	    int     i;
381
382	    (void) dobackp(s, 0);
383	    for (i = 0; i < pargc; i++) {
384		*vl++ = pargv[i];
385		if (vl == &nv[size]) {
386		    size += GLOBSPACE;
387		    nv = (Char **) xrealloc((ptr_t) nv,
388					    (size_t) (size * sizeof(Char *)));
389		    vl = &nv[size - GLOBSPACE];
390		}
391	    }
392	    xfree((ptr_t) pargv);
393	    pargv = NULL;
394	}
395	else {
396	    *vl++ = Strsave(s);
397	    if (vl == &nv[size]) {
398		size += GLOBSPACE;
399		nv = (Char **) xrealloc((ptr_t) nv,
400					(size_t) (size * sizeof(Char *)));
401		vl = &nv[size - GLOBSPACE];
402	    }
403	}
404    }
405    *vl = NULL;
406
407    if (noglob)
408	return (nv);
409
410    /*
411     * Step 2: expand braces
412     */
413    el = vl;
414    expbrace(&nv, &el, size);
415
416
417    /*
418     * Step 3: expand ~ =
419     */
420    vl = nv;
421    for (s = *vl; s; s = *++vl)
422	switch (*s) {
423	    Char gp[BUFSIZE], *ns;
424	case '~':
425	    *vl = globtilde(nv, s);
426	    break;
427	case '=':
428	    if ((ns = globequal(gp, s)) == NULL) {
429		if (!adrof(STRnonomatch)) {
430		    /* Error */
431		    blkfree(nv);
432		    stderror(ERR_DEEP);
433		}
434	    }
435	    if (ns && ns != s) {
436		/* Expansion succeeded */
437		xfree((ptr_t) s);
438		*vl = Strsave(gp);
439	    }
440	    break;
441	default:
442	    break;
443	}
444    vl = nv;
445
446    /*
447     * Step 4: expand .. if the variable symlinks==expand is set
448     */
449    if (symlinks == SYM_EXPAND) {
450	for (s = *vl; s; s = *++vl) {
451	    *vl = dnormalize(s, 1);
452	    xfree((ptr_t) s);
453	}
454    }
455    vl = nv;
456
457    return (vl);
458}
459
460static Char *
461handleone(str, vl, action)
462    Char   *str, **vl;
463    int     action;
464{
465
466    Char   **vlp = vl;
467    int chars;
468    Char **t, *p, *strp;
469
470    switch (action) {
471    case G_ERROR:
472	setname(short2str(str));
473	blkfree(vl);
474	stderror(ERR_NAME | ERR_AMBIG);
475	break;
476    case G_APPEND:
477	chars = 0;
478	for (t = vlp; (p = *t++) != '\0'; chars++)
479	    while (*p++)
480		chars++;
481	str = (Char *)xmalloc((size_t)(chars * sizeof(Char)));
482	for (t = vlp, strp = str; (p = *t++) != '\0'; chars++) {
483	    while (*p)
484		 *strp++ = *p++ & TRIM;
485	    *strp++ = ' ';
486	}
487	*--strp = '\0';
488	blkfree(vl);
489	break;
490    case G_IGNORE:
491	str = Strsave(strip(*vlp));
492	blkfree(vl);
493	break;
494    default:
495	break;
496    }
497    return (str);
498}
499
500static Char **
501libglob(vl)
502    Char  **vl;
503{
504    int     gflgs = GLOB_QUOTE | GLOB_NOMAGIC | GLOB_ALTNOT;
505    glob_t  globv;
506    char   *ptr;
507    int     nonomatch = adrof(STRnonomatch) != 0, magic = 0, match = 0;
508
509    if (!vl || !vl[0])
510	return(vl);
511
512    globv.gl_offs = 0;
513    globv.gl_pathv = 0;
514    globv.gl_pathc = 0;
515
516    if (nonomatch)
517	gflgs |= GLOB_NOCHECK;
518
519    do {
520	ptr = short2qstr(*vl);
521	switch (glob(ptr, gflgs, 0, &globv)) {
522	case GLOB_ABEND:
523	    globfree(&globv);
524	    setname(ptr);
525	    stderror(ERR_NAME | ERR_GLOB);
526	    /* NOTREACHED */
527	case GLOB_NOSPACE:
528	    globfree(&globv);
529	    stderror(ERR_NOMEM);
530	    /* NOTREACHED */
531	default:
532	    break;
533	}
534	if (globv.gl_flags & GLOB_MAGCHAR) {
535	    match |= (globv.gl_matchc != 0);
536	    magic = 1;
537	}
538	gflgs |= GLOB_APPEND;
539    }
540    while (*++vl);
541    vl = (globv.gl_pathc == 0 || (magic && !match && !nonomatch)) ?
542	NULL : blk2short(globv.gl_pathv);
543    globfree(&globv);
544    return (vl);
545}
546
547Char   *
548globone(str, action)
549    Char   *str;
550    int     action;
551{
552
553    Char   *v[2], **vl, **vo;
554    int gflg;
555
556    noglob = adrof(STRnoglob) != 0;
557    gflag = 0;
558    v[0] = str;
559    v[1] = 0;
560    tglob(v);
561    gflg = gflag;
562    if (gflg == G_NONE)
563	return (strip(Strsave(str)));
564
565    if (gflg & G_CSH) {
566	/*
567	 * Expand back-quote, tilde and brace
568	 */
569	vo = globexpand(v);
570	if (noglob || (gflg & G_GLOB) == 0) {
571	    if (vo[0] == NULL) {
572		xfree((ptr_t) vo);
573		return (Strsave(STRNULL));
574	    }
575	    if (vo[1] != NULL)
576		return (handleone(str, vo, action));
577	    else {
578		str = strip(vo[0]);
579		xfree((ptr_t) vo);
580		return (str);
581	    }
582	}
583    }
584    else if (noglob || (gflg & G_GLOB) == 0)
585	return (strip(Strsave(str)));
586    else
587	vo = v;
588
589    vl = libglob(vo);
590    if ((gflg & G_CSH) && vl != vo)
591	blkfree(vo);
592    if (vl == NULL) {
593	setname(short2str(str));
594	stderror(ERR_NAME | ERR_NOMATCH);
595    }
596    if (vl[0] == NULL) {
597	xfree((ptr_t) vl);
598	return (Strsave(STRNULL));
599    }
600    if (vl[1])
601	return (handleone(str, vl, action));
602    else {
603	str = strip(*vl);
604	xfree((ptr_t) vl);
605	return (str);
606    }
607}
608
609Char  **
610globall(v)
611    Char  **v;
612{
613    Char  **vl, **vo;
614    int gflg = gflag;
615
616    if (!v || !v[0]) {
617	gargv = saveblk(v);
618	gargc = blklen(gargv);
619	return (gargv);
620    }
621
622    noglob = adrof(STRnoglob) != 0;
623
624    if (gflg & G_CSH)
625	/*
626	 * Expand back-quote, tilde and brace
627	 */
628	vl = vo = globexpand(v);
629    else
630	vl = vo = saveblk(v);
631
632    if (!noglob && (gflg & G_GLOB)) {
633	vl = libglob(vo);
634	if (vl != vo)
635	    blkfree(vo);
636    }
637    else
638	trim(vl);
639
640    gargc = vl ? blklen(vl) : 0;
641    return (gargv = vl);
642}
643
644void
645ginit()
646{
647    gargsiz = GLOBSPACE;
648    gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
649    gargv[0] = 0;
650    gargc = 0;
651}
652
653void
654rscan(t, f)
655    register Char **t;
656    void    (*f) __P((int));
657{
658    register Char *p;
659
660    while ((p = *t++) != '\0')
661	while (*p)
662	    (*f) (*p++);
663}
664
665void
666trim(t)
667    register Char **t;
668{
669    register Char *p;
670
671    while ((p = *t++) != '\0')
672	while (*p)
673	    *p++ &= TRIM;
674}
675
676void
677tglob(t)
678    register Char **t;
679{
680    register Char *p, *c;
681
682    while ((p = *t++) != '\0') {
683	if (*p == '~' || *p == '=')
684	    gflag |= G_CSH;
685	else if (*p == '{' &&
686		 (p[1] == '\0' || (p[1] == '}' && p[2] == '\0')))
687	    continue;
688	/*
689	 * The following line used to be *(c = p++), but hp broke their
690	 * optimizer in 9.01, so we break the assignment into two pieces
691	 * The careful reader here will note that *most* compiler workarounds
692	 * in tcsh are either for apollo/DomainOS or hpux. Is it a coincidence?
693	 */
694	while ( *(c = p) != '\0') {
695	    p++;
696	    if (*c == '`') {
697		gflag |= G_CSH;
698#ifdef notdef
699		/*
700		 * We do want to expand echo `echo '*'`, so we don't\
701		 * use this piece of code anymore.
702		 */
703		while (*p && *p != '`')
704		    if (*p++ == '\\') {
705			if (*p)		/* Quoted chars */
706			    p++;
707			else
708			    break;
709		    }
710		if (*p)			/* The matching ` */
711		    p++;
712		else
713		    break;
714#endif
715	    }
716	    else if (*c == '{')
717		gflag |= G_CSH;
718	    else if (isglob(*c))
719		gflag |= G_GLOB;
720	    else if (symlinks == SYM_EXPAND &&
721		*p && ISDOTDOT(c) && (c == *(t-1) || *(c-1) == '/') )
722	    	gflag |= G_CSH;
723	}
724    }
725}
726
727/*
728 * Command substitute cp.  If literal, then this is a substitution from a
729 * << redirection, and so we should not crunch blanks and tabs, separating
730 * words only at newlines.
731 */
732Char  **
733dobackp(cp, literal)
734    Char   *cp;
735    bool    literal;
736{
737    register Char *lp, *rp;
738    Char   *ep, word[LONGBSIZE];
739
740    if (pargv) {
741#ifdef notdef
742	abort();
743#endif
744	blkfree(pargv);
745    }
746    pargsiz = GLOBSPACE;
747    pargv = (Char **) xmalloc((size_t) (sizeof(Char *) * pargsiz));
748    pargv[0] = NULL;
749    pargcp = pargs = word;
750    pargc = 0;
751    pnleft = LONGBSIZE - 4;
752    for (;;) {
753#if defined(DSPMBYTE)
754	for (lp = cp;; lp++) { /* } */
755	    if (*lp == '`' &&
756		(lp-1 < cp || !Ismbyte2(*lp) || !Ismbyte1(*(lp-1)))) {
757		break;
758	    }
759#else /* DSPMBYTE */
760	for (lp = cp; *lp != '`'; lp++) {
761#endif /* DSPMBYTE */
762	    if (*lp == 0) {
763		if (pargcp != pargs)
764		    pword(LONGBSIZE);
765		return (pargv);
766	    }
767	    psave(*lp);
768	}
769	lp++;
770	for (rp = lp; *rp && *rp != '`'; rp++)
771	    if (*rp == '\\') {
772		rp++;
773		if (!*rp)
774		    goto oops;
775	    }
776	if (!*rp)
777    oops:  stderror(ERR_UNMATCHED, '`');
778	ep = Strsave(lp);
779	ep[rp - lp] = 0;
780	backeval(ep, literal);
781	cp = rp + 1;
782    }
783}
784
785
786static void
787backeval(cp, literal)
788    Char   *cp;
789    bool    literal;
790{
791    register int icnt, c;
792    register Char *ip;
793    struct command faket;
794    bool    hadnl;
795    int     pvec[2], quoted;
796    Char   *fakecom[2], ibuf[BUFSIZE];
797    char    tibuf[BUFSIZE];
798
799    hadnl = 0;
800    icnt = 0;
801    quoted = (literal || (cp[0] & QUOTE)) ? QUOTE : 0;
802    faket.t_dtyp = NODE_COMMAND;
803    faket.t_dflg = F_BACKQ;
804    faket.t_dlef = 0;
805    faket.t_drit = 0;
806    faket.t_dspr = 0;
807    faket.t_dcom = fakecom;
808    fakecom[0] = STRfakecom1;
809    fakecom[1] = 0;
810
811    /*
812     * We do the psave job to temporarily change the current job so that the
813     * following fork is considered a separate job.  This is so that when
814     * backquotes are used in a builtin function that calls glob the "current
815     * job" is not corrupted.  We only need one level of pushed jobs as long as
816     * we are sure to fork here.
817     */
818    psavejob();
819
820    /*
821     * It would be nicer if we could integrate this redirection more with the
822     * routines in sh.sem.c by doing a fake execute on a builtin function that
823     * was piped out.
824     */
825    mypipe(pvec);
826    if (pfork(&faket, -1) == 0) {
827	struct command *t;
828
829	(void) close(pvec[0]);
830	(void) dmove(pvec[1], 1);
831	(void) dmove(SHDIAG,  2);
832	initdesc();
833	closem();
834	/*
835	 * Bugfix for nested backquotes by Michael Greim <greim@sbsvax.UUCP>,
836	 * posted to comp.bugs.4bsd 12 Sep. 1989.
837	 */
838	if (pargv)		/* mg, 21.dec.88 */
839	    blkfree(pargv), pargv = 0, pargsiz = 0;
840	/* mg, 21.dec.88 */
841	arginp = cp;
842	for (arginp = cp; *cp; cp++) {
843	    *cp &= TRIM;
844	    if (*cp == '\n' || *cp == '\r')
845		*cp = ' ';
846	}
847
848        /*
849	 * In the child ``forget'' everything about current aliases or
850	 * eval vectors.
851	 */
852	alvec = NULL;
853	evalvec = NULL;
854	alvecp = NULL;
855	evalp = NULL;
856	(void) lex(&paraml);
857	if (seterr)
858	    stderror(ERR_OLD);
859	alias(&paraml);
860	t = syntax(paraml.next, &paraml, 0);
861	if (seterr)
862	    stderror(ERR_OLD);
863	if (t)
864	    t->t_dflg |= F_NOFORK;
865#ifdef SIGTSTP
866	(void) sigignore(SIGTSTP);
867#endif
868#ifdef SIGTTIN
869	(void) sigignore(SIGTTIN);
870#endif
871#ifdef SIGTTOU
872	(void) sigignore(SIGTTOU);
873#endif
874	execute(t, -1, NULL, NULL, TRUE);
875	exitstat();
876    }
877    xfree((ptr_t) cp);
878    (void) close(pvec[1]);
879    c = 0;
880    ip = NULL;
881    do {
882	int     cnt = 0;
883
884	for (;;) {
885	    if (icnt == 0) {
886		int     i;
887
888		ip = ibuf;
889		do
890		    icnt = read(pvec[0], tibuf, BUFSIZE);
891		while (icnt == -1 && errno == EINTR);
892		if (icnt <= 0) {
893		    c = -1;
894		    break;
895		}
896		for (i = 0; i < icnt; i++)
897		    ip[i] = (unsigned char) tibuf[i];
898	    }
899	    if (hadnl)
900		break;
901	    --icnt;
902	    c = (*ip++ & TRIM);
903	    if (c == 0)
904		break;
905#ifdef WINNT_NATIVE
906	    if (c == '\r')
907	    	c = ' ';
908#endif /* WINNT_NATIVE */
909	    if (c == '\n') {
910		/*
911		 * Continue around the loop one more time, so that we can eat
912		 * the last newline without terminating this word.
913		 */
914		hadnl = 1;
915		continue;
916	    }
917	    if (!quoted && (c == ' ' || c == '\t'))
918		break;
919	    cnt++;
920	    psave(c | quoted);
921	}
922	/*
923	 * Unless at end-of-file, we will form a new word here if there were
924	 * characters in the word, or in any case when we take text literally.
925	 * If we didn't make empty words here when literal was set then we
926	 * would lose blank lines.
927	 */
928	if (c != -1 && (cnt || literal))
929	    pword(BUFSIZE);
930	hadnl = 0;
931    } while (c >= 0);
932    (void) close(pvec[0]);
933    pwait();
934    prestjob();
935}
936
937static void
938psave(c)
939    int    c;
940{
941    if (--pnleft <= 0)
942	stderror(ERR_WTOOLONG);
943    *pargcp++ = (Char) c;
944}
945
946static void
947pword(bufsiz)
948    int    bufsiz;
949{
950    psave(0);
951    if (pargc == pargsiz - 1) {
952	pargsiz += GLOBSPACE;
953	pargv = (Char **) xrealloc((ptr_t) pargv,
954				   (size_t) (pargsiz * sizeof(Char *)));
955    }
956    pargv[pargc++] = Strsave(pargs);
957    pargv[pargc] = NULL;
958    pargcp = pargs;
959    pnleft = bufsiz - 4;
960}
961
962int
963Gmatch(string, pattern)
964    Char *string, *pattern;
965{
966    return Gnmatch(string, pattern, NULL);
967}
968
969int
970Gnmatch(string, pattern, endstr)
971    Char *string, *pattern, **endstr;
972{
973    Char **blk, **p, *tstring = string;
974    int	   gpol = 1, gres = 0;
975
976    if (*pattern == '^') {
977	gpol = 0;
978	pattern++;
979    }
980
981    blk = (Char **) xmalloc((size_t) (GLOBSPACE * sizeof(Char *)));
982    blk[0] = Strsave(pattern);
983    blk[1] = NULL;
984
985    expbrace(&blk, NULL, GLOBSPACE);
986
987    if (endstr == NULL)
988	/* Exact matches only */
989	for (p = blk; *p; p++)
990	    gres |= t_pmatch(string, *p, &tstring, 0) == 2 ? 1 : 0;
991    else {
992	/* partial matches */
993	int minc = 0x7fffffff;
994	for (p = blk; *p; p++)
995	    if (t_pmatch(string, *p, &tstring, 0) != 0) {
996		int t = (int) (tstring - string);
997		gres |= 1;
998		if (minc == -1 || minc > t)
999		    minc = t;
1000	    }
1001	*endstr = string + minc;
1002    }
1003
1004    blkfree(blk);
1005    return(gres == gpol);
1006}
1007
1008/* t_pmatch():
1009 *	Return 2 on exact match,
1010 *	Return 1 on substring match.
1011 *	Return 0 on no match.
1012 *	*estr will point to the end of the longest exact or substring match.
1013 */
1014int
1015t_pmatch(string, pattern, estr, cs)
1016    Char *string, *pattern, **estr;
1017    int cs;
1018{
1019    Char    stringc, patternc;
1020    int     match, negate_range;
1021    Char    rangec, *oestr, *pestr;
1022
1023    for (;; ++string) {
1024	stringc = *string & TRIM;
1025	/*
1026	 * apollo compiler bug: switch (patternc = *pattern++) dies
1027	 */
1028	patternc = *pattern++;
1029	switch (patternc) {
1030	case 0:
1031	    *estr = string;
1032	    return (stringc == 0 ? 2 : 1);
1033	case '?':
1034	    if (stringc == 0)
1035		return (0);
1036	    *estr = string;
1037	    break;
1038	case '*':
1039	    if (!*pattern) {
1040		while (*string) string++;
1041		*estr = string;
1042		return (2);
1043	    }
1044	    oestr = *estr;
1045	    pestr = NULL;
1046
1047	    do {
1048		switch(t_pmatch(string, pattern, estr, cs)) {
1049		case 0:
1050		    break;
1051		case 1:
1052		    pestr = *estr;
1053		    break;
1054		case 2:
1055		    return 2;
1056		default:
1057		    abort();	/* Cannot happen */
1058		}
1059		*estr = string;
1060	    }
1061	    while (*string++);
1062
1063	    if (pestr) {
1064		*estr = pestr;
1065		return 1;
1066	    }
1067	    else {
1068		*estr = oestr;
1069		return 0;
1070	    }
1071
1072	case '[':
1073	    match = 0;
1074	    if ((negate_range = (*pattern == '^')) != 0)
1075		pattern++;
1076	    while ((rangec = *pattern++) != '\0') {
1077		if (rangec == ']')
1078		    break;
1079		if (match)
1080		    continue;
1081		if (rangec == '-' && *(pattern-2) != '[' && *pattern  != ']') {
1082		    match = (globcharcoll(stringc, *pattern & TRIM, cs) <= 0 &&
1083		    globcharcoll(*(pattern-2) & TRIM, stringc, cs) <= 0);
1084		    pattern++;
1085		}
1086		else
1087		    match = (stringc == (rangec & TRIM));
1088	    }
1089	    if (rangec == 0)
1090		stderror(ERR_NAME | ERR_MISSING, ']');
1091	    if (match == negate_range)
1092		return (0);
1093	    *estr = string;
1094	    break;
1095	default:
1096	    if ((patternc & TRIM) != stringc)
1097		return (0);
1098	    *estr = string;
1099	    break;
1100	}
1101    }
1102}
1103
1104void
1105Gcat(s1, s2)
1106    Char   *s1, *s2;
1107{
1108    register Char *p, *q;
1109    int     n;
1110
1111    for (p = s1; *p++;)
1112	continue;
1113    for (q = s2; *q++;)
1114	continue;
1115    n = (int) ((p - s1) + (q - s2) - 1);
1116    if (++gargc >= gargsiz) {
1117	gargsiz += GLOBSPACE;
1118	gargv = (Char **) xrealloc((ptr_t) gargv,
1119				   (size_t) (gargsiz * sizeof(Char *)));
1120    }
1121    gargv[gargc] = 0;
1122    p = gargv[gargc - 1] = (Char *) xmalloc((size_t) (n * sizeof(Char)));
1123    for (q = s1; (*p++ = *q++) != '\0';)
1124	continue;
1125    for (p--, q = s2; (*p++ = *q++) != '\0';)
1126	continue;
1127}
1128
1129#if defined(FILEC) && defined(TIOCSTI)
1130int
1131sortscmp(a, b)
1132    register Char **a, **b;
1133{
1134    if (!a)			/* check for NULL */
1135	return (b ? 1 : 0);
1136    if (!b)
1137	return (-1);
1138
1139    if (!*a)			/* check for NULL */
1140	return (*b ? 1 : 0);
1141    if (!*b)
1142	return (-1);
1143
1144    return (int) collate(*a, *b);
1145}
1146
1147#endif
1148