Annotation of 43BSDReno/lib/libc/gen/glob.c, revision 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.