|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1989 The Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * Guido van Rossum. ! 7: * ! 8: * Redistribution and use in source and binary forms are permitted provided ! 9: * that: (1) source distributions retain this entire copyright notice and ! 10: * comment, and (2) distributions including binaries display the following ! 11: * acknowledgement: ``This product includes software developed by the ! 12: * University of California, Berkeley and its contributors'' in the ! 13: * documentation or other materials provided with the distribution and in ! 14: * all advertising materials mentioning features or use of this software. ! 15: * Neither the name of the University nor the names of its contributors may ! 16: * be used to endorse or promote products derived from this software without ! 17: * specific prior written permission. ! 18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED ! 19: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF ! 20: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 21: */ ! 22: ! 23: #if defined(LIBC_SCCS) && !defined(lint) ! 24: static char sccsid[] = "@(#)glob.c 5.3 (Berkeley) 6/23/90"; ! 25: #endif /* LIBC_SCCS and not lint */ ! 26: ! 27: /* ! 28: * Glob: the interface is a superset of the one defined in POSIX 1003.2, ! 29: * draft 9. ! 30: * ! 31: * The [!...] convention to negate a range is supported (SysV, Posix, ksh). ! 32: * ! 33: * Optional extra services, controlled by flags not defined by POSIX: ! 34: * GLOB_QUOTE: escaping convention: \ inhibits any special meaning ! 35: the following character might have (except \ at end of ! 36: * string is kept); ! 37: */ ! 38: ! 39: #include <sys/param.h> ! 40: #include <sys/stat.h> ! 41: #include <dirent.h> ! 42: #include <glob.h> ! 43: #include <ctype.h> ! 44: #include <errno.h> ! 45: #include <string.h> ! 46: #include <stdio.h> ! 47: ! 48: char *malloc(), *realloc(); ! 49: ! 50: typedef int bool_t; ! 51: ! 52: #define DOLLAR '$' ! 53: #define DOT '.' ! 54: #define EOS '\0' ! 55: #define LBRACKET '[' ! 56: #define NOT '!' ! 57: #define QUESTION '?' ! 58: #define QUOTE '\\' ! 59: #define RANGE '-' ! 60: #define RBRACKET ']' ! 61: #define SEP '/' ! 62: #define STAR '*' ! 63: #define TILDE '~' ! 64: #define UNDERSCORE '_' ! 65: ! 66: #define METABIT 0x80 ! 67: #define META(c) ((c)|METABIT) ! 68: #define M_ALL META('*') ! 69: #define M_END META(']') ! 70: #define M_NOT META('!') ! 71: #define M_ONE META('?') ! 72: #define M_RNG META('-') ! 73: #define M_SET META('[') ! 74: #define ismeta(c) (((c)&METABIT) != 0) ! 75: ! 76: static ! 77: compare(p, q) ! 78: void **p, **q; ! 79: { ! 80: return(strcmp(*(char **)p, *(char **)q)); ! 81: } ! 82: ! 83: ! 84: /* ! 85: * The main glob() routine: compiles the pattern (optionally processing ! 86: * quotes), calls glob1() to do the real pattern matching, and finally ! 87: * sorts the list (unless unsorted operation is requested). Returns 0 ! 88: * if things went well, nonzero if errors occurred. It is not an error ! 89: * to find no matches. ! 90: */ ! 91: glob(pattern, flags, errfunc, pglob) ! 92: char *pattern; ! 93: int flags, (*errfunc)(); ! 94: glob_t *pglob; ! 95: { ! 96: int err, oldpathc; ! 97: char *bufnext, *bufend, *compilebuf, *compilepat, *patnext; ! 98: char c, patbuf[MAXPATHLEN+1]; ! 99: ! 100: patnext = pattern; ! 101: if (!(flags & GLOB_APPEND)) { ! 102: pglob->gl_pathc = 0; ! 103: pglob->gl_pathv = NULL; ! 104: if (!(flags & GLOB_DOOFFS)) ! 105: pglob->gl_offs = 0; ! 106: } ! 107: pglob->gl_flags = flags; ! 108: pglob->gl_errfunc = errfunc; ! 109: oldpathc = pglob->gl_pathc; ! 110: ! 111: bufnext = patbuf; ! 112: bufend = bufnext+MAXPATHLEN; ! 113: ! 114: compilebuf = bufnext; ! 115: compilepat = patnext; ! 116: while (bufnext < bufend && (c = *patnext++) != EOS) { ! 117: switch (c) { ! 118: case LBRACKET: ! 119: c = *patnext; ! 120: if (c == NOT) ! 121: ++patnext; ! 122: if (*patnext == EOS || ! 123: strchr(patnext+1, RBRACKET) == NULL) { ! 124: *bufnext++ = LBRACKET; ! 125: if (c == NOT) ! 126: --patnext; ! 127: break; ! 128: } ! 129: *bufnext++ = M_SET; ! 130: if (c == NOT) ! 131: *bufnext++ = M_NOT; ! 132: c = *patnext++; ! 133: do { ! 134: /* todo: quoting */ ! 135: *bufnext++ = c; ! 136: if (*patnext == RANGE && ! 137: (c = patnext[1]) != RBRACKET) { ! 138: *bufnext++ = M_RNG; ! 139: *bufnext++ = c; ! 140: patnext += 2; ! 141: } ! 142: } while ((c = *patnext++) != RBRACKET); ! 143: *bufnext++ = M_END; ! 144: break; ! 145: case QUESTION: ! 146: *bufnext++ = M_ONE; ! 147: break; ! 148: case QUOTE: ! 149: if (!(flags & GLOB_QUOTE)) ! 150: *bufnext++ = QUOTE; ! 151: else { ! 152: if ((c = *patnext++) == EOS) { ! 153: c = QUOTE; ! 154: --patnext; ! 155: } ! 156: *bufnext++ = c; ! 157: } ! 158: break; ! 159: case STAR: ! 160: *bufnext++ = M_ALL; ! 161: break; ! 162: default: ! 163: *bufnext++ = c; ! 164: break; ! 165: } ! 166: } ! 167: *bufnext = EOS; ! 168: ! 169: if ((err = glob1(patbuf, pglob)) != 0) ! 170: return(err); ! 171: ! 172: if (pglob->gl_pathc == oldpathc && flags & GLOB_NOCHECK) { ! 173: if (!(flags & GLOB_QUOTE)) ! 174: (void)strcpy(compilebuf, compilepat); ! 175: else { ! 176: /* ! 177: * copy pattern, interpreting quotes; this is slightly ! 178: * different than the interpretation of quotes above ! 179: * -- which should prevail? ! 180: */ ! 181: while (*compilepat != EOS) { ! 182: if (*compilepat == QUOTE) { ! 183: if (*++compilepat == EOS) ! 184: --compilepat; ! 185: } ! 186: *compilebuf++ = *compilepat++; ! 187: } ! 188: *compilebuf = EOS; ! 189: } ! 190: return(globextend(patbuf, pglob)); ! 191: } else if (!(flags & GLOB_NOSORT)) ! 192: qsort((char*) (pglob->gl_pathv + pglob->gl_offs + oldpathc), ! 193: pglob->gl_pathc - oldpathc, sizeof(char*), compare); ! 194: return(0); ! 195: } ! 196: ! 197: static ! 198: glob1(pattern, pglob) ! 199: char *pattern; ! 200: glob_t *pglob; ! 201: { ! 202: char pathbuf[MAXPATHLEN+1]; ! 203: ! 204: /* ! 205: * a null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ ! 206: if (*pattern == EOS) ! 207: return(0); ! 208: return(glob2(pathbuf, pathbuf, pattern, pglob)); ! 209: } ! 210: ! 211: /* ! 212: * functions glob2 and glob3 are mutually recursive; there is one level ! 213: * of recursion for each segment in the pattern that contains one or ! 214: * more meta characters. ! 215: */ ! 216: static ! 217: glob2(pathbuf, pathend, pattern, pglob) ! 218: char *pathbuf, *pathend, *pattern; ! 219: glob_t *pglob; ! 220: { ! 221: struct stat sbuf; ! 222: bool_t anymeta = 0; ! 223: char *p, *q; ! 224: ! 225: /* ! 226: * loop over pattern segments until end of pattern or until ! 227: * segment with meta character found. ! 228: */ ! 229: for (;;) { ! 230: if (*pattern == EOS) { /* end of pattern? */ ! 231: *pathend = EOS; ! 232: if (stat(pathbuf, &sbuf) != 0) ! 233: return(0); /* need error call here? */ ! 234: if ((pglob->gl_flags & GLOB_MARK) && ! 235: pathend[-1] != SEP && S_ISDIR(sbuf.st_mode)) { ! 236: *pathend++ = SEP; ! 237: *pathend = EOS; ! 238: } ! 239: return(globextend(pathbuf, pglob)); ! 240: } ! 241: ! 242: /* find end of next segment, copy tentatively to pathend */ ! 243: q = pathend; ! 244: p = pattern; ! 245: while (*p != EOS && *p != SEP) { ! 246: if (ismeta(*p)) ! 247: anymeta = 1; ! 248: *q++ = *p++; ! 249: } ! 250: ! 251: if (!anymeta) { /* no expansion, do next segment */ ! 252: pathend = q; ! 253: pattern = p; ! 254: while (*pattern == SEP) ! 255: *pathend++ = *pattern++; ! 256: } else /* need expansion, recurse */ ! 257: return(glob3(pathbuf, pathend, pattern, p, pglob)); ! 258: } ! 259: /* NOTREACHED */ ! 260: } ! 261: ! 262: static ! 263: glob3(pathbuf, pathend, pattern, restpattern, pglob) ! 264: char *pathbuf, *pathend, *pattern, *restpattern; ! 265: glob_t *pglob; ! 266: { ! 267: extern int errno; ! 268: DIR *dirp; ! 269: struct dirent *dp; ! 270: int len, err; ! 271: ! 272: *pathend = EOS; ! 273: errno = 0; ! 274: if (!(dirp = opendir(pathbuf))) ! 275: /* todo: don't call for ENOENT or ENOTDIR? */ ! 276: if (pglob->gl_errfunc && ! 277: (*pglob->gl_errfunc)(pathbuf, errno) || ! 278: (pglob->gl_flags & GLOB_ERR)) ! 279: return(GLOB_ABEND); ! 280: else ! 281: return(0); ! 282: ! 283: err = 0; ! 284: ! 285: /* search directory for matching names */ ! 286: while ((dp = readdir(dirp))) { ! 287: /* initial DOT must be matched literally */ ! 288: if (dp->d_name[0] == DOT && *pattern != DOT) ! 289: continue; ! 290: if (!match(dp->d_name, pattern, restpattern)) ! 291: continue; ! 292: len = dp->d_namlen; ! 293: (void)strcpy(pathend, dp->d_name); ! 294: err = glob2(pathbuf, pathend+len, restpattern, pglob); ! 295: if (err) ! 296: break; ! 297: } ! 298: /* todo: check error from readdir? */ ! 299: (void)closedir(dirp); ! 300: return(err); ! 301: } ! 302: ! 303: ! 304: /* ! 305: * Extend the gl_pathv member of a glob_t structure to accomodate a new item, ! 306: * add the new item, and update gl_pathc. ! 307: * ! 308: * This assumes the BSD realloc, which only copies the block when its size ! 309: * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic ! 310: * behavior. ! 311: * ! 312: * Return 0 if new item added, error code if memory couldn't be allocated. ! 313: * ! 314: * Invariant of the glob_t structure: ! 315: * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and ! 316: * gl_pathv points to (gl_offs + gl_pathc + 1) items. ! 317: */ ! 318: static ! 319: globextend(path, pglob) ! 320: char *path; ! 321: glob_t *pglob; ! 322: { ! 323: register char **pathv; ! 324: register int i; ! 325: u_int copysize, newsize; ! 326: char *copy; ! 327: ! 328: newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs); ! 329: pathv = (char **)realloc((char *)(pathv = pglob->gl_pathv), newsize); ! 330: if (pathv == NULL) ! 331: return(GLOB_NOSPACE); ! 332: ! 333: if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { ! 334: /* first time around -- clear initial gl_offs items */ ! 335: pathv += pglob->gl_offs; ! 336: for (i = pglob->gl_offs; --i >= 0; ) ! 337: *--pathv = NULL; ! 338: } ! 339: pglob->gl_pathv = pathv; ! 340: ! 341: copysize = strlen(path) + 1; ! 342: if ((copy = malloc(copysize)) != NULL) { ! 343: (void)strcpy(copy, path); ! 344: pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; ! 345: } ! 346: pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; ! 347: return((copy == NULL) ? GLOB_NOSPACE : 0); ! 348: } ! 349: ! 350: ! 351: /* ! 352: * pattern matching function for filenames. Each occurrence of the * ! 353: * pattern causes a recursion level. ! 354: */ ! 355: static bool_t ! 356: match(name, pat, patend) ! 357: register char *name, *pat, *patend; ! 358: { ! 359: bool_t ok, negate_range; ! 360: char c, k; ! 361: ! 362: while (pat < patend) { ! 363: c = *pat++; ! 364: switch (c & 0xff) { ! 365: case M_ALL: ! 366: if (pat == patend) ! 367: return(1); ! 368: for (; *name != EOS; ++name) { ! 369: if (match(name, pat, patend)) ! 370: return(1); ! 371: } ! 372: return(0); ! 373: case M_ONE: ! 374: if (*name++ == EOS) ! 375: return(0); ! 376: break; ! 377: case M_SET: ! 378: ok = 0; ! 379: k = *name++; ! 380: if (negate_range = (*pat & 0xff) == M_NOT) ! 381: ++pat; ! 382: while (((c = *pat++) & 0xff) != M_END) { ! 383: if ((*pat & 0xff) == M_RNG) { ! 384: if (c <= k && k <= pat[1]) ! 385: ok = 1; ! 386: pat += 2; ! 387: } ! 388: else if (c == k) ! 389: ok = 1; ! 390: } ! 391: if (ok == negate_range) ! 392: return(0); ! 393: break; ! 394: default: ! 395: if (*name++ != c) ! 396: return(0); ! 397: break; ! 398: } ! 399: } ! 400: return(*name == EOS); ! 401: } ! 402: ! 403: /* free allocated data belonging to a glob_t structure */ ! 404: void ! 405: globfree(pglob) ! 406: glob_t *pglob; ! 407: { ! 408: register int i; ! 409: register char **pp; ! 410: ! 411: if (pglob->gl_pathv != NULL) { ! 412: pp = pglob->gl_pathv + pglob->gl_offs; ! 413: for (i = pglob->gl_pathc; i--; ++pp) ! 414: if (*pp) ! 415: (void)free(*pp); ! 416: (void)free((char *)pp); ! 417: } ! 418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.