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