Added a new function, wildmatch_array(), that lets the caller pass
authorWayne Davison <wayned@samba.org>
Mon, 2 Jan 2006 17:46:15 +0000 (17:46 +0000)
committerWayne Davison <wayned@samba.org>
Mon, 2 Jan 2006 17:46:15 +0000 (17:46 +0000)
the text-string as an array of strings (with a terminating NULL
pointer at the end).  Also added litmatch_array(), which does a
literal match (no wildcards or special chars) against an array of
strings.

lib/wildmatch.c

index 2f0023d..4b54864 100644 (file)
@@ -59,8 +59,9 @@ int wildmatch_iteration_count;
 
 static int force_lower_case = 0;
 
-/* Match pattern "p" against string "text". */
-static int dowild(const uchar *p, const uchar *text)
+/* Match pattern "p" against the a virtually-joined string consisting
+ * of "text" and any strings in array "a". */
+static int dowild(const uchar *p, const uchar *text, const uchar*const *a)
 {
     uchar p_ch;
 
@@ -71,8 +72,14 @@ static int dowild(const uchar *p, const uchar *text)
     for ( ; (p_ch = *p) != '\0'; text++, p++) {
        int matched, special;
        uchar t_ch, prev_ch;
-       if ((t_ch = *text) == '\0' && p_ch != '*')
-           return ABORT_ALL;
+       while ((t_ch = *text) == '\0') {
+           if (*a == NULL) {
+               if (p_ch != '*')
+                   return ABORT_ALL;
+               break;
+           }
+           text = *a++;
+       }
        if (force_lower_case && ISUPPER(t_ch))
            t_ch = tolower(t_ch);
        switch (p_ch) {
@@ -99,14 +106,27 @@ static int dowild(const uchar *p, const uchar *text)
            if (*p == '\0') {
                /* Trailing "**" matches everything.  Trailing "*" matches
                 * only if there are no more slash characters. */
-               return special? TRUE : strchr((char*)text, '/') == NULL;
+               if (!special) {
+                   do {
+                       if (strchr((char*)text, '/') != NULL)
+                           return FALSE;
+                   } while ((text = *a++) != NULL);
+               }
+               return TRUE;
            }
-           for ( ; t_ch; (t_ch = *++text)) {
-               if ((matched = dowild(p, text)) != FALSE) {
+           while (1) {
+               if (t_ch == '\0') {
+                   if ((text = *a++) == NULL)
+                       break;
+                   t_ch = *text;
+                   continue;
+               }
+               if ((matched = dowild(p, text, a)) != FALSE) {
                    if (!special || matched != ABORT_TO_STARSTAR)
                        return matched;
                } else if (!special && t_ch == '/')
                    return ABORT_TO_STARSTAR;
+               t_ch = *++text;
            }
            return ABORT_ALL;
          case '[':
@@ -205,27 +225,144 @@ static int dowild(const uchar *p, const uchar *text)
        }
     }
 
-    return *text == '\0';
+    do {
+       if (*text)
+           return FALSE;
+    } while ((text = *a++) != NULL);
+
+    return TRUE;
+}
+
+/* Match literal string "s" against the a virtually-joined string consisting
+ * of "text" and any strings in array "a". */
+static int doliteral(const uchar *s, const uchar *text, const uchar*const *a)
+{
+    for ( ; *s != '\0'; text++, s++) {
+       while (*text == '\0') {
+           if ((text = *a++) == NULL)
+               return FALSE;
+       }
+       if (*text != *s)
+           return FALSE;
+    }
+
+    do {
+       if (*text)
+           return FALSE;
+    } while ((text = *a++) != NULL);
+
+    return TRUE;
+}
+
+/* Return the last "count" path elements from the concatenated string.
+ * We return a string pointer to the start of the string, and update the
+ * array pointer-pointer to point to any remaining string elements. */
+static const uchar *trailing_N_elements(const uchar*const **a_ptr, int count)
+{
+    const uchar*const *a = *a_ptr;
+    const uchar*const *first_a = a;
+
+    while (*a)
+           a++;
+
+    while (a != first_a) {
+       const uchar *s = *--a;
+       s += strlen((char*)s);
+       while (--s >= *a) {
+           if (*s == '/' && !--count) {
+               *a_ptr = a+1;
+               return s+1;
+           }
+       }
+    }
+
+    if (count == 1) {
+       *a_ptr = a+1;
+       return *a;
+    }
+
+    return NULL;
 }
 
 /* Match the "pattern" against the "text" string. */
 int wildmatch(const char *pattern, const char *text)
 {
+    static const uchar *nomore[1]; /* A NULL pointer. */
 #ifdef WILD_TEST_ITERATIONS
     wildmatch_iteration_count = 0;
 #endif
-    return dowild((const uchar*)pattern, (const uchar*)text) == TRUE;
+    return dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
 }
 
 /* Match the "pattern" against the forced-to-lower-case "text" string. */
 int iwildmatch(const char *pattern, const char *text)
 {
+    static const uchar *nomore[1]; /* A NULL pointer. */
     int ret;
 #ifdef WILD_TEST_ITERATIONS
     wildmatch_iteration_count = 0;
 #endif
     force_lower_case = 1;
-    ret = dowild((const uchar*)pattern, (const uchar*)text) == TRUE;
+    ret = dowild((const uchar*)pattern, (const uchar*)text, nomore) == TRUE;
     force_lower_case = 0;
     return ret;
 }
+
+/* Match pattern "p" against the a virtually-joined string consisting
+ * of all the pointers in array "texts" (which has a NULL pointer at the
+ * end).  The int "where" can be 0 (normal matching), > 0 (match only
+ * the trailing N slash-separated filename components of "texts"), or < 0
+ * (match the "pattern" at the start or after any slash in "texts"). */
+int wildmatch_array(const char *pattern, const char*const *texts, int where)
+{
+    const uchar *p = (const uchar*)pattern;
+    const uchar*const *a = (const uchar*const*)texts;
+    const uchar *text;
+    int matched;
+
+#ifdef WILD_TEST_ITERATIONS
+    wildmatch_iteration_count = 0;
+#endif
+
+    if (where > 0)
+       text = trailing_N_elements(&a, where);
+    else
+       text = *a++;
+    if (!text)
+       return FALSE;
+
+    if ((matched = dowild(p, text, a)) != TRUE && where < 0
+     && matched != ABORT_ALL) {
+       while (1) {
+           if (*text == '\0') {
+               if ((text = (uchar*)*a++) == NULL)
+                   return FALSE;
+               continue;
+           }
+           if (*text++ == '/' && (matched = dowild(p, text, a)) != FALSE
+            && matched != ABORT_TO_STARSTAR)
+               break;
+       }
+    }
+    return matched == TRUE;
+}
+
+/* Match literal string "s" against the a virtually-joined string consisting
+ * of all the pointers in array "texts" (which has a NULL pointer at the
+ * end).  The int "where" can be 0 (normal matching), or > 0 (match
+ * only the trailing N slash-separated filename components of "texts"). */
+int litmatch_array(const char *string, const char*const *texts, int where)
+{
+    const uchar *s = (const uchar*)string;
+    const uchar*const *a = (const uchar* const*)texts;
+    const uchar *text;
+
+    if (where > 0)
+       text = trailing_N_elements(&a, where);
+    else
+       text = *a++;
+    if (!text)
+       return FALSE;
+
+    return doliteral(s, text, a) == TRUE;
+}