From 28ba35171bca7d911bcd74724bf4dfdca46b4590 Mon Sep 17 00:00:00 2001 From: bigfoot547 Date: Fri, 7 Nov 2025 23:28:54 -0600 Subject: initial commit --- .gitignore | 3 +++ config.h.in | 19 +++++++++++++++++++ main.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ meson.build | 12 ++++++++++++ pipeline.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ pipeline.h | 41 +++++++++++++++++++++++++++++++++++++++++ 6 files changed, 191 insertions(+) create mode 100644 .gitignore create mode 100644 config.h.in create mode 100644 main.c create mode 100644 meson.build create mode 100644 pipeline.c create mode 100644 pipeline.h 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 + +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 +#include +#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 */ -- cgit v1.2.3-70-g09d2