|
|
1.9 ! fvdl 1: /* $NetBSD: glob.c,v 1.8 1997/10/21 00:56:55 fvdl Exp $ */
1.5 cgd 2:
1.1 cgd 3: /*
1.4 cgd 4: * Copyright (c) 1989, 1993
5: * The Regents of the University of California. All rights reserved.
1.1 cgd 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:
1.6 christos 39: #include <sys/cdefs.h>
1.1 cgd 40: #if defined(LIBC_SCCS) && !defined(lint)
1.5 cgd 41: #if 0
42: static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
43: #else
1.8 fvdl 44: __RCSID("$NetBSD: glob.c,v 1.7 1997/07/21 14:07:17 jtc Exp $");
1.5 cgd 45: #endif
1.1 cgd 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.
1.2 mycroft 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.
1.4 cgd 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
1.1 cgd 69: * gl_matchc:
70: * Number of matches in the current invocation of glob.
71: */
1.9 ! fvdl 72: #define __LIBC12_SOURCE__
1.1 cgd 73:
1.7 jtc 74: #include "namespace.h"
1.1 cgd 75: #include <sys/param.h>
76: #include <sys/stat.h>
1.4 cgd 77: #include <ctype.h>
1.1 cgd 78: #include <dirent.h>
1.4 cgd 79: #include <errno.h>
1.1 cgd 80: #include <glob.h>
1.4 cgd 81: #include <pwd.h>
1.1 cgd 82: #include <stdio.h>
83: #include <stdlib.h>
1.4 cgd 84: #include <string.h>
85: #include <unistd.h>
1.7 jtc 86:
87: #ifdef __weak_alias
88: __weak_alias(glob,_glob);
89: __weak_alias(globfree,_globfree);
90: #endif
1.1 cgd 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 '_'
1.4 cgd 105: #define LBRACE '{'
106: #define RBRACE '}'
107: #define SLASH '/'
108: #define COMMA ','
109:
110: #ifndef DEBUG
1.1 cgd 111:
112: #define M_QUOTE 0x8000
113: #define M_PROTECT 0x4000
114: #define M_MASK 0xffff
115: #define M_ASCII 0x00ff
116:
1.4 cgd 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))
1.1 cgd 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 *));
1.4 cgd 143: static void g_Ctoc __P((const Char *, char *));
1.9 ! fvdl 144: static int g_lstat __P((Char *, struct stat12 *, glob_t *));
! 145: static DIR *g_opendir __P((Char *, glob_t *));
1.1 cgd 146: static Char *g_strchr __P((Char *, int));
1.4 cgd 147: #ifdef notdef
148: static Char *g_strcat __P((Char *, const Char *));
149: #endif
1.9 ! fvdl 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 *));
1.1 cgd 159: static int match __P((Char *, Char *, Char *));
160: #ifdef DEBUG
1.4 cgd 161: static void qprintf __P((const char *, Char *));
1.1 cgd 162: #endif
163:
1.4 cgd 164: int
1.1 cgd 165: glob(pattern, flags, errfunc, pglob)
166: const char *pattern;
1.4 cgd 167: int flags, (*errfunc) __P((const char *, int));
1.9 ! fvdl 168: glob_t *pglob;
1.1 cgd 169: {
1.4 cgd 170: const u_char *patnext;
171: int c;
172: Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
1.1 cgd 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:
1.4 cgd 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;
1.9 ! fvdl 218: glob_t *pglob;
1.4 cgd 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;
1.9 ! fvdl 242: glob_t *pglob;
1.4 cgd 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;
1.9 ! fvdl 349: glob_t *pglob;
1.4 cgd 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;
1.9 ! fvdl 410: glob_t *pglob;
1.4 cgd 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;
1.1 cgd 418: bufnext = patbuf;
1.4 cgd 419:
1.1 cgd 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 ||
1.4 cgd 428: g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
1.1 cgd 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);
1.2 mycroft 447: pglob->gl_flags |= GLOB_MAGCHAR;
1.1 cgd 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;
1.2 mycroft 456: /* collapse adjacent stars to one,
457: * to avoid exponential behavior
458: */
459: if (bufnext == patbuf || bufnext[-1] != M_ALL)
460: *bufnext++ = M_ALL;
1.1 cgd 461: break;
462: default:
463: *bufnext++ = CHAR(c);
464: break;
465: }
466: }
467: *bufnext = EOS;
468: #ifdef DEBUG
1.4 cgd 469: qprintf("glob0:", patbuf);
1.1 cgd 470: #endif
471:
472: if ((err = glob1(patbuf, pglob)) != 0)
473: return(err);
474:
1.2 mycroft 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 &&
1.4 cgd 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))
1.1 cgd 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:
1.4 cgd 499: static int
1.1 cgd 500: glob1(pattern, pglob)
501: Char *pattern;
1.9 ! fvdl 502: glob_t *pglob;
1.1 cgd 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: */
1.4 cgd 517: static int
1.1 cgd 518: glob2(pathbuf, pathend, pattern, pglob)
519: Char *pathbuf, *pathend, *pattern;
1.9 ! fvdl 520: glob_t *pglob;
1.1 cgd 521: {
1.8 fvdl 522: struct stat12 sb;
1.1 cgd 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;
1.2 mycroft 533: if (g_lstat(pathbuf, &sb, pglob))
1.1 cgd 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) &&
1.2 mycroft 539: (g_stat(pathbuf, &sb, pglob) == 0) &&
1.1 cgd 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:
1.4 cgd 568: static int
1.1 cgd 569: glob3(pathbuf, pathend, pattern, restpattern, pglob)
570: Char *pathbuf, *pathend, *pattern, *restpattern;
1.9 ! fvdl 571: glob_t *pglob;
1.1 cgd 572: {
573: register struct dirent *dp;
574: DIR *dirp;
1.4 cgd 575: int err;
1.2 mycroft 576: char buf[MAXPATHLEN];
1.1 cgd 577:
1.4 cgd 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: */
1.6 christos 584: struct dirent *(*readdirfunc) __P((void *));
1.4 cgd 585:
1.1 cgd 586: *pathend = EOS;
587: errno = 0;
588:
1.2 mycroft 589: if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
1.1 cgd 590: /* TODO: don't call for ENOENT or ENOTDIR? */
1.2 mycroft 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: }
1.1 cgd 599:
600: err = 0;
601:
602: /* Search directory for matching names. */
1.2 mycroft 603: if (pglob->gl_flags & GLOB_ALTDIRFUNC)
604: readdirfunc = pglob->gl_readdir;
605: else
1.6 christos 606: readdirfunc = (struct dirent *(*)__P((void *))) readdir;
1.2 mycroft 607: while ((dp = (*readdirfunc)(dirp))) {
1.1 cgd 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;
1.4 cgd 615: (*dc++ = *sc++) != EOS;)
616: continue;
1.1 cgd 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:
1.2 mycroft 626: if (pglob->gl_flags & GLOB_ALTDIRFUNC)
627: (*pglob->gl_closedir)(dirp);
628: else
629: closedir(dirp);
1.1 cgd 630: return(err);
631: }
632:
633:
634: /*
1.9 ! fvdl 635: * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
1.1 cgd 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: *
1.9 ! fvdl 644: * Invariant of the glob_t structure:
1.1 cgd 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)
1.4 cgd 650: const Char *path;
1.9 ! fvdl 651: glob_t *pglob;
1.1 cgd 652: {
653: register char **pathv;
654: register int i;
655: u_int newsize;
656: char *copy;
1.4 cgd 657: const Char *p;
1.1 cgd 658:
659: newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
1.4 cgd 660: pathv = pglob->gl_pathv ?
661: realloc((char *)pglob->gl_pathv, newsize) :
662: malloc(newsize);
1.1 cgd 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:
1.4 cgd 674: for (p = path; *p++;)
675: continue;
1.1 cgd 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: */
1.4 cgd 689: static int
1.1 cgd 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);
1.2 mycroft 702: do
703: if (match(name, pat, patend))
704: return(1);
705: while (*name++ != EOS);
1.1 cgd 706: return(0);
707: case M_ONE:
708: if (*name++ == EOS)
709: return(0);
710: break;
711: case M_SET:
712: ok = 0;
1.2 mycroft 713: if ((k = *name++) == EOS)
714: return(0);
1.4 cgd 715: if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
1.1 cgd 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:
1.9 ! fvdl 736: /* Free allocated data belonging to a glob_t structure. */
1.1 cgd 737: void
738: globfree(pglob)
1.9 ! fvdl 739: glob_t *pglob;
1.1 cgd 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 *
1.2 mycroft 754: g_opendir(str, pglob)
1.1 cgd 755: register Char *str;
1.9 ! fvdl 756: glob_t *pglob;
1.1 cgd 757: {
758: char buf[MAXPATHLEN];
759:
760: if (!*str)
1.2 mycroft 761: strcpy(buf, ".");
762: else
763: g_Ctoc(str, buf);
1.4 cgd 764:
1.2 mycroft 765: if (pglob->gl_flags & GLOB_ALTDIRFUNC)
766: return((*pglob->gl_opendir)(buf));
1.4 cgd 767:
1.1 cgd 768: return(opendir(buf));
769: }
770:
771: static int
1.2 mycroft 772: g_lstat(fn, sb, pglob)
1.1 cgd 773: register Char *fn;
1.8 fvdl 774: struct stat12 *sb;
1.9 ! fvdl 775: glob_t *pglob;
1.1 cgd 776: {
777: char buf[MAXPATHLEN];
778:
779: g_Ctoc(fn, buf);
1.2 mycroft 780: if (pglob->gl_flags & GLOB_ALTDIRFUNC)
781: return((*pglob->gl_lstat)(buf, sb));
1.1 cgd 782: return(lstat(buf, sb));
783: }
784:
785: static int
1.2 mycroft 786: g_stat(fn, sb, pglob)
1.1 cgd 787: register Char *fn;
1.8 fvdl 788: struct stat12 *sb;
1.9 ! fvdl 789: glob_t *pglob;
1.1 cgd 790: {
791: char buf[MAXPATHLEN];
792:
793: g_Ctoc(fn, buf);
1.2 mycroft 794: if (pglob->gl_flags & GLOB_ALTDIRFUNC)
795: return((*pglob->gl_stat)(buf, sb));
1.1 cgd 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:
1.4 cgd 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:
1.1 cgd 829: static void
830: g_Ctoc(str, buf)
1.4 cgd 831: register const Char *str;
1.1 cgd 832: char *buf;
833: {
834: register char *dc;
835:
1.4 cgd 836: for (dc = buf; (*dc++ = *str++) != EOS;)
837: continue;
1.1 cgd 838: }
839:
840: #ifdef DEBUG
841: static void
1.4 cgd 842: qprintf(str, s)
843: const char *str;
1.1 cgd 844: register Char *s;
845: {
846: register Char *p;
847:
1.4 cgd 848: (void)printf("%s:\n", str);
1.1 cgd 849: for (p = s; *p; p++)
1.2 mycroft 850: (void)printf("%c", CHAR(*p));
1.1 cgd 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++)
1.2 mycroft 856: (void)printf("%c", ismeta(*p) ? '_' : ' ');
1.1 cgd 857: (void)printf("\n");
858: }
859: #endif