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