summary refs log tree commit diff
path: root/patch.c
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2024-10-31 14:59:17 +0900
committerNguyễn Gia Phong <cnx@loang.net>2024-10-31 14:59:17 +0900
commit95f3fe2b800940f75949b069f50a2da4712435fd (patch)
tree5d666af0ce716adcbb740f3cb4fd5a4688604c68 /patch.c
parent11ab3cc687bfeb64e1bb223e4e690fe423e6a15c (diff)
downloadtaosc-95f3fe2b800940f75949b069f50a2da4712435fd.tar.gz
Glue things together into a pipeline
Diffstat (limited to 'patch.c')
-rw-r--r--patch.c102
1 files changed, 102 insertions, 0 deletions
diff --git a/patch.c b/patch.c
new file mode 100644
index 0000000..2aa697b
--- /dev/null
+++ b/patch.c
@@ -0,0 +1,102 @@
+/*
+ * Dynamic patch
+ * Copyright (C) 2024  Nguyễn Gia Phong
+ *
+ * This file is part of taosc.
+ *
+ * Taosc is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Taosc is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with taosc.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include "stdlib.c"
+
+const char *taosc_predicate;
+const void *taosc_destination;
+
+/*
+ * Get an environment variable and parse as a number.
+ * Return 0 on error.
+ */
+uint64_t getenvull(const char *name)
+{
+	const char *const s = getenv(name);
+	if (s == NULL)
+		return 0ULL;
+	errno = 0;
+	const uint64_t u = strtoull(s, NULL, 0);
+	if (errno)
+		return 0ULL;
+	return u;
+}
+
+void init(int argc, const char *const *argv, const char **envp)
+{
+	environ = envp;
+	taosc_predicate = getenv("TAOSC_PREDICATE");
+	if (taosc_predicate == NULL)
+		taosc_predicate = "p0"; /* false */
+	taosc_destination = (void *) getenvull("TAOSC_DESTINATION");
+}
+
+/* Parse *p as an integer. */
+int64_t scani(const char **p)
+{
+	int64_t i = 0;
+	for (; **p >= '0' && **p <= '9'; ++*p)
+		i = i * 10 + **p - '0';
+	return i;
+}
+
+/* Parse and evaluate *ptr in a prefix Polish notation, recursively. */
+int64_t eval(const char **ptr, const int64_t *env)
+{
+	const char op = *(*ptr)++;
+	switch (op) {
+	case 'n': /* negative integer */
+		return -scani(ptr);
+	case 'p': /* positive integer */
+		return scani(ptr);
+	case 'v': /* variable look up */
+		return env[scani(ptr)];
+	}
+	const bool eq = **ptr == '=';
+	*ptr += eq;
+	const int64_t a = eval(ptr, env);
+	const int64_t b = eval(ptr, env);
+	switch (op) {
+	case '=':
+		return a == b;
+	case '!':
+		return a != b;
+	case '>':
+		return eq ? (a >= b) : (a > b);
+	case '<':
+		return eq ? (a <= b) : (a < b);
+	case '+':
+		return a + b;
+	case '-':
+		return a - b;
+	case '*':
+		return a * b;
+	case '/':
+		return a / b;
+	default:
+		__builtin_unreachable();
+	}
+}
+
+const void *dest(const struct STATE *state)
+{
+	const char *tmp = taosc_predicate;
+	return eval(&tmp, (const int64_t *) state) ? NULL : taosc_destination;
+}