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

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: 
1.1.1.2 ! misho      56: extern int ignore_case;
        !            57: 
1.1       misho      58: #ifdef WILD_TEST_ITERATIONS
                     59: int wildmatch_iteration_count;
                     60: #endif
                     61: 
                     62: static int force_lower_case = 0;
                     63: 
                     64: /* Match pattern "p" against the a virtually-joined string consisting
                     65:  * of "text" and any strings in array "a". */
                     66: static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
                     67: {
                     68:     uchar p_ch;
                     69: 
                     70: #ifdef WILD_TEST_ITERATIONS
                     71:     wildmatch_iteration_count++;
                     72: #endif
                     73: 
                     74:     for ( ; (p_ch = *p) != '\0'; text++, p++) {
                     75:        int matched, special;
                     76:        uchar t_ch, prev_ch;
1.1.1.2 ! misho      77:        if (ignore_case && ISUPPER(p_ch))
        !            78:            p_ch = tolower(p_ch);
1.1       misho      79:        while ((t_ch = *text) == '\0') {
                     80:            if (*a == NULL) {
                     81:                if (p_ch != '*')
                     82:                    return ABORT_ALL;
                     83:                break;
                     84:            }
                     85:            text = *a++;
                     86:        }
                     87:        if (force_lower_case && ISUPPER(t_ch))
                     88:            t_ch = tolower(t_ch);
                     89:        switch (p_ch) {
                     90:          case '\\':
                     91:            /* Literal match with following character.  Note that the test
                     92:             * in "default" handles the p[1] == '\0' failure case. */
                     93:            p_ch = *++p;
                     94:            /* FALLTHROUGH */
                     95:          default:
                     96:            if (t_ch != p_ch)
                     97:                return FALSE;
                     98:            continue;
                     99:          case '?':
                    100:            /* Match anything but '/'. */
                    101:            if (t_ch == '/')
                    102:                return FALSE;
                    103:            continue;
                    104:          case '*':
                    105:            if (*++p == '*') {
                    106:                while (*++p == '*') {}
                    107:                special = TRUE;
                    108:            } else
                    109:                special = FALSE;
                    110:            if (*p == '\0') {
                    111:                /* Trailing "**" matches everything.  Trailing "*" matches
                    112:                 * only if there are no more slash characters. */
                    113:                if (!special) {
                    114:                    do {
                    115:                        if (strchr((char*)text, '/') != NULL)
                    116:                            return FALSE;
                    117:                    } while ((text = *a++) != NULL);
                    118:                }
                    119:                return TRUE;
                    120:            }
                    121:            while (1) {
                    122:                if (t_ch == '\0') {
                    123:                    if ((text = *a++) == NULL)
                    124:                        break;
                    125:                    t_ch = *text;
                    126:                    continue;
                    127:                }
                    128:                if ((matched = dowild(p, text, a)) != FALSE) {
                    129:                    if (!special || matched != ABORT_TO_STARSTAR)
                    130:                        return matched;
                    131:                } else if (!special && t_ch == '/')
                    132:                    return ABORT_TO_STARSTAR;
                    133:                t_ch = *++text;
                    134:            }
                    135:            return ABORT_ALL;
                    136:          case '[':
                    137:            p_ch = *++p;
                    138: #ifdef NEGATE_CLASS2
                    139:            if (p_ch == NEGATE_CLASS2)
                    140:                p_ch = NEGATE_CLASS;
                    141: #endif
                    142:            /* Assign literal TRUE/FALSE because of "matched" comparison. */
                    143:            special = p_ch == NEGATE_CLASS? TRUE : FALSE;
                    144:            if (special) {
                    145:                /* Inverted character class. */
                    146:                p_ch = *++p;
                    147:            }
                    148:            prev_ch = 0;
                    149:            matched = FALSE;
                    150:            do {
                    151:                if (!p_ch)
                    152:                    return ABORT_ALL;
                    153:                if (p_ch == '\\') {
                    154:                    p_ch = *++p;
                    155:                    if (!p_ch)
                    156:                        return ABORT_ALL;
                    157:                    if (t_ch == p_ch)
                    158:                        matched = TRUE;
                    159:                } else if (p_ch == '-' && prev_ch && p[1] && p[1] != ']') {
                    160:                    p_ch = *++p;
                    161:                    if (p_ch == '\\') {
                    162:                        p_ch = *++p;
                    163:                        if (!p_ch)
                    164:                            return ABORT_ALL;
                    165:                    }
                    166:                    if (t_ch <= p_ch && t_ch >= prev_ch)
                    167:                        matched = TRUE;
                    168:                    p_ch = 0; /* This makes "prev_ch" get set to 0. */
                    169:                } else if (p_ch == '[' && p[1] == ':') {
                    170:                    const uchar *s;
                    171:                    int i;
                    172:                    for (s = p += 2; (p_ch = *p) && p_ch != ']'; p++) {} /*SHARED ITERATOR*/
                    173:                    if (!p_ch)
                    174:                        return ABORT_ALL;
                    175:                    i = p - s - 1;
                    176:                    if (i < 0 || p[-1] != ':') {
                    177:                        /* Didn't find ":]", so treat like a normal set. */
                    178:                        p = s - 2;
                    179:                        p_ch = '[';
                    180:                        if (t_ch == p_ch)
                    181:                            matched = TRUE;
                    182:                        continue;
                    183:                    }
                    184:                    if (CC_EQ(s,i, "alnum")) {
                    185:                        if (ISALNUM(t_ch))
                    186:                            matched = TRUE;
                    187:                    } else if (CC_EQ(s,i, "alpha")) {
                    188:                        if (ISALPHA(t_ch))
                    189:                            matched = TRUE;
                    190:                    } else if (CC_EQ(s,i, "blank")) {
                    191:                        if (ISBLANK(t_ch))
                    192:                            matched = TRUE;
                    193:                    } else if (CC_EQ(s,i, "cntrl")) {
                    194:                        if (ISCNTRL(t_ch))
                    195:                            matched = TRUE;
                    196:                    } else if (CC_EQ(s,i, "digit")) {
                    197:                        if (ISDIGIT(t_ch))
                    198:                            matched = TRUE;
                    199:                    } else if (CC_EQ(s,i, "graph")) {
                    200:                        if (ISGRAPH(t_ch))
                    201:                            matched = TRUE;
                    202:                    } else if (CC_EQ(s,i, "lower")) {
                    203:                        if (ISLOWER(t_ch))
                    204:                            matched = TRUE;
                    205:                    } else if (CC_EQ(s,i, "print")) {
                    206:                        if (ISPRINT(t_ch))
                    207:                            matched = TRUE;
                    208:                    } else if (CC_EQ(s,i, "punct")) {
                    209:                        if (ISPUNCT(t_ch))
                    210:                            matched = TRUE;
                    211:                    } else if (CC_EQ(s,i, "space")) {
                    212:                        if (ISSPACE(t_ch))
                    213:                            matched = TRUE;
                    214:                    } else if (CC_EQ(s,i, "upper")) {
                    215:                        if (ISUPPER(t_ch))
                    216:                            matched = TRUE;
                    217:                    } else if (CC_EQ(s,i, "xdigit")) {
                    218:                        if (ISXDIGIT(t_ch))
                    219:                            matched = TRUE;
                    220:                    } else /* malformed [:class:] string */
                    221:                        return ABORT_ALL;
                    222:                    p_ch = 0; /* This makes "prev_ch" get set to 0. */
                    223:                } else if (t_ch == p_ch)
                    224:                    matched = TRUE;
                    225:            } while (prev_ch = p_ch, (p_ch = *++p) != ']');
                    226:            if (matched == special || t_ch == '/')
                    227:                return FALSE;
                    228:            continue;
                    229:        }
                    230:     }
                    231: 
                    232:     do {
                    233:        if (*text)
                    234:            return FALSE;
                    235:     } while ((text = *a++) != NULL);
                    236: 
                    237:     return TRUE;
                    238: }
                    239: 
                    240: /* Match literal string "s" against the a virtually-joined string consisting
                    241:  * of "text" and any strings in array "a". */
                    242: static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
                    243: {
1.1.1.2 ! misho     244:     uchar s_ch, t_ch;
1.1       misho     245:     for ( ; *s != '\0'; text++, s++) {
                    246:        while (*text == '\0') {
                    247:            if ((text = *a++) == NULL)
                    248:                return FALSE;
                    249:        }
1.1.1.2 ! misho     250:        s_ch = *s;
        !           251:        t_ch = *text;
        !           252:        if (ignore_case) {
        !           253:            if (ISUPPER(s_ch))
        !           254:                s_ch = tolower(s_ch);
        !           255:            if (ISUPPER(t_ch))
        !           256:                t_ch = tolower(t_ch);
        !           257:        }
        !           258:        if (t_ch != s_ch)
1.1       misho     259:            return FALSE;
                    260:     }
                    261: 
                    262:     do {
                    263:        if (*text)
                    264:            return FALSE;
                    265:     } while ((text = *a++) != NULL);
                    266: 
                    267:     return TRUE;
                    268: }
                    269: 
                    270: /* Return the last "count" path elements from the concatenated string.
                    271:  * We return a string pointer to the start of the string, and update the
                    272:  * array pointer-pointer to point to any remaining string elements. */
                    273: static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
                    274: {
                    275:     const uchar*const *a = *a_ptr;
                    276:     const uchar*const *first_a = a;
                    277: 
                    278:     while (*a)
                    279:            a++;
                    280: 
                    281:     while (a != first_a) {
                    282:        const uchar *s = *--a;
                    283:        s += strlen((char*)s);
                    284:        while (--s >= *a) {
                    285:            if (*s == '/' && !--count) {
                    286:                *a_ptr = a+1;
                    287:                return s+1;
                    288:            }
                    289:        }
                    290:     }
                    291: 
                    292:     if (count == 1) {
                    293:        *a_ptr = a+1;
                    294:        return *a;
                    295:     }
                    296: 
                    297:     return NULL;
                    298: }
                    299: 
                    300: /* Match the "pattern" against the "text" string. */
                    301: int wildmatch(const char *pattern, const char *text)
                    302: {
                    303:     static const uchar *nomore[1]; /* A NULL pointer. */
1.1.1.2 ! misho     304:     int ret;
1.1       misho     305: #ifdef WILD_TEST_ITERATIONS
                    306:     wildmatch_iteration_count = 0;
                    307: #endif
1.1.1.2 ! misho     308:     force_lower_case = ignore_case;
        !           309:     ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
        !           310:     force_lower_case = 0;
        !           311:     return ret;
1.1       misho     312: }
                    313: 
                    314: /* Match the "pattern" against the forced-to-lower-case "text" string. */
                    315: int iwildmatch(const char *pattern, const char *text)
                    316: {
                    317:     static const uchar *nomore[1]; /* A NULL pointer. */
                    318:     int ret;
                    319: #ifdef WILD_TEST_ITERATIONS
                    320:     wildmatch_iteration_count = 0;
                    321: #endif
                    322:     force_lower_case = 1;
                    323:     ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
                    324:     force_lower_case = 0;
                    325:     return ret;
                    326: }
                    327: 
                    328: /* Match pattern "p" against the a virtually-joined string consisting
                    329:  * of all the pointers in array "texts" (which has a NULL pointer at the
                    330:  * end).  The int "where" can be 0 (normal matching), > 0 (match only
                    331:  * the trailing N slash-separated filename components of "texts"), or < 0
                    332:  * (match the "pattern" at the start or after any slash in "texts"). */
                    333: int wildmatch_array(const char *pattern, const char*const *texts, int where)
                    334: {
                    335:     const uchar *p = (const uchar*)pattern;
                    336:     const uchar*const *a = (const uchar*const*)texts;
                    337:     const uchar *text;
                    338:     int matched;
                    339: 
                    340: #ifdef WILD_TEST_ITERATIONS
                    341:     wildmatch_iteration_count = 0;
                    342: #endif
                    343: 
                    344:     if (where > 0)
                    345:        text = trailing_N_elements(&a, where);
                    346:     else
                    347:        text = *a++;
                    348:     if (!text)
                    349:        return FALSE;
                    350: 
1.1.1.2 ! misho     351:     force_lower_case = ignore_case;
        !           352: 
1.1       misho     353:     if ((matched = dowild(p, text, a)) != TRUE && where < 0
                    354:      && matched != ABORT_ALL) {
                    355:        while (1) {
                    356:            if (*text == '\0') {
                    357:                if ((text = (uchar*)*a++) == NULL)
1.1.1.2 ! misho     358:                    break;
1.1       misho     359:                continue;
                    360:            }
                    361:            if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
                    362:             && matched != ABORT_TO_STARSTAR)
                    363:                break;
                    364:        }
                    365:     }
1.1.1.2 ! misho     366: 
        !           367:     force_lower_case = 0;
        !           368: 
1.1       misho     369:     return matched == TRUE;
                    370: }
                    371: 
                    372: /* Match literal string "s" against the a virtually-joined string consisting
                    373:  * of all the pointers in array "texts" (which has a NULL pointer at the
                    374:  * end).  The int "where" can be 0 (normal matching), or > 0 (match
                    375:  * only the trailing N slash-separated filename components of "texts"). */
                    376: int litmatch_array(const char *string, const char*const *texts, int where)
                    377: {
                    378:     const uchar *s = (const uchar*)string;
                    379:     const uchar*const *a = (const uchar* const*)texts;
                    380:     const uchar *text;
                    381: 
                    382:     if (where > 0)
                    383:        text = trailing_N_elements(&a, where);
                    384:     else
                    385:        text = *a++;
                    386:     if (!text)
                    387:        return FALSE;
                    388: 
                    389:     return doliteral(s, text, a) == TRUE;
                    390: }

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