From adf08f89142e65ca73e4d114a378646c149da83f Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Sun, 16 Dec 2018 15:14:06 +1030 Subject: [PATCH] common/json: restore json_delve() for simple plugin parsing. This was removed (as unused) in 6269a4c55d592e8720b7f2a304c21f61f7931238; now I've even added tests. Signed-off-by: Rusty Russell --- common/json.c | 37 +++++++++++++++++ common/json.h | 5 +++ common/test/run-json.c | 93 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 135 insertions(+) diff --git a/common/json.c b/common/json.c index c4c511478..08ce199a1 100644 --- a/common/json.c +++ b/common/json.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -273,3 +274,39 @@ void json_tok_remove(jsmntok_t **tokens, jsmntok_t *tok, size_t num) tal_resize(tokens, tal_count(*tokens) - remove_count); (*tokens)->size -= num; } + +const jsmntok_t *json_delve(const char *buffer, + const jsmntok_t *tok, + const char *guide) +{ + while (*guide) { + const char *key; + size_t len = strcspn(guide+1, ".[]"); + + key = tal_strndup(tmpctx, guide+1, len); + switch (guide[0]) { + case '.': + if (tok->type != JSMN_OBJECT) + return NULL; + tok = json_get_member(buffer, tok, key); + if (!tok) + return NULL; + break; + case '[': + if (tok->type != JSMN_ARRAY) + return NULL; + tok = json_get_arr(tok, atol(key)); + if (!tok) + return NULL; + /* Must be terminated */ + assert(guide[1+strlen(key)] == ']'); + len++; + break; + default: + abort(); + } + guide += len + 1; + } + + return tok; +} diff --git a/common/json.h b/common/json.h index 730430389..2882cf185 100644 --- a/common/json.h +++ b/common/json.h @@ -73,4 +73,9 @@ jsmntok_t *json_tok_copy(const tal_t *ctx, const jsmntok_t *tok); */ void json_tok_remove(jsmntok_t **tokens, jsmntok_t *tok, size_t num); +/* Guide is a string with . for members, [] around indexes. */ +const jsmntok_t *json_delve(const char *buffer, + const jsmntok_t *tok, + const char *guide); + #endif /* LIGHTNING_COMMON_JSON_H */ diff --git a/common/test/run-json.c b/common/test/run-json.c index cea278fa5..71e4b7069 100644 --- a/common/test/run-json.c +++ b/common/test/run-json.c @@ -1,4 +1,5 @@ #include "../json.c" +#include #include #include @@ -38,11 +39,103 @@ static int test_json_tok_bitcoin_amount(void) return 0; } +static void test_json_delve(void) +{ + const jsmntok_t *toks, *t; + char *buf; + bool ok; + + buf = "{\"1\":\"one\", \"2\":\"two\", \"3\":[\"three\", {\"deeper\": 17}]}"; + toks = json_parse_input(tmpctx, buf, strlen(buf), &ok); + assert(ok); + + t = json_delve(buf, toks, ".1"); + assert(t); + assert(t->type == JSMN_STRING); + assert(json_tok_streq(buf, t, "one")); + assert(t == toks+2); + + t = json_delve(buf, toks, ".2"); + assert(t); + assert(t->type == JSMN_STRING); + assert(json_tok_streq(buf, t, "two")); + assert(t == toks+4); + + t = json_delve(buf, toks, ".3"); + assert(t); + assert(t->type == JSMN_ARRAY); + assert(t == toks+6); + + t = json_delve(buf, toks, ".3[0]"); + assert(t); + assert(t->type == JSMN_STRING); + assert(json_tok_streq(buf, t, "three")); + assert(t == toks+7); + + t = json_delve(buf, toks, ".3[1]"); + assert(t); + assert(t->type == JSMN_OBJECT); + assert(t == toks+8); + + t = json_delve(buf, toks, ".3[1].deeper"); + assert(t); + assert(t->type == JSMN_PRIMITIVE); + assert(memeq(buf + t->start, t->end - t->start, "17", strlen("17"))); + assert(t == toks+10); + + t = json_delve(buf, toks, ".4"); + assert(!t); + t = json_delve(buf, toks, "[0]"); + assert(!t); + t = json_delve(buf, toks, ".deeper"); + assert(!t); + t = json_delve(buf, toks, ".3[2]"); + assert(!t); + t = json_delve(buf, toks, ".3[2].deeper"); + assert(!t); + t = json_delve(buf, toks, ".3[0].deeper"); + assert(!t); + t = json_delve(buf, toks, ".3[1].deeper[0]"); + assert(!t); + t = json_delve(buf, toks, ".3[1][0]"); + assert(!t); + + /* Now a real example. */ + buf = "{\n" + " \"jsonrpc\": \"2.0\", \n" + " \"method\": \"init\", \n" + " \"id\": 1, \n" + " \"params\": {\n" + " \"options\": {\n" + " }, \n" + " \"configuration\": {\n" + " \"lightning-dir\": \"/tmp/ltests-n2hyd543/test_pay_plugin_1/lightning-2/\", \n" + " \"rpc-file\": \"lightning-rpc\"\n" + " }\n" + " }\n" + "}\n" + "\n"; + toks = json_parse_input(tmpctx, buf, strlen(buf), &ok); + assert(ok); + + t = json_delve(buf, toks, ".rpcfile"); + assert(!t); + t = json_delve(buf, toks, ".configuration.rpc-file"); + assert(!t); + t = json_delve(buf, toks, ".params.configuration.rpc-file"); + assert(t); + assert(t->type == JSMN_STRING); + assert(json_tok_streq(buf, t, "lightning-rpc")); +} + int main(void) { setup_locale(); + setup_tmpctx(); test_json_tok_bitcoin_amount(); + test_json_delve(); assert(!taken_any()); take_cleanup(); + tal_free(tmpctx); }