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