Annotation of embedaddon/rsync/lib/wildmatch.c, revision 1.1

1.1     ! misho       1: /*
        !             2: **  Do shell-style pattern matching for ?, \, [], and * characters.
        !             3: **  It is 8bit clean.
        !             4: **
        !             5: **  Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
        !             6: **  Rich $alz is now <rsalz@bbn.com>.
        !             7: **
        !             8: **  Modified by Wayne Davison to special-case '/' matching, to make '**'
        !             9: **  work differently than '*', and to fix the character-class code.
        !            10: */
        !            11: 
        !            12: #include "rsync.h"
        !            13: 
        !            14: /* What character marks an inverted character class? */
        !            15: #define NEGATE_CLASS   '!'
        !            16: #define NEGATE_CLASS2  '^'
        !            17: 
        !            18: #define FALSE 0
        !            19: #define TRUE 1
        !            20: #define ABORT_ALL -1
        !            21: #define ABORT_TO_STARSTAR -2
        !            22: 
        !            23: #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
        !            24:                                    && *(class) == *(litmatch) \
        !            25:                                    && strncmp((char*)class, litmatch, len) == 0)
        !            26: 
        !            27: #if defined STDC_HEADERS || !defined isascii
        !            28: # define ISASCII(c) 1
        !            29: #else
        !            30: # define ISASCII(c) isascii(c)
        !            31: #endif
        !            32: 
        !            33: #ifdef isblank
        !            34: # define ISBLANK(c) (ISASCII(c) && isblank(c))
        !            35: #else
        !            36: # define ISBLANK(c) ((c) == ' ' || (c) == '\t')
        !            37: #endif
        !            38: 
        !            39: #ifdef isgraph
        !            40: # define ISGRAPH(c) (ISASCII(c) && isgraph(c))
        !            41: #else
        !            42: # define ISGRAPH(c) (ISASCII(c) && isprint(c) && !isspace(c))
        !            43: #endif
        !            44: 
        !            45: #define ISPRINT(c) (ISASCII(c) && isprint(c))
        !            46: #define ISDIGIT(c) (ISASCII(c) && isdigit(c))
        !            47: #define ISALNUM(c) (ISASCII(c) && isalnum(c))
        !            48: #define ISALPHA(c) (ISASCII(c) && isalpha(c))
        !            49: #define ISCNTRL(c) (ISASCII(c) && iscntrl(c))
        !            50: #define ISLOWER(c) (ISASCII(c) && islower(c))
        !            51: #define ISPUNCT(c) (ISASCII(c) && ispunct(c))
        !            52: #define ISSPACE(c) (ISASCII(c) && isspace(c))
        !            53: #define ISUPPER(c) (ISASCII(c) && isupper(c))
        !            54: #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
        !            55: 
        !            56: #ifdef WILD_TEST_ITERATIONS
        !            57: int wildmatch_iteration_count;
        !            58: #endif
        !            59: 
        !            60: static int force_lower_case = 0;
        !            61: 
        !            62: /* Match pattern "p" against the a virtually-joined string consisting
        !            63:  * of "text" and any strings in array "a". */
        !            64: static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
        !            65: {
        !            66:     uchar p_ch;
        !            67: 
        !            68: #ifdef WILD_TEST_ITERATIONS
        !            69:     wildmatch_iteration_count++;
        !            70: #endif
        !            71: 
        !            72:     for ( ; (p_ch = *p) != '\0'; text++, p++) {
        !            73:        int matched, special;
        !            74:        uchar t_ch, prev_ch;
        !            75:        while ((t_ch = *text) == '\0') {
        !            76:            if (*a == NULL) {
        !            77:                if (p_ch != '*')
        !            78:                    return ABORT_ALL;
        !            79:                break;
        !            80:            }
        !            81:            text = *a++;
        !            82:        }
        !            83:        if (force_lower_case && ISUPPER(t_ch))
        !            84:            t_ch = tolower(t_ch);
        !            85:        switch (p_ch) {
        !            86:          case '\\':
        !            87:            /* Literal match with following character.  Note that the test
        !            88:             * in "default" handles the p[1] == '\0' failure case. */
        !            89:            p_ch = *++p;
        !            90:            /* FALLTHROUGH */
        !            91:          default:
        !            92:            if (t_ch != p_ch)
        !            93:                return FALSE;
        !            94:            continue;
        !            95:          case '?':
        !            96:            /* Match anything but '/'. */
        !            97:            if (t_ch == '/')
        !            98:                return FALSE;
        !            99:            continue;
        !           100:          case '*':
        !           101:            if (*++p == '*') {
        !           102:                while (*++p == '*') {}
        !           103:                special = TRUE;
        !           104:            } else
        !           105:                special = FALSE;
        !           106:            if (*p == '\0') {
        !           107:                /* Trailing "**" matches everything.  Trailing "*" matches
        !           108:                 * only if there are no more slash characters. */
        !           109:                if (!special) {
        !           110:                    do {
        !           111:                        if (strchr((char*)text, '/') != NULL)
        !           112:                            return FALSE;
        !           113:                    } while ((text = *a++) != NULL);
        !           114:                }
        !           115:                return TRUE;
        !           116:            }
        !           117:            while (1) {
        !           118:                if (t_ch == '\0') {
        !           119:                    if ((text = *a++) == NULL)
        !           120:                        break;
        !           121:                    t_ch = *text;
        !           122:                    continue;
        !           123:                }
        !           124:                if ((matched = dowild(p, text, a)) != FALSE) {
        !           125:                    if (!special || matched != ABORT_TO_STARSTAR)
        !           126:                        return matched;
        !           127:                } else if (!special && t_ch == '/')
        !           128:                    return ABORT_TO_STARSTAR;
        !           129:                t_ch = *++text;
        !           130:            }
        !           131:            return ABORT_ALL;
        !           132:          case '[':
        !           133:            p_ch = *++p;
        !           134: #ifdef NEGATE_CLASS2
        !           135:            if (p_ch == NEGATE_CLASS2)
        !           136:                p_ch = NEGATE_CLASS;
        !           137: #endif
        !           138:            /* Assign literal TRUE/FALSE because of "matched" comparison. */
        !           139:            special = p_ch == NEGATE_CLASS? TRUE : FALSE;
        !           140:            if (special) {
        !           141:                /* Inverted character class. */
        !           142:                p_ch = *++p;
        !           143:            }
        !           144:            prev_ch = 0;
        !           145:            matched = FALSE;
        !           146:            do {
        !           147:                if (!p_ch)
        !           148:                    return ABORT_ALL;
        !           149:                if (p_ch == '\\') {
        !           150:                    p_ch = *++p;
        !           151:                    if (!p_ch)
        !           152:                        return ABORT_ALL;
        !           153:                    if (t_ch == p_ch)
        !           154:                        matched = TRUE;
        !           155:                } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
        !           156:                    p_ch = *++p;
        !           157:                    if (p_ch == '\\') {
        !           158:                        p_ch = *++p;
        !           159:                        if (!p_ch)
        !           160:                            return ABORT_ALL;
        !           161:                    }
        !           162:                    if (t_ch <= p_ch && t_ch >= prev_ch)
        !           163:                        matched = TRUE;
        !           164:                    p_ch = 0; /* This makes "prev_ch" get set to 0. */
        !           165:                } else if (p_ch == '[' && p[1] == ':') {
        !           166:                    const uchar *s;
        !           167:                    int i;
        !           168:                    for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
        !           169:                    if (!p_ch)
        !           170:                        return ABORT_ALL;
        !           171:                    i = p - s - 1;
        !           172:                    if (i < 0 || p[-1] != ':') {
        !           173:                        /* Didn't find ":]", so treat like a normal set. */
        !           174:                        p = s - 2;
        !           175:                        p_ch = '[';
        !           176:                        if (t_ch == p_ch)
        !           177:                            matched = TRUE;
        !           178:                        continue;
        !           179:                    }
        !           180:                    if (CC_EQ(s,i, "alnum")) {
        !           181:                        if (ISALNUM(t_ch))
        !           182:                            matched = TRUE;
        !           183:                    } else if (CC_EQ(s,i, "alpha")) {
        !           184:                        if (ISALPHA(t_ch))
        !           185:                            matched = TRUE;
        !           186:                    } else if (CC_EQ(s,i, "blank")) {
        !           187:                        if (ISBLANK(t_ch))
        !           188:                            matched = TRUE;
        !           189:                    } else if (CC_EQ(s,i, "cntrl")) {
        !           190:                        if (ISCNTRL(t_ch))
        !           191:                            matched = TRUE;
        !           192:                    } else if (CC_EQ(s,i, "digit")) {
        !           193:                        if (ISDIGIT(t_ch))
        !           194:                            matched = TRUE;
        !           195:                    } else if (CC_EQ(s,i, "graph")) {
        !           196:                        if (ISGRAPH(t_ch))
        !           197:                            matched = TRUE;
        !           198:                    } else if (CC_EQ(s,i, "lower")) {
        !           199:                        if (ISLOWER(t_ch))
        !           200:                            matched = TRUE;
        !           201:                    } else if (CC_EQ(s,i, "print")) {
        !           202:                        if (ISPRINT(t_ch))
        !           203:                            matched = TRUE;
        !           204:                    } else if (CC_EQ(s,i, "punct")) {
        !           205:                        if (ISPUNCT(t_ch))
        !           206:                            matched = TRUE;
        !           207:                    } else if (CC_EQ(s,i, "space")) {
        !           208:                        if (ISSPACE(t_ch))
        !           209:                            matched = TRUE;
        !           210:                    } else if (CC_EQ(s,i, "upper")) {
        !           211:                        if (ISUPPER(t_ch))
        !           212:                            matched = TRUE;
        !           213:                    } else if (CC_EQ(s,i, "xdigit")) {
        !           214:                        if (ISXDIGIT(t_ch))
        !           215:                            matched = TRUE;
        !           216:                    } else /* malformed [:class:] string */
        !           217:                        return ABORT_ALL;
        !           218:                    p_ch = 0; /* This makes "prev_ch" get set to 0. */
        !           219:                } else if (t_ch == p_ch)
        !           220:                    matched = TRUE;
        !           221:            } while (prev_ch = p_ch, (p_ch = *++p) != ']');
        !           222:            if (matched == special || t_ch == '/')
        !           223:                return FALSE;
        !           224:            continue;
        !           225:        }
        !           226:     }
        !           227: 
        !           228:     do {
        !           229:        if (*text)
        !           230:            return FALSE;
        !           231:     } while ((text = *a++) != NULL);
        !           232: 
        !           233:     return TRUE;
        !           234: }
        !           235: 
        !           236: /* Match literal string "s" against the a virtually-joined string consisting
        !           237:  * of "text" and any strings in array "a". */
        !           238: static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
        !           239: {
        !           240:     for ( ; *s != '\0'; text++, s++) {
        !           241:        while (*text == '\0') {
        !           242:            if ((text = *a++) == NULL)
        !           243:                return FALSE;
        !           244:        }
        !           245:        if (*text != *s)
        !           246:            return FALSE;
        !           247:     }
        !           248: 
        !           249:     do {
        !           250:        if (*text)
        !           251:            return FALSE;
        !           252:     } while ((text = *a++) != NULL);
        !           253: 
        !           254:     return TRUE;
        !           255: }
        !           256: 
        !           257: /* Return the last "count" path elements from the concatenated string.
        !           258:  * We return a string pointer to the start of the string, and update the
        !           259:  * array pointer-pointer to point to any remaining string elements. */
        !           260: static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
        !           261: {
        !           262:     const uchar*const *a = *a_ptr;
        !           263:     const uchar*const *first_a = a;
        !           264: 
        !           265:     while (*a)
        !           266:            a++;
        !           267: 
        !           268:     while (a != first_a) {
        !           269:        const uchar *s = *--a;
        !           270:        s += strlen((char*)s);
        !           271:        while (--s >= *a) {
        !           272:            if (*s == '/' && !--count) {
        !           273:                *a_ptr = a+1;
        !           274:                return s+1;
        !           275:            }
        !           276:        }
        !           277:     }
        !           278: 
        !           279:     if (count == 1) {
        !           280:        *a_ptr = a+1;
        !           281:        return *a;
        !           282:     }
        !           283: 
        !           284:     return NULL;
        !           285: }
        !           286: 
        !           287: /* Match the "pattern" against the "text" string. */
        !           288: int wildmatch(const char *pattern, const char *text)
        !           289: {
        !           290:     static const uchar *nomore[1]; /* A NULL pointer. */
        !           291: #ifdef WILD_TEST_ITERATIONS
        !           292:     wildmatch_iteration_count = 0;
        !           293: #endif
        !           294:     return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
        !           295: }
        !           296: 
        !           297: /* Match the "pattern" against the forced-to-lower-case "text" string. */
        !           298: int iwildmatch(const char *pattern, const char *text)
        !           299: {
        !           300:     static const uchar *nomore[1]; /* A NULL pointer. */
        !           301:     int ret;
        !           302: #ifdef WILD_TEST_ITERATIONS
        !           303:     wildmatch_iteration_count = 0;
        !           304: #endif
        !           305:     force_lower_case = 1;
        !           306:     ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
        !           307:     force_lower_case = 0;
        !           308:     return ret;
        !           309: }
        !           310: 
        !           311: /* Match pattern "p" against the a virtually-joined string consisting
        !           312:  * of all the pointers in array "texts" (which has a NULL pointer at the
        !           313:  * end).  The int "where" can be 0 (normal matching), > 0 (match only
        !           314:  * the trailing N slash-separated filename components of "texts"), or < 0
        !           315:  * (match the "pattern" at the start or after any slash in "texts"). */
        !           316: int wildmatch_array(const char *pattern, const char*const *texts, int where)
        !           317: {
        !           318:     const uchar *p = (const uchar*)pattern;
        !           319:     const uchar*const *a = (const uchar*const*)texts;
        !           320:     const uchar *text;
        !           321:     int matched;
        !           322: 
        !           323: #ifdef WILD_TEST_ITERATIONS
        !           324:     wildmatch_iteration_count = 0;
        !           325: #endif
        !           326: 
        !           327:     if (where > 0)
        !           328:        text = trailing_N_elements(&a, where);
        !           329:     else
        !           330:        text = *a++;
        !           331:     if (!text)
        !           332:        return FALSE;
        !           333: 
        !           334:     if ((matched = dowild(p, text, a)) != TRUE && where < 0
        !           335:      && matched != ABORT_ALL) {
        !           336:        while (1) {
        !           337:            if (*text == '\0') {
        !           338:                if ((text = (uchar*)*a++) == NULL)
        !           339:                    return FALSE;
        !           340:                continue;
        !           341:            }
        !           342:            if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
        !           343:             && matched != ABORT_TO_STARSTAR)
        !           344:                break;
        !           345:        }
        !           346:     }
        !           347:     return matched == TRUE;
        !           348: }
        !           349: 
        !           350: /* Match literal string "s" against the a virtually-joined string consisting
        !           351:  * of all the pointers in array "texts" (which has a NULL pointer at the
        !           352:  * end).  The int "where" can be 0 (normal matching), or > 0 (match
        !           353:  * only the trailing N slash-separated filename components of "texts"). */
        !           354: int litmatch_array(const char *string, const char*const *texts, int where)
        !           355: {
        !           356:     const uchar *s = (const uchar*)string;
        !           357:     const uchar*const *a = (const uchar* const*)texts;
        !           358:     const uchar *text;
        !           359: 
        !           360:     if (where > 0)
        !           361:        text = trailing_N_elements(&a, where);
        !           362:     else
        !           363:        text = *a++;
        !           364:     if (!text)
        !           365:        return FALSE;
        !           366: 
        !           367:     return doliteral(s, text, a) == TRUE;
        !           368: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>