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