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