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