Simplified the character-class code a bit.
[rsync/rsync.git] / lib / wildmatch.c
index 06eb4d7..9276954 100644 (file)
 /* What character marks an inverted character class? */
 #define NEGATE_CLASS '!'
 
-#define false 0
-#define true 1
+#define FALSE 0
+#define TRUE 1
+#define ABORT_ALL -1
+#define ABORT_TO_STARSTAR -2
 
-/* Look for pattern "p" in the "text" string. */
-int
-wildmatch(const char *p, const char *text)
+#ifdef WILD_TEST_ITERATIONS
+int wildmatch_iteration_count;
+#endif
+
+static int domatch(const char *p, const char *text)
 {
     int matched, special;
     char ch, prev;
 
+#ifdef WILD_TEST_ITERATIONS
+    wildmatch_iteration_count++;
+#endif
+
     for ( ; (ch = *p) != '\0'; text++, p++) {
        if (*text == '\0' && ch != '*')
-           return false;
+           return FALSE;
        switch (ch) {
          case '\\':
            /* Literal match with following character.  Note that the test
@@ -35,62 +43,68 @@ wildmatch(const char *p, const char *text)
            /* FALLTHROUGH */
          default:
            if (*text != ch)
-               return false;
+               return FALSE;
            continue;
          case '?':
            /* Match anything but '/'. */
            if (*text == '/')
-               return false;
+               return FALSE;
            continue;
          case '*':
            if (*++p == '*') {
                while (*++p == '*') {}
-               special = true;
+               special = TRUE;
            }
            else
-               special = false;
+               special = FALSE;
            if (*p == '\0') {
-               /* Trailing "**" matches everything. */
-               return special? true : strchr(text, '/') == 0;
+               /* Trailing "**" matches everything.  Trailing "*" matches
+                * only if there are no more slash characters. */
+               return special? TRUE : strchr(text, '/') == NULL;
            }
            for ( ; *text; text++) {
-               if (wildmatch(p, text))
-                   return true;
-               if (!special && *text == '/')
-                   return false;
+               if ((matched = domatch(p, text)) != FALSE) {
+                   if (!special || matched != ABORT_TO_STARSTAR)
+                       return matched;
+               }
+               else if (!special && *text == '/')
+                   return ABORT_TO_STARSTAR;
            }
-           return false;
+           return ABORT_ALL;
          case '[':
-           special = *++p == NEGATE_CLASS ? true : false;
+           ch = *++p;
+           /* Assign literal TRUE/FALSE because of "matched" comparison. */
+           special = ch == NEGATE_CLASS? TRUE : FALSE;
            if (special) {
                /* Inverted character class. */
-               p++;
-           }
-           prev = 0;
-           matched = false;
-           ch = *p;
-           if (ch == ']' || ch == '-') {
-               if (*text == ch)
-                   matched = true;
-               prev = ch;
                ch = *++p;
            }
-           for ( ; ch != ']'; prev = ch, ch = *++p) {
+           prev = 0;
+           matched = FALSE;
+           do {
                if (!ch)
-                   return false;
+                   return FALSE;
                if (ch == '-' && prev && p[1] && p[1] != ']') {
                    if (*text <= *++p && *text >= prev)
-                       matched = true;
+                       matched = TRUE;
                    ch = 0; /* This makes "prev" get set to 0. */
                }
                else if (*text == ch)
-                   matched = true;
-           }
+                   matched = TRUE;
+           } while (prev = ch, (ch = *++p) != ']');
            if (matched == special)
-               return false;
+               return FALSE;
            continue;
        }
     }
 
     return *text == '\0';
 }
+
+int wildmatch(const char *p, const char *text)
+{
+#ifdef WILD_TEST_ITERATIONS
+    wildmatch_iteration_count = 0;
+#endif
+    return domatch(p, text) == TRUE;
+}