xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.bin/ftp/glob.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  *	Copyright 2002 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  *	Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
28*0Sstevel@tonic-gate /*	All Rights Reserved  	*/
29*0Sstevel@tonic-gate 
30*0Sstevel@tonic-gate /*
31*0Sstevel@tonic-gate  *	University Copyright- Copyright (c) 1982, 1986, 1988
32*0Sstevel@tonic-gate  *	The Regents of the University of California
33*0Sstevel@tonic-gate  *	All Rights Reserved
34*0Sstevel@tonic-gate  *
35*0Sstevel@tonic-gate  *	University Acknowledgment- Portions of this document are derived from
36*0Sstevel@tonic-gate  *	software developed by the University of California, Berkeley, and its
37*0Sstevel@tonic-gate  *	contributors.
38*0Sstevel@tonic-gate  */
39*0Sstevel@tonic-gate 
40*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * C-shell glob for random programs.
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #include "ftp_var.h"
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #ifndef NCARGS
49*0Sstevel@tonic-gate #define	NCARGS	5120
50*0Sstevel@tonic-gate #endif
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #define	QUOTE 0200
53*0Sstevel@tonic-gate #define	TRIM 0177
54*0Sstevel@tonic-gate #define	eq(a, b)	(strcmp(a, b) == 0)
55*0Sstevel@tonic-gate 
56*0Sstevel@tonic-gate /*
57*0Sstevel@tonic-gate  * According to the person who wrote the C shell "glob" code, a reasonable
58*0Sstevel@tonic-gate  * limit on number of arguments would seem to be the maximum number of
59*0Sstevel@tonic-gate  * characters in an arg list / 6.
60*0Sstevel@tonic-gate  *
61*0Sstevel@tonic-gate  * XXX:	With the new VM system, NCARGS has become enormous, making
62*0Sstevel@tonic-gate  *	it impractical to allocate arrays with NCARGS / 6 entries on
63*0Sstevel@tonic-gate  *	the stack.  The proper fix is to revamp code elsewhere (in
64*0Sstevel@tonic-gate  *	sh.dol.c and sh.glob.c) to use a different technique for handling
65*0Sstevel@tonic-gate  *	command line arguments.  In the meantime, we simply fall back
66*0Sstevel@tonic-gate  *	on using the old value of NCARGS.
67*0Sstevel@tonic-gate  */
68*0Sstevel@tonic-gate #ifdef	notyet
69*0Sstevel@tonic-gate #define	GAVSIZ	(NCARGS / 6)
70*0Sstevel@tonic-gate #else	/* notyet */
71*0Sstevel@tonic-gate #define	GAVSIZ	(10240 / 6)
72*0Sstevel@tonic-gate #endif	/* notyet */
73*0Sstevel@tonic-gate 
74*0Sstevel@tonic-gate static	char **gargv;		/* Pointer to the (stack) arglist */
75*0Sstevel@tonic-gate static	char **agargv;
76*0Sstevel@tonic-gate static	int agargv_size;
77*0Sstevel@tonic-gate static	long gargc;		/* Number args in gargv */
78*0Sstevel@tonic-gate static	short gflag;
79*0Sstevel@tonic-gate static char *strspl();
80*0Sstevel@tonic-gate static char *strend(char *cp);
81*0Sstevel@tonic-gate static char *strspl(char *cp, char *dp);
82*0Sstevel@tonic-gate static int tglob(char c);
83*0Sstevel@tonic-gate static char **copyblk(char **v);
84*0Sstevel@tonic-gate static void ginit(char **agargv);
85*0Sstevel@tonic-gate static void addpath(char c);
86*0Sstevel@tonic-gate static int any(int c, char *s);
87*0Sstevel@tonic-gate static void Gcat(char *s1, char *s2);
88*0Sstevel@tonic-gate static void collect(char *as);
89*0Sstevel@tonic-gate static void acollect(char *as);
90*0Sstevel@tonic-gate static void sort(void);
91*0Sstevel@tonic-gate static void expand(char *as);
92*0Sstevel@tonic-gate static void matchdir(char *pattern);
93*0Sstevel@tonic-gate static int execbrc(char *p, char *s);
94*0Sstevel@tonic-gate static int ftp_fnmatch(wchar_t t_ch, wchar_t t_fch, wchar_t t_lch);
95*0Sstevel@tonic-gate static int gethdir(char *home);
96*0Sstevel@tonic-gate static void xfree(char *cp);
97*0Sstevel@tonic-gate static void rscan(char **t, int (*f)(char));
98*0Sstevel@tonic-gate static int letter(char c);
99*0Sstevel@tonic-gate static int digit(char c);
100*0Sstevel@tonic-gate static int match(char *s, char *p);
101*0Sstevel@tonic-gate static int amatch(char *s, char *p);
102*0Sstevel@tonic-gate static int blklen(char **av);
103*0Sstevel@tonic-gate static char **blkcpy(char **oav, char **bv);
104*0Sstevel@tonic-gate 
105*0Sstevel@tonic-gate static	int globcnt;
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate static char	*globchars = "`{[*?";
108*0Sstevel@tonic-gate 
109*0Sstevel@tonic-gate static	char *gpath, *gpathp, *lastgpathp;
110*0Sstevel@tonic-gate static	int globbed;
111*0Sstevel@tonic-gate static	char *entp;
112*0Sstevel@tonic-gate static	char **sortbas;
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate char **
115*0Sstevel@tonic-gate glob(char *v)
116*0Sstevel@tonic-gate {
117*0Sstevel@tonic-gate 	char agpath[FTPBUFSIZ];
118*0Sstevel@tonic-gate 	char *vv[2];
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (agargv == NULL) {
121*0Sstevel@tonic-gate 		agargv = (char **)malloc(GAVSIZ * sizeof (char *));
122*0Sstevel@tonic-gate 		agargv_size = GAVSIZ;
123*0Sstevel@tonic-gate 		if (agargv == NULL) {
124*0Sstevel@tonic-gate 			globerr = "Arguments too long.";
125*0Sstevel@tonic-gate 			return (0);
126*0Sstevel@tonic-gate 		}
127*0Sstevel@tonic-gate 	}
128*0Sstevel@tonic-gate 	vv[0] = v;
129*0Sstevel@tonic-gate 	vv[1] = 0;
130*0Sstevel@tonic-gate 	globerr = 0;
131*0Sstevel@tonic-gate 	gflag = 0;
132*0Sstevel@tonic-gate 	rscan(vv, tglob);
133*0Sstevel@tonic-gate 	if (gflag == 0)
134*0Sstevel@tonic-gate 		return (copyblk(vv));
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate 	gpath = agpath;
137*0Sstevel@tonic-gate 	gpathp = gpath;
138*0Sstevel@tonic-gate 	*gpathp = 0;
139*0Sstevel@tonic-gate 	lastgpathp = &gpath[sizeof (agpath) - 2];
140*0Sstevel@tonic-gate 	ginit(agargv);
141*0Sstevel@tonic-gate 	globcnt = 0;
142*0Sstevel@tonic-gate 	collect(v);
143*0Sstevel@tonic-gate 	if (globcnt == 0 && (gflag&1)) {
144*0Sstevel@tonic-gate 		blkfree(gargv);
145*0Sstevel@tonic-gate 		if (gargv == agargv)
146*0Sstevel@tonic-gate 			agargv = 0;
147*0Sstevel@tonic-gate 		gargv = 0;
148*0Sstevel@tonic-gate 		return (0);
149*0Sstevel@tonic-gate 	} else
150*0Sstevel@tonic-gate 		return (gargv = copyblk(gargv));
151*0Sstevel@tonic-gate }
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate static void
154*0Sstevel@tonic-gate ginit(char **agargv)
155*0Sstevel@tonic-gate {
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate 	agargv[0] = 0;
158*0Sstevel@tonic-gate 	gargv = agargv;
159*0Sstevel@tonic-gate 	sortbas = agargv;
160*0Sstevel@tonic-gate 	gargc = 0;
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate static void
164*0Sstevel@tonic-gate collect(char *as)
165*0Sstevel@tonic-gate {
166*0Sstevel@tonic-gate 	if (eq(as, "{") || eq(as, "{}")) {
167*0Sstevel@tonic-gate 		Gcat(as, "");
168*0Sstevel@tonic-gate 		sort();
169*0Sstevel@tonic-gate 	} else
170*0Sstevel@tonic-gate 		acollect(as);
171*0Sstevel@tonic-gate }
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate static void
174*0Sstevel@tonic-gate acollect(char *as)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	register long ogargc = gargc;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	gpathp = gpath; *gpathp = 0; globbed = 0;
179*0Sstevel@tonic-gate 	expand(as);
180*0Sstevel@tonic-gate 	if (gargc != ogargc)
181*0Sstevel@tonic-gate 		sort();
182*0Sstevel@tonic-gate }
183*0Sstevel@tonic-gate 
184*0Sstevel@tonic-gate static void
185*0Sstevel@tonic-gate sort(void)
186*0Sstevel@tonic-gate {
187*0Sstevel@tonic-gate 	register char **p1, **p2, *c;
188*0Sstevel@tonic-gate 	char **Gvp = &gargv[gargc];
189*0Sstevel@tonic-gate 
190*0Sstevel@tonic-gate 	p1 = sortbas;
191*0Sstevel@tonic-gate 	while (p1 < Gvp-1) {
192*0Sstevel@tonic-gate 		p2 = p1;
193*0Sstevel@tonic-gate 		while (++p2 < Gvp)
194*0Sstevel@tonic-gate 			if (strcmp(*p1, *p2) > 0)
195*0Sstevel@tonic-gate 				c = *p1, *p1 = *p2, *p2 = c;
196*0Sstevel@tonic-gate 		p1++;
197*0Sstevel@tonic-gate 	}
198*0Sstevel@tonic-gate 	sortbas = Gvp;
199*0Sstevel@tonic-gate }
200*0Sstevel@tonic-gate 
201*0Sstevel@tonic-gate static void
202*0Sstevel@tonic-gate expand(char *as)
203*0Sstevel@tonic-gate {
204*0Sstevel@tonic-gate 	register char *cs;
205*0Sstevel@tonic-gate 	register char *sgpathp, *oldcs;
206*0Sstevel@tonic-gate 	struct stat stb;
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate 	sgpathp = gpathp;
209*0Sstevel@tonic-gate 	cs = as;
210*0Sstevel@tonic-gate 	if (*cs == '~' && gpathp == gpath) {
211*0Sstevel@tonic-gate 		addpath('~');
212*0Sstevel@tonic-gate 		cs++;
213*0Sstevel@tonic-gate 		while (letter(*cs) || digit(*cs) || *cs == '-')
214*0Sstevel@tonic-gate 			addpath(*cs++);
215*0Sstevel@tonic-gate 		if (!*cs || *cs == '/') {
216*0Sstevel@tonic-gate 			if (gpathp != gpath + 1) {
217*0Sstevel@tonic-gate 				*gpathp = 0;
218*0Sstevel@tonic-gate 				if (gethdir(gpath + 1))
219*0Sstevel@tonic-gate 					globerr = "Unknown user name after ~";
220*0Sstevel@tonic-gate 				(void) strcpy(gpath, gpath + 1);
221*0Sstevel@tonic-gate 			} else
222*0Sstevel@tonic-gate 				(void) strcpy(gpath, home);
223*0Sstevel@tonic-gate 			gpathp = strend(gpath);
224*0Sstevel@tonic-gate 		}
225*0Sstevel@tonic-gate 	}
226*0Sstevel@tonic-gate 	while (!any(*cs, globchars)) {
227*0Sstevel@tonic-gate 		if (*cs == 0) {
228*0Sstevel@tonic-gate 			if (!globbed)
229*0Sstevel@tonic-gate 				Gcat(gpath, "");
230*0Sstevel@tonic-gate 			else if (stat(gpath, &stb) >= 0) {
231*0Sstevel@tonic-gate 				Gcat(gpath, "");
232*0Sstevel@tonic-gate 				globcnt++;
233*0Sstevel@tonic-gate 			}
234*0Sstevel@tonic-gate 			goto endit;
235*0Sstevel@tonic-gate 		}
236*0Sstevel@tonic-gate 		addpath(*cs++);
237*0Sstevel@tonic-gate 	}
238*0Sstevel@tonic-gate 	oldcs = cs;
239*0Sstevel@tonic-gate 	while (cs > as && *cs != '/')
240*0Sstevel@tonic-gate 		cs--, gpathp--;
241*0Sstevel@tonic-gate 	if (*cs == '/')
242*0Sstevel@tonic-gate 		cs++, gpathp++;
243*0Sstevel@tonic-gate 	*gpathp = 0;
244*0Sstevel@tonic-gate 	if (*oldcs == '{') {
245*0Sstevel@tonic-gate 		(void) execbrc(cs, ((char *)0));
246*0Sstevel@tonic-gate 		return;
247*0Sstevel@tonic-gate 	}
248*0Sstevel@tonic-gate 	matchdir(cs);
249*0Sstevel@tonic-gate endit:
250*0Sstevel@tonic-gate 	gpathp = sgpathp;
251*0Sstevel@tonic-gate 	*gpathp = 0;
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate static void
255*0Sstevel@tonic-gate matchdir(char *pattern)
256*0Sstevel@tonic-gate {
257*0Sstevel@tonic-gate 	struct stat stb;
258*0Sstevel@tonic-gate 	register struct dirent *dp;
259*0Sstevel@tonic-gate 	DIR *dirp;
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate 	/*
262*0Sstevel@tonic-gate 	 * BSD/SunOS open() system call maps a null pathname into
263*0Sstevel@tonic-gate 	 * "." while System V does not.
264*0Sstevel@tonic-gate 	 */
265*0Sstevel@tonic-gate 	if (*gpath == (char)0) {
266*0Sstevel@tonic-gate 		dirp = opendir(".");
267*0Sstevel@tonic-gate 	} else
268*0Sstevel@tonic-gate 		dirp = opendir(gpath);
269*0Sstevel@tonic-gate 	if (dirp == NULL) {
270*0Sstevel@tonic-gate 		if (globbed)
271*0Sstevel@tonic-gate 			return;
272*0Sstevel@tonic-gate 		goto patherr2;
273*0Sstevel@tonic-gate 	}
274*0Sstevel@tonic-gate 	if (fstat(dirp->dd_fd, &stb) < 0)
275*0Sstevel@tonic-gate 		goto patherr1;
276*0Sstevel@tonic-gate 	if (!S_ISDIR(stb.st_mode)) {
277*0Sstevel@tonic-gate 		errno = ENOTDIR;
278*0Sstevel@tonic-gate 		goto patherr1;
279*0Sstevel@tonic-gate 	}
280*0Sstevel@tonic-gate 	while ((dp = readdir(dirp)) != NULL) {
281*0Sstevel@tonic-gate 		if (dp->d_ino == 0)
282*0Sstevel@tonic-gate 			continue;
283*0Sstevel@tonic-gate 		if (match(dp->d_name, pattern)) {
284*0Sstevel@tonic-gate 			Gcat(gpath, dp->d_name);
285*0Sstevel@tonic-gate 			globcnt++;
286*0Sstevel@tonic-gate 		}
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 	closedir(dirp);
289*0Sstevel@tonic-gate 	return;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate patherr1:
292*0Sstevel@tonic-gate 	closedir(dirp);
293*0Sstevel@tonic-gate patherr2:
294*0Sstevel@tonic-gate 	globerr = "Bad directory components";
295*0Sstevel@tonic-gate }
296*0Sstevel@tonic-gate 
297*0Sstevel@tonic-gate static int
298*0Sstevel@tonic-gate execbrc(char *p, char *s)
299*0Sstevel@tonic-gate {
300*0Sstevel@tonic-gate 	char restbuf[FTPBUFSIZ + 2];
301*0Sstevel@tonic-gate 	register char *pe, *pm, *pl;
302*0Sstevel@tonic-gate 	int brclev = 0;
303*0Sstevel@tonic-gate 	char *lm, savec, *sgpathp;
304*0Sstevel@tonic-gate 	int	len;
305*0Sstevel@tonic-gate 
306*0Sstevel@tonic-gate 	for (lm = restbuf; *p != '{'; *lm += len, p += len) {
307*0Sstevel@tonic-gate 		if ((len = mblen(p, MB_CUR_MAX)) <= 0)
308*0Sstevel@tonic-gate 			len = 1;
309*0Sstevel@tonic-gate 		memcpy(lm, p, len);
310*0Sstevel@tonic-gate 	}
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate 	for (pe = ++p; *pe; pe += len) {
313*0Sstevel@tonic-gate 		if ((len = mblen(pe, MB_CUR_MAX)) <= 0)
314*0Sstevel@tonic-gate 			len = 1;
315*0Sstevel@tonic-gate 
316*0Sstevel@tonic-gate 		switch (*pe) {
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 		case '{':
319*0Sstevel@tonic-gate 			brclev++;
320*0Sstevel@tonic-gate 			continue;
321*0Sstevel@tonic-gate 
322*0Sstevel@tonic-gate 		case '}':
323*0Sstevel@tonic-gate 			if (brclev == 0)
324*0Sstevel@tonic-gate 				goto pend;
325*0Sstevel@tonic-gate 			brclev--;
326*0Sstevel@tonic-gate 			continue;
327*0Sstevel@tonic-gate 
328*0Sstevel@tonic-gate 		case '[':
329*0Sstevel@tonic-gate 			for (pe++; *pe && *pe != ']'; pe += len) {
330*0Sstevel@tonic-gate 				if ((len = mblen(pe, MB_CUR_MAX)) <= 0)
331*0Sstevel@tonic-gate 					len = 1;
332*0Sstevel@tonic-gate 			}
333*0Sstevel@tonic-gate 			len = 1;
334*0Sstevel@tonic-gate 			continue;
335*0Sstevel@tonic-gate 		}
336*0Sstevel@tonic-gate 	}
337*0Sstevel@tonic-gate pend:
338*0Sstevel@tonic-gate 	brclev = 0;
339*0Sstevel@tonic-gate 	for (pl = pm = p; pm <= pe; pm += len) {
340*0Sstevel@tonic-gate 		if ((len = mblen(pm, MB_CUR_MAX)) <= 0)
341*0Sstevel@tonic-gate 			len = 1;
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 		switch (*pm & (QUOTE|TRIM)) {
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 		case '{':
346*0Sstevel@tonic-gate 			brclev++;
347*0Sstevel@tonic-gate 			continue;
348*0Sstevel@tonic-gate 
349*0Sstevel@tonic-gate 		case '}':
350*0Sstevel@tonic-gate 			if (brclev) {
351*0Sstevel@tonic-gate 				brclev--;
352*0Sstevel@tonic-gate 				continue;
353*0Sstevel@tonic-gate 			}
354*0Sstevel@tonic-gate 			goto doit;
355*0Sstevel@tonic-gate 
356*0Sstevel@tonic-gate 		case ','|QUOTE:
357*0Sstevel@tonic-gate 		case ',':
358*0Sstevel@tonic-gate 			if (brclev)
359*0Sstevel@tonic-gate 				continue;
360*0Sstevel@tonic-gate doit:
361*0Sstevel@tonic-gate 			savec = *pm;
362*0Sstevel@tonic-gate 			*pm = 0;
363*0Sstevel@tonic-gate 			(void) strcpy(lm, pl);
364*0Sstevel@tonic-gate 			(void) strcat(restbuf, pe + 1);
365*0Sstevel@tonic-gate 			*pm = savec;
366*0Sstevel@tonic-gate 			if (s == 0) {
367*0Sstevel@tonic-gate 				sgpathp = gpathp;
368*0Sstevel@tonic-gate 				expand(restbuf);
369*0Sstevel@tonic-gate 				gpathp = sgpathp;
370*0Sstevel@tonic-gate 				*gpathp = 0;
371*0Sstevel@tonic-gate 			} else if (amatch(s, restbuf))
372*0Sstevel@tonic-gate 				return (1);
373*0Sstevel@tonic-gate 			sort();
374*0Sstevel@tonic-gate 			pl = pm + 1;
375*0Sstevel@tonic-gate 			if (brclev)
376*0Sstevel@tonic-gate 				return (0);
377*0Sstevel@tonic-gate 			continue;
378*0Sstevel@tonic-gate 
379*0Sstevel@tonic-gate 		case '[':
380*0Sstevel@tonic-gate 			for (pm++; *pm && *pm != ']'; pm += len) {
381*0Sstevel@tonic-gate 				if ((len = mblen(pm, MB_CUR_MAX)) <= 0)
382*0Sstevel@tonic-gate 					len = 1;
383*0Sstevel@tonic-gate 			}
384*0Sstevel@tonic-gate 			len = 1;
385*0Sstevel@tonic-gate 			if (!*pm)
386*0Sstevel@tonic-gate 				pm--;
387*0Sstevel@tonic-gate 			continue;
388*0Sstevel@tonic-gate 		}
389*0Sstevel@tonic-gate 	}
390*0Sstevel@tonic-gate 	if (brclev)
391*0Sstevel@tonic-gate 		goto doit;
392*0Sstevel@tonic-gate 	return (0);
393*0Sstevel@tonic-gate }
394*0Sstevel@tonic-gate 
395*0Sstevel@tonic-gate static int
396*0Sstevel@tonic-gate match(char *s, char *p)
397*0Sstevel@tonic-gate {
398*0Sstevel@tonic-gate 	register int c;
399*0Sstevel@tonic-gate 	register char *sentp;
400*0Sstevel@tonic-gate 	char sglobbed = globbed;
401*0Sstevel@tonic-gate 
402*0Sstevel@tonic-gate 	if (*s == '.' && *p != '.')
403*0Sstevel@tonic-gate 		return (0);
404*0Sstevel@tonic-gate 	sentp = entp;
405*0Sstevel@tonic-gate 	entp = s;
406*0Sstevel@tonic-gate 	c = amatch(s, p);
407*0Sstevel@tonic-gate 	entp = sentp;
408*0Sstevel@tonic-gate 	globbed = sglobbed;
409*0Sstevel@tonic-gate 	return (c);
410*0Sstevel@tonic-gate }
411*0Sstevel@tonic-gate 
412*0Sstevel@tonic-gate static int
413*0Sstevel@tonic-gate amatch(char *s, char *p)
414*0Sstevel@tonic-gate {
415*0Sstevel@tonic-gate 	wchar_t scc;
416*0Sstevel@tonic-gate 	int ok;
417*0Sstevel@tonic-gate 	wchar_t lc1, lc2;
418*0Sstevel@tonic-gate 	char *sgpathp;
419*0Sstevel@tonic-gate 	struct stat stb;
420*0Sstevel@tonic-gate 	wchar_t c, cc;
421*0Sstevel@tonic-gate 	int	len_s, len_p;
422*0Sstevel@tonic-gate 
423*0Sstevel@tonic-gate 	globbed = 1;
424*0Sstevel@tonic-gate 	for (;;) {
425*0Sstevel@tonic-gate 		if ((len_s = mbtowc(&scc, s, MB_CUR_MAX)) <= 0) {
426*0Sstevel@tonic-gate 			scc = (unsigned char)*s;
427*0Sstevel@tonic-gate 			len_s = 1;
428*0Sstevel@tonic-gate 		}
429*0Sstevel@tonic-gate 		/* scc = *s++ & TRIM; */
430*0Sstevel@tonic-gate 		s += len_s;
431*0Sstevel@tonic-gate 
432*0Sstevel@tonic-gate 		if ((len_p = mbtowc(&c, p, MB_CUR_MAX)) <= 0) {
433*0Sstevel@tonic-gate 			c = (unsigned char)*p;
434*0Sstevel@tonic-gate 			len_p = 1;
435*0Sstevel@tonic-gate 		}
436*0Sstevel@tonic-gate 		p += len_p;
437*0Sstevel@tonic-gate 		switch (c) {
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 		case '{':
440*0Sstevel@tonic-gate 			return (execbrc(p - len_p, s - len_s));
441*0Sstevel@tonic-gate 
442*0Sstevel@tonic-gate 		case '[':
443*0Sstevel@tonic-gate 			ok = 0;
444*0Sstevel@tonic-gate 			lc1 = 0;
445*0Sstevel@tonic-gate 			while ((cc = *p) != '\0') {
446*0Sstevel@tonic-gate 				if ((len_p = mbtowc(&cc, p, MB_CUR_MAX)) <= 0) {
447*0Sstevel@tonic-gate 					cc = (unsigned char)*p;
448*0Sstevel@tonic-gate 					len_p = 1;
449*0Sstevel@tonic-gate 				}
450*0Sstevel@tonic-gate 				p += len_p;
451*0Sstevel@tonic-gate 				if (cc == ']') {
452*0Sstevel@tonic-gate 					if (ok)
453*0Sstevel@tonic-gate 						break;
454*0Sstevel@tonic-gate 					return (0);
455*0Sstevel@tonic-gate 				}
456*0Sstevel@tonic-gate 				if (cc == '-') {
457*0Sstevel@tonic-gate 					if ((len_p = mbtowc(&lc2, p,
458*0Sstevel@tonic-gate 					    MB_CUR_MAX)) <= 0) {
459*0Sstevel@tonic-gate 						lc2 = (unsigned char)*p;
460*0Sstevel@tonic-gate 						len_p = 1;
461*0Sstevel@tonic-gate 					}
462*0Sstevel@tonic-gate 					p += len_p;
463*0Sstevel@tonic-gate 					if (ftp_fnmatch(scc, lc1, lc2))
464*0Sstevel@tonic-gate 						ok++;
465*0Sstevel@tonic-gate 				} else
466*0Sstevel@tonic-gate 					if (scc == (lc1 = cc))
467*0Sstevel@tonic-gate 						ok++;
468*0Sstevel@tonic-gate 			}
469*0Sstevel@tonic-gate 			if (cc == 0)
470*0Sstevel@tonic-gate 				if (!ok)
471*0Sstevel@tonic-gate 					return (0);
472*0Sstevel@tonic-gate 			continue;
473*0Sstevel@tonic-gate 
474*0Sstevel@tonic-gate 		case '*':
475*0Sstevel@tonic-gate 			if (!*p)
476*0Sstevel@tonic-gate 				return (1);
477*0Sstevel@tonic-gate 			if (*p == '/') {
478*0Sstevel@tonic-gate 				p++;
479*0Sstevel@tonic-gate 				goto slash;
480*0Sstevel@tonic-gate 			}
481*0Sstevel@tonic-gate 			s -= len_s;
482*0Sstevel@tonic-gate 			do {
483*0Sstevel@tonic-gate 				if (amatch(s, p))
484*0Sstevel@tonic-gate 					return (1);
485*0Sstevel@tonic-gate 			} while (*s++);
486*0Sstevel@tonic-gate 			return (0);
487*0Sstevel@tonic-gate 
488*0Sstevel@tonic-gate 		case 0:
489*0Sstevel@tonic-gate 			return (scc == 0);
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 		default:
492*0Sstevel@tonic-gate 			if (c != scc)
493*0Sstevel@tonic-gate 				return (0);
494*0Sstevel@tonic-gate 			continue;
495*0Sstevel@tonic-gate 
496*0Sstevel@tonic-gate 		case '?':
497*0Sstevel@tonic-gate 			if (scc == 0)
498*0Sstevel@tonic-gate 				return (0);
499*0Sstevel@tonic-gate 			continue;
500*0Sstevel@tonic-gate 
501*0Sstevel@tonic-gate 		case '/':
502*0Sstevel@tonic-gate 			if (scc)
503*0Sstevel@tonic-gate 				return (0);
504*0Sstevel@tonic-gate slash:
505*0Sstevel@tonic-gate 			s = entp;
506*0Sstevel@tonic-gate 			sgpathp = gpathp;
507*0Sstevel@tonic-gate 			while (*s)
508*0Sstevel@tonic-gate 				addpath(*s++);
509*0Sstevel@tonic-gate 			addpath('/');
510*0Sstevel@tonic-gate 			if (stat(gpath, &stb) == 0 && S_ISDIR(stb.st_mode))
511*0Sstevel@tonic-gate 				if (*p == 0) {
512*0Sstevel@tonic-gate 					Gcat(gpath, "");
513*0Sstevel@tonic-gate 					globcnt++;
514*0Sstevel@tonic-gate 				} else
515*0Sstevel@tonic-gate 					expand(p);
516*0Sstevel@tonic-gate 			gpathp = sgpathp;
517*0Sstevel@tonic-gate 			*gpathp = 0;
518*0Sstevel@tonic-gate 			return (0);
519*0Sstevel@tonic-gate 		}
520*0Sstevel@tonic-gate 	}
521*0Sstevel@tonic-gate }
522*0Sstevel@tonic-gate 
523*0Sstevel@tonic-gate #ifdef notdef
524*0Sstevel@tonic-gate static
525*0Sstevel@tonic-gate Gmatch(s, p)
526*0Sstevel@tonic-gate 	register char *s, *p;
527*0Sstevel@tonic-gate {
528*0Sstevel@tonic-gate 	register int scc;
529*0Sstevel@tonic-gate 	int ok, lc;
530*0Sstevel@tonic-gate 	int c, cc;
531*0Sstevel@tonic-gate 
532*0Sstevel@tonic-gate 	for (;;) {
533*0Sstevel@tonic-gate 		scc = *s++ & TRIM;
534*0Sstevel@tonic-gate 		switch (c = *p++) {
535*0Sstevel@tonic-gate 
536*0Sstevel@tonic-gate 		case '[':
537*0Sstevel@tonic-gate 			ok = 0;
538*0Sstevel@tonic-gate 			lc = 077777;
539*0Sstevel@tonic-gate 			while (cc = *p++) {
540*0Sstevel@tonic-gate 				if (cc == ']') {
541*0Sstevel@tonic-gate 					if (ok)
542*0Sstevel@tonic-gate 						break;
543*0Sstevel@tonic-gate 					return (0);
544*0Sstevel@tonic-gate 				}
545*0Sstevel@tonic-gate 				if (cc == '-') {
546*0Sstevel@tonic-gate 					if (lc <= scc && scc <= *p++)
547*0Sstevel@tonic-gate 						ok++;
548*0Sstevel@tonic-gate 				} else
549*0Sstevel@tonic-gate 					if (scc == (lc = cc))
550*0Sstevel@tonic-gate 						ok++;
551*0Sstevel@tonic-gate 			}
552*0Sstevel@tonic-gate 			if (cc == 0)
553*0Sstevel@tonic-gate 				if (ok)
554*0Sstevel@tonic-gate 					p--;
555*0Sstevel@tonic-gate 				else
556*0Sstevel@tonic-gate 					return (0);
557*0Sstevel@tonic-gate 			continue;
558*0Sstevel@tonic-gate 
559*0Sstevel@tonic-gate 		case '*':
560*0Sstevel@tonic-gate 			if (!*p)
561*0Sstevel@tonic-gate 				return (1);
562*0Sstevel@tonic-gate 			for (s--; *s; s++)
563*0Sstevel@tonic-gate 				if (Gmatch(s, p))
564*0Sstevel@tonic-gate 					return (1);
565*0Sstevel@tonic-gate 			return (0);
566*0Sstevel@tonic-gate 
567*0Sstevel@tonic-gate 		case 0:
568*0Sstevel@tonic-gate 			return (scc == 0);
569*0Sstevel@tonic-gate 
570*0Sstevel@tonic-gate 		default:
571*0Sstevel@tonic-gate 			if ((c & TRIM) != scc)
572*0Sstevel@tonic-gate 				return (0);
573*0Sstevel@tonic-gate 			continue;
574*0Sstevel@tonic-gate 
575*0Sstevel@tonic-gate 		case '?':
576*0Sstevel@tonic-gate 			if (scc == 0)
577*0Sstevel@tonic-gate 				return (0);
578*0Sstevel@tonic-gate 			continue;
579*0Sstevel@tonic-gate 
580*0Sstevel@tonic-gate 		}
581*0Sstevel@tonic-gate 	}
582*0Sstevel@tonic-gate }
583*0Sstevel@tonic-gate #endif
584*0Sstevel@tonic-gate 
585*0Sstevel@tonic-gate static void
586*0Sstevel@tonic-gate Gcat(char *s1, char *s2)
587*0Sstevel@tonic-gate {
588*0Sstevel@tonic-gate 	if (gargc >= agargv_size - 1) {
589*0Sstevel@tonic-gate 		char **tmp;
590*0Sstevel@tonic-gate 
591*0Sstevel@tonic-gate 		if (globerr) {
592*0Sstevel@tonic-gate 			return;
593*0Sstevel@tonic-gate 		}
594*0Sstevel@tonic-gate 		tmp = (char **)realloc(agargv,
595*0Sstevel@tonic-gate 		    (agargv_size + GAVSIZ) * sizeof (char *));
596*0Sstevel@tonic-gate 		if (tmp == NULL) {
597*0Sstevel@tonic-gate 			globerr = "Arguments too long";
598*0Sstevel@tonic-gate 			return;
599*0Sstevel@tonic-gate 		} else {
600*0Sstevel@tonic-gate 			agargv = tmp;
601*0Sstevel@tonic-gate 			agargv_size += GAVSIZ;
602*0Sstevel@tonic-gate 		}
603*0Sstevel@tonic-gate 		gargv = agargv;
604*0Sstevel@tonic-gate 		sortbas = agargv;
605*0Sstevel@tonic-gate 	}
606*0Sstevel@tonic-gate 	gargc++;
607*0Sstevel@tonic-gate 	gargv[gargc] = 0;
608*0Sstevel@tonic-gate 	gargv[gargc - 1] = strspl(s1, s2);
609*0Sstevel@tonic-gate }
610*0Sstevel@tonic-gate 
611*0Sstevel@tonic-gate static void
612*0Sstevel@tonic-gate addpath(char c)
613*0Sstevel@tonic-gate {
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate 	if (gpathp >= lastgpathp)
616*0Sstevel@tonic-gate 		globerr = "Pathname too long";
617*0Sstevel@tonic-gate 	else {
618*0Sstevel@tonic-gate 		*gpathp++ = c;
619*0Sstevel@tonic-gate 		*gpathp = 0;
620*0Sstevel@tonic-gate 	}
621*0Sstevel@tonic-gate }
622*0Sstevel@tonic-gate 
623*0Sstevel@tonic-gate static void
624*0Sstevel@tonic-gate rscan(char **t, int (*f)(char))
625*0Sstevel@tonic-gate {
626*0Sstevel@tonic-gate 	register char *p, c;
627*0Sstevel@tonic-gate 	int	len;
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	while (p = *t++) {
630*0Sstevel@tonic-gate 		if (f == tglob)
631*0Sstevel@tonic-gate 			if (*p == '~')
632*0Sstevel@tonic-gate 				gflag |= 2;
633*0Sstevel@tonic-gate 			else if (eq(p, "{") || eq(p, "{}"))
634*0Sstevel@tonic-gate 				continue;
635*0Sstevel@tonic-gate 		while ((c = *p) != '\0') {
636*0Sstevel@tonic-gate 			(void) (*f)(c);
637*0Sstevel@tonic-gate 			if ((len = mblen(p, MB_CUR_MAX)) <= 0)
638*0Sstevel@tonic-gate 				len = 1;
639*0Sstevel@tonic-gate 			p += len;
640*0Sstevel@tonic-gate 		}
641*0Sstevel@tonic-gate 	}
642*0Sstevel@tonic-gate }
643*0Sstevel@tonic-gate 
644*0Sstevel@tonic-gate static int
645*0Sstevel@tonic-gate tglob(char c)
646*0Sstevel@tonic-gate {
647*0Sstevel@tonic-gate 	if (any(c, globchars))
648*0Sstevel@tonic-gate 		gflag |= c == '{' ? 2 : 1;
649*0Sstevel@tonic-gate 	return (c);
650*0Sstevel@tonic-gate }
651*0Sstevel@tonic-gate 
652*0Sstevel@tonic-gate static int
653*0Sstevel@tonic-gate letter(char c)
654*0Sstevel@tonic-gate {
655*0Sstevel@tonic-gate 	return (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || c == '_');
656*0Sstevel@tonic-gate }
657*0Sstevel@tonic-gate 
658*0Sstevel@tonic-gate static int
659*0Sstevel@tonic-gate digit(char c)
660*0Sstevel@tonic-gate {
661*0Sstevel@tonic-gate 	return (c >= '0' && c <= '9');
662*0Sstevel@tonic-gate }
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate static int
665*0Sstevel@tonic-gate any(int c, char *s)
666*0Sstevel@tonic-gate {
667*0Sstevel@tonic-gate 	int	len;
668*0Sstevel@tonic-gate 
669*0Sstevel@tonic-gate 	while (*s) {
670*0Sstevel@tonic-gate 		if (*s == c)
671*0Sstevel@tonic-gate 			return (1);
672*0Sstevel@tonic-gate 		if ((len = mblen(s, MB_CUR_MAX)) <= 0)
673*0Sstevel@tonic-gate 			len = 1;
674*0Sstevel@tonic-gate 		s += len;
675*0Sstevel@tonic-gate 	}
676*0Sstevel@tonic-gate 	return (0);
677*0Sstevel@tonic-gate }
678*0Sstevel@tonic-gate 
679*0Sstevel@tonic-gate static int
680*0Sstevel@tonic-gate blklen(char **av)
681*0Sstevel@tonic-gate {
682*0Sstevel@tonic-gate 	register int i = 0;
683*0Sstevel@tonic-gate 
684*0Sstevel@tonic-gate 	while (*av++)
685*0Sstevel@tonic-gate 		i++;
686*0Sstevel@tonic-gate 	return (i);
687*0Sstevel@tonic-gate }
688*0Sstevel@tonic-gate 
689*0Sstevel@tonic-gate static char **
690*0Sstevel@tonic-gate blkcpy(char **oav, char **bv)
691*0Sstevel@tonic-gate {
692*0Sstevel@tonic-gate 	register char **av = oav;
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate 	while (*av++ = *bv++)
695*0Sstevel@tonic-gate 		continue;
696*0Sstevel@tonic-gate 	return (oav);
697*0Sstevel@tonic-gate }
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate void
700*0Sstevel@tonic-gate blkfree(char **av0)
701*0Sstevel@tonic-gate {
702*0Sstevel@tonic-gate 	register char **av = av0;
703*0Sstevel@tonic-gate 
704*0Sstevel@tonic-gate 	while (*av)
705*0Sstevel@tonic-gate 		xfree(*av++);
706*0Sstevel@tonic-gate 	free(av0);
707*0Sstevel@tonic-gate }
708*0Sstevel@tonic-gate 
709*0Sstevel@tonic-gate static void
710*0Sstevel@tonic-gate xfree(char *cp)
711*0Sstevel@tonic-gate {
712*0Sstevel@tonic-gate 	extern char end[];
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	if (cp >= end && cp < (char *)&cp)
715*0Sstevel@tonic-gate 		free(cp);
716*0Sstevel@tonic-gate }
717*0Sstevel@tonic-gate 
718*0Sstevel@tonic-gate static char *
719*0Sstevel@tonic-gate strspl(char *cp, char *dp)
720*0Sstevel@tonic-gate {
721*0Sstevel@tonic-gate 	register char *ep = malloc((unsigned)(strlen(cp) + strlen(dp) + 1));
722*0Sstevel@tonic-gate 
723*0Sstevel@tonic-gate 	if (ep == (char *)0)
724*0Sstevel@tonic-gate 		fatal("Out of memory");
725*0Sstevel@tonic-gate 	(void) strcpy(ep, cp);
726*0Sstevel@tonic-gate 	(void) strcat(ep, dp);
727*0Sstevel@tonic-gate 	return (ep);
728*0Sstevel@tonic-gate }
729*0Sstevel@tonic-gate 
730*0Sstevel@tonic-gate static char **
731*0Sstevel@tonic-gate copyblk(char **v)
732*0Sstevel@tonic-gate {
733*0Sstevel@tonic-gate 	register char **nv = (char **)malloc((unsigned)((blklen(v) + 1) *
734*0Sstevel@tonic-gate 	    sizeof (char **)));
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	if (nv == (char **)0)
737*0Sstevel@tonic-gate 		fatal("Out of memory");
738*0Sstevel@tonic-gate 
739*0Sstevel@tonic-gate 	return (blkcpy(nv, v));
740*0Sstevel@tonic-gate }
741*0Sstevel@tonic-gate 
742*0Sstevel@tonic-gate static char *
743*0Sstevel@tonic-gate strend(char *cp)
744*0Sstevel@tonic-gate {
745*0Sstevel@tonic-gate 
746*0Sstevel@tonic-gate 	while (*cp)
747*0Sstevel@tonic-gate 		cp++;
748*0Sstevel@tonic-gate 	return (cp);
749*0Sstevel@tonic-gate }
750*0Sstevel@tonic-gate /*
751*0Sstevel@tonic-gate  * Extract a home directory from the password file
752*0Sstevel@tonic-gate  * The argument points to a buffer where the name of the
753*0Sstevel@tonic-gate  * user whose home directory is sought is currently.
754*0Sstevel@tonic-gate  * We write the home directory of the user back there.
755*0Sstevel@tonic-gate  */
756*0Sstevel@tonic-gate gethdir(char *home)
757*0Sstevel@tonic-gate {
758*0Sstevel@tonic-gate 	register struct passwd *pp = getpwnam(home);
759*0Sstevel@tonic-gate 
760*0Sstevel@tonic-gate 	if (!pp || home + strlen(pp->pw_dir) >= lastgpathp)
761*0Sstevel@tonic-gate 		return (1);
762*0Sstevel@tonic-gate 	(void) strcpy(home, pp->pw_dir);
763*0Sstevel@tonic-gate 	return (0);
764*0Sstevel@tonic-gate }
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate static int
767*0Sstevel@tonic-gate ftp_fnmatch(wchar_t t_ch, wchar_t t_fch, wchar_t t_lch)
768*0Sstevel@tonic-gate {
769*0Sstevel@tonic-gate 	char	t_char[MB_LEN_MAX + 1];
770*0Sstevel@tonic-gate 	char	t_patan[MB_LEN_MAX * 2 + 8];
771*0Sstevel@tonic-gate 	char	*p;
772*0Sstevel@tonic-gate 	int	i;
773*0Sstevel@tonic-gate 
774*0Sstevel@tonic-gate 	if ((t_ch == t_fch) || (t_ch == t_lch))
775*0Sstevel@tonic-gate 		return (1);
776*0Sstevel@tonic-gate 
777*0Sstevel@tonic-gate 	p = t_patan;
778*0Sstevel@tonic-gate 	if ((i = wctomb(t_char, (wchar_t)t_ch)) <= 0)
779*0Sstevel@tonic-gate 		return (0);
780*0Sstevel@tonic-gate 	t_char[i] = 0;
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate 	*p++ = '[';
783*0Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_fch)) <= 0)
784*0Sstevel@tonic-gate 		return (0);
785*0Sstevel@tonic-gate 	p += i;
786*0Sstevel@tonic-gate 	*p++ = '-';
787*0Sstevel@tonic-gate 	if ((i = wctomb(p, (wchar_t)t_lch)) <= 0)
788*0Sstevel@tonic-gate 		return (0);
789*0Sstevel@tonic-gate 	p += i;
790*0Sstevel@tonic-gate 	*p++ = ']';
791*0Sstevel@tonic-gate 	*p = 0;
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	if (fnmatch(t_patan, t_char, FNM_NOESCAPE))
794*0Sstevel@tonic-gate 		return (0);
795*0Sstevel@tonic-gate 	return (1);
796*0Sstevel@tonic-gate }
797