From caea0053d2abc141ab585324fb51f8c536db249b Mon Sep 17 00:00:00 2001 From: Jose Bollo Date: Mon, 25 Feb 2019 14:45:57 +0100 Subject: globmatch: Add globmatch to wrap fnmatch Change-Id: I1effa961a169cce444ea246f5d7f8839b4937403 Signed-off-by: Jose Bollo --- CMakeLists.txt | 1 + src/CMakeLists.txt | 2 + src/afb-api-v3.c | 4 +- src/afb-args.c | 1 + src/afb-export.c | 1 - src/afb-hook.c | 3 +- src/globmatch.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/globmatch.h | 42 ++++++++++++++++++++ src/globset.c | 55 +------------------------- 9 files changed, 163 insertions(+), 57 deletions(-) create mode 100644 src/globmatch.c create mode 100644 src/globmatch.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 853f5fee..7a7ab429 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e3ee7533..8d898328 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -43,6 +43,7 @@ add_definitions( -DWITH_FDEV_EPOLL=$> -DWITH_LIBMICROHTTPD=$ -DWITH_MONITORING=$ + -DWITH_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 diff --git a/src/afb-api-v3.c b/src/afb-api-v3.c index 7b889ee8..caaaff4c 100644 --- a/src/afb-api-v3.c +++ b/src/afb-api-v3.c @@ -21,7 +21,6 @@ #include #include #include -#include #include @@ -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 diff --git a/src/afb-args.c b/src/afb-args.c index b7ef1f59..edc0a32f 100644 --- a/src/afb-args.c +++ b/src/afb-args.c @@ -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; diff --git a/src/afb-export.c b/src/afb-export.c index 202a73f6..eff17316 100644 --- a/src/afb-export.c +++ b/src/afb-export.c @@ -20,7 +20,6 @@ #include #include #include -#include #include #include diff --git a/src/afb-hook.c b/src/afb-hook.c index f8b593df..075f6a06 100644 --- a/src/afb-hook.c +++ b/src/afb-hook.c @@ -44,9 +44,10 @@ #include "afb-evt.h" #include "afb-api.h" #include "afb-msg-json.h" + +#include "globmatch.h" #include "verbose.h" -#include #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 index 00000000..4cb1f001 --- /dev/null +++ b/src/globmatch.c @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2018, 2019 "IoT.bzh" + * Author: José Bollo + * + * 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 + +#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 index 00000000..2f05c169 --- /dev/null +++ b/src/globmatch.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2018, 2019 "IoT.bzh" + * Author: José Bollo + * + * 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 + +#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 diff --git a/src/globset.c b/src/globset.c index 2bad449f..0ea448be 100644 --- a/src/globset.c +++ b/src/globset.c @@ -22,8 +22,7 @@ #include #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; -- cgit 1.2.3-korg