cli: sync argpar - adjust to iterator API
[babeltrace.git] / src / cli / babeltrace2-cfg-cli-args.c
index ae8e8eef3f2fe9d3bae984e06007b9b2e18383c7..86bf918e7a1e5218020c1cef158720f651327fea 100644 (file)
@@ -1,25 +1,9 @@
 /*
- * Babeltrace trace converter - parameter parsing
+ * SPDX-License-Identifier: MIT
  *
  * Copyright 2016 Philippe Proulx <pproulx@efficios.com>
  *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
+ * Babeltrace trace converter - parameter parsing
  */
 
 #define BT_LOG_TAG "CLI/CFG-CLI-ARGS"
 #include "autodisc/autodisc.h"
 #include "common/version.h"
 
-/* Offset option with "is set" boolean */
-struct offset_opt {
-       int64_t value;
-       bool is_set;
-};
-
-/* Legacy "ctf"/"lttng-live" format options */
-struct ctf_legacy_opts {
-       struct offset_opt offset_s;
-       struct offset_opt offset_ns;
-       bool stream_intersection;
-};
-
-/* Legacy "text" format options */
-struct text_legacy_opts {
-       /*
-        * output, dbg_info_dir, dbg_info_target_prefix, names,
-        * and fields are owned by this.
-        */
-       GString *output;
-       GString *dbg_info_dir;
-       GString *dbg_info_target_prefix;
-       const bt_value *names;
-       const bt_value *fields;
-
-       /* Flags */
-       bool no_delta;
-       bool clock_cycles;
-       bool clock_seconds;
-       bool clock_date;
-       bool clock_gmt;
-       bool dbg_info_full_path;
-       bool verbose;
-};
-
-/* Legacy input format format */
-enum legacy_input_format {
-       LEGACY_INPUT_FORMAT_NONE = 0,
-       LEGACY_INPUT_FORMAT_CTF,
-       LEGACY_INPUT_FORMAT_LTTNG_LIVE,
-};
-
-/* Legacy output format format */
-enum legacy_output_format {
-       LEGACY_OUTPUT_FORMAT_NONE = 0,
-       LEGACY_OUTPUT_FORMAT_TEXT,
-       LEGACY_OUTPUT_FORMAT_DUMMY,
-};
-
 #define BT_CLI_LOGE_APPEND_CAUSE_OOM() BT_CLI_LOGE_APPEND_CAUSE("Out of memory.")
+#define WHILE_PARSING_ARG_N_FMT "While parsing argument #%d (`%s`): "
 
 /*
  * Returns the plugin name, component class name, component class type,
@@ -240,16 +176,96 @@ end:
        return;
 }
 
+static
+void print_and_indent(const char *str)
+{
+       const char *ch = &str[0];
+
+       for (; *ch != '\0'; ch++) {
+               if (*ch == '\n') {
+                       if (ch[1] != '\0') {
+                               printf("\n  ");
+                       }
+               } else {
+                       printf("%c", *ch);
+               }
+       }
+
+       printf("\n");
+}
+
 /*
  * Prints the Babeltrace version.
  */
 static
 void print_version(void)
 {
-       if (GIT_VERSION[0] == '\0') {
-               puts("Babeltrace " VERSION);
-       } else {
-               puts("Babeltrace " VERSION  " - " GIT_VERSION);
+       bool has_extra_name = strlen(BT_VERSION_EXTRA_NAME) > 0;
+       bool has_extra_description = strlen(BT_VERSION_EXTRA_DESCRIPTION) > 0;
+       bool has_extra_patch_names = strlen(BT_VERSION_EXTRA_PATCHES) > 0;
+       bool has_extra = has_extra_name || has_extra_description ||
+               has_extra_patch_names;
+
+       printf("%sBabeltrace %s%s",
+               bt_common_color_bold(),
+               VERSION,
+               bt_common_color_reset());
+
+       if (strlen(BT_VERSION_NAME) > 0) {
+               printf(" \"%s%s%s%s\"",
+                       bt_common_color_fg_bright_blue(),
+                       bt_common_color_bold(),
+                       BT_VERSION_NAME,
+                       bt_common_color_reset());
+       }
+
+       if (strlen(BT_VERSION_GIT) > 0) {
+               printf(" [%s%s%s]",
+                       bt_common_color_fg_yellow(),
+                       BT_VERSION_GIT,
+                       bt_common_color_reset());
+       }
+
+       printf("\n");
+
+       if (strlen(BT_VERSION_DESCRIPTION) > 0) {
+               unsigned int columns;
+               GString *descr;
+
+               if (bt_common_get_term_size(&columns, NULL) < 0) {
+                       /* Width not found: default to 80 */
+                       columns = 80;
+               }
+
+               descr = bt_common_fold(BT_VERSION_DESCRIPTION, columns, 0);
+               BT_ASSERT(descr);
+               printf("\n%s\n", descr->str);
+               g_string_free(descr, TRUE);
+       }
+
+       if (has_extra) {
+               printf("\n");
+
+               if (has_extra_name) {
+                       printf("%sExtra name%s: %s\n",
+                               bt_common_color_fg_cyan(),
+                               bt_common_color_reset(),
+                               BT_VERSION_EXTRA_NAME);
+               }
+
+               if (has_extra_description) {
+                       printf("%sExtra description%s:\n  ",
+                               bt_common_color_fg_cyan(),
+                               bt_common_color_reset());
+                       print_and_indent(BT_VERSION_EXTRA_DESCRIPTION);
+               }
+
+               if (has_extra_patch_names) {
+                       printf("%sExtra patch names%s:\n  ",
+                               bt_common_color_fg_cyan(),
+                               bt_common_color_reset());
+                       print_and_indent(BT_VERSION_EXTRA_PATCHES);
+               }
        }
 }
 
@@ -452,7 +468,7 @@ void bt_config_destroy(bt_object *obj)
                }
                break;
        default:
-               abort();
+               bt_common_abort();
        }
 
        g_free(cfg);
@@ -488,9 +504,9 @@ GScanner *create_csv_identifiers_scanner(void)
 {
        GScanner *scanner;
        GScannerConfig scanner_config = {
-               .cset_skip_characters = " \t\n",
-               .cset_identifier_first = G_CSET_a_2_z G_CSET_A_2_Z "_",
-               .cset_identifier_nth = G_CSET_a_2_z G_CSET_A_2_Z ":_-",
+               .cset_skip_characters = (gchar *) " \t\n",
+               .cset_identifier_first = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z "_",
+               .cset_identifier_nth = (gchar *) G_CSET_a_2_z G_CSET_A_2_Z ":_-",
                .case_sensitive = TRUE,
                .cpair_comment_single = NULL,
                .skip_comment_multi = TRUE,
@@ -735,7 +751,7 @@ int insert_flat_params_from_array(GString *params_arg,
                const bt_value *names_array, const char *prefix)
 {
        int ret = 0;
-       int i;
+       uint64_t i;
        GString *tmpstr = NULL, *default_value = NULL;
        bool default_set = false, non_default_set = false;
 
@@ -764,16 +780,10 @@ int insert_flat_params_from_array(GString *params_arg,
        for (i = 0; i < bt_value_array_get_length(names_array); i++) {
                const bt_value *str_obj =
                        bt_value_array_borrow_element_by_index_const(names_array,
-                                                                    i);
+                               i);
                const char *suffix;
                bool is_default = false;
 
-               if (!str_obj) {
-                       BT_CLI_LOGE_APPEND_CAUSE("Unexpected error.");
-                       ret = -1;
-                       goto end;
-               }
-
                suffix = bt_value_string_get(str_obj);
 
                g_string_assign(tmpstr, prefix);
@@ -892,7 +902,7 @@ void add_run_cfg_comp(struct bt_config *cfg,
                g_ptr_array_add(cfg->cmd_data.run.sinks, cfg_comp);
                break;
        default:
-               abort();
+               bt_common_abort();
        }
 }
 
@@ -1280,32 +1290,153 @@ void print_expected_params_format(FILE *fp)
        fprintf(fp, "babeltrace2 from a shell.\n");
 }
 
+/*
+ * Given argpar error status `status` and error `error`, return a formatted
+ * error message describing the error.
+ *
+ * `argv` is the argument vector that was being parsed.
+ *
+ * `prefix_fmt` (formatted using the following arguments) is prepended to
+ * the error message.
+ *
+ * The returned string must be freed by the caller.
+ */
 static
-bool help_option_is_specified(
-               const struct bt_argpar_parse_ret *argpar_parse_ret)
+GString *__BT_ATTR_FORMAT_PRINTF(3, 4) format_arg_error(
+               const struct argpar_error *error,
+               const char **argv, const char *prefix_fmt, ...)
+
 {
-       int i;
-       bool specified = false;
+       GString *str = g_string_new(NULL);
+       va_list args;
 
-       for (i = 0; i < argpar_parse_ret->items->len; i++) {
-               struct bt_argpar_item *argpar_item =
-                       g_ptr_array_index(argpar_parse_ret->items, i);
-               struct bt_argpar_item_opt *argpar_item_opt;
+       va_start(args, prefix_fmt);
+       g_string_append_vprintf(str, prefix_fmt, args);
+       va_end(args);
 
-               if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) {
-                       continue;
+       g_string_append(str, ": ");
+
+       switch (argpar_error_type(error))
+       {
+       case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG:
+       {
+               bool is_short;
+               const struct argpar_opt_descr *descr =
+                       argpar_error_opt_descr(error, &is_short);
+               int orig_index = argpar_error_orig_index(error);
+               const char *arg = argv[orig_index];
+
+               if (is_short) {
+                       g_string_append_printf(
+                               str,
+                               WHILE_PARSING_ARG_N_FMT "Missing required argument for option `-%c`",
+                               orig_index + 1, arg, descr->short_name);
+               } else {
+                       g_string_append_printf(
+                               str,
+                               WHILE_PARSING_ARG_N_FMT "Missing required argument for option `--%s`",
+                               orig_index + 1, arg, descr->long_name);
                }
 
-               argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
-               if (argpar_item_opt->descr->id == OPT_HELP) {
-                       specified = true;
-                       break;
+               break;
+       }
+       case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG:
+       {
+               bool is_short;
+               const struct argpar_opt_descr *descr =
+                       argpar_error_opt_descr(error, &is_short);
+               int orig_index = argpar_error_orig_index(error);
+               const char *arg = argv[orig_index];
+
+               if (is_short) {
+                       g_string_append_printf(
+                               str,
+                               WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `-%c`",
+                               orig_index + 1, arg, descr->short_name);
+               } else {
+                       g_string_append_printf(
+                               str,
+                               WHILE_PARSING_ARG_N_FMT "Unexpected argument for option `--%s`",
+                               orig_index + 1, arg, descr->long_name);
                }
+
+               break;
+       }
+       case ARGPAR_ERROR_TYPE_UNKNOWN_OPT:
+       {
+               int orig_index = argpar_error_orig_index(error);
+               const char *unknown_opt = argpar_error_unknown_opt_name(error);
+               const char *arg = argv[orig_index];
+
+               g_string_append_printf(
+                       str,
+                       WHILE_PARSING_ARG_N_FMT "Unknown option `%s`",
+                       orig_index + 1, arg, unknown_opt);
+
+               break;
+       }
+
+       default:
+               BT_ASSERT(0);
+       }
+
+       return str;
+}
+
+enum parse_next_item_status
+{
+       PARSE_NEXT_ITEM_STATUS_OK = 0,
+       PARSE_NEXT_ITEM_STATUS_END = 1,
+       PARSE_NEXT_ITEM_STATUS_ERROR = -1,
+};
+
+/*
+ * Parse the next item using `iter`.  Log and append an error if necessary.
+ *
+ * The item in `*item` on entry is freed, and the new item is also
+ * returned in `*item`.
+ */
+static
+enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
+               const struct argpar_item **item, const char **argv,
+               const char *command)
+{
+       enum argpar_iter_next_status status;
+       const struct argpar_error *error = NULL;
+       enum parse_next_item_status ret;
+
+       ARGPAR_ITEM_DESTROY_AND_RESET(*item);
+       status = argpar_iter_next(iter, item, &error);
+
+       switch (status) {
+       case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               ret = PARSE_NEXT_ITEM_STATUS_ERROR;
+               break;
+       case ARGPAR_ITER_NEXT_STATUS_ERROR:
+       {
+               GString *err_str = format_arg_error(error, argv,
+                       "While parsing `%s` command's command-line arguments", command);
+               BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str);
+               g_string_free(err_str, TRUE);
+               ret = PARSE_NEXT_ITEM_STATUS_ERROR;
+               break;
+       }
+       case ARGPAR_ITER_NEXT_STATUS_END:
+               ret = PARSE_NEXT_ITEM_STATUS_END;
+               break;
+       case ARGPAR_ITER_NEXT_STATUS_OK:
+               ret = PARSE_NEXT_ITEM_STATUS_OK;
+               break;
+       default:
+               bt_common_abort();
        }
 
-       return specified;
+       argpar_error_destroy(error);
+       return ret;
 }
 
+
 /*
  * Prints the help command usage.
  */
@@ -1325,10 +1456,10 @@ void print_help_usage(FILE *fp)
 }
 
 static
-const struct bt_argpar_opt_descr help_options[] = {
+const struct argpar_opt_descr help_options[] = {
        /* id, short_name, long_name, with_arg */
        { OPT_HELP, 'h', "help", false },
-       BT_ARGPAR_OPT_DESCR_SENTINEL
+       ARGPAR_OPT_DESCR_SENTINEL
 };
 
 /*
@@ -1343,11 +1474,12 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
                int default_log_level)
 {
        struct bt_config *cfg = NULL;
+       const char *plugin_comp_cls_arg = NULL;
        char *plugin_name = NULL, *comp_cls_name = NULL;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
-       struct bt_argpar_item_non_opt *non_opt;
        GString *substring = NULL;
        size_t end_pos;
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
 
        *retcode = 0;
        cfg = bt_config_help_create(plugin_paths, default_log_level);
@@ -1355,63 +1487,77 @@ struct bt_config *bt_config_help_from_args(int argc, const char *argv[],
                goto error;
        }
 
-       /* Parse options */
-       argpar_parse_ret = bt_argpar_parse(argc, argv, help_options, true);
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing `help` command's command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(argc, argv, help_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       if (help_option_is_specified(&argpar_parse_ret)) {
-               print_help_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
+       while (true) {
+               enum parse_next_item_status status =
+                       parse_next_item(argpar_iter, &argpar_item, argv, "help");
+
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
+
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_opt_descr *opt_descr =
+                               argpar_item_opt_descr(argpar_item);
+
+                       switch (opt_descr->id) {
+                       case OPT_HELP:
+                               print_help_usage(stdout);
+                               *retcode = -1;
+                               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                               goto end;
+                       default:
+                               bt_common_abort();
+                       }
+               } else {
+                       const char *arg = argpar_item_non_opt_arg(argpar_item);
+
+                       if (plugin_comp_cls_arg) {
+                               BT_CLI_LOGE_APPEND_CAUSE(
+                                       "Extraneous command-line argument specified to `help` command: `%s`.",
+                                       arg);
+                               goto error;
+                       }
+
+                       plugin_comp_cls_arg = arg;
+               }
        }
 
-       if (argpar_parse_ret.items->len == 0) {
+       if (!plugin_comp_cls_arg) {
                BT_CLI_LOGE_APPEND_CAUSE(
                        "Missing plugin name or component class descriptor.");
                goto error;
-       } else if (argpar_parse_ret.items->len > 1) {
-               /*
-                * At this point we know there are least two non-option
-                * arguments because we don't reach here with `--help`,
-                * the only option.
-                */
-               non_opt = argpar_parse_ret.items->pdata[1];
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "Extraneous command-line argument specified to `help` command: `%s`.",
-                       non_opt->arg);
-               goto error;
        }
 
-       non_opt = argpar_parse_ret.items->pdata[0];
-
        /* Look for unescaped dots in the argument. */
-       substring = bt_common_string_until(non_opt->arg, ".\\", ".", &end_pos);
+       substring = bt_common_string_until(plugin_comp_cls_arg, ".\\", ".", &end_pos);
        if (!substring) {
                BT_CLI_LOGE_APPEND_CAUSE("Could not consume argument: arg=%s",
-                       non_opt->arg);
+                       plugin_comp_cls_arg);
                goto error;
        }
 
-       if (end_pos == strlen(non_opt->arg)) {
+       if (end_pos == strlen(plugin_comp_cls_arg)) {
                /* Didn't find an unescaped dot, treat it as a plugin name. */
                g_string_assign(cfg->cmd_data.help.cfg_component->plugin_name,
-                       non_opt->arg);
+                       plugin_comp_cls_arg);
        } else {
                /*
                 * Found an unescaped dot, treat it as a component class name.
                 */
-               plugin_comp_cls_names(non_opt->arg, NULL, &plugin_name, &comp_cls_name,
+               plugin_comp_cls_names(plugin_comp_cls_arg, NULL, &plugin_name, &comp_cls_name,
                        &cfg->cmd_data.help.cfg_component->type);
                if (!plugin_name || !comp_cls_name) {
                        BT_CLI_LOGE_APPEND_CAUSE(
                                "Could not parse argument as a component class name: arg=%s",
-                               non_opt->arg);
+                               plugin_comp_cls_arg);
                        goto error;
                }
 
@@ -1435,7 +1581,8 @@ end:
                g_string_free(substring, TRUE);
        }
 
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_iter_destroy(argpar_iter);
+       argpar_item_destroy(argpar_item);
 
        return cfg;
 }
@@ -1458,11 +1605,11 @@ void print_query_usage(FILE *fp)
 }
 
 static
-const struct bt_argpar_opt_descr query_options[] = {
+const struct argpar_opt_descr query_options[] = {
        /* id, short_name, long_name, with_arg */
        { OPT_HELP, 'h', "help", false },
        { OPT_PARAMS, 'p', "params", true },
-       BT_ARGPAR_OPT_DESCR_SENTINEL
+       ARGPAR_OPT_DESCR_SENTINEL
 };
 
 /*
@@ -1476,12 +1623,12 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                int *retcode, const bt_value *plugin_paths,
                int default_log_level)
 {
-       int i;
        struct bt_config *cfg = NULL;
        const char *component_class_spec = NULL;
        const char *query_object = NULL;
        GString *error_str = NULL;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
 
        bt_value *params = bt_value_map_create();
        if (!params) {
@@ -1501,32 +1648,33 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                goto error;
        }
 
-       /* Parse options */
-       argpar_parse_ret = bt_argpar_parse(argc, argv, query_options, true);
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing `query` command's command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(argc, argv, query_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       if (help_option_is_specified(&argpar_parse_ret)) {
-               print_query_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
+       while (true) {
+               enum parse_next_item_status status =
+                       parse_next_item(argpar_iter, &argpar_item, argv, "query");
 
-       for (i = 0; i < argpar_parse_ret.items->len; i++) {
-               struct bt_argpar_item *argpar_item =
-                       g_ptr_array_index(argpar_parse_ret.items, i);
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
 
-               if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
-                       struct bt_argpar_item_opt *argpar_item_opt =
-                               (struct bt_argpar_item_opt *) argpar_item;
-                       const char *arg = argpar_item_opt->arg;
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_opt_descr *opt_descr =
+                               argpar_item_opt_descr(argpar_item);
+                       const char *arg = argpar_item_opt_arg(argpar_item);
 
-                       switch (argpar_item_opt->descr->id) {
+                       switch (opt_descr->id) {
+                       case OPT_HELP:
+                               print_query_usage(stdout);
+                               *retcode = -1;
+                               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                               goto end;
                        case OPT_PARAMS:
                        {
                                bt_value *parsed_params = bt_param_parse(arg, error_str);
@@ -1547,13 +1695,10 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                                break;
                        }
                        default:
-                               BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
-                                       argpar_item_opt->descr->id);
-                               goto error;
+                               bt_common_abort();
                        }
                } else {
-                       struct bt_argpar_item_non_opt *argpar_item_non_opt
-                               = (struct bt_argpar_item_non_opt *) argpar_item;
+                       const char *arg = argpar_item_non_opt_arg(argpar_item);
 
                        /*
                         * We need exactly two non-option arguments
@@ -1561,12 +1706,12 @@ struct bt_config *bt_config_query_from_args(int argc, const char *argv[],
                         * specification and query object.
                         */
                        if (!component_class_spec) {
-                               component_class_spec = argpar_item_non_opt->arg;
+                               component_class_spec = arg;
                        } else if (!query_object) {
-                               query_object = argpar_item_non_opt->arg;
+                               query_object = arg;
                        } else {
                                BT_CLI_LOGE_APPEND_CAUSE("Extraneous command-line argument specified to `query` command: `%s`.",
-                                       argpar_item_non_opt->arg);
+                                       arg);
                                goto error;
                        }
                }
@@ -1604,7 +1749,8 @@ error:
        BT_OBJECT_PUT_REF_AND_RESET(cfg);
 
 end:
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_iter_destroy(argpar_iter);
+       argpar_item_destroy(argpar_item);
 
        if (error_str) {
                g_string_free(error_str, TRUE);
@@ -1632,10 +1778,10 @@ void print_list_plugins_usage(FILE *fp)
 }
 
 static
-const struct bt_argpar_opt_descr list_plugins_options[] = {
+const struct argpar_opt_descr list_plugins_options[] = {
        /* id, short_name, long_name, with_arg */
        { OPT_HELP, 'h', "help", false },
-       BT_ARGPAR_OPT_DESCR_SENTINEL
+       ARGPAR_OPT_DESCR_SENTINEL
 };
 
 /*
@@ -1649,7 +1795,8 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
                int *retcode, const bt_value *plugin_paths)
 {
        struct bt_config *cfg = NULL;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
 
        *retcode = 0;
        cfg = bt_config_list_plugins_create(plugin_paths);
@@ -1657,36 +1804,42 @@ struct bt_config *bt_config_list_plugins_from_args(int argc, const char *argv[],
                goto error;
        }
 
-       /* Parse options */
-       argpar_parse_ret = bt_argpar_parse(argc, argv, list_plugins_options, true);
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing `list-plugins` command's command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(argc, argv, list_plugins_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       if (help_option_is_specified(&argpar_parse_ret)) {
-               print_list_plugins_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
+       while (true) {
+               enum parse_next_item_status status =
+                       parse_next_item(argpar_iter, &argpar_item, argv, "list-plugins");
 
-       if (argpar_parse_ret.items->len > 0) {
-               /*
-                * At this point we know there's at least one non-option
-                * argument because we don't reach here with `--help`,
-                * the only option.
-                */
-               struct bt_argpar_item_non_opt *non_opt =
-                       argpar_parse_ret.items->pdata[0];
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
 
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "Extraneous command-line argument specified to `list-plugins` command: `%s`.",
-                       non_opt->arg);
-               goto error;
-       }
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_opt_descr *opt_descr =
+                               argpar_item_opt_descr(argpar_item);
+
+                       switch (opt_descr->id) {
+                       case OPT_HELP:
+                               print_list_plugins_usage(stdout);
+                               *retcode = -1;
+                               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                               goto end;
+                       default:
+                               bt_common_abort();
+                       }
+               } else {
+                       BT_CLI_LOGE_APPEND_CAUSE(
+                               "Extraneous command-line argument specified to `list-plugins` command: `%s`.",
+                               argpar_item_non_opt_arg(argpar_item));
+                       goto error;
+               }
+               }
 
        goto end;
 
@@ -1695,7 +1848,8 @@ error:
        BT_OBJECT_PUT_REF_AND_RESET(cfg);
 
 end:
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_iter_destroy(argpar_iter);
+       argpar_item_destroy(argpar_item);
 
        return cfg;
 }
@@ -1793,10 +1947,10 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
        long retry_duration = -1;
        bt_value_map_extend_status extend_status;
        GString *error_str = NULL;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
-       int i;
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
 
-       static const struct bt_argpar_opt_descr run_options[] = {
+       static const struct argpar_opt_descr run_options[] = {
                { OPT_BASE_PARAMS, 'b', "base-params", true },
                { OPT_COMPONENT, 'c', "component", true },
                { OPT_CONNECT, 'x', "connect", true },
@@ -1805,7 +1959,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                { OPT_PARAMS, 'p', "params", true },
                { OPT_RESET_BASE_PARAMS, 'r', "reset-base-params", false },
                { OPT_RETRY_DURATION, '\0', "retry-duration", true },
-               BT_ARGPAR_OPT_DESCR_SENTINEL
+               ARGPAR_OPT_DESCR_SENTINEL
        };
 
        *retcode = 0;
@@ -1846,42 +2000,40 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                goto error;
        }
 
-       /* Parse options */
-       argpar_parse_ret = bt_argpar_parse(argc, argv, run_options, true);
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing `run` command's command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(argc, argv, run_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       if (help_option_is_specified(&argpar_parse_ret)) {
-               print_run_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       for (i = 0; i < argpar_parse_ret.items->len; i++) {
-               struct bt_argpar_item *argpar_item =
-                       g_ptr_array_index(argpar_parse_ret.items, i);
-               struct bt_argpar_item_opt *argpar_item_opt;
+       while (true) {
+               enum parse_next_item_status status;
+               const struct argpar_opt_descr *opt_descr;
                const char *arg;
 
-               /* This command does not accept non-option arguments.*/
-               if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
-                       struct bt_argpar_item_non_opt *argpar_nonopt_item =
-                               (struct bt_argpar_item_non_opt *) argpar_item;
+               status = parse_next_item(argpar_iter, &argpar_item, argv, "run");
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
 
+               /* This command does not accept non-option arguments.*/
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_NON_OPT) {
                        BT_CLI_LOGE_APPEND_CAUSE("Unexpected argument: `%s`",
-                               argpar_nonopt_item->arg);
+                               argpar_item_non_opt_arg(argpar_item));
                        goto error;
                }
 
-               argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
-               arg = argpar_item_opt->arg;
+               opt_descr = argpar_item_opt_descr(argpar_item);
+               arg = argpar_item_opt_arg(argpar_item);
 
-               switch (argpar_item_opt->descr->id) {
+               switch (opt_descr->id) {
+               case OPT_HELP:
+                       print_run_usage(stdout);
+                       *retcode = -1;
+                       BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                       goto end;
                case OPT_COMPONENT:
                {
                        enum bt_config_component_dest dest;
@@ -1906,7 +2058,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                                dest = BT_CONFIG_COMPONENT_DEST_SINK;
                                break;
                        default:
-                               abort();
+                               bt_common_abort();
                        }
 
                        BT_ASSERT(cur_base_params);
@@ -1999,14 +2151,14 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        break;
                case OPT_RETRY_DURATION: {
                        gchar *end;
-                       size_t arg_len = strlen(argpar_item_opt->arg);
+                       size_t arg_len = strlen(arg);
 
-                       retry_duration = g_ascii_strtoll(argpar_item_opt->arg, &end, 10);
+                       retry_duration = g_ascii_strtoll(arg, &end, 10);
 
-                       if (arg_len == 0 || end != (argpar_item_opt->arg + arg_len)) {
+                       if (arg_len == 0 || end != (arg + arg_len)) {
                                BT_CLI_LOGE_APPEND_CAUSE(
                                        "Could not parse --retry-duration option's argument as an unsigned integer: `%s`",
-                                       argpar_item_opt->arg);
+                                       arg);
                                goto error;
                        }
 
@@ -2021,9 +2173,7 @@ struct bt_config *bt_config_run_from_args(int argc, const char *argv[],
                        break;
                }
                default:
-                       BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
-                               argpar_item_opt->descr->id);
-                       goto error;
+                       bt_common_abort();
                }
        }
 
@@ -2058,7 +2208,9 @@ end:
                g_string_free(error_str, TRUE);
        }
 
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_iter_destroy(argpar_iter);
+       argpar_item_destroy(argpar_item);
+
        BT_OBJECT_PUT_REF_AND_RESET(cur_cfg_comp);
        BT_VALUE_PUT_REF_AND_RESET(cur_base_params);
        BT_VALUE_PUT_REF_AND_RESET(instance_names);
@@ -2073,33 +2225,27 @@ struct bt_config *bt_config_run_from_args_array(const bt_value *run_args,
 {
        struct bt_config *cfg = NULL;
        const char **argv;
-       int64_t i, len;
-       const size_t argc = bt_value_array_get_length(run_args);
+       uint64_t i, len = bt_value_array_get_length(run_args);
 
-       argv = calloc(argc, sizeof(*argv));
+       BT_ASSERT(len <= SIZE_MAX);
+       argv = calloc((size_t) len, sizeof(*argv));
        if (!argv) {
                BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto end;
        }
 
-       len = bt_value_array_get_length(run_args);
-       if (len < 0) {
-               BT_CLI_LOGE_APPEND_CAUSE("Invalid executable arguments.");
-               goto end;
-       }
        for (i = 0; i < len; i++) {
                const bt_value *arg_value =
                        bt_value_array_borrow_element_by_index_const(run_args,
-                                                                    i);
+                               i);
                const char *arg;
 
-               BT_ASSERT(arg_value);
                arg = bt_value_string_get(arg_value);
                BT_ASSERT(arg);
                argv[i] = arg;
        }
 
-       cfg = bt_config_run_from_args(argc, argv, retcode,
+       cfg = bt_config_run_from_args((int) len, argv, retcode,
                plugin_paths, default_log_level);
 
 end:
@@ -2231,7 +2377,7 @@ void print_convert_usage(FILE *fp)
 }
 
 static
-const struct bt_argpar_opt_descr convert_options[] = {
+const struct argpar_opt_descr convert_options[] = {
        /* id, short_name, long_name, with_arg */
        { OPT_BEGIN, 'b', "begin", true },
        { OPT_CLOCK_CYCLES, '\0', "clock-cycles", false },
@@ -2267,7 +2413,7 @@ const struct bt_argpar_opt_descr convert_options[] = {
        { OPT_STREAM_INTERSECTION, '\0', "stream-intersection", false },
        { OPT_TIMERANGE, '\0', "timerange", true },
        { OPT_VERBOSE, 'v', "verbose", false },
-       BT_ARGPAR_OPT_DESCR_SENTINEL
+       ARGPAR_OPT_DESCR_SENTINEL
 };
 
 static
@@ -2357,7 +2503,7 @@ int append_run_args_for_implicit_component(
                bt_value *run_args)
 {
        int ret = 0;
-       size_t i;
+       uint64_t i;
        GString *component_arg_for_run = NULL;
 
        if (!impl_args->exists) {
@@ -2400,16 +2546,12 @@ int append_run_args_for_implicit_component(
                }
        }
 
-       for (i = 0; i < bt_value_array_get_length(impl_args->extra_params);
-                       i++) {
+       for (i = 0; i < bt_value_array_get_length(impl_args->extra_params); i++) {
                const bt_value *elem;
                const char *arg;
 
-               elem = bt_value_array_borrow_element_by_index(impl_args->extra_params,
-                                                             i);
-               if (!elem) {
-                       goto error;
-               }
+               elem = bt_value_array_borrow_element_by_index(
+                       impl_args->extra_params, i);
 
                BT_ASSERT(bt_value_is_string(elem));
                arg = bt_value_string_get(elem);
@@ -2628,7 +2770,7 @@ int bt_value_to_cli_param_value_append(const bt_value *value, GString *buf)
                break;
        }
        default:
-               abort();
+               bt_common_abort();
        }
 
        ret = 0;
@@ -3203,7 +3345,8 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
        char *output = NULL;
        struct auto_source_discovery auto_disc = { NULL };
        GString *auto_disc_comp_name = NULL;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
        GString *name_gstr = NULL;
        GString *component_arg_for_run = NULL;
        bt_value *live_inputs_array_val = NULL;
@@ -3326,35 +3469,36 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         * arguments if needed to automatically name unnamed component
         * instances.
         */
-       argpar_parse_ret = bt_argpar_parse(argc, argv, convert_options, true);
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing `convert` command's command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(argc, argv, convert_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       if (help_option_is_specified(&argpar_parse_ret)) {
-               print_convert_usage(stdout);
-               *retcode = -1;
-               BT_OBJECT_PUT_REF_AND_RESET(cfg);
-               goto end;
-       }
-
-       for (i = 0; i < argpar_parse_ret.items->len; i++) {
-               struct bt_argpar_item *argpar_item =
-                       g_ptr_array_index(argpar_parse_ret.items, i);
-               struct bt_argpar_item_opt *argpar_item_opt;
+       while (true) {
+               enum parse_next_item_status status;
                char *name = NULL;
                char *plugin_name = NULL;
                char *comp_cls_name = NULL;
-               const char *arg;
 
-               if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
-                       argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
-                       arg = argpar_item_opt->arg;
+               status = parse_next_item(argpar_iter, &argpar_item, argv, "convert");
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
+
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_opt_descr *opt_descr =
+                               argpar_item_opt_descr(argpar_item);
+                       const char *arg = argpar_item_opt_arg(argpar_item);
 
-                       switch (argpar_item_opt->descr->id) {
+                       switch (opt_descr->id) {
+                       case OPT_HELP:
+                               print_convert_usage(stdout);
+                               *retcode = -1;
+                               BT_OBJECT_PUT_REF_AND_RESET(cfg);
+                               goto end;
                        case OPT_COMPONENT:
                        {
                                bt_component_class_type type;
@@ -3440,7 +3584,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                        sink_names = g_list_append(sink_names, name_gstr);
                                        break;
                                default:
-                                       abort();
+                                       bt_common_abort();
                                }
                                name_gstr = NULL;
 
@@ -3505,6 +3649,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                        }
                                } else if (current_item_type == CONVERT_CURRENT_ITEM_TYPE_NON_OPT) {
                                        uint64_t idx = bt_value_array_get_length(non_opt_loglevels) - 1;
+                                       enum bt_value_array_set_element_by_index_status set_element_status;
                                        bt_value *log_level_str_value;
 
                                        log_level_str_value = bt_value_string_create_init(arg);
@@ -3513,9 +3658,11 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                                goto error;
                                        }
 
-                                       if (bt_value_array_set_element_by_index(non_opt_loglevels, idx,
-                                                       log_level_str_value)) {
-                                               bt_value_put_ref(log_level_str_value);
+                                       set_element_status =
+                                               bt_value_array_set_element_by_index(non_opt_loglevels,
+                                                       idx, log_level_str_value);
+                                       bt_value_put_ref(log_level_str_value);
+                                       if (set_element_status != BT_VALUE_ARRAY_SET_ELEMENT_BY_INDEX_STATUS_OK) {
                                                BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                                goto error;
                                        }
@@ -3568,20 +3715,15 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                /* Ignore in this pass */
                                break;
                        default:
-                               BT_CLI_LOGE_APPEND_CAUSE("Unknown command-line option specified (option code %d).",
-                                       argpar_item_opt->descr->id);
-                               goto error;
+                               bt_common_abort();
                        }
-               } else if (argpar_item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
-                       struct bt_argpar_item_non_opt *argpar_item_non_opt;
+               } else {
+                       const char *arg = argpar_item_non_opt_arg(argpar_item);
                        bt_value_array_append_element_status append_status;
 
                        current_item_type = CONVERT_CURRENT_ITEM_TYPE_NON_OPT;
 
-                       argpar_item_non_opt = (struct bt_argpar_item_non_opt *) argpar_item;
-
-                       append_status = bt_value_array_append_string_element(non_opts,
-                               argpar_item_non_opt->arg);
+                       append_status = bt_value_array_append_string_element(non_opts, arg);
                        if (append_status != BT_VALUE_ARRAY_APPEND_ELEMENT_STATUS_OK) {
                                BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
@@ -3599,8 +3741,6 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                BT_CLI_LOGE_APPEND_CAUSE_OOM();
                                goto error;
                        }
-               } else {
-                       abort();
                }
        }
 
@@ -3609,23 +3749,36 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         * arguments into implicit component instances for the run
         * command.
         */
-       for (i = 0; i < argpar_parse_ret.items->len; i++) {
-               struct bt_argpar_item *argpar_item =
-                       g_ptr_array_index(argpar_parse_ret.items, i);
-               struct bt_argpar_item_opt *argpar_item_opt;
+       argpar_iter_destroy(argpar_iter);
+       argpar_iter = argpar_iter_create(argc, argv, convert_options);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
+               goto error;
+       }
+
+       while (true) {
+               enum parse_next_item_status status;
+               const struct argpar_opt_descr *opt_descr;
                const char *arg;
 
-               if (argpar_item->type != BT_ARGPAR_ITEM_TYPE_OPT) {
+               status = parse_next_item(argpar_iter, &argpar_item, argv, "convert");
+               if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+                       goto error;
+               } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
+                       break;
+               }
+
+               if (argpar_item_type(argpar_item) != ARGPAR_ITEM_TYPE_OPT) {
                        continue;
                }
 
-               argpar_item_opt = (struct bt_argpar_item_opt *) argpar_item;
-               arg = argpar_item_opt->arg;
+               opt_descr = argpar_item_opt_descr(argpar_item);
+               arg = argpar_item_opt_arg(argpar_item);
 
-               switch (argpar_item_opt->descr->id) {
+               switch (opt_descr->id) {
                case OPT_BEGIN:
                        if (trimmer_has_begin) {
-                               printf("At --begin option: --begin or --timerange option already specified\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("At --begin option: --begin or --timerange option already specified\n    %s\n",
                                        arg);
                                goto error;
                        }
@@ -3640,7 +3793,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        break;
                case OPT_END:
                        if (trimmer_has_end) {
-                               printf("At --end option: --end or --timerange option already specified\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("At --end option: --end or --timerange option already specified\n    %s\n",
                                        arg);
                                goto error;
                        }
@@ -3659,7 +3812,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        char *end;
 
                        if (trimmer_has_begin || trimmer_has_end) {
-                               printf("At --timerange option: --begin, --end, or --timerange option already specified\n    %s\n",
+                               BT_CLI_LOGE_APPEND_CAUSE("At --timerange option: --begin, --end, or --timerange option already specified\n    %s\n",
                                        arg);
                                goto error;
                        }
@@ -3892,8 +4045,18 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                        *default_log_level =
                                logging_level_min(*default_log_level, BT_LOG_TRACE);
                        break;
-               default:
+               case OPT_COMPONENT:
+               case OPT_HELP:
+               case OPT_LOG_LEVEL:
+               case OPT_OMIT_HOME_PLUGIN_PATH:
+               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+               case OPT_PARAMS:
+               case OPT_PLUGIN_PATH:
+               case OPT_RETRY_DURATION:
+                       /* Ignore in this pass */
                        break;
+               default:
+                       bt_common_abort();
                }
        }
 
@@ -4075,7 +4238,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
 
                        if (auto_source_discovery_restrict_plugin_name) {
                                plugin_count = 1;
-                               plugin = find_loaded_plugin(auto_source_discovery_restrict_plugin_name);
+                               plugin = borrow_loaded_plugin_by_name(auto_source_discovery_restrict_plugin_name);
                                plugins = &plugin;
                        } else {
                                plugin_count = get_loaded_plugins_count();
@@ -4338,20 +4501,21 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
         * here.
         */
        if (print_run_args || print_run_args_0) {
+               uint64_t args_idx, args_len;
                if (stream_intersection_mode) {
                        BT_CLI_LOGE_APPEND_CAUSE("Cannot specify --stream-intersection with --run-args or --run-args-0.");
                        goto error;
                }
 
-               for (i = 0; i < bt_value_array_get_length(run_args); i++) {
+               args_len = bt_value_array_get_length(run_args);
+               for (args_idx = 0; args_idx < args_len; args_idx++) {
                        const bt_value *arg_value =
                                bt_value_array_borrow_element_by_index(run_args,
-                                                                      i);
+                                       args_idx);
                        const char *arg;
                        GString *quoted = NULL;
                        const char *arg_to_print;
 
-                       BT_ASSERT(arg_value);
                        arg = bt_value_string_get(arg_value);
 
                        if (print_run_args) {
@@ -4371,7 +4535,7 @@ struct bt_config *bt_config_convert_from_args(int argc, const char *argv[],
                                g_string_free(quoted, TRUE);
                        }
 
-                       if (i < bt_value_array_get_length(run_args) - 1) {
+                       if (args_idx < args_len - 1) {
                                if (print_run_args) {
                                        putchar(' ');
                                } else {
@@ -4399,7 +4563,8 @@ error:
        BT_OBJECT_PUT_REF_AND_RESET(cfg);
 
 end:
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_iter_destroy(argpar_iter);
+       argpar_item_destroy(argpar_item);
 
        free(output);
 
@@ -4484,18 +4649,19 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                const bt_interrupter *interrupter)
 {
        struct bt_config *config = NULL;
-       int i;
        int top_level_argc;
        const char **top_level_argv;
        int command_argc = -1;
        const char **command_argv = NULL;
        const char *command_name = NULL;
        int default_log_level = -1;
-       struct bt_argpar_parse_ret argpar_parse_ret = { 0 };
+       struct argpar_iter *argpar_iter = NULL;
+       const struct argpar_item *argpar_item = NULL;
+       const struct argpar_error *argpar_error = NULL;
        bt_value *plugin_paths = NULL;
 
        /* Top-level option descriptions. */
-       static const struct bt_argpar_opt_descr descrs[] = {
+       static const struct argpar_opt_descr descrs[] = {
                { OPT_DEBUG, 'd', "debug", false },
                { OPT_HELP, 'h', "help", false },
                { OPT_LOG_LEVEL, 'l', "log-level", true },
@@ -4504,7 +4670,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                { OPT_OMIT_HOME_PLUGIN_PATH, '\0', "omit-home-plugin-path", false },
                { OPT_OMIT_SYSTEM_PLUGIN_PATH, '\0', "omit-system-plugin-path", false },
                { OPT_PLUGIN_PATH, '\0', "plugin-path", true },
-               BT_ARGPAR_OPT_DESCR_SENTINEL
+               ARGPAR_OPT_DESCR_SENTINEL
        };
 
        enum command_type {
@@ -4552,90 +4718,130 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
        /* Skip first argument, the name of the program. */
        top_level_argc = argc - 1;
        top_level_argv = argv + 1;
-       argpar_parse_ret = bt_argpar_parse(top_level_argc, top_level_argv,
-               descrs, false);
 
-       if (argpar_parse_ret.error) {
-               BT_CLI_LOGE_APPEND_CAUSE(
-                       "While parsing command-line arguments: %s",
-                       argpar_parse_ret.error->str);
+       argpar_iter = argpar_iter_create(top_level_argc, top_level_argv, descrs);
+       if (!argpar_iter) {
+               BT_CLI_LOGE_APPEND_CAUSE_OOM();
                goto error;
        }
 
-       for (i = 0; i < argpar_parse_ret.items->len; i++) {
-               struct bt_argpar_item *item;
+       while (true) {
+               enum argpar_iter_next_status status;
 
-               item = g_ptr_array_index(argpar_parse_ret.items, i);
+               ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
+               status = argpar_iter_next(argpar_iter, &argpar_item, &argpar_error);
 
-               if (item->type == BT_ARGPAR_ITEM_TYPE_OPT) {
-                       struct bt_argpar_item_opt *item_opt =
-                               (struct bt_argpar_item_opt *) item;
+               switch (status) {
+               case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
+                       BT_CLI_LOGE_APPEND_CAUSE_OOM();
+                       goto error;
+               case ARGPAR_ITER_NEXT_STATUS_ERROR:
+               {
+                       if (argpar_error_type(argpar_error)
+                                       != ARGPAR_ERROR_TYPE_UNKNOWN_OPT) {
+                               GString *err_str = format_arg_error(argpar_error, top_level_argv,
+                                       "While parsing command-line arguments");
+                               BT_CLI_LOGE_APPEND_CAUSE("%s", err_str->str);
+                               g_string_free(err_str, TRUE);
+                               goto error;
+                       }
 
-                       switch (item_opt->descr->id) {
-                               case OPT_DEBUG:
-                                       default_log_level =
-                                               logging_level_min(default_log_level, BT_LOG_TRACE);
-                                       break;
-                               case OPT_VERBOSE:
-                                       default_log_level =
-                                               logging_level_min(default_log_level, BT_LOG_INFO);
-                                       break;
-                               case OPT_LOG_LEVEL:
-                               {
-                                       int level = bt_log_get_level_from_string(item_opt->arg);
+                       break;
+               }
+               default:
+                       break;
+               }
 
-                                       if (level < 0) {
-                                               BT_CLI_LOGE_APPEND_CAUSE(
-                                                       "Invalid argument for --log-level option:\n    %s",
-                                                       item_opt->arg);
-                                               goto error;
-                                       }
+               if (status == ARGPAR_ITER_NEXT_STATUS_END) {
+                       break;
+               }
 
-                                       default_log_level =
-                                               logging_level_min(default_log_level, level);
-                                       break;
+               if (status == ARGPAR_ITER_NEXT_STATUS_ERROR) {
+                       BT_ASSERT(argpar_error_type(argpar_error) ==
+                               ARGPAR_ERROR_TYPE_UNKNOWN_OPT);
+                       /*
+                        * Unknown option, assume this is implicitly the
+                        * convert command, stop processing arguments.
+                        */
+                       break;
+               }
+
+               if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_opt_descr *opt_descr =
+                               argpar_item_opt_descr(argpar_item);
+                       const char *arg = argpar_item_opt_arg(argpar_item);
+
+                       switch (opt_descr->id) {
+                       case OPT_DEBUG:
+                               default_log_level =
+                                       logging_level_min(default_log_level, BT_LOG_TRACE);
+                               break;
+                       case OPT_VERBOSE:
+                               default_log_level =
+                                       logging_level_min(default_log_level, BT_LOG_INFO);
+                               break;
+                       case OPT_LOG_LEVEL:
+                       {
+                               int level = bt_log_get_level_from_string(arg);
+
+                               if (level < 0) {
+                                       BT_CLI_LOGE_APPEND_CAUSE(
+                                               "Invalid argument for --log-level option:\n    %s",
+                                               arg);
+                                       goto error;
                                }
-                               case OPT_PLUGIN_PATH:
-                                       if (bt_config_append_plugin_paths_check_setuid_setgid(
-                                                       plugin_paths, item_opt->arg)) {
-                                               goto error;
-                                       }
-                                       break;
-                               case OPT_OMIT_SYSTEM_PLUGIN_PATH:
-                                       omit_system_plugin_path = true;
-                                       break;
-                               case OPT_OMIT_HOME_PLUGIN_PATH:
-                                       omit_home_plugin_path = true;
-                                       break;
-                               case OPT_VERSION:
-                                       print_version();
-                                       goto end;
-                               case OPT_HELP:
-                                       print_gen_usage(stdout);
-                                       goto end;
+
+                               default_log_level =
+                                       logging_level_min(default_log_level, level);
+                               break;
                        }
-               } else if (item->type == BT_ARGPAR_ITEM_TYPE_NON_OPT) {
-                       struct bt_argpar_item_non_opt *item_non_opt =
-                               (struct bt_argpar_item_non_opt *) item;
+                       case OPT_PLUGIN_PATH:
+                               if (bt_config_append_plugin_paths_check_setuid_setgid(
+                                               plugin_paths, arg)) {
+                                       goto error;
+                               }
+                               break;
+                       case OPT_OMIT_SYSTEM_PLUGIN_PATH:
+                               omit_system_plugin_path = true;
+                               break;
+                       case OPT_OMIT_HOME_PLUGIN_PATH:
+                               omit_home_plugin_path = true;
+                               break;
+                       case OPT_VERSION:
+                               print_version();
+                               goto end;
+                       case OPT_HELP:
+                               print_gen_usage(stdout);
+                               goto end;
+                       default:
+                               bt_common_abort();
+                       }
+               } else {
+                       const char *arg = argpar_item_non_opt_arg(argpar_item);
+                       unsigned int orig_index = argpar_item_non_opt_orig_index(argpar_item);
+
                        /*
                         * First unknown argument: is it a known command
                         * name?
                         */
-                       command_argc =
-                               top_level_argc - item_non_opt->orig_index - 1;
-                       command_argv =
-                               &top_level_argv[item_non_opt->orig_index + 1];
+                       command_argc = top_level_argc - orig_index - 1;
+                       command_argv = &top_level_argv[orig_index + 1];
 
-                       if (strcmp(item_non_opt->arg, "convert") == 0) {
+                       if (strcmp(arg, "convert") == 0) {
                                command_type = COMMAND_TYPE_CONVERT;
-                       } else if (strcmp(item_non_opt->arg, "list-plugins") == 0) {
+                               command_name = "convert";
+                       } else if (strcmp(arg, "list-plugins") == 0) {
                                command_type = COMMAND_TYPE_LIST_PLUGINS;
-                       } else if (strcmp(item_non_opt->arg, "help") == 0) {
+                               command_name = "list-plugins";
+                       } else if (strcmp(arg, "help") == 0) {
                                command_type = COMMAND_TYPE_HELP;
-                       } else if (strcmp(item_non_opt->arg, "query") == 0) {
+                               command_name = "help";
+                       } else if (strcmp(arg, "query") == 0) {
                                command_type = COMMAND_TYPE_QUERY;
-                       } else if (strcmp(item_non_opt->arg, "run") == 0) {
+                               command_name = "query";
+                       } else if (strcmp(arg, "run") == 0) {
                                command_type = COMMAND_TYPE_RUN;
+                               command_name = "run";
                        } else {
                                /*
                                 * Non-option argument, but not a known
@@ -4647,12 +4853,16 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                                command_argc++;
                                command_argv--;
                        }
+
+                       /* Stop processing arguments. */
                        break;
                }
        }
 
        if (command_type == COMMAND_TYPE_NONE) {
-               if (argpar_parse_ret.ingested_orig_args == top_level_argc) {
+               unsigned int ingested_orig_args = argpar_iter_ingested_orig_args(argpar_iter);
+
+               if (ingested_orig_args == top_level_argc) {
                        /*
                         * We only got non-help, non-version general options
                         * like --verbose and --debug, without any other
@@ -4669,10 +4879,8 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                 */
                command_type = COMMAND_TYPE_CONVERT;
                command_name = "convert";
-               command_argc =
-                       top_level_argc - argpar_parse_ret.ingested_orig_args;
-               command_argv =
-                       &top_level_argv[argpar_parse_ret.ingested_orig_args];
+               command_argc = top_level_argc - ingested_orig_args;
+               command_argv = &top_level_argv[ingested_orig_args];
        }
 
        BT_ASSERT(command_argv);
@@ -4728,7 +4936,7 @@ struct bt_config *bt_config_cli_args_create(int argc, const char *argv[],
                        default_log_level);
                break;
        default:
-               abort();
+               bt_common_abort();
        }
 
        if (config) {
@@ -4743,7 +4951,9 @@ error:
        *retcode = 1;
 
 end:
-       bt_argpar_parse_ret_fini(&argpar_parse_ret);
+       argpar_error_destroy(argpar_error);
+       argpar_item_destroy(argpar_item);
+       argpar_iter_destroy(argpar_iter);
        bt_value_put_ref(plugin_paths);
        return config;
 }
This page took 0.042551 seconds and 4 git commands to generate.