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