From c54abe7826293ffe352119b30d0c12c9216b4cfc Mon Sep 17 00:00:00 2001 From: Simon Marchi Date: Thu, 15 Aug 2019 00:00:15 -0400 Subject: [PATCH] cli: allow map values in --params arguments This patch makes it possible to use map values in --params arguments. For example: --params 'a={hi="mlady",mapping={tete="epaule",genou="orteil"}}' The chosen syntax uses curly braces to delimit the map. It uses an equal sign between the key an value, to be consistent with the syntax of the implicit map at the top-level of `--params` values. Speaking of which: it's not done in this patch, but it should be possible to make the new function a bit more generic and re-use it for parsing the top-level dict of `--params` values. Change-Id: I1400ff6a2cf6c9132a9c5dd731a462f43225146b Signed-off-by: Simon Marchi Reviewed-on: https://review.lttng.org/c/babeltrace/+/1936 Tested-by: jenkins Reviewed-by: Philippe Proulx --- src/cli/babeltrace2-cfg-cli-args.c | 2 + src/cli/babeltrace2-cfg-cli-params-arg.c | 107 +++++++++++++++++++++++ tests/cli/params/test_params | 4 +- 3 files changed, 112 insertions(+), 1 deletion(-) diff --git a/src/cli/babeltrace2-cfg-cli-args.c b/src/cli/babeltrace2-cfg-cli-args.c index 1e2da506..1bc0aade 100644 --- a/src/cli/babeltrace2-cfg-cli-args.c +++ b/src/cli/babeltrace2-cfg-cli-args.c @@ -1300,6 +1300,8 @@ void print_expected_params_format(FILE *fp) fprintf(fp, "* Double-quoted string (accepts escape characters).\n"); fprintf(fp, "* Array, formatted as an opening `[`, a list of comma-separated values\n"); fprintf(fp, " (as described by the current list) and a closing `]`.\n"); + fprintf(fp, "* Map, formatted as an opening `{`, a comma-separated list of PARAM=VALUE\n"); + fprintf(fp, " assignments and a closing `}`.\n"); fprintf(fp, "\n"); fprintf(fp, "You can put whitespaces allowed around individual `=` and `,` symbols.\n"); fprintf(fp, "\n"); diff --git a/src/cli/babeltrace2-cfg-cli-params-arg.c b/src/cli/babeltrace2-cfg-cli-params-arg.c index 79cde929..bd953c3a 100644 --- a/src/cli/babeltrace2-cfg-cli-params-arg.c +++ b/src/cli/babeltrace2-cfg-cli-params-arg.c @@ -253,6 +253,110 @@ end: return array_value; } +/* + * Parses the current and following tokens as a map. Maps are + * formatted as an opening `{`, a list of comma-separated entries, and a + * closing `}`. And entry is a key (an unquoted string), an equal sign and + * a value. For convenience, this function supports an optional trailing comma + * after the last value. + * + * The current token of the parser must be the opening curly bracket + * (`{`) of the array. + */ +static +bt_value *ini_parse_map(struct ini_parsing_state *state) +{ + bt_value *map_value; + GTokenType token_type; + gchar *key = NULL; + + /* The `{` character must have already been ingested */ + BT_ASSERT(g_scanner_cur_token(state->scanner) == G_TOKEN_CHAR); + BT_ASSERT(g_scanner_cur_value(state->scanner).v_char == '{'); + + map_value = bt_value_map_create (); + if (!map_value) { + ini_append_oom_error(state->ini_error); + goto error; + } + + token_type = g_scanner_get_next_token(state->scanner); + + /* While the current token is not a `}` */ + while (!(token_type == G_TOKEN_CHAR && + g_scanner_cur_value(state->scanner).v_char == '}')) { + bt_value *entry_value; + bt_value_map_insert_entry_status insert_entry_status; + + /* Expect map key. */ + if (token_type != G_TOKEN_IDENTIFIER) { + ini_append_error_expecting(state, state->scanner, + "unquoted map key"); + goto error; + } + + g_free(key); + key = g_strdup(g_scanner_cur_value(state->scanner).v_identifier); + + token_type = g_scanner_get_next_token(state->scanner); + + /* Expect equal sign. */ + if (token_type != G_TOKEN_CHAR || + g_scanner_cur_value(state->scanner).v_char != '=') { + ini_append_error_expecting(state, + state->scanner, "'='"); + goto error; + } + + token_type = g_scanner_get_next_token(state->scanner); + + /* Parse the entry value... */ + entry_value = ini_parse_value(state); + if (!entry_value) { + goto error; + } + + /* ... and add it to the result map */ + insert_entry_status = + bt_value_map_insert_entry(map_value, key, entry_value); + BT_VALUE_PUT_REF_AND_RESET(entry_value); + if (insert_entry_status != BT_VALUE_MAP_INSERT_ENTRY_STATUS_OK) { + goto error; + } + + /* + * Ingest the token following the value. It should be + * either a comma or closing curly bracket. + */ + token_type = g_scanner_get_next_token(state->scanner); + if (token_type == G_TOKEN_CHAR && + g_scanner_cur_value(state->scanner).v_char == ',') { + /* + * Ingest the token following the comma. If it + * happens to be a closing curly bracket, exit + * the loop and we are done (we allow trailing + * commas). Otherwise, we are ready for the next + * ini_parse_value() call. + */ + token_type = g_scanner_get_next_token(state->scanner); + } else if (token_type != G_TOKEN_CHAR || + g_scanner_cur_value(state->scanner).v_char != '}') { + ini_append_error_expecting(state, state->scanner, + "`,` or `}`"); + goto error; + } + } + + goto end; +error: + BT_VALUE_PUT_REF_AND_RESET(map_value); + +end: + g_free(key); + + return map_value; +} + /* * Parses the current token (and the following ones if needed) as a * value, returning it as a `bt_value *`. @@ -274,6 +378,9 @@ bt_value *ini_parse_value(struct ini_parsing_state *state) } else if (state->scanner->value.v_char == '[') { /* Array */ value = ini_parse_array(state); + } else if (state->scanner->value.v_char == '{') { + /* Map */ + value = ini_parse_map(state); } else { ini_append_error_expecting(state, state->scanner, "value"); goto end; diff --git a/tests/cli/params/test_params b/tests/cli/params/test_params index 273b6244..7403fea7 100755 --- a/tests/cli/params/test_params +++ b/tests/cli/params/test_params @@ -27,7 +27,7 @@ fi # shellcheck source=../../utils/utils.sh SH_TAP=1 source "$UTILSSH" -NUM_TESTS=8 +NUM_TESTS=9 plan_tests $NUM_TESTS @@ -65,5 +65,7 @@ expect_success 'float scientific notation' 'a=10.5e6, b=10.5E6, c=10.5e-6, d=10. '{a=10500000.0, b=10500000.0, c=1.05e-05, d=1.05e-05}' expect_success 'array' 'a=[1, [["hi",]]]' \ '{a=[1, [[hi]]]}' +expect_success 'map' 'a={},b={salut="la gang",comment="ca va",oh={x=2}}' \ + '{a={}, b={comment=ca va, oh={x=2}, salut=la gang}}' rm -f "$expected_file" -- 2.34.1