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