1 2

[PATCH 1/2] Add initial pattern matching implementation

Details
Message ID
<20181227163225.30279-1-sir@cmpwn.com>
Download raw message
Patch +53 -0
---
 include/mrsh/match.h |  7 +++++++
 meson.build          |  1 +
 shell/match.c        | 45 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 53 insertions(+)
 create mode 100644 include/mrsh/match.h
 create mode 100644 shell/match.c

diff --git a/include/mrsh/match.h b/include/mrsh/match.h
new file mode 100644
index 0000000..23df70b
--- /dev/null
+++ b/include/mrsh/match.h
@@ -0,0 +1,7 @@
+#ifndef MRSH_MATCH_H
+#define MRSH_MATCH_H
+#include <stdbool.h>
+
+bool mrsh_match(const char *pattern, const char *test, bool filename);
+
+#endif
diff --git a/meson.build b/meson.build
index 82fcc67..9a06212 100644
--- a/meson.build
+++ b/meson.build
@@ -74,6 +74,7 @@ lib_mrsh = library(
 		'parser/program.c',
 		'parser/word.c',
 		'shell/arithm.c',
+		'shell/match.c',
 		'shell/path.c',
 		'shell/process.c',
 		'shell/redir.c',
diff --git a/shell/match.c b/shell/match.c
new file mode 100644
index 0000000..cd5830b
--- /dev/null
+++ b/shell/match.c
@@ -0,0 +1,45 @@
+#include <assert.h>
+#include <mrsh/match.h>
+#include <stdbool.h>
+#include <string.h>
+
+bool mrsh_match(const char *pattern, const char *test, bool filename) {
+	/* TODO: Consider the implications of quoting */
+	assert(!filename); /* TODO: filename expansion */
+	size_t i, j;
+	for (i = 0, j = 0; i < strlen(pattern) && j < strlen(test); ++i, ++j) {
+		switch (pattern[i]) {
+		case '?': /* Matches any character */
+			break;
+		case '*':; /* Matches any number of characters */
+			char next = pattern[++i];
+			if (!next) {
+				return true;
+			}
+			for (; test[j] && test[j] != next; ++j) {
+				/* This space intentionally left blank */
+			}
+			if (!test[j]) {
+				return false;
+			}
+			break;
+		case '[':
+			/* TODO: bracket expressions */
+			assert(false);
+			break;
+		case '\\':
+			++i;
+			/* fallthrough */
+		default:
+			if (pattern[i] != test[j]) {
+				return false;
+			}
+			break;
+		}
+	}
+	if (pattern[i] && !test[j]) {
+		/* Handle case of empty test string and wildcard */
+		return pattern[i] == '*';
+	}
+	return !pattern[i] && !test[j];
+}
-- 
2.20.1
Details
Message ID
<tLIbZckiQn8w-pUWYy8SzPGSuIoY8dzGTYszoTlB0JzbWRaWlNI_40mwYd469TF-5UIruDCD1wN0iB3DtRt-prqiR4dvWbF7IQ6DR_RnOeo=@emersion.fr>
In-Reply-To
<20181227163225.30279-1-sir@cmpwn.com> (view parent)
Download raw message
Would it be possible to use fnmatch(3) here?