[klibc] Add fnmatch() function for udev support
Add fnmatch() function to support udev. Thanks to Aaron Griffin for the
original implementation.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
diff --git a/usr/include/fnmatch.h b/usr/include/fnmatch.h
new file mode 100644
index 0000000..d58ecf6
--- /dev/null
+++ b/usr/include/fnmatch.h
@@ -0,0 +1,16 @@
+#ifndef _FNMATCH_H
+#define _FNMATCH_H
+
+#include <klibc/extern.h>
+
+#define FNM_NOMATCH 1
+
+#define FNM_PATHNAME 1
+#define FNM_FILE_NAME FNM_PATHNAME
+#define FNM_NOESCAPE 2
+#define FNM_PERIOD 4
+
+__extern int fnmatch(const char *, const char *, int);
+
+#endif /* _FNMATCH_H */
+
diff --git a/usr/klibc/Kbuild b/usr/klibc/Kbuild
index b47d6e3..e6b96b6 100644
--- a/usr/klibc/Kbuild
+++ b/usr/klibc/Kbuild
@@ -36,6 +36,7 @@
strncat.o strlcpy.o strlcat.o \
strstr.o strncmp.o strncpy.o strrchr.o \
strxspn.o strspn.o strcspn.o strpbrk.o strsep.o strtok.o \
+ fnmatch.o \
gethostname.o getdomainname.o getcwd.o \
seteuid.o setegid.o \
getenv.o setenv.o putenv.o __put_env.o unsetenv.o \
diff --git a/usr/klibc/fnmatch.c b/usr/klibc/fnmatch.c
new file mode 100644
index 0000000..39f1f0e
--- /dev/null
+++ b/usr/klibc/fnmatch.c
@@ -0,0 +1,72 @@
+/*
+ * fnmatch.c
+ *
+ * Original implementation by Aaron Griffin, modified by H. Peter Anvin
+ */
+
+#include <fnmatch.h>
+
+int fnmatch(const char *p, const char *s, int flags)
+{
+ if (flags & FNM_PATHNAME && *s == '/')
+ return (*p != '/') || fnmatch(p+1, s+1, flags);
+ if (flags & FNM_PERIOD && *s == '.')
+ return (*p != '.') || fnmatch(p+1, s+1, flags);
+
+ flags &= ~FNM_PERIOD; /* Only applies at beginning */
+
+ if (!(flags & FNM_NOESCAPE) && *p == '\\') {
+ p++;
+ return (*p != *s) || fnmatch(p+1, s+1, flags);
+ }
+
+ if (*s == '\0') {
+ while (*p == '*')
+ p++;
+ return (*p != '\0');
+ }
+
+ switch (*p) {
+ case '[':
+ {
+ int not = 0;
+ p++;
+ if (*p == '!') {
+ not = 1;
+ p++;
+ }
+ while ((*p != '\0') && (*p != ']')) {
+ int match = 0;
+ if (p[1] == '-') {
+ if ((*s >= *p) && (*s <= p[2]))
+ match = 1;
+ p += 3;
+ } else {
+ match = (*p == *s);
+ p++;
+ }
+ if (match ^ not) {
+ while ((*p != '\0') && (*p != ']'))
+ p++;
+ if (*p == ']')
+ return fnmatch(p+1, s+1, flags);
+ }
+ }
+ }
+ break;
+ case '*':
+ if (fnmatch(p, s+1, flags))
+ return fnmatch(p+1, s, flags);
+ return 0;
+ case '\0':
+ if (*s == '\0') {
+ return 0;
+ }
+ break;
+ default:
+ if ((*p == *s) || (*p == '?'))
+ return fnmatch(p+1, s+1, flags);
+ break;
+ }
+ return 1;
+}
diff --git a/usr/klibc/tests/Kbuild b/usr/klibc/tests/Kbuild
index a97e86c..af14763 100644
--- a/usr/klibc/tests/Kbuild
+++ b/usr/klibc/tests/Kbuild
@@ -15,6 +15,7 @@
environ.shared-y := environ.o
fcntl.shared-y := fcntl.o
+fnmatch.shared-y := fnmatch.o
getopttest.shared-y := getopttest.o
getpagesize.shared-y := getpagesize.o
hello.shared-y := hello.o
diff --git a/usr/klibc/tests/fnmatch.c b/usr/klibc/tests/fnmatch.c
new file mode 100644
index 0000000..4150857
--- /dev/null
+++ b/usr/klibc/tests/fnmatch.c
@@ -0,0 +1,15 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+
+int main(int argc, char *argv[])
+{
+ int flags = atoi(argv[3]);
+ int match = fnmatch(argv[1], argv[2], flags);
+
+ printf("\"%s\" matches \"%s\": %d\n", argv[1], argv[2], match);
+
+ return match;
+}
+
+