wildmatch: adjust "**" behavior
[git/git.git] / wildmatch.c
index 4653dd6..85bc0df 100644 (file)
@@ -9,7 +9,10 @@
 **  work differently than '*', and to fix the character-class code.
 */
 
 **  work differently than '*', and to fix the character-class code.
 */
 
-#include "rsync.h"
+#include "cache.h"
+#include "wildmatch.h"
+
+typedef unsigned char uchar;
 
 /* What character marks an inverted character class? */
 #define NEGATE_CLASS   '!'
 
 /* What character marks an inverted character class? */
 #define NEGATE_CLASS   '!'
@@ -17,8 +20,6 @@
 
 #define FALSE 0
 #define TRUE 1
 
 #define FALSE 0
 #define TRUE 1
-#define ABORT_ALL -1
-#define ABORT_TO_STARSTAR -2
 
 #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
                                    && *(class) == *(litmatch) \
 
 #define CC_EQ(class, len, litmatch) ((len) == sizeof (litmatch)-1 \
                                    && *(class) == *(litmatch) \
 #define ISUPPER(c) (ISASCII(c) && isupper(c))
 #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
 
 #define ISUPPER(c) (ISASCII(c) && isupper(c))
 #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
 
-static int force_lower_case = 0;
-
 /* Match pattern "p" against "text" */
 /* Match pattern "p" against "text" */
-static int dowild(const uchar *p, const uchar *text)
+static int dowild(const uchar *p, const uchar *text, int force_lower_case)
 {
        uchar p_ch;
 
 {
        uchar p_ch;
 
@@ -67,6 +66,8 @@ static int dowild(const uchar *p, const uchar *text)
                        return ABORT_ALL;
                if (force_lower_case && ISUPPER(t_ch))
                        t_ch = tolower(t_ch);
                        return ABORT_ALL;
                if (force_lower_case && ISUPPER(t_ch))
                        t_ch = tolower(t_ch);
+               if (force_lower_case && ISUPPER(p_ch))
+                       p_ch = tolower(p_ch);
                switch (p_ch) {
                case '\\':
                        /* Literal match with following character.  Note that the test
                switch (p_ch) {
                case '\\':
                        /* Literal match with following character.  Note that the test
@@ -75,17 +76,23 @@ static int dowild(const uchar *p, const uchar *text)
                        /* FALLTHROUGH */
                default:
                        if (t_ch != p_ch)
                        /* FALLTHROUGH */
                default:
                        if (t_ch != p_ch)
-                               return FALSE;
+                               return NOMATCH;
                        continue;
                case '?':
                        /* Match anything but '/'. */
                        if (t_ch == '/')
                        continue;
                case '?':
                        /* Match anything but '/'. */
                        if (t_ch == '/')
-                               return FALSE;
+                               return NOMATCH;
                        continue;
                case '*':
                        if (*++p == '*') {
                        continue;
                case '*':
                        if (*++p == '*') {
+                               const uchar *prev_p = p - 2;
                                while (*++p == '*') {}
                                while (*++p == '*') {}
-                               special = TRUE;
+                               if ((prev_p == text || *prev_p == '/') ||
+                                   (*p == '\0' || *p == '/' ||
+                                    (p[0] == '\\' && p[1] == '/'))) {
+                                       special = TRUE;
+                               } else
+                                       return ABORT_MALFORMED;
                        } else
                                special = FALSE;
                        if (*p == '\0') {
                        } else
                                special = FALSE;
                        if (*p == '\0') {
@@ -93,14 +100,14 @@ static int dowild(const uchar *p, const uchar *text)
                                 * only if there are no more slash characters. */
                                if (!special) {
                                        if (strchr((char*)text, '/') != NULL)
                                 * only if there are no more slash characters. */
                                if (!special) {
                                        if (strchr((char*)text, '/') != NULL)
-                                               return FALSE;
+                                               return NOMATCH;
                                }
                                }
-                               return TRUE;
+                               return MATCH;
                        }
                        while (1) {
                                if (t_ch == '\0')
                                        break;
                        }
                        while (1) {
                                if (t_ch == '\0')
                                        break;
-                               if ((matched = dowild(p, text)) != FALSE) {
+                               if ((matched = dowild(p, text,  force_lower_case)) != NOMATCH) {
                                        if (!special || matched != ABORT_TO_STARSTAR)
                                                return matched;
                                } else if (!special && t_ch == '/')
                                        if (!special || matched != ABORT_TO_STARSTAR)
                                                return matched;
                                } else if (!special && t_ch == '/')
@@ -199,26 +206,17 @@ static int dowild(const uchar *p, const uchar *text)
                                        matched = TRUE;
                        } while (prev_ch = p_ch, (p_ch = *++p) != ']');
                        if (matched == special || t_ch == '/')
                                        matched = TRUE;
                        } while (prev_ch = p_ch, (p_ch = *++p) != ']');
                        if (matched == special || t_ch == '/')
-                               return FALSE;
+                               return NOMATCH;
                        continue;
                }
        }
 
                        continue;
                }
        }
 
-       return *text ? FALSE : TRUE;
+       return *text ? NOMATCH : MATCH;
 }
 
 /* Match the "pattern" against the "text" string. */
 }
 
 /* Match the "pattern" against the "text" string. */
-int wildmatch(const char *pattern, const char *text)
-{
-       return dowild((const uchar*)pattern, (const uchar*)text) == TRUE;
-}
-
-/* Match the "pattern" against the forced-to-lower-case "text" string. */
-int iwildmatch(const char *pattern, const char *text)
+int wildmatch(const char *pattern, const char *text, int flags)
 {
 {
-       int ret;
-       force_lower_case = 1;
-       ret = dowild((const uchar*)pattern, (const uchar*)text) == TRUE;
-       force_lower_case = 0;
-       return ret;
+       return dowild((const uchar*)pattern, (const uchar*)text,
+                     flags & FNM_CASEFOLD ? 1 :0);
 }
 }