Annotation of 43BSDReno/lib/libc/gen/glob.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.