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