sh.glob.c revision 145479
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
35RCSID("$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
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((Char));
84static	void	  backeval	__P((Char *, int));
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	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
261static void
262expbrace(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
337static Char **
338globexpand(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
434static Char *
435handleone(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
474static Char **
475libglob(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
521Char   *
522globone(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
583Char  **
584globall(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
618void
619ginit()
620{
621    gargsiz = GLOBSPACE;
622    gargv = (Char **) xmalloc((size_t) (sizeof(Char *) * gargsiz));
623    gargv[0] = 0;
624    gargc = 0;
625}
626
627void
628rscan(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
639void
640trim(t)
641    Char **t;
642{
643    Char *p;
644
645    while ((p = *t++) != '\0')
646	while (*p)
647	    *p++ &= TRIM;
648}
649
650void
651tglob(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 */
706Char  **
707dobackp(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
752static void
753backeval(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
963static void
964psave(c)
965    Char   c;
966{
967    if (--pnleft <= 0)
968	stderror(ERR_WTOOLONG);
969    *pargcp++ = (Char) c;
970}
971
972static void
973pword(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
989int
990Gmatch(string, pattern)
991    Char *string, *pattern;
992{
993    return Gnmatch(string, pattern, NULL);
994}
995
996int
997Gnmatch(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 */
1041int
1042t_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
1148void
1149Gcat(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)
1174int
1175sortscmp(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