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