]> sigrok.org Git - sigrok-cli.git/commitdiff
parsers: extend options parser, support optional ID in key-value lists
authorGerhard Sittig <redacted>
Sat, 23 May 2020 09:29:23 +0000 (11:29 +0200)
committerGerhard Sittig <redacted>
Mon, 3 Aug 2020 20:24:11 +0000 (22:24 +0200)
The options parser accepts a colon separated list of key-value pairs, and
a special case where the first item is not a pair but a single word which
is an identifier. This lets users select a device driver, or input/output
format, or decoder.

Extend the options parser to also support an optional identifier as the
first item in a list of key-value pairs. Check the first item's keyword
for a caller specified literal. This change remains backwards compatible
(does not affect behaviour) when users don't pass the special keyword.

decode.c
input.c
main.c
parsers.c
session.c
sigrok-cli.h

index a4d4652b36a274dca32d5a104d22c3c912a388b3..4ddf34afbbaf00db414a041f4ef2e61ddc27bc0f 100644 (file)
--- a/decode.c
+++ b/decode.c
@@ -139,7 +139,7 @@ static int register_pd(char *opt_pds, char *opt_pd_annotations)
 
        pdtokens = g_strsplit(opt_pds, ",", 0);
        for (pdtok = pdtokens; *pdtok; pdtok++) {
-               if (!(pd_opthash = parse_generic_arg(*pdtok, TRUE))) {
+               if (!(pd_opthash = parse_generic_arg(*pdtok, TRUE, NULL))) {
                        g_critical("Invalid protocol decoder option '%s'.", *pdtok);
                        break;
                }
diff --git a/input.c b/input.c
index 0c8d48670ac8f17ea5e9e666c75a1dfe4160dfbf..6c149722588db3a88ff0f7ca3618a4f213f77426 100644 (file)
--- a/input.c
+++ b/input.c
@@ -51,7 +51,7 @@ static void load_input_file_module(struct df_arg_desc *df_arg)
        mod_id = NULL;
        mod_args = NULL;
        if (opt_input_format) {
-               mod_args = parse_generic_arg(opt_input_format, TRUE);
+               mod_args = parse_generic_arg(opt_input_format, TRUE, NULL);
                mod_id = g_hash_table_lookup(mod_args, "sigrok_key");
        }
 
diff --git a/main.c b/main.c
index 02f69a2ebbb5d998bf609844b01c488a525c613b..db2bdc016df58f86eef252345f02b667b6c3316d 100644 (file)
--- a/main.c
+++ b/main.c
@@ -140,7 +140,7 @@ static void get_option(void)
        if (!(ci = sr_key_info_name_get(SR_KEY_CONFIG, opt_get)))
                g_critical("Unknown option '%s'", opt_get);
 
-       if ((devargs = parse_generic_arg(opt_config, FALSE)))
+       if ((devargs = parse_generic_arg(opt_config, FALSE, NULL)))
                set_dev_options(sdi, devargs);
        else
                devargs = NULL;
@@ -186,7 +186,7 @@ static void set_options(void)
                return;
        }
 
-       if (!(devargs = parse_generic_arg(opt_config, FALSE)))
+       if (!(devargs = parse_generic_arg(opt_config, FALSE, NULL)))
                return;
 
        if (!(devices = device_scan())) {
index 5652b78dc096eaf3ef95d43e63e61a6f656eb891..4f3b0c5203752a4bf404b260641fca8e6436a53e 100644 (file)
--- a/parsers.c
+++ b/parsers.c
@@ -267,11 +267,44 @@ int parse_triggerstring(const struct sr_dev_inst *sdi, const char *s,
        return !error;
 }
 
-GHashTable *parse_generic_arg(const char *arg, gboolean sep_first)
+/**
+ * Create hash table from colon separated key-value pairs input text.
+ *
+ * Accepts input text as it was specified by users. Splits the colon
+ * separated key-value pairs and creates a hash table from these items.
+ * Optionally supports special forms which are useful for different CLI
+ * features.
+ *
+ * Typical form: <key>=<val>[:<key>=<val>]*
+ * Generic list of key-value pairs, all items being equal. Mere set.
+ *
+ * ID form: <id>[:<key>=<val>]*
+ * First item is not a key-value pair, instead it's an identifier. Used
+ * to specify a protocol decoder, or a device driver, or an input/output
+ * file format, optionally followed by more parameters' values. The ID
+ * part of the input spec is not optional.
+ *
+ * Optional ID: [<sel>=<id>][:<key>=<val>]*
+ * All items are key-value pairs. The first item _may_ be an identifier,
+ * if its key matches a caller specified key name. Otherwise the input
+ * text is the above typical form, a mere list of key-value pairs while
+ * none of them is special.
+ *
+ * @param[in] arg Input text.
+ * @param[in] sep_first Boolean, whether ID form is required.
+ * @param[in] key_first Keyword name if optional ID is applicable.
+ *
+ * @returns A hash table which contains the key/value pairs, or #NULL
+ *   when the input is invalid.
+ */
+GHashTable *parse_generic_arg(const char *arg,
+       gboolean sep_first, const char *key_first)
 {
        GHashTable *hash;
        int i;
        char **elements, *e;
+       int l;
+       const char *s;
 
        if (!arg || !arg[0])
                return NULL;
@@ -280,9 +313,29 @@ GHashTable *parse_generic_arg(const char *arg, gboolean sep_first)
        hash = g_hash_table_new_full(g_str_hash, g_str_equal,
                        g_free, g_free);
        elements = g_strsplit(arg, ":", 0);
-       if (sep_first)
+       if (sep_first) {
+               /*
+                * Caller requested "<id>[:<key>=<val>]*" case, Consume the
+                * first item, before processing more key-value pairs below.
+                */
                g_hash_table_insert(hash, g_strdup("sigrok_key"),
                                g_strdup(elements[i++]));
+       } else if (key_first && *key_first) {
+               /*
+                * Caller requested "[<sig>=<id>][:<key>=<val>]*" case.
+                * Optional special handling of the first item, but only
+                * consume this first item here when its keyword matched
+                * the caller's specification.
+                */
+               l = strlen(key_first);
+               s = elements[i];
+               e = strchr(s, '=');
+               if (e && e - s == l && g_str_has_prefix(s, key_first)) {
+                       g_hash_table_insert(hash,
+                               g_strdup("sigrok_key"), g_strdup(++e));
+                       i++;
+               }
+       }
        for (; elements[i]; i++) {
                e = strchr(elements[i], '=');
                if (!e)
@@ -463,7 +516,7 @@ int parse_driver(char *arg, struct sr_dev_driver **driver, GSList **drvopts)
        if (!arg)
                return FALSE;
 
-       drvargs = parse_generic_arg(arg, TRUE);
+       drvargs = parse_generic_arg(arg, TRUE, NULL);
 
        drvname = g_strdup(g_hash_table_lookup(drvargs, "sigrok_key"));
        g_hash_table_remove(drvargs, "sigrok_key");
index b3d39ff8ac1f35d58dc978ed73caab41898794fc..56a4d25e30bb050a2feaccc06e526b41dedd7268 100644 (file)
--- a/session.c
+++ b/session.c
@@ -92,7 +92,7 @@ const struct sr_output *setup_output_format(const struct sr_dev_inst *sdi, FILE
                }
        }
 
-       fmtargs = parse_generic_arg(opt_output_format, TRUE);
+       fmtargs = parse_generic_arg(opt_output_format, TRUE, NULL);
        fmtspec = g_hash_table_lookup(fmtargs, "sigrok_key");
        if (!fmtspec)
                g_critical("Invalid output format.");
@@ -138,7 +138,7 @@ const struct sr_transform *setup_transform_module(const struct sr_dev_inst *sdi)
        GHashTable *fmtargs, *fmtopts;
        char *fmtspec;
 
-       fmtargs = parse_generic_arg(opt_transform_module, TRUE);
+       fmtargs = parse_generic_arg(opt_transform_module, TRUE, NULL);
        fmtspec = g_hash_table_lookup(fmtargs, "sigrok_key");
        if (!fmtspec)
                g_critical("Invalid transform module.");
@@ -766,7 +766,7 @@ void run_session(void)
        }
 
        if (opt_config) {
-               if ((devargs = parse_generic_arg(opt_config, FALSE))) {
+               if ((devargs = parse_generic_arg(opt_config, FALSE, NULL))) {
                        if (set_dev_options(sdi, devargs) != SR_OK)
                                return;
                        g_hash_table_destroy(devargs);
index a3905fd3b841e4e5416ae0c55e8c17e7876515b7..b5603c306d90d6d4f8e3d55e4ee73372cba952e6 100644 (file)
@@ -105,7 +105,8 @@ struct sr_channel *find_channel(GSList *channellist, const char *channelname);
 GSList *parse_channelstring(struct sr_dev_inst *sdi, const char *channelstring);
 int parse_triggerstring(const struct sr_dev_inst *sdi, const char *s,
                struct sr_trigger **trigger);
-GHashTable *parse_generic_arg(const char *arg, gboolean sep_first);
+GHashTable *parse_generic_arg(const char *arg,
+               gboolean sep_first, const char *key_first);
 GHashTable *generic_arg_to_opt(const struct sr_option **opts, GHashTable *genargs);
 GSList *check_unknown_keys(const struct sr_option **avail, GHashTable *used);
 gboolean warn_unknown_keys(const struct sr_option **avail, GHashTable *used,