aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar bigfoot547 <[email protected]>2025-11-07 23:28:54 -0600
committerLibravatar bigfoot547 <[email protected]>2025-11-07 23:28:54 -0600
commit28ba35171bca7d911bcd74724bf4dfdca46b4590 (patch)
treecd90e78aa7f947bbf2ce51f5ea91b7c1b353d642
initial commit
-rw-r--r--.gitignore3
-rw-r--r--config.h.in19
-rw-r--r--main.c57
-rw-r--r--meson.build12
-rw-r--r--pipeline.c59
-rw-r--r--pipeline.h41
6 files changed, 191 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..dceeaad
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+builddir/
+.cache/
+compile_commands.json
diff --git a/config.h.in b/config.h.in
new file mode 100644
index 0000000..9ef3491
--- /dev/null
+++ b/config.h.in
@@ -0,0 +1,19 @@
+#ifndef PTXMC_CONFIG_H_INCLUDED
+#define PTXMC_CONFIG_H_INCLUDED
+
+#mesondefine HAS_ATTR_WUR
+#mesondefine HAS_ATTR_ALWAYS_INLINE
+
+#ifdef HAS_ATTR_WUR
+#define ATTR_WUR __attribute__((warn_unused_result))
+#else
+#define ATTR_WUR
+#endif
+
+#ifdef HAS_ATTR_ALWAYS_INLINE
+#define ATTR_ALWAYS_INLINE __attribute__((always_inline))
+#else
+#define ATTR_ALWAYS_INLINE
+#endif
+
+#endif /* include guard */
diff --git a/main.c b/main.c
new file mode 100644
index 0000000..e1e22ec
--- /dev/null
+++ b/main.c
@@ -0,0 +1,57 @@
+#include "pipeline.h"
+
+#define UNUSED(_v) ((void)(_v))
+
+PIPELINE_STAGE int stage(struct pipeline_ctx_t *ctx, void *data, size_t len)
+{
+ UNUSED(ctx);
+ UNUSED(data);
+ UNUSED(len);
+ return 1;
+}
+
+PIPELINE_STAGE int identity_stage(struct pipeline_ctx_t *ctx, void *data, size_t len) {
+ return pipeline_next(ctx, data, len);
+}
+
+/* mockup:
+ * Pipeline signature: D -> D*1
+ * int simple_1to1_stage(struct pipeline_ctx *ctx, void *data, size_t len) {
+ * void *out = ... transform data ...;
+ * size_t out_len = ^^^;
+ * return pipeline_next(ctx, out, out_len);
+ * }
+ *
+ * Pipeline signature: D -> D*(0,n)
+ * int complex_1tomany_stage(struct pipeline_ctx *ctx, void *data, size_t len) {
+ * int err;
+ * for (void *out; has_data(data, len); out = next_data(data, &len)) {
+ * if (!out) {
+ * return -1; ... next_data failed somehow ...
+ * }
+ *
+ * if ((err = pipeline_next(ctx, out, out_len)) < 0) {
+ * return err;
+ * }
+ * }
+ * return 0;
+ * }
+ *
+ * Pipeline signature: D -> D*1
+ * int stateful_stage(struct pipeline_ctx *ctx, void *data, size_t len) {
+ * my_stage_t *stg = ctx->me;
+ * stg->stat_in += len;
+ * return pipeline_next(ctx, data, len);
+ * }
+ *
+ * Pipeline signature: D -> void (i.e., never calls next)
+ * int terminal_stage(struct pipeline_ctx *ctx, void *data, size_t len) {
+ * my_handler_t *handler = ctx->me;
+ * handler->do_handle(data, len);
+ * return 0; ... return values should indicate pipeline (i.e., parsing) errors, not application errors ...
+ * }
+ */
+
+int main(void) {
+ return 0;
+}
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..4e2d1b6
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,12 @@
+project('ptxmc', 'c', default_options : ['c_std=c11'])
+
+c_comp = meson.get_compiler('c')
+
+conf_data = configuration_data()
+conf_data.set('HAS_ATTR_WUR', c_comp.has_function_attribute('warn_unused_result'))
+conf_data.set('HAS_ATTR_ALWAYS_INLINE', c_comp.has_function_attribute('always_inline'))
+configure_file(input : 'config.h.in', output : 'config.h', configuration : conf_data)
+
+conf_include = include_directories('.')
+
+executable('ptxmc', 'main.c', 'pipeline.c', include_directories : conf_include)
diff --git a/pipeline.c b/pipeline.c
new file mode 100644
index 0000000..477421f
--- /dev/null
+++ b/pipeline.c
@@ -0,0 +1,59 @@
+#include "pipeline.h"
+#include <string.h>
+
+int pipeline_add_stage_after(struct pipeline_t *pl, struct pipeline_stage_t *stage, const char *name)
+{
+ if (!name) {
+ /* name == NULL: insert at end of pipeline */
+ stage->next = NULL;
+
+#if 0
+ if (pl->first) {
+ struct pipeline_stage_t *tail = pl->first;
+ for (; tail->next; tail = tail->next);
+ tail->next = stage;
+ } else { /* corner case: pipeline is empty */
+ pl->first = stage;
+ }
+#else
+ /* i like this implementation because it's pretty */
+ struct pipeline_stage_t **ptail = &pl->first;
+ for (; *ptail; ptail = &(*ptail)->next);
+ *ptail = stage;
+#endif
+
+ return 1;
+ }
+
+ for (struct pipeline_stage_t *cur = pl->first; cur; cur = cur->next) {
+ if (name == cur->name || !strcmp(name, cur->name)) {
+ stage->next = cur->next;
+ cur->next = stage;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int pipeline_add_stage_before(struct pipeline_t *pl, struct pipeline_stage_t *stage, const char *name)
+{
+ if (!name || !pl->first || name == pl->first->name || !strcmp(name, pl->first->name)) {
+ stage->next = pl->first;
+ pl->first = stage;
+ return 1;
+ }
+
+ /* note that it's okay we don't properly check if prev->first->name equals name here, since that was done above. */
+ for (struct pipeline_stage_t *cur = pl->first->next, *prev = pl->first; cur; prev = cur, cur = cur->next) {
+ if (name == cur->name || !strcmp(name, cur->name)) {
+ prev->next = stage;
+ stage->next = cur;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+
diff --git a/pipeline.h b/pipeline.h
new file mode 100644
index 0000000..e164c58
--- /dev/null
+++ b/pipeline.h
@@ -0,0 +1,41 @@
+#ifndef PTXMC_PIPELINE_H_INCLUDED
+#define PTXMC_PIPELINE_H_INCLUDED
+
+#include <assert.h>
+#include <stddef.h>
+#include "config.h"
+
+#define PIPELINE_STAGE ATTR_WUR
+
+struct pipeline_ctx_t;
+typedef int (pipeline_stage_proc)(struct pipeline_ctx_t * /*ctx*/, void * /*data*/, size_t /*len*/) PIPELINE_STAGE;
+
+struct pipeline_stage_t
+{
+ const char *name;
+ pipeline_stage_proc *proc;
+ struct pipeline_stage_t *next;
+ void *user;
+};
+
+struct pipeline_t
+{
+ struct pipeline_stage_t *first;
+};
+
+struct pipeline_ctx_t
+{
+ struct pipeline_stage_t *stage;
+};
+
+int pipeline_add_stage_before(struct pipeline_t *pl, struct pipeline_stage_t *stage, const char *name);
+int pipeline_add_stage_after(struct pipeline_t *pl, struct pipeline_stage_t *stage, const char *name);
+
+ATTR_ALWAYS_INLINE inline int pipeline_next(struct pipeline_ctx_t *ctx, void *data, size_t len)
+{
+ assert(ctx->stage->next);
+ ctx->stage = ctx->stage->next;
+ return (ctx->stage->proc)(ctx, data, len);
+}
+
+#endif /* include guard */