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