On Fri, Mar 22, 2013 at 06:24:39PM -0400, Jeff King wrote:
> I'm having trouble figuring out the right solution for this.

Thanks for looking into this. It was on my todo list, but you beat me
to it :)

> But then here we'll end up feeding "foo/" to be compared with "foo",
> which we don't want. For a pattern "foo", we want to match _either_
> "foo/" or "foo". So you'd think something like:
> 
>   if (pathlen && pathname[pathlen-1] == '/')
>           pathlen--;
> 
> would work. But it seems that match_basename, despite taking the length
> of all of the strings we pass it, will happily use NUL-terminated
> functions like strcmp or fnmatch. Converting the former to check lengths
> should be pretty straightforward. But there is no version of fnmatch
> that does what we want. I wonder if we using wildmatch can get around
> this limitation.

You can use nwildmatch() from this patch. I tested it lightly with
t3070-wildmatch.sh, feeding the strings with no terminating NUL. It
seems to work ok.

-- 8< --
Subject: [PATCH] wildmatch: do not require "text" to be NUL-terminated

This may be helpful when we just want to match a part of "text".
nwildmatch can be used for this purpose.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 wildmatch.c | 25 +++++++++++++------------
 wildmatch.h | 11 +++++++++--
 2 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/wildmatch.c b/wildmatch.c
index 7192bdc..f97ae2a 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -52,7 +52,8 @@ typedef unsigned char uchar;
 #define ISXDIGIT(c) (ISASCII(c) && isxdigit(c))
 
 /* Match pattern "p" against "text" */
-static int dowild(const uchar *p, const uchar *text, unsigned int flags)
+static int dowild(const uchar *p, const uchar *text,
+                 const uchar *textend, unsigned int flags)
 {
        uchar p_ch;
        const uchar *pattern = p;
@@ -60,8 +61,9 @@ static int dowild(const uchar *p, const uchar *text, unsigned 
int flags)
        for ( ; (p_ch = *p) != '\0'; text++, p++) {
                int matched, match_slash, negated;
                uchar t_ch, prev_ch;
-               if ((t_ch = *text) == '\0' && p_ch != '*')
+               if (text >= textend && p_ch != '*')
                        return WM_ABORT_ALL;
+               t_ch = *text;
                if ((flags & WM_CASEFOLD) && ISUPPER(t_ch))
                        t_ch = tolower(t_ch);
                if ((flags & WM_CASEFOLD) && ISUPPER(p_ch))
@@ -101,7 +103,7 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                                         * both foo/bar and foo/a/bar.
                                         */
                                        if (p[0] == '/' &&
-                                           dowild(p + 1, text, flags) == 
WM_MATCH)
+                                           dowild(p + 1, text, textend, flags) 
== WM_MATCH)
                                                return WM_MATCH;
                                        match_slash = 1;
                                } else
@@ -130,9 +132,7 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                                /* the slash is consumed by the top-level for 
loop */
                                break;
                        }
-                       while (1) {
-                               if (t_ch == '\0')
-                                       break;
+                       while (text < textend) {
                                /*
                                 * Try to advance faster when an asterisk is
                                 * followed by a literal. We know in this case
@@ -145,18 +145,18 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                                        p_ch = *p;
                                        if ((flags & WM_CASEFOLD) && 
ISUPPER(p_ch))
                                                p_ch = tolower(p_ch);
-                                       while ((t_ch = *text) != '\0' &&
+                                       while (text < textend &&
                                               (match_slash || t_ch != '/')) {
                                                if ((flags & WM_CASEFOLD) && 
ISUPPER(t_ch))
                                                        t_ch = tolower(t_ch);
                                                if (t_ch == p_ch)
                                                        break;
-                                               text++;
+                                               t_ch = *++text;
                                        }
                                        if (t_ch != p_ch)
                                                return WM_NOMATCH;
                                }
-                               if ((matched = dowild(p, text, flags)) != 
WM_NOMATCH) {
+                               if ((matched = dowild(p, text, textend, flags)) 
!= WM_NOMATCH) {
                                        if (!match_slash || matched != 
WM_ABORT_TO_STARSTAR)
                                                return matched;
                                } else if (!match_slash && t_ch == '/')
@@ -261,12 +261,13 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                }
        }
 
-       return *text ? WM_NOMATCH : WM_MATCH;
+       return text < textend ? WM_NOMATCH : WM_MATCH;
 }
 
 /* Match the "pattern" against the "text" string. */
-int wildmatch(const char *pattern, const char *text,
+int nwildmatch(const char *pattern, const char *text, int textlen,
              unsigned int flags, struct wildopts *wo)
 {
-       return dowild((const uchar*)pattern, (const uchar*)text, flags);
+       return dowild((const uchar*)pattern, (const uchar*)text,
+                     (const uchar*)text + textlen, flags);
 }
diff --git a/wildmatch.h b/wildmatch.h
index 4090c8f..cdd7544 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -12,7 +12,14 @@
 
 struct wildopts;
 
-int wildmatch(const char *pattern, const char *text,
-             unsigned int flags,
+int nwildmatch(const char *pattern, const char *text,
+             int len, unsigned int flags,
              struct wildopts *wo);
+
+/* Match the "pattern" against the "text" string. */
+static inline int wildmatch(const char *pattern, const char *text,
+             unsigned int flags, struct wildopts *wo)
+{
+       return nwildmatch(pattern, text, strlen(text), flags, wo);
+}
 #endif
-- 
1.8.2.83.gc99314b

-- 8< --
--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to