glob.c revision 98937
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Guido van Rossum.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#include "includes.h"
38#include <ctype.h>
39
40static long
41get_arg_max(void)
42{
43#ifdef ARG_MAX
44	return(ARG_MAX);
45#elif defined(HAVE_SYSCONF) && defined(_SC_ARG_MAX)
46	return(sysconf(_SC_ARG_MAX));
47#else
48	return(256); /* XXX: arbitrary */
49#endif
50}
51
52#if !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) || \
53    !defined(GLOB_HAS_GL_MATCHC)
54
55#if defined(LIBC_SCCS) && !defined(lint)
56#if 0
57static char sccsid[] = "@(#)glob.c	8.3 (Berkeley) 10/13/93";
58#else
59static char rcsid[] = "$OpenBSD: glob.c,v 1.16 2001/04/05 18:36:12 deraadt Exp $";
60#endif
61#endif /* LIBC_SCCS and not lint */
62
63/*
64 * glob(3) -- a superset of the one defined in POSIX 1003.2.
65 *
66 * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
67 *
68 * Optional extra services, controlled by flags not defined by POSIX:
69 *
70 * GLOB_QUOTE:
71 *	Escaping convention: \ inhibits any special meaning the following
72 *	character might have (except \ at end of string is retained).
73 * GLOB_MAGCHAR:
74 *	Set in gl_flags if pattern contained a globbing character.
75 * GLOB_NOMAGIC:
76 *	Same as GLOB_NOCHECK, but it will only append pattern if it did
77 *	not contain any magic characters.  [Used in csh style globbing]
78 * GLOB_ALTDIRFUNC:
79 *	Use alternately specified directory access functions.
80 * GLOB_TILDE:
81 *	expand ~user/foo to the /home/dir/of/user/foo
82 * GLOB_BRACE:
83 *	expand {1,2}{a,b} to 1a 1b 2a 2b
84 * gl_matchc:
85 *	Number of matches in the current invocation of glob.
86 */
87
88
89#define	DOLLAR		'$'
90#define	DOT		'.'
91#define	EOS		'\0'
92#define	LBRACKET	'['
93#define	NOT		'!'
94#define	QUESTION	'?'
95#define	QUOTE		'\\'
96#define	RANGE		'-'
97#define	RBRACKET	']'
98#define	SEP		'/'
99#define	STAR		'*'
100#define	TILDE		'~'
101#define	UNDERSCORE	'_'
102#define	LBRACE		'{'
103#define	RBRACE		'}'
104#define	SLASH		'/'
105#define	COMMA		','
106
107#ifndef DEBUG
108
109#define	M_QUOTE		0x8000
110#define	M_PROTECT	0x4000
111#define	M_MASK		0xffff
112#define	M_ASCII		0x00ff
113
114typedef u_short Char;
115
116#else
117
118#define	M_QUOTE		0x80
119#define	M_PROTECT	0x40
120#define	M_MASK		0xff
121#define	M_ASCII		0x7f
122
123typedef char Char;
124
125#endif
126
127
128#define	CHAR(c)		((Char)((c)&M_ASCII))
129#define	META(c)		((Char)((c)|M_QUOTE))
130#define	M_ALL		META('*')
131#define	M_END		META(']')
132#define	M_NOT		META('!')
133#define	M_ONE		META('?')
134#define	M_RNG		META('-')
135#define	M_SET		META('[')
136#define	ismeta(c)	(((c)&M_QUOTE) != 0)
137
138
139static int	 compare __P((const void *, const void *));
140static int	 g_Ctoc __P((const Char *, char *, u_int));
141static int	 g_lstat __P((Char *, struct stat *, glob_t *));
142static DIR	*g_opendir __P((Char *, glob_t *));
143static Char	*g_strchr __P((Char *, int));
144static int	 g_stat __P((Char *, struct stat *, glob_t *));
145static int	 glob0 __P((const Char *, glob_t *));
146static int	 glob1 __P((Char *, Char *, glob_t *, size_t *));
147static int	 glob2 __P((Char *, Char *, Char *, Char *, Char *, Char *,
148		    glob_t *, size_t *));
149static int	 glob3 __P((Char *, Char *, Char *, Char *, Char *, Char *,
150		    Char *, Char *, glob_t *, size_t *));
151static int	 globextend __P((const Char *, glob_t *, size_t *));
152static const Char *
153		 globtilde __P((const Char *, Char *, size_t, glob_t *));
154static int	 globexp1 __P((const Char *, glob_t *));
155static int	 globexp2 __P((const Char *, const Char *, glob_t *, int *));
156static int	 match __P((Char *, Char *, Char *));
157#ifdef DEBUG
158static void	 qprintf __P((const char *, Char *));
159#endif
160
161int
162glob(pattern, flags, errfunc, pglob)
163	const char *pattern;
164	int flags, (*errfunc) __P((const char *, int));
165	glob_t *pglob;
166{
167	const u_char *patnext;
168	int c;
169	Char *bufnext, *bufend, patbuf[MAXPATHLEN];
170
171	patnext = (u_char *) pattern;
172	if (!(flags & GLOB_APPEND)) {
173		pglob->gl_pathc = 0;
174		pglob->gl_pathv = NULL;
175		if (!(flags & GLOB_DOOFFS))
176			pglob->gl_offs = 0;
177	}
178	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
179	pglob->gl_errfunc = errfunc;
180	pglob->gl_matchc = 0;
181
182	bufnext = patbuf;
183	bufend = bufnext + MAXPATHLEN - 1;
184	if (flags & GLOB_NOESCAPE)
185		while (bufnext < bufend && (c = *patnext++) != EOS)
186			*bufnext++ = c;
187	else {
188		/* Protect the quoted characters. */
189		while (bufnext < bufend && (c = *patnext++) != EOS)
190			if (c == QUOTE) {
191				if ((c = *patnext++) == EOS) {
192					c = QUOTE;
193					--patnext;
194				}
195				*bufnext++ = c | M_PROTECT;
196			} else
197				*bufnext++ = c;
198	}
199	*bufnext = EOS;
200
201	if (flags & GLOB_BRACE)
202		return globexp1(patbuf, pglob);
203	else
204		return glob0(patbuf, pglob);
205}
206
207/*
208 * Expand recursively a glob {} pattern. When there is no more expansion
209 * invoke the standard globbing routine to glob the rest of the magic
210 * characters
211 */
212static int
213globexp1(pattern, pglob)
214	const Char *pattern;
215	glob_t *pglob;
216{
217	const Char* ptr = pattern;
218	int rv;
219
220	/* Protect a single {}, for find(1), like csh */
221	if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
222		return glob0(pattern, pglob);
223
224	while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
225		if (!globexp2(ptr, pattern, pglob, &rv))
226			return rv;
227
228	return glob0(pattern, pglob);
229}
230
231
232/*
233 * Recursive brace globbing helper. Tries to expand a single brace.
234 * If it succeeds then it invokes globexp1 with the new pattern.
235 * If it fails then it tries to glob the rest of the pattern and returns.
236 */
237static int
238globexp2(ptr, pattern, pglob, rv)
239	const Char *ptr, *pattern;
240	glob_t *pglob;
241	int *rv;
242{
243	int     i;
244	Char   *lm, *ls;
245	const Char *pe, *pm, *pl;
246	Char    patbuf[MAXPATHLEN];
247
248	/* copy part up to the brace */
249	for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
250		;
251	*lm = EOS;
252	ls = lm;
253
254	/* Find the balanced brace */
255	for (i = 0, pe = ++ptr; *pe; pe++)
256		if (*pe == LBRACKET) {
257			/* Ignore everything between [] */
258			for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
259				;
260			if (*pe == EOS) {
261				/*
262				 * We could not find a matching RBRACKET.
263				 * Ignore and just look for RBRACE
264				 */
265				pe = pm;
266			}
267		} else if (*pe == LBRACE)
268			i++;
269		else if (*pe == RBRACE) {
270			if (i == 0)
271				break;
272			i--;
273		}
274
275	/* Non matching braces; just glob the pattern */
276	if (i != 0 || *pe == EOS) {
277		*rv = glob0(patbuf, pglob);
278		return 0;
279	}
280
281	for (i = 0, pl = pm = ptr; pm <= pe; pm++) {
282		switch (*pm) {
283		case LBRACKET:
284			/* Ignore everything between [] */
285			for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
286				;
287			if (*pm == EOS) {
288				/*
289				 * We could not find a matching RBRACKET.
290				 * Ignore and just look for RBRACE
291				 */
292				pm = pl;
293			}
294			break;
295
296		case LBRACE:
297			i++;
298			break;
299
300		case RBRACE:
301			if (i) {
302				i--;
303				break;
304			}
305			/* FALLTHROUGH */
306		case COMMA:
307			if (i && *pm == COMMA)
308				break;
309			else {
310				/* Append the current string */
311				for (lm = ls; (pl < pm); *lm++ = *pl++)
312					;
313
314				/*
315				 * Append the rest of the pattern after the
316				 * closing brace
317				 */
318				for (pl = pe + 1; (*lm++ = *pl++) != EOS; )
319					;
320
321				/* Expand the current pattern */
322#ifdef DEBUG
323				qprintf("globexp2:", patbuf);
324#endif
325				*rv = globexp1(patbuf, pglob);
326
327				/* move after the comma, to the next string */
328				pl = pm + 1;
329			}
330			break;
331
332		default:
333			break;
334		}
335	}
336	*rv = 0;
337	return 0;
338}
339
340
341
342/*
343 * expand tilde from the passwd file.
344 */
345static const Char *
346globtilde(pattern, patbuf, patbuf_len, pglob)
347	const Char *pattern;
348	Char *patbuf;
349	size_t patbuf_len;
350	glob_t *pglob;
351{
352	struct passwd *pwd;
353	char *h;
354	const Char *p;
355	Char *b, *eb;
356
357	if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
358		return pattern;
359
360	/* Copy up to the end of the string or / */
361	eb = &patbuf[patbuf_len - 1];
362	for (p = pattern + 1, h = (char *) patbuf;
363	    h < (char *)eb && *p && *p != SLASH; *h++ = *p++)
364		;
365
366	*h = EOS;
367
368#if 0
369	if (h == (char *)eb)
370		return what;
371#endif
372
373	if (((char *) patbuf)[0] == EOS) {
374		/*
375		 * handle a plain ~ or ~/ by expanding $HOME
376		 * first and then trying the password file
377		 */
378#if 0
379		if (issetugid() != 0 || (h = getenv("HOME")) == NULL) {
380#endif
381		if ((getuid() != geteuid()) || (h = getenv("HOME")) == NULL) {
382			if ((pwd = getpwuid(getuid())) == NULL)
383				return pattern;
384			else
385				h = pwd->pw_dir;
386		}
387	} else {
388		/*
389		 * Expand a ~user
390		 */
391		if ((pwd = getpwnam((char*) patbuf)) == NULL)
392			return pattern;
393		else
394			h = pwd->pw_dir;
395	}
396
397	/* Copy the home directory */
398	for (b = patbuf; b < eb && *h; *b++ = *h++)
399		;
400
401	/* Append the rest of the pattern */
402	while (b < eb && (*b++ = *p++) != EOS)
403		;
404	*b = EOS;
405
406	return patbuf;
407}
408
409
410/*
411 * The main glob() routine: compiles the pattern (optionally processing
412 * quotes), calls glob1() to do the real pattern matching, and finally
413 * sorts the list (unless unsorted operation is requested).  Returns 0
414 * if things went well, nonzero if errors occurred.  It is not an error
415 * to find no matches.
416 */
417static int
418glob0(pattern, pglob)
419	const Char *pattern;
420	glob_t *pglob;
421{
422	const Char *qpatnext;
423	int c, err, oldpathc;
424	Char *bufnext, patbuf[MAXPATHLEN];
425	size_t limit = 0;
426
427	qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob);
428	oldpathc = pglob->gl_pathc;
429	bufnext = patbuf;
430
431	/* We don't need to check for buffer overflow any more. */
432	while ((c = *qpatnext++) != EOS) {
433		switch (c) {
434		case LBRACKET:
435			c = *qpatnext;
436			if (c == NOT)
437				++qpatnext;
438			if (*qpatnext == EOS ||
439			    g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
440				*bufnext++ = LBRACKET;
441				if (c == NOT)
442					--qpatnext;
443				break;
444			}
445			*bufnext++ = M_SET;
446			if (c == NOT)
447				*bufnext++ = M_NOT;
448			c = *qpatnext++;
449			do {
450				*bufnext++ = CHAR(c);
451				if (*qpatnext == RANGE &&
452				    (c = qpatnext[1]) != RBRACKET) {
453					*bufnext++ = M_RNG;
454					*bufnext++ = CHAR(c);
455					qpatnext += 2;
456				}
457			} while ((c = *qpatnext++) != RBRACKET);
458			pglob->gl_flags |= GLOB_MAGCHAR;
459			*bufnext++ = M_END;
460			break;
461		case QUESTION:
462			pglob->gl_flags |= GLOB_MAGCHAR;
463			*bufnext++ = M_ONE;
464			break;
465		case STAR:
466			pglob->gl_flags |= GLOB_MAGCHAR;
467			/* collapse adjacent stars to one,
468			 * to avoid exponential behavior
469			 */
470			if (bufnext == patbuf || bufnext[-1] != M_ALL)
471				*bufnext++ = M_ALL;
472			break;
473		default:
474			*bufnext++ = CHAR(c);
475			break;
476		}
477	}
478	*bufnext = EOS;
479#ifdef DEBUG
480	qprintf("glob0:", patbuf);
481#endif
482
483	if ((err = glob1(patbuf, patbuf+MAXPATHLEN-1, pglob, &limit)) != 0)
484		return(err);
485
486	/*
487	 * If there was no match we are going to append the pattern
488	 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
489	 * and the pattern did not contain any magic characters
490	 * GLOB_NOMAGIC is there just for compatibility with csh.
491	 */
492	if (pglob->gl_pathc == oldpathc) {
493		if ((pglob->gl_flags & GLOB_NOCHECK) ||
494		    ((pglob->gl_flags & GLOB_NOMAGIC) &&
495		    !(pglob->gl_flags & GLOB_MAGCHAR)))
496			return(globextend(pattern, pglob, &limit));
497		else
498			return(GLOB_NOMATCH);
499	}
500	if (!(pglob->gl_flags & GLOB_NOSORT))
501		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
502		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
503	return(0);
504}
505
506static int
507compare(p, q)
508	const void *p, *q;
509{
510	return(strcmp(*(char **)p, *(char **)q));
511}
512
513static int
514glob1(pattern, pattern_last, pglob, limitp)
515	Char *pattern, *pattern_last;
516	glob_t *pglob;
517	size_t *limitp;
518{
519	Char pathbuf[MAXPATHLEN];
520
521	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
522	if (*pattern == EOS)
523		return(0);
524	return(glob2(pathbuf, pathbuf+MAXPATHLEN-1,
525	    pathbuf, pathbuf+MAXPATHLEN-1,
526	    pattern, pattern_last, pglob, limitp));
527}
528
529/*
530 * The functions glob2 and glob3 are mutually recursive; there is one level
531 * of recursion for each segment in the pattern that contains one or more
532 * meta characters.
533 */
534static int
535glob2(pathbuf, pathbuf_last, pathend, pathend_last, pattern,
536    pattern_last, pglob, limitp)
537	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
538	Char *pattern, *pattern_last;
539	glob_t *pglob;
540	size_t *limitp;
541{
542	struct stat sb;
543	Char *p, *q;
544	int anymeta;
545
546	/*
547	 * Loop over pattern segments until end of pattern or until
548	 * segment with meta character found.
549	 */
550	for (anymeta = 0;;) {
551		if (*pattern == EOS) {		/* End of pattern? */
552			*pathend = EOS;
553			if (g_lstat(pathbuf, &sb, pglob))
554				return(0);
555
556			if (((pglob->gl_flags & GLOB_MARK) &&
557			    pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) ||
558			    (S_ISLNK(sb.st_mode) &&
559			    (g_stat(pathbuf, &sb, pglob) == 0) &&
560			    S_ISDIR(sb.st_mode)))) {
561				if (pathend+1 > pathend_last)
562					return (1);
563				*pathend++ = SEP;
564				*pathend = EOS;
565			}
566			++pglob->gl_matchc;
567			return(globextend(pathbuf, pglob, limitp));
568		}
569
570		/* Find end of next segment, copy tentatively to pathend. */
571		q = pathend;
572		p = pattern;
573		while (*p != EOS && *p != SEP) {
574			if (ismeta(*p))
575				anymeta = 1;
576			if (q+1 > pathend_last)
577				return (1);
578			*q++ = *p++;
579		}
580
581		if (!anymeta) {		/* No expansion, do next segment. */
582			pathend = q;
583			pattern = p;
584			while (*pattern == SEP) {
585				if (pathend+1 > pathend_last)
586					return (1);
587				*pathend++ = *pattern++;
588			}
589		} else
590			/* Need expansion, recurse. */
591			return(glob3(pathbuf, pathbuf_last, pathend,
592			    pathend_last, pattern, pattern_last,
593			    p, pattern_last, pglob, limitp));
594	}
595	/* NOTREACHED */
596}
597
598static int
599glob3(pathbuf, pathbuf_last, pathend, pathend_last, pattern, pattern_last,
600    restpattern, restpattern_last, pglob, limitp)
601	Char *pathbuf, *pathbuf_last, *pathend, *pathend_last;
602	Char *pattern, *pattern_last, *restpattern, *restpattern_last;
603	glob_t *pglob;
604	size_t *limitp;
605{
606	register struct dirent *dp;
607	DIR *dirp;
608	int err;
609	char buf[MAXPATHLEN];
610
611	/*
612	 * The readdirfunc declaration can't be prototyped, because it is
613	 * assigned, below, to two functions which are prototyped in glob.h
614	 * and dirent.h as taking pointers to differently typed opaque
615	 * structures.
616	 */
617	struct dirent *(*readdirfunc)();
618
619	if (pathend > pathend_last)
620		return (1);
621	*pathend = EOS;
622	errno = 0;
623
624	if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
625		/* TODO: don't call for ENOENT or ENOTDIR? */
626		if (pglob->gl_errfunc) {
627			if (g_Ctoc(pathbuf, buf, sizeof(buf)))
628				return(GLOB_ABORTED);
629			if (pglob->gl_errfunc(buf, errno) ||
630			    pglob->gl_flags & GLOB_ERR)
631				return(GLOB_ABORTED);
632		}
633		return(0);
634	}
635
636	err = 0;
637
638	/* Search directory for matching names. */
639	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
640		readdirfunc = pglob->gl_readdir;
641	else
642		readdirfunc = readdir;
643	while ((dp = (*readdirfunc)(dirp))) {
644		register u_char *sc;
645		register Char *dc;
646
647		/* Initial DOT must be matched literally. */
648		if (dp->d_name[0] == DOT && *pattern != DOT)
649			continue;
650		dc = pathend;
651		sc = (u_char *) dp->d_name;
652		while (dc < pathend_last && (*dc++ = *sc++) != EOS)
653			;
654		if (dc >= pathend_last) {
655			*dc = EOS;
656			err = 1;
657			break;
658		}
659
660		if (!match(pathend, pattern, restpattern)) {
661			*pathend = EOS;
662			continue;
663		}
664		err = glob2(pathbuf, pathbuf_last, --dc, pathend_last,
665		    restpattern, restpattern_last, pglob, limitp);
666		if (err)
667			break;
668	}
669
670	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
671		(*pglob->gl_closedir)(dirp);
672	else
673		closedir(dirp);
674	return(err);
675}
676
677
678/*
679 * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
680 * add the new item, and update gl_pathc.
681 *
682 * This assumes the BSD realloc, which only copies the block when its size
683 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
684 * behavior.
685 *
686 * Return 0 if new item added, error code if memory couldn't be allocated.
687 *
688 * Invariant of the glob_t structure:
689 *	Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
690 *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
691 */
692static int
693globextend(path, pglob, limitp)
694	const Char *path;
695	glob_t *pglob;
696	size_t *limitp;
697{
698	register char **pathv;
699	register int i;
700	u_int newsize, len;
701	char *copy;
702	const Char *p;
703
704	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
705	pathv = pglob->gl_pathv ? realloc((char *)pglob->gl_pathv, newsize) :
706	    malloc(newsize);
707	if (pathv == NULL) {
708		if (pglob->gl_pathv) {
709			free(pglob->gl_pathv);
710			pglob->gl_pathv = NULL;
711		}
712		return(GLOB_NOSPACE);
713	}
714
715	if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
716		/* first time around -- clear initial gl_offs items */
717		pathv += pglob->gl_offs;
718		for (i = pglob->gl_offs; --i >= 0; )
719			*--pathv = NULL;
720	}
721	pglob->gl_pathv = pathv;
722
723	for (p = path; *p++;)
724		;
725	len = (size_t)(p - path);
726	*limitp += len;
727	if ((copy = malloc(len)) != NULL) {
728		if (g_Ctoc(path, copy, len)) {
729			free(copy);
730			return(GLOB_NOSPACE);
731		}
732		pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
733	}
734	pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
735
736	if ((pglob->gl_flags & GLOB_LIMIT) &&
737	    newsize + *limitp >= (u_int) get_arg_max()) {
738		errno = 0;
739		return(GLOB_NOSPACE);
740	}
741
742	return(copy == NULL ? GLOB_NOSPACE : 0);
743}
744
745
746/*
747 * pattern matching function for filenames.  Each occurrence of the *
748 * pattern causes a recursion level.
749 */
750static int
751match(name, pat, patend)
752	register Char *name, *pat, *patend;
753{
754	int ok, negate_range;
755	Char c, k;
756
757	while (pat < patend) {
758		c = *pat++;
759		switch (c & M_MASK) {
760		case M_ALL:
761			if (pat == patend)
762				return(1);
763			do
764			    if (match(name, pat, patend))
765				    return(1);
766			while (*name++ != EOS)
767				;
768			return(0);
769		case M_ONE:
770			if (*name++ == EOS)
771				return(0);
772			break;
773		case M_SET:
774			ok = 0;
775			if ((k = *name++) == EOS)
776				return(0);
777			if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
778				++pat;
779			while (((c = *pat++) & M_MASK) != M_END)
780				if ((*pat & M_MASK) == M_RNG) {
781					if (c <= k && k <= pat[1])
782						ok = 1;
783					pat += 2;
784				} else if (c == k)
785					ok = 1;
786			if (ok == negate_range)
787				return(0);
788			break;
789		default:
790			if (*name++ != c)
791				return(0);
792			break;
793		}
794	}
795	return(*name == EOS);
796}
797
798/* Free allocated data belonging to a glob_t structure. */
799void
800globfree(pglob)
801	glob_t *pglob;
802{
803	register int i;
804	register char **pp;
805
806	if (pglob->gl_pathv != NULL) {
807		pp = pglob->gl_pathv + pglob->gl_offs;
808		for (i = pglob->gl_pathc; i--; ++pp)
809			if (*pp)
810				free(*pp);
811		free(pglob->gl_pathv);
812		pglob->gl_pathv = NULL;
813	}
814}
815
816static DIR *
817g_opendir(str, pglob)
818	register Char *str;
819	glob_t *pglob;
820{
821	char buf[MAXPATHLEN];
822
823	if (!*str)
824		strcpy(buf, ".");
825	else {
826		if (g_Ctoc(str, buf, sizeof(buf)))
827			return(NULL);
828	}
829
830	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
831		return((*pglob->gl_opendir)(buf));
832
833	return(opendir(buf));
834}
835
836static int
837g_lstat(fn, sb, pglob)
838	register Char *fn;
839	struct stat *sb;
840	glob_t *pglob;
841{
842	char buf[MAXPATHLEN];
843
844	if (g_Ctoc(fn, buf, sizeof(buf)))
845		return(-1);
846	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
847		return((*pglob->gl_lstat)(buf, sb));
848	return(lstat(buf, sb));
849}
850
851static int
852g_stat(fn, sb, pglob)
853	register Char *fn;
854	struct stat *sb;
855	glob_t *pglob;
856{
857	char buf[MAXPATHLEN];
858
859	if (g_Ctoc(fn, buf, sizeof(buf)))
860		return(-1);
861	if (pglob->gl_flags & GLOB_ALTDIRFUNC)
862		return((*pglob->gl_stat)(buf, sb));
863	return(stat(buf, sb));
864}
865
866static Char *
867g_strchr(str, ch)
868	Char *str;
869	int ch;
870{
871	do {
872		if (*str == ch)
873			return (str);
874	} while (*str++);
875	return (NULL);
876}
877
878static int
879g_Ctoc(str, buf, len)
880	register const Char *str;
881	char *buf;
882	u_int len;
883{
884
885	while (len--) {
886		if ((*buf++ = *str++) == EOS)
887			return (0);
888	}
889	return (1);
890}
891
892#ifdef DEBUG
893static void
894qprintf(str, s)
895	const char *str;
896	register Char *s;
897{
898	register Char *p;
899
900	(void)printf("%s:\n", str);
901	for (p = s; *p; p++)
902		(void)printf("%c", CHAR(*p));
903	(void)printf("\n");
904	for (p = s; *p; p++)
905		(void)printf("%c", *p & M_PROTECT ? '"' : ' ');
906	(void)printf("\n");
907	for (p = s; *p; p++)
908		(void)printf("%c", ismeta(*p) ? '_' : ' ');
909	(void)printf("\n");
910}
911#endif
912
913#endif /* !defined(HAVE_GLOB) || !defined(GLOB_HAS_ALTDIRFUNC) ||
914          !defined(GLOB_HAS_GL_MATCHC) */
915
916