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