diff options
| author | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-09-06 00:52:48 +0200 |
|---|---|---|
| committer | Xavier Del Campo Romero <xavi92@disroot.org> | 2026-09-06 13:11:49 +0200 |
| commit | 6d018c0f032a371751226ae442d559e2bc35dc76 (patch) | |
| tree | 2513cdf4a141c41e0b6b5fb68f2f1868f196b5aa | |
| parent | b7052e17a426b22c1c48b0d50bf169c3c3bbdda0 (diff) | |
| download | prc-6d018c0f032a371751226ae442d559e2bc35dc76.tar.gz | |
| -rw-r--r-- | src/prc/CMakeLists.txt | 9 | ||||
| -rw-r--r-- | src/prc/prc.c | 367 |
2 files changed, 376 insertions, 0 deletions
diff --git a/src/prc/CMakeLists.txt b/src/prc/CMakeLists.txt new file mode 100644 index 0000000..7625917 --- /dev/null +++ b/src/prc/CMakeLists.txt @@ -0,0 +1,9 @@ +add_executable(${PROJECT_NAME} ${PROJECT_NAME}.c) +target_compile_definitions(${PROJECT_NAME} PRIVATE + PREFIX="${CMAKE_INSTALL_PREFIX}") +target_compile_options(${PROJECT_NAME} PRIVATE -g -Wall -pedantic) +set_target_properties(${PROJECT_NAME} PROPERTIES C_STANDARD 99 C_EXTENSIONS OFF) +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + target_compile_options(${PROJECT_NAME} PRIVATE -Og) +endif() +install(TARGETS ${PROJECT_NAME}) diff --git a/src/prc/prc.c b/src/prc/prc.c new file mode 100644 index 0000000..9c7d82d --- /dev/null +++ b/src/prc/prc.c @@ -0,0 +1,367 @@ +#include <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct input +{ + const char **v; + size_t n; +}; + +struct rwinput +{ + char **v; + size_t n; +}; + +struct dstr +{ + char *s; +}; + +struct state +{ + struct input sources, incs, libs, ldirs; + struct rwinput objs; + const char *prefix, *name, *out; + const struct arg *arg; + int componly; +}; + +struct arg +{ + const char *s; + int (*f)(struct state *, const char *); + + enum + { + NOVAL, + SPACEVAL = 1, + EQVAL = 1 << 1, + JOINVAL = 1 << 2 + } v; +}; + +static int comp(struct state *s, const char *val) +{ + s->componly = 1; + return 0; +} + +static int ldflag(struct state *s, const char *val) +{ + fprintf(stderr, "%s: TODO, val=%s\n", __func__, val); + return -1; +} + +static int optim(struct state *s, const char *val) +{ + return 0; +} + +static int out(struct state *s, const char *val) +{ + s->out = val; + return 0; +} + +static int addinput(struct state *s, struct input *i, const char *val) +{ + size_t n = i->n + 1; + const char **v = realloc(i->v, n * sizeof *v); + + if (!v) + { + perror("realloc(3)"); + return -1; + } + + v[i->n++] = val; + i->v = v; + s->arg = NULL; + return 0; +} + +static int inc(struct state *s, const char *val) +{ + return addinput(s, &s->incs, val); +} + +static int lib(struct state *s, const char *val) +{ + return addinput(s, &s->libs, val); +} + +static int ldir(struct state *s, const char *val) +{ + return addinput(s, &s->ldirs, val); +} + +static int opt(struct state *s, const struct arg *a, const char *arg) +{ + const struct arg *prev = s->arg; + const char *v = arg + strlen(a->s); + + if (prev && prev->v) + { + fprintf(stderr, "%s: option '%s' requires a value\n", s->name, prev->s); + return -1; + } + else if (*v) + { + if (!(a->v & JOINVAL)) + { + fprintf(stderr, "%s: unrecognized command-line option '%s'\n", + s->name, arg); + return -1; + } + } + else if (a->v & SPACEVAL) + { + s->arg = a; + return 0; + } + else + v = NULL; + + return a->f(s, v); +} + +static int addfile(struct state *s, const char *arg) +{ + return addinput(s, &s->sources, arg); +} + +static int arg(struct state *s, const char *arg) +{ + static const struct arg args[] = + { + {"-c", comp}, + {"-O", optim, JOINVAL}, + {"-Wl,", ldflag, JOINVAL}, + {"-o", out, SPACEVAL | JOINVAL}, + {"-I", inc, SPACEVAL | JOINVAL}, + {"-l", lib, SPACEVAL | JOINVAL}, + {"-L", ldir, SPACEVAL | JOINVAL} + }; + + const struct arg *prev = s->arg; + + for (size_t i = 0; i < sizeof args / sizeof *args; i++) + { + const struct arg *a = &args[i]; + + if (!strncmp(arg, a->s, strlen(a->s))) + return opt(s, a, arg); + } + + if (prev) + { + if (*arg != '-') + return prev->f(s, arg); + } + else + return addfile(s, arg); + + return 0; +} + +static void print_input(const struct input *in) +{ + fprintf(stderr, ": ["); + + for (size_t i = 0; i < in->n; i++) + { + fprintf(stderr, "%s", in->v[i]); + + if (i + 1 < in->n) + fprintf(stderr, ", "); + } + + fprintf(stderr, "]\n"); +} + +static int append(struct dstr *d, const char *fmt, ...) +{ + int ret = 1, n; + char *s; + va_list ap; + size_t len = d->s ? strlen(d->s) : 0; + + va_start(ap, fmt); + + if ((n = vsnprintf(NULL, 0, fmt, ap)) < 0) + { + fprintf(stderr, "vsnprintf(3) failed\n"); + goto end; + } + else if (!(s = realloc(d->s, len + n + 1))) + { + perror("realloc(3)"); + goto end; + } + + va_end(ap); + va_start(ap, fmt); + vsprintf(s + len, fmt, ap); + d->s = s; + ret = 0; + +end: + va_end(ap); + return ret; +} + +static void free_dstr(struct dstr *d) +{ + free(d->s); +} + +static int as(struct state *s, const char *src) +{ + int ret = -1; + struct dstr d = {0}; + + if (append(&d, "as %s")) + goto end; + + ret = 0; + +end: + free_dstr(&d); + return ret; +} + +static int qbe(struct state *s, const char *src) +{ + fprintf(stderr, "%s: TODO\n", __func__); + return -1; +} + +static int prc1(struct state *s, const char *src) +{ + int ret = -1; + struct dstr d = {0}; + const struct input *incs = &s->incs; + + if (append(&d, "%s/libexec/prc1 %s", s->prefix, src)) + goto end; + + for (size_t i = 0; i < incs->n; i++) + if (append(&d, " -I %s", incs->v[i])) + goto end; + + ret = 0; + +end: + free_dstr(&d); + return ret; +} + +static int runtool(struct state *s, const char *src) +{ + static const struct t + { + const char *suffix; + int (*f)(struct state *, const char *); + } tb[] = + { + {"o", as}, + {"obj", as}, + {"qbe", qbe}, + }; + + const char *sep = strchr(src, '.'); + + if (sep) + for (size_t i = 0; i < sizeof tb / sizeof *tb; i++) + { + const char *ext = sep + 1; + const struct t *t = &tb[i]; + + if (!strcmp(ext, t->suffix)) + return t->f(s, src); + } + + return prc1(s, src); +} + +static int reconcile(struct state *s) +{ + fprintf(stderr, "sources"); + print_input(&s->sources); + fprintf(stderr, "incs"); + print_input(&s->incs); + fprintf(stderr, "ldirs"); + print_input(&s->ldirs); + fprintf(stderr, "libs"); + print_input(&s->libs); + fprintf(stderr, "out: %s\n", s->out); + + for (size_t i = 0; i < s->sources.n; i++) + if (runtool(s, s->sources.v[i])) + return -1; + + return 0; +} + +static void free_input(struct input *i) +{ + free(i->v); +} + +static void free_rwinput(struct rwinput *in) +{ + for (size_t i = 0; i < in->n; i++) + free(in->v[i]); + + free(in->v); +} + +static void free_state(struct state *s) +{ + free_input(&s->sources); + free_input(&s->incs); + free_input(&s->libs); + free_input(&s->ldirs); + free_rwinput(&s->objs); +} + +int main(int argc, char *argv[]) +{ + int ret = EXIT_FAILURE; + struct state s = + { + .name = *argv, + .out = "a.out", + .prefix = getenv("PRCPREFIX") + }; + + if (argc == 1) + { + fprintf(stderr, "%s [options ...] file...\n", *argv); + goto end; + } + else if (!s.prefix) + s.prefix = PREFIX; + + for (int i = 1; i < argc; i++) + if (arg(&s, argv[i])) + goto end; + + if (s.arg) + { + fprintf(stderr, "%s: command-line argument '%s' requires an argument\n", + s.name, s.arg->s); + goto end; + } + else if (reconcile(&s)) + goto end; + + ret = EXIT_SUCCESS; +end: + free_state(&s); + return ret; +} |
