diff options
Diffstat (limited to 'src/globmatch.c')
-rw-r--r-- | src/globmatch.c | 111 |
1 files changed, 111 insertions, 0 deletions
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 <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 |