From cf86c748705b15349f5811ab3f0dc18cd4231ca8 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 11 Jul 2018 11:59:53 +0930 Subject: [PATCH] params: add helper to provide default initialization. @wythe points out that many cases want a default value, not NULL. Nicer to do it in the param_parse() call. Signed-off-by: Rusty Russell --- lightningd/params.c | 11 +++++++---- lightningd/params.h | 17 +++++++++++++++++ lightningd/test/run-params.c | 24 ++++++++++++------------ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/lightningd/params.c b/lightningd/params.c index 6148b6dd0..53e1afb97 100644 --- a/lightningd/params.c +++ b/lightningd/params.c @@ -10,13 +10,14 @@ struct param { const char *name; bool is_set; + bool required; param_cb cb; void *arg; size_t argsize; }; static void param_add(struct param **params, - const char *name, param_cb cb, void *arg, + const char *name, bool required, param_cb cb, void *arg, size_t argsize) { #if DEVELOPER @@ -31,6 +32,7 @@ static void param_add(struct param **params, last->is_set = false; last->name = name; + last->required = required; last->cb = cb; last->arg = arg; last->argsize = argsize; @@ -101,7 +103,7 @@ static struct param *post_check(struct command *cmd, struct param *params) struct param *last = first + tal_count(params); /* Make sure required params were provided. */ - while (first != last && first->argsize == 0) { + while (first != last && first->required) { if (!first->is_set) { command_fail(cmd, JSONRPC2_INVALID_PARAMS, "missing required parameter: '%s'", @@ -214,7 +216,7 @@ static int comp_by_arg(const struct param *a, const struct param *b, static int comp_req_order(const struct param *a, const struct param *b, void *unused) { - if (a->argsize != 0 && b->argsize == 0) + if (!a->required && b->required) return 0; return 1; } @@ -294,10 +296,11 @@ bool param_parse(struct command *cmd, const char *buffer, va_start(ap, tokens); while ((name = va_arg(ap, const char *)) != NULL) { + bool required = va_arg(ap, int); param_cb cb = va_arg(ap, param_cb); void *arg = va_arg(ap, void *); size_t argsize = va_arg(ap, size_t); - param_add(¶ms, name, cb, arg, argsize); + param_add(¶ms, name, required, cb, arg, argsize); } va_end(ap); diff --git a/lightningd/params.h b/lightningd/params.h index 88c0f8c14..9d6382fd7 100644 --- a/lightningd/params.h +++ b/lightningd/params.h @@ -60,6 +60,7 @@ typedef bool(*param_cb)(const char *buffer, const jsmntok_t *tok, void *arg); */ #define param_req(name, cb, arg) \ name"", \ + true, \ (cb), \ (arg) + 0*sizeof((cb)((const char *)NULL, \ (const jsmntok_t *)NULL, \ @@ -72,12 +73,27 @@ typedef bool(*param_cb)(const char *buffer, const jsmntok_t *tok, void *arg); */ #define param_opt(name, cb, arg) \ name"", \ + false, \ (cb), \ (arg) + 0*sizeof((cb)((const char *)NULL, \ (const jsmntok_t *)NULL,\ *(arg)) == true), \ sizeof(**(arg)) +/* + * Similar to param_req but for optional parameters. + * If not found during parsing, @arg will be set to @def. + * allocated, otherwise it will be set to NULL. + */ +#define param_opt_default(name, cb, arg, def) \ + name"", \ + false, \ + (cb), \ + (arg) + 0*sizeof((cb)((const char *)NULL, \ + (const jsmntok_t *)NULL, \ + (arg)) == true), \ + ((void)((*arg) = (def)), 0) + /* * For when you want an optional raw token. * @@ -85,6 +101,7 @@ typedef bool(*param_cb)(const char *buffer, const jsmntok_t *tok, void *arg); */ #define param_opt_tok(name, arg) \ name"", \ + false, \ json_tok_tok, \ (arg) + 0*sizeof(*(arg) == (jsmntok_t *)NULL), \ sizeof(const jsmntok_t *) diff --git a/lightningd/test/run-params.c b/lightningd/test/run-params.c index 584b9577e..dd0f62e2d 100644 --- a/lightningd/test/run-params.c +++ b/lightningd/test/run-params.c @@ -198,12 +198,12 @@ static void dup_names(void) static void null_params(void) { - uint64_t *ints = tal_arr(cmd, uint64_t, 4); - uint64_t **intptrs = tal_arr(cmd, uint64_t *, 3); + uint64_t *ints = tal_arr(cmd, uint64_t, 5); + uint64_t **intptrs = tal_arr(cmd, uint64_t *, 2); /* no null params */ struct json *j = json_parse(cmd, "[ '10', '11', '12', '13', '14', '15', '16']"); - for (int i = 0; i < tal_count(ints); ++i) + for (int i = 0; i < tal_count(ints) - 1; ++i) ints[i] = i; assert(param_parse(cmd, j->buffer, j->toks, @@ -211,9 +211,9 @@ static void null_params(void) param_req("1", json_tok_u64, &ints[1]), param_req("2", json_tok_u64, &ints[2]), param_req("3", json_tok_u64, &ints[3]), - param_opt("4", json_tok_u64, &intptrs[0]), - param_opt("5", json_tok_u64, &intptrs[1]), - param_opt("6", json_tok_u64, &intptrs[2]), + param_opt_default("4", json_tok_u64, &ints[4], 999), + param_opt("5", json_tok_u64, &intptrs[0]), + param_opt("6", json_tok_u64, &intptrs[1]), NULL)); for (int i = 0; i < tal_count(ints); ++i) assert(ints[i] == i + 10); @@ -234,11 +234,11 @@ static void null_params(void) param_req("3", json_tok_u64, &ints[3]), param_opt("4", json_tok_u64, &intptrs[0]), param_opt("5", json_tok_u64, &intptrs[1]), - param_opt("6", json_tok_u64, &intptrs[2]), + param_opt_default("6", json_tok_u64, &ints[4], 888), NULL)); assert(*intptrs[0] == 14); assert(intptrs[1] == NULL); - assert(intptrs[2] == NULL); + assert(ints[4] == 888); } #if DEVELOPER @@ -337,13 +337,13 @@ static void bad_programmer(void) /* Add required param after optional */ struct json *j = json_parse(cmd, "[ '25', '546', '26', '1.1' ]"); - unsigned int *msatoshi; + unsigned int msatoshi; double riskfactor; param_parse(cmd, j->buffer, j->toks, param_req("u64", json_tok_u64, &ival), param_req("double", json_tok_double, &dval), - param_opt("msatoshi", - json_tok_number, &msatoshi), + param_opt_default("msatoshi", + json_tok_number, &msatoshi, 100), param_req("riskfactor", json_tok_double, &riskfactor), NULL); restore_assert(old_stderr); @@ -361,7 +361,7 @@ static void add_members(struct param **params, char *name = tal_fmt(tmpctx, "%i", i); json_add_num(obj, name, i); json_add_num(arr, NULL, i); - param_add(params, name, + param_add(params, name, true, typesafe_cb_preargs(bool, void *, json_tok_number, &ints[i],