diff options
Diffstat (limited to 'src/prc1/arg.c')
| -rw-r--r-- | src/prc1/arg.c | 123 |
1 files changed, 123 insertions, 0 deletions
diff --git a/src/prc1/arg.c b/src/prc1/arg.c new file mode 100644 index 0000000..f61bca7 --- /dev/null +++ b/src/prc1/arg.c @@ -0,0 +1,123 @@ +#include "arg.h" +#include "dbg.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +struct arg +{ + const char *s; + int (*f)(struct args *, const char *); + + enum + { + NOVAL, + SPACEVAL = 1, + EQVAL = 1 << 1, + JOINVAL = 1 << 2 + } v; +}; + +static int debug(struct args *a, const char *arg) +{ + dbgen = 1; + return 0; +} + +static int inc(struct args *a, const char *arg) +{ + struct arg_input *i = &a->incs; + 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++] = arg; + i->v = v; + return 0; +} + +static int opt(struct args *args, const struct arg *a, const char *arg) +{ + const struct arg *prev = args->arg; + const char *v = arg + strlen(a->s); + + if (prev && prev->v) + { + fprintf(stderr, "%s: option '%s' requires a value\n", args->name, + prev->s); + return -1; + } + else if (*v) + { + if (!(a->v & JOINVAL)) + { + fprintf(stderr, "%s: unrecognized command-line option '%s'\n", + args->name, arg); + return -1; + } + } + else if (a->v & SPACEVAL) + { + args->arg = a; + return 0; + } + else + v = NULL; + + return a->f(args, v); +} + +int arg(struct args *a, const char *value) +{ + static const struct arg args[] = + { + {"-d", debug}, + {"-I", inc, SPACEVAL | JOINVAL} + }; + + const struct arg *prev = a->arg; + + for (size_t i = 0; i < sizeof args / sizeof *args; i++) + { + const struct arg *arg = &args[i]; + + if (!strncmp(value, arg->s, strlen(arg->s))) + return opt(a, arg, value); + } + + if (prev) + { + if (*value != '-' && prev->f(a, value)) + return -1; + + a->arg = NULL; + } + else if (a->src) + { + fprintf(stderr, "%s: only one source file allowed\n", a->name); + return -1; + } + else + a->src = value; + + return 0; +} + +void arg_defaults(struct args *a) +{ +} + +static void free_input(struct arg_input *i) +{ + free(i->v); +} + +void arg_free(struct args *a) +{ + free_input(&a->incs); +} |
