Argument numbers in add-trigger argument parsing error messages are
wrong. For example:
$ ./src/bin/lttng/lttng add-trigger --condition event-rule-matches --foo
Error: While parsing argument #1 (`--foo`): Unknown option `--foo`
This is due to the fact that multiple separate argpar iterators are
created to parse an add-trigger command line. Iterators are created at
the top-level, to parse the top-level arguments. Iterators are also
created when parsing a condition or an action, to parse the arguments
specific to that condition or action. As a result, iterators are passed
a subset of the full command line, and the argument indices in the error
messages are off.
Fix that by passing around an "argc offset", which represents by how
much what's being parsed is offset from the full command-line. Use that
to adjust the error messages to give indices that make sense to the
user:
$ ./src/bin/lttng/lttng add-trigger --condition event-rule-matches --foo
Error: While parsing argument #4 (`--foo`): Unknown option `--foo`
Change-Id: I1d312593d338641d0ec10abe515b640771a1f160
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
-struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
+struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv,
+ int argc_offset)
{
enum lttng_event_rule_type event_rule_type =
LTTNG_EVENT_RULE_TYPE_UNKNOWN;
{
enum lttng_event_rule_type event_rule_type =
LTTNG_EVENT_RULE_TYPE_UNKNOWN;
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, *argv,
- false, NULL);
+ status = parse_next_item(argpar_iter, &argpar_item,
+ argc_offset, *argv, false, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
-struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
+struct lttng_condition *handle_condition_event(int *argc, const char ***argv,
+ int argc_offset)
{
struct parse_event_rule_res res;
struct lttng_condition *c;
size_t i;
{
struct parse_event_rule_res res;
struct lttng_condition *c;
size_t i;
- res = parse_event_rule(argc, argv);
+ res = parse_event_rule(argc, argv, argc_offset);
if (!res.er) {
c = NULL;
goto error;
if (!res.er) {
c = NULL;
goto error;
struct condition_descr {
const char *name;
struct condition_descr {
const char *name;
- struct lttng_condition *(*handler) (int *argc, const char ***argv);
+ struct lttng_condition *(*handler) (int *argc, const char ***argv,
+ int argc_offset);
static
struct lttng_condition *parse_condition(const char *condition_name, int *argc,
static
struct lttng_condition *parse_condition(const char *condition_name, int *argc,
+ const char ***argv, int argc_offset)
{
int i;
struct lttng_condition *cond;
{
int i;
struct lttng_condition *cond;
- cond = descr->handler(argc, argv);
+ cond = descr->handler(argc, argv, argc_offset);
if (!cond) {
/* The handler has already printed an error message. */
goto error;
if (!cond) {
/* The handler has already printed an error message. */
goto error;
-struct lttng_action *handle_action_notify(int *argc, const char ***argv)
+struct lttng_action *handle_action_notify(int *argc, const char ***argv,
+ int argc_offset)
{
struct lttng_action *action = NULL;
struct argpar_iter *argpar_iter = NULL;
{
struct lttng_action *action = NULL;
struct argpar_iter *argpar_iter = NULL;
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, *argv,
- false, "While parsing `notify` action:");
+ status = parse_next_item(argpar_iter, &argpar_item,
+ argc_offset, *argv, false,
+ "While parsing `notify` action:");
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
static struct lttng_action *handle_action_simple_session_with_policy(int *argc,
const char ***argv,
static struct lttng_action *handle_action_simple_session_with_policy(int *argc,
const char ***argv,
struct lttng_action *(*create_action_cb)(void),
enum lttng_action_status (*set_session_name_cb)(
struct lttng_action *, const char *),
struct lttng_action *(*create_action_cb)(void),
enum lttng_action_status (*set_session_name_cb)(
struct lttng_action *, const char *),
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, *argv,
- false, "While parsing `%s` action:", action_name);
+ status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
+ *argv, false,
+ "While parsing `%s` action:", action_name);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
static
struct lttng_action *handle_action_start_session(int *argc,
static
struct lttng_action *handle_action_start_session(int *argc,
+ const char ***argv, int argc_offset)
{
return handle_action_simple_session_with_policy(argc, argv,
{
return handle_action_simple_session_with_policy(argc, argv,
lttng_action_start_session_create,
lttng_action_start_session_set_session_name,
lttng_action_start_session_set_rate_policy, "start");
lttng_action_start_session_create,
lttng_action_start_session_set_session_name,
lttng_action_start_session_set_rate_policy, "start");
static
struct lttng_action *handle_action_stop_session(int *argc,
static
struct lttng_action *handle_action_stop_session(int *argc,
+ const char ***argv, int argc_offset)
{
return handle_action_simple_session_with_policy(argc, argv,
{
return handle_action_simple_session_with_policy(argc, argv,
lttng_action_stop_session_create,
lttng_action_stop_session_set_session_name,
lttng_action_stop_session_set_rate_policy, "stop");
lttng_action_stop_session_create,
lttng_action_stop_session_set_session_name,
lttng_action_stop_session_set_rate_policy, "stop");
static
struct lttng_action *handle_action_rotate_session(int *argc,
static
struct lttng_action *handle_action_rotate_session(int *argc,
+ const char ***argv, int argc_offset)
{
return handle_action_simple_session_with_policy(argc, argv,
{
return handle_action_simple_session_with_policy(argc, argv,
lttng_action_rotate_session_create,
lttng_action_rotate_session_set_session_name,
lttng_action_rotate_session_set_rate_policy,
lttng_action_rotate_session_create,
lttng_action_rotate_session_set_session_name,
lttng_action_rotate_session_set_rate_policy,
static
struct lttng_action *handle_action_snapshot_session(int *argc,
static
struct lttng_action *handle_action_snapshot_session(int *argc,
+ const char ***argv, int argc_offset)
{
struct lttng_action *action = NULL;
struct argpar_iter *argpar_iter = NULL;
{
struct lttng_action *action = NULL;
struct argpar_iter *argpar_iter = NULL;
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, *argv,
- false, "While parsing `snapshot` action:");
+ status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
+ *argv, false, "While parsing `snapshot` action:");
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
struct action_descr {
const char *name;
struct action_descr {
const char *name;
- struct lttng_action *(*handler) (int *argc, const char ***argv);
+ struct lttng_action *(*handler) (int *argc, const char ***argv,
+ int argc_offset);
-struct lttng_action *parse_action(const char *action_name, int *argc, const char ***argv)
+struct lttng_action *parse_action(const char *action_name, int *argc,
+ const char ***argv, int argc_offset)
{
int i;
struct lttng_action *action;
{
int i;
struct lttng_action *action;
- action = descr->handler(argc, argv);
+ action = descr->handler(argc, argv, argc_offset);
if (!action) {
/* The handler has already printed an error message. */
goto error;
if (!action) {
/* The handler has already printed an error message. */
goto error;
- status = parse_next_item(argpar_iter, &argpar_item, my_argv,
- true, NULL);
+ status = parse_next_item(argpar_iter, &argpar_item,
+ argc - my_argc, my_argv, true, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
- condition = parse_condition(arg, &my_argc, &my_argv);
+ condition = parse_condition(arg, &my_argc, &my_argv,
+ argc - my_argc);
if (!condition) {
/*
* An error message was already printed by
if (!condition) {
/*
* An error message was already printed by
- action = parse_action(arg, &my_argc, &my_argv);
+ action = parse_action(arg, &my_argc, &my_argv,
+ argc - my_argc);
if (!action) {
/*
* An error message was already printed by
if (!action) {
/*
* An error message was already printed by
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, argv,
+ status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
true, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
true, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
while (true) {
enum parse_next_item_status status;
while (true) {
enum parse_next_item_status status;
- status = parse_next_item(argpar_iter, &argpar_item, argv,
+ status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
true, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
true, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
goto error;
* `context_fmt`, if non-NULL, is formatted using `args` and prepended to the
* error message.
*
* `context_fmt`, if non-NULL, is formatted using `args` and prepended to the
* error message.
*
+ * Add `argc_offset` the the argument index mentioned in the error message.
+ *
* The returned string must be freed by the caller.
*/
* The returned string must be freed by the caller.
*/
-static ATTR_FORMAT_PRINTF(3, 0)
-char *format_arg_error_v(const struct argpar_error *error,
+static ATTR_FORMAT_PRINTF(4, 0)
+char *format_arg_error_v(const struct argpar_error *error, int argc_offset,
const char **argv, const char *context_fmt, va_list args)
{
char *str = NULL;
const char **argv, const char *context_fmt, va_list args)
{
char *str = NULL;
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Missing required argument for option `%s`",
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Missing required argument for option `%s`",
- orig_index + 1, arg, arg);
+ orig_index + 1 + argc_offset, argv[orig_index], arg);
if (ret < 0) {
goto end;
}
if (ret < 0) {
goto end;
}
if (is_short) {
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `-%c`",
if (is_short) {
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `-%c`",
- orig_index + 1, arg, descr->short_name);
+ orig_index + 1 + argc_offset, arg, descr->short_name);
} else {
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `--%s`",
} else {
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `--%s`",
- orig_index + 1, arg, descr->long_name);
+ orig_index + 1 + argc_offset, arg, descr->long_name);
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unknown option `%s`",
ret = strutils_appendf(&str,
WHILE_PARSING_ARG_N_ARG_FMT "Unknown option `%s`",
- orig_index + 1, argv[orig_index], unknown_opt);
+ orig_index + 1 + argc_offset, argv[orig_index], unknown_opt);
}
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
}
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
- const struct argpar_item **item, const char **argv,
- bool unknown_opt_is_error, const char *context_fmt, ...)
+ const struct argpar_item **item, int argc_offset,
+ const char **argv, bool unknown_opt_is_error,
+ const char *context_fmt, ...)
{
enum argpar_iter_next_status status;
const struct argpar_error *error = NULL;
{
enum argpar_iter_next_status status;
const struct argpar_error *error = NULL;
}
va_start(args, context_fmt);
}
va_start(args, context_fmt);
- err_str = format_arg_error_v(error, argv, context_fmt, args);
+ err_str = format_arg_error_v(error, argc_offset, argv,
+ context_fmt, args);
va_end(args);
if (err_str) {
va_end(args);
if (err_str) {
* On error, print a descriptive error message and return
* PARSE_NEXT_ITEM_STATUS_ERROR. If `context_fmt` is non-NULL, it is formatted
* using the following arguments and prepended to the error message.
* On error, print a descriptive error message and return
* PARSE_NEXT_ITEM_STATUS_ERROR. If `context_fmt` is non-NULL, it is formatted
* using the following arguments and prepended to the error message.
+ * Add `argc_offset` to the argument index mentioned in the error message.
*
* If `unknown_opt_is_error` is true, an unknown option is considered an error.
* Otherwise, it is considered as the end of the argument list.
*/
*
* If `unknown_opt_is_error` is true, an unknown option is considered an error.
* Otherwise, it is considered as the end of the argument list.
*/
-ATTR_FORMAT_PRINTF(5, 6)
+ATTR_FORMAT_PRINTF(6, 7)
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
- const struct argpar_item **item, const char **argv,
- bool unknown_opt_is_error, const char *context_fmt, ...);
+ const struct argpar_item **item, int argc_offset,
+ const char **argv, bool unknown_opt_is_error,
+ const char *context_fmt, ...);
test_failure "no args" "Error: Missing --condition."
test_failure "unknown option" \
test_failure "no args" "Error: Missing --condition."
test_failure "unknown option" \
- "Error: While parsing argument #1 (\`--hello\`): Unknown option \`--hello\`" \
+ "Error: While parsing argument #2 (\`--hello\`): Unknown option \`--hello\`" \
--hello
test_failure "missing --action" \
--hello
test_failure "missing --action" \
--action notify
test_failure "missing argument to --name" \
--action notify
test_failure "missing argument to --name" \
- "Error: While parsing argument #1 (\`--name\`): Missing required argument for option \`--name\`" \
+ "Error: While parsing argument #2 (\`--name\`): Missing required argument for option \`--name\`" \
--name
for cmd in rate-policy=once-after rate-policy=every; do
--name
for cmd in rate-policy=once-after rate-policy=every; do
# `--condition` failures
test_failure "missing args after --condition" \
# `--condition` failures
test_failure "missing args after --condition" \
- "Error: While parsing argument #1 (\`--condition\`): Missing required argument for option \`--condition\`" \
+ "Error: While parsing argument #2 (\`--condition\`): Missing required argument for option \`--condition\`" \
--condition
test_failure "unknown --condition" \
"Error: Unknown condition name 'zoofest'" \
--condition
test_failure "unknown --condition" \
"Error: Unknown condition name 'zoofest'" \
--action notify
test_failure "--condition event-rule-matches --capture: missing argument (end of arg list)" \
--action notify
test_failure "--condition event-rule-matches --capture: missing argument (end of arg list)" \
- 'Error: While parsing argument #2 (`--capture`): Missing required argument for option `--capture`' \
+ 'Error: While parsing argument #7 (`--capture`): Missing required argument for option `--capture`' \
--action notify \
--condition event-rule-matches --type=user --capture
--action notify \
--condition event-rule-matches --type=user --capture
# `--action` failures
test_failure "missing args after --action" \
# `--action` failures
test_failure "missing args after --action" \
- "Error: While parsing argument #1 (\`--action\`): Missing required argument for option \`--action\`" \
+ "Error: While parsing argument #5 (\`--action\`): Missing required argument for option \`--action\`" \
--condition event-rule-matches --type=user \
--action
--condition event-rule-matches --type=user \
--action