diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2017-12-01 19:30:36 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2017-12-01 19:30:36 -0800 |
commit | 64266ae7f7f3d127f92accde2b78f84f5cdec7f1 (patch) | |
tree | 42251092033a8ed4b95a651327667fe3487f68a3 /args.c | |
parent | 6c94850e2cf44009648fd3d2ce3ef010aea8a7a0 (diff) | |
download | txr-64266ae7f7f3d127f92accde2b78f84f5cdec7f1.tar.gz txr-64266ae7f7f3d127f92accde2b78f84f5cdec7f1.tar.bz2 txr-64266ae7f7f3d127f92accde2b78f84f5cdec7f1.zip |
args: keyword extraction mechanism.
Implement a mechanism for extracting keyword arguments out of
"struct args *" argument lists which avoids consing up an
argument list and scanning it multiple times for multiple
keywords.
* args.c (args_for_each): New function.
(struct args_bool_key, struct args_bool_ctx): New struct
types.
(args_key_check_store): New static function.
(args_keys_extract_vl, args_key_extract): New functions.
* args.h (args_for_each, args_keys_extract_vl,
args_key_extract): Declared.
Diffstat (limited to 'args.c')
-rw-r--r-- | args.c | 89 |
1 files changed, 89 insertions, 0 deletions
@@ -28,7 +28,9 @@ #include <stddef.h> #include <signal.h> #include <string.h> +#include <stdarg.h> #include "config.h" +#include ALLOCA_H #include "lib.h" #include "signal.h" #include "unwind.h" @@ -119,3 +121,90 @@ val args_copy_to_list(struct args *args) return out; } + +void args_for_each(struct args *args, + int (*fn)(val arg, int ix, mem_t *ctx), + mem_t *ctx) +{ + int i; + val iter; + + for (i = 0; i < args->fill; i++) + if (fn(args->arg[i], i, ctx)) + args->arg[i] = nil; + + for (iter = args->list; iter; iter = cdr(iter), i++) + if (fn(car(iter), i, ctx)) + rplaca(iter, nil); +} + +struct args_bool_key { + struct args_bool_key *next; + val key; + val arg_p; + val *store; +}; + +struct args_bool_ctx { + struct args_bool_key *akl; + val *next_arg_store; +}; + +static int args_key_check_store(val arg, int ix, mem_t *ctx) +{ + struct args_bool_ctx *acx = coerce(struct args_bool_ctx *, ctx); + struct args_bool_key **pakl, *akl; + val *store = 0; + + if (acx->next_arg_store != 0) { + *acx->next_arg_store = arg; + acx->next_arg_store = 0; + return 0; + } + + for (pakl = &acx->akl, akl = *pakl; + akl != 0; + pakl = &akl->next, akl = *pakl) + { + if (store != 0) + *store = arg; + if (akl->key == arg) { + if (akl->arg_p) + acx->next_arg_store = akl->store; + else + *akl->store = t; + *pakl = akl->next; + } + } + + return 0; +} + +void args_keys_extract_vl(struct args *args, va_list vl) +{ + struct args_bool_ctx acx = { 0 }; + + for (;;) { + val key; + struct args_bool_key *nakl; + if ((key = va_arg (vl, val)) == nil) + break; + nakl = coerce(struct args_bool_key *, alloca(sizeof *nakl)); + nakl->key = key; + nakl->arg_p = va_arg (vl, val); + nakl->store = va_arg (vl, val *); + nakl->next = acx.akl; + acx.akl = nakl; + } + + if (acx.akl != 0) + args_for_each(args, args_key_check_store, coerce(mem_t *, &acx)); +} + +void args_keys_extract(struct args *args, ...) +{ + va_list vl; + va_start (vl, args); + args_keys_extract_vl(args, vl); + va_end (vl); +} |