X-Git-Url: https://sigrok.org/gitweb/?a=blobdiff_plain;f=parsers.c;h=4f3b0c5203752a4bf404b260641fca8e6436a53e;hb=cad0cba6bb76d7aab6304aef41a2dd304ddad974;hp=f7d03bc6bbf230d9af2247b11ecf1fd43755e27d;hpb=662a1e27fa9573a35a6f9a6f699dee2be447826a;p=sigrok-cli.git diff --git a/parsers.c b/parsers.c index f7d03bc..4f3b0c5 100644 --- a/parsers.c +++ b/parsers.c @@ -17,6 +17,7 @@ * along with this program. If not, see . */ +#include #include #include #include @@ -24,8 +25,6 @@ #include #include "sigrok-cli.h" -extern struct sr_context *sr_ctx; - struct sr_channel *find_channel(GSList *channellist, const char *channelname) { struct sr_channel *ch; @@ -268,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: =[:=]* + * Generic list of key-value pairs, all items being equal. Mere set. + * + * ID form: [:=]* + * 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: [=][:=]* + * 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; @@ -281,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 "[:=]*" 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 "[=][:=]*" 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) @@ -298,6 +350,57 @@ GHashTable *parse_generic_arg(const char *arg, gboolean sep_first) return hash; } +GSList *check_unknown_keys(const struct sr_option **avail, GHashTable *used) +{ + GSList *unknown; + GHashTableIter iter; + void *key; + const char *used_id; + size_t avail_idx; + const char *avail_id, *found_id; + + /* Collect a list of used but not available keywords. */ + unknown = NULL; + g_hash_table_iter_init(&iter, used); + while (g_hash_table_iter_next(&iter, &key, NULL)) { + used_id = key; + found_id = NULL; + for (avail_idx = 0; avail[avail_idx] && avail[avail_idx]->id; avail_idx++) { + avail_id = avail[avail_idx]->id; + if (strcmp(avail_id, used_id) == 0) { + found_id = avail_id; + break; + } + } + if (!found_id) + unknown = g_slist_append(unknown, g_strdup(used_id)); + } + + /* Return the list of unknown keywords, or NULL if empty. */ + return unknown; +} + +gboolean warn_unknown_keys(const struct sr_option **avail, GHashTable *used, + const char *caption) +{ + GSList *unknown, *l; + gboolean had_unknown; + const char *s; + + if (!caption || !*caption) + caption = "Unknown keyword"; + + unknown = check_unknown_keys(avail, used); + had_unknown = unknown != NULL; + for (l = unknown; l; l = l->next) { + s = l->data; + g_warning("%s: %s.", caption, s); + } + g_slist_free_full(unknown, g_free); + + return had_unknown; +} + GHashTable *generic_arg_to_opt(const struct sr_option **opts, GHashTable *genargs) { GHashTable *hash; @@ -410,12 +513,15 @@ int parse_driver(char *arg, struct sr_dev_driver **driver, GSList **drvopts) int i; char *drvname; - drvargs = parse_generic_arg(arg, TRUE); + if (!arg) + return FALSE; + + drvargs = parse_generic_arg(arg, TRUE, NULL); drvname = g_strdup(g_hash_table_lookup(drvargs, "sigrok_key")); g_hash_table_remove(drvargs, "sigrok_key"); *driver = NULL; - drivers = sr_driver_list(); + drivers = sr_driver_list(sr_ctx); for (i = 0; drivers[i]; i++) { if (strcmp(drivers[i]->name, drvname)) continue;