globmatch: Add globmatch to wrap fnmatch
authorJose Bollo <jose.bollo@iot.bzh>
Mon, 25 Feb 2019 13:45:57 +0000 (14:45 +0100)
committerJosé Bollo <jose.bollo@iot.bzh>
Fri, 22 Mar 2019 11:21:54 +0000 (12:21 +0100)
Change-Id: I1effa961a169cce444ea246f5d7f8839b4937403
Signed-off-by: Jose Bollo <jose.bollo@iot.bzh>
CMakeLists.txt
src/CMakeLists.txt
src/afb-api-v3.c
src/afb-args.c
src/afb-export.c
src/afb-hook.c
src/globmatch.c [new file with mode: 0644]
src/globmatch.h [new file with mode: 0644]
src/globset.c

index 853f5fe..7a7ab42 100644 (file)
@@ -59,6 +59,7 @@ option(WITH_LEGACY_BINDING_V2     "Includes the legacy Binding API version 2" ON
 option(WITH_LEGACY_BINDING_VDYN   "Includes the legacy Binding API version dynamic" OFF)
 option(WITH_DYNAMIC_BINDING       "Allow to load dynamic bindings (shared libraries)" ON)
 option(WITH_LIBMICROHTTPD         "Activates HTTP server through LIBMICROHTTPD" ON)
+option(WITH_FNMATCH               "Use fnmatch where possible"             ON)
 
 ############################################################################
 # legacy options
index e3ee753..8d89832 100644 (file)
@@ -43,6 +43,7 @@ add_definitions(
   -DWITH_FDEV_EPOLL=$<NOT:$<BOOL:${WITH_SYSTEMD}>>
   -DWITH_LIBMICROHTTPD=$<BOOL:${WITH_LIBMICROHTTPD}>
   -DWITH_MONITORING=$<BOOL:${WITH_MONITORING}>
+  -DWITH_FNMATCH=$<BOOL:${WITH_FNMATCH}>
 )
 
 if (WITH_SUPERVISOR)
@@ -109,6 +110,7 @@ SET(AFB_LIB_SOURCES
        fdev.c
        fdev-epoll.c
        fdev-systemd.c
+       globmatch.c
        globset.c
        jobs.c
        locale-root.c
index 7b889ee..caaaff4 100644 (file)
@@ -21,7 +21,6 @@
 #include <string.h>
 #include <assert.h>
 #include <errno.h>
-#include <fnmatch.h>
 
 #include <json-c/json.h>
 
@@ -34,8 +33,9 @@
 #include "afb-auth.h"
 #include "afb-export.h"
 #include "afb-xreq.h"
-#include "verbose.h"
+#include "globmatch.h"
 #include "sig-monitor.h"
+#include "verbose.h"
 
 /*
  * Description of a binding
index b7ef1f5..edc0a32 100644 (file)
@@ -574,6 +574,7 @@ static int config_has(struct json_object *config, int optid)
        return json_object_object_get_ex(config, name_of_optid(optid), NULL);
 }
 
+__attribute__((unused))
 static int config_has_bool(struct json_object *config, int optid)
 {
        struct json_object *x;
index 202a73f..eff1731 100644 (file)
@@ -20,7 +20,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <errno.h>
-#include <fnmatch.h>
 #include <ctype.h>
 
 #include <json-c/json.h>
index f8b593d..075f6a0 100644 (file)
 #include "afb-evt.h"
 #include "afb-api.h"
 #include "afb-msg-json.h"
+
+#include "globmatch.h"
 #include "verbose.h"
 
-#include <fnmatch.h>
 #define MATCH(pattern,string)   (\
                pattern \
                        ? !fnmatch((pattern),(string),FNM_CASEFOLD|FNM_EXTMATCH|FNM_PERIOD) \
diff --git a/src/globmatch.c b/src/globmatch.c
new file mode 100644 (file)
index 0000000..4cb1f00
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018, 2019 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <ctype.h>
+
+#include "globmatch.h"
+
+/**
+ * Matches whether the string 'str' matches the pattern 'pat'
+ * and returns its matching score.
+ *
+ * @param pat the glob pattern
+ * @param str the string to match
+ * @return 0 if no match or number representing the matching score
+ */
+static unsigned match(const char *pat, const char *str, int flags)
+{
+       unsigned r, rs, rr;
+       char c, x;
+       int eq;
+
+       /* scan the prefix without glob */
+       r = 1;
+       while ((c = *pat++) != GLOB) {
+               x = *str++;
+               eq = (flags & FNM_CASEFOLD) ? (tolower(c) == tolower(x)) : (c == x);
+               if (!eq)
+                       return 0; /* no match */
+               if (!c)
+                       return r; /* match up to end */
+               r++;
+       }
+
+       /* glob found */
+       c = *pat++;
+       if (!c) {
+               /* not followed by pattern */
+               if (flags & FNM_PATHNAME) {
+                       while(*str)
+                               if (*str++ == '/')
+                                       return 0;
+               }
+               return r;
+       }
+
+       /* evaluate the best score for following pattern */
+       rs = 0;
+       while (*str) {
+               x = *str++;
+               eq = (flags & FNM_CASEFOLD) ? (tolower(c) == tolower(x)) : (c == x);
+               if (eq) {
+                       /* first char matches, check remaining string */
+                       rr = match(pat, str, flags);
+                       if (rr > rs)
+                               rs = rr;
+               } else if ((flags & FNM_PATHNAME) && x == '/')
+                       return 0;
+       }
+
+       /* best score or not match if rs == 0 */
+       return rs ? rs + r : 0;
+}
+
+/**
+ * Matches whether the string 'str' matches the pattern 'pat'
+ * and returns its matching score.
+ *
+ * @param pat the glob pattern
+ * @param str the string to match
+ * @return 0 if no match or number representing the matching score
+ */
+unsigned globmatch(const char *pat, const char *str)
+{
+       return match(pat, str, 0);
+}
+
+/**
+ * Matches whether the string 'str' matches the pattern 'pat'
+ * and returns its matching score.
+ *
+ * @param pat the glob pattern
+ * @param str the string to match
+ * @return 0 if no match or number representing the matching score
+ */
+unsigned globmatchi(const char *pat, const char *str)
+{
+       return match(pat, str, FNM_CASEFOLD);
+}
+
+#if !WITH_FNMATCH
+int fnmatch(const char *pattern, const char *string, int flags)
+{
+       return !match(pattern, string, flags);
+}
+#endif
diff --git a/src/globmatch.h b/src/globmatch.h
new file mode 100644 (file)
index 0000000..2f05c16
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2018, 2019 "IoT.bzh"
+ * Author: José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#define GLOB    '*'
+
+extern unsigned globmatch(const char *pat, const char *str);
+extern unsigned globmatchi(const char *pat, const char *str);
+
+#if WITH_FNMATCH
+
+#include <fnmatch.h>
+
+#else
+
+#define        FNM_PATHNAME    (1 << 0)        /* No wildcard can ever match `/'.  */
+#define        FNM_NOESCAPE    (1 << 1)        /* Backslashes don't quote special chars.  */
+#define        FNM_PERIOD      (1 << 2)        /* Leading `.' is matched only explicitly.  */
+#define FNM_FILE_NAME  FNM_PATHNAME    /* Preferred GNU name.  */
+#define FNM_LEADING_DIR (1 << 3)       /* Ignore `/...' after a match.  */
+#define FNM_CASEFOLD   (1 << 4)        /* Compare without regard to case.  */
+#define FNM_EXTMATCH   (1 << 5)        /* Use ksh-like extended matching. */
+#define        FNM_NOMATCH     1
+
+extern int fnmatch(const char *pattern, const char *string, int flags);
+
+#endif
index 2bad449..0ea448b 100644 (file)
@@ -22,8 +22,7 @@
 #include <errno.h>
 
 #include "globset.h"
-
-#define GLOB '*'
+#include "globmatch.h"
 
 /*************************************************************************
  * internal types
@@ -62,49 +61,6 @@ struct globset
        unsigned count;
 };
 
-/**
- * Matches whether the string 'str' matches the pattern 'pat'
- * and returns its matching score.
- *
- * @param pat the glob pattern
- * @param str the string to match
- * @return 0 if no match or number representing the matching score
- */
-static unsigned match(const char *pat, const char *str)
-{
-       unsigned r, rs, rr;
-       char c;
-
-       /* scan the prefix without glob */
-       r = 1;
-       while ((c = *pat++) != GLOB) {
-               if (c != *str++)
-                       return 0; /* no match */
-               if (!c)
-                       return r; /* match up to end */
-               r++;
-       }
-
-       /* glob found */
-       c = *pat++;
-       if (!c)
-               return r; /* not followed by pattern */
-
-       /* evaluate the best score for following pattern */
-       rs = 0;
-       while (*str) {
-               if (*str++ == c) {
-                       /* first char matches, check remaining string */
-                       rr = match(pat, str);
-                       if (rr > rs)
-                               rs = rr;
-               }
-       }
-
-       /* best score or not match if rs == 0 */
-       return rs ? rs + r : 0;
-}
-
 /**
  * Normalize the string 'from' to the string 'to' and computes the hash code.
  * The normalization translates upper characters to lower characters.
@@ -235,13 +191,6 @@ static struct pathndl *search(
        return ph;
 }
 
-
-
-
-
-
-
-
 /**
  * Allocates a new set of handlers
  *
@@ -436,7 +385,7 @@ const struct globset_handler *globset_match(
                s = 0;
                iph = set->globs;
                while(iph) {
-                       g = match(iph->handler.pattern, txt);
+                       g = globmatch(iph->handler.pattern, txt);
                        if (g > s) {
                                s = g;
                                ph = iph;