Added in the ABORT optimization logic from a newer wildmat release,
[rsync/rsync.git] / lib / wildmatch.c
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
17 #define FALSE 0
18 #define TRUE 1
19 #define ABORT -1
20
21 static int domatch(const char *p, const char *text)
22 {
23     int matched, special;
24     char ch, prev;
25
26     for ( ; (ch = *p) != '\0'; text++, p++) {
27         if (*text == '\0' && ch != '*')
28             return FALSE;
29         switch (ch) {
30           case '\\':
31             /* Literal match with following character.  Note that the test
32              * in "default" handles the p[1] == '\0' failure case. */
33             ch = *++p;
34             /* FALLTHROUGH */
35           default:
36             if (*text != ch)
37                 return FALSE;
38             continue;
39           case '?':
40             /* Match anything but '/'. */
41             if (*text == '/')
42                 return FALSE;
43             continue;
44           case '*':
45             if (*++p == '*') {
46                 while (*++p == '*') {}
47                 special = TRUE;
48             }
49             else
50                 special = FALSE;
51             if (*p == '\0') {
52                 /* Trailing "**" matches everything.  Trailing "*" matches
53                  * only if there are no more slash characters. */
54                 return special? TRUE : strchr(text, '/') == 0;
55             }
56             for ( ; *text; text++) {
57                 if ((matched = domatch(p, text)) != FALSE)
58                     return matched;
59                 if (!special && *text == '/')
60                     return FALSE;
61             }
62             return ABORT;
63           case '[':
64             special = *++p == NEGATE_CLASS ? TRUE : FALSE;
65             if (special) {
66                 /* Inverted character class. */
67                 p++;
68             }
69             prev = 0;
70             matched = FALSE;
71             ch = *p;
72             if (ch == ']' || ch == '-') {
73                 if (*text == ch)
74                     matched = TRUE;
75                 prev = ch;
76                 ch = *++p;
77             }
78             for ( ; ch != ']'; prev = ch, ch = *++p) {
79                 if (!ch)
80                     return FALSE;
81                 if (ch == '-' && prev && p[1] && p[1] != ']') {
82                     if (*text <= *++p && *text >= prev)
83                         matched = TRUE;
84                     ch = 0; /* This makes "prev" get set to 0. */
85                 }
86                 else if (*text == ch)
87                     matched = TRUE;
88             }
89             if (matched == special)
90                 return FALSE;
91             continue;
92         }
93     }
94
95     return *text == '\0';
96 }
97
98 int wildmatch(const char *p, const char *text)
99 {
100     return domatch(p, text) == TRUE;
101 }