lttng: fix argument numbers in add-trigger error messages
[lttng-tools.git] / src / common / argpar-utils / argpar-utils.c
1 /*
2 * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "argpar-utils.h"
9
10 #include <stdio.h>
11
12 #include <common/error.h>
13 #include <common/string-utils/string-utils.h>
14
15 #define WHILE_PARSING_ARG_N_ARG_FMT "While parsing argument #%d (`%s`): "
16
17 /*
18 * Given argpar error status `status` and error `error`, return a formatted
19 * error message describing the error.
20 *
21 * `argv` is the argument vector that was being parsed.
22 *
23 * `context_fmt`, if non-NULL, is formatted using `args` and prepended to the
24 * error message.
25 *
26 * Add `argc_offset` the the argument index mentioned in the error message.
27 *
28 * The returned string must be freed by the caller.
29 */
30 static
31 char *format_arg_error_v(const struct argpar_error *error, int argc_offset,
32 const char **argv, const char *context_fmt, va_list args)
33 {
34 char *str = NULL;
35 char *str_ret = NULL;
36 int ret;
37
38 if (context_fmt) {
39 ret = vasprintf(&str, context_fmt, args);
40 if (ret == -1) {
41 /*
42 * If vasprintf fails, the content of str is undefined,
43 * and we shouldn't try to free it.
44 */
45 str = NULL;
46 goto end;
47 }
48
49 ret = strutils_append_str(&str, ": ");
50 if (ret < 0) {
51 goto end;
52 }
53 }
54
55 switch (argpar_error_type(error))
56 {
57 case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG:
58 {
59 int orig_index = argpar_error_orig_index(error);
60 const char *arg = argv[orig_index];
61
62 ret = strutils_appendf(&str,
63 WHILE_PARSING_ARG_N_ARG_FMT "Missing required argument for option `%s`",
64 orig_index + 1 + argc_offset, argv[orig_index], arg);
65 if (ret < 0) {
66 goto end;
67 }
68
69 break;
70 }
71 case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG:
72 {
73 bool is_short;
74 const struct argpar_opt_descr *descr =
75 argpar_error_opt_descr(error, &is_short);
76 int orig_index = argpar_error_orig_index(error);
77 const char *arg = argv[orig_index];
78
79 if (is_short) {
80 ret = strutils_appendf(&str,
81 WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `-%c`",
82 orig_index + 1 + argc_offset, arg, descr->short_name);
83 } else {
84 ret = strutils_appendf(&str,
85 WHILE_PARSING_ARG_N_ARG_FMT "Unexpected argument for option `--%s`",
86 orig_index + 1 + argc_offset, arg, descr->long_name);
87 }
88
89 if (ret < 0) {
90 goto end;
91 }
92
93 break;
94 }
95 case ARGPAR_ERROR_TYPE_UNKNOWN_OPT:
96 {
97 int orig_index = argpar_error_orig_index(error);
98 const char *unknown_opt = argpar_error_unknown_opt_name(error);
99
100 ret = strutils_appendf(&str,
101 WHILE_PARSING_ARG_N_ARG_FMT "Unknown option `%s`",
102 orig_index + 1 + argc_offset, argv[orig_index], unknown_opt);
103
104 if (ret < 0) {
105 goto end;
106 }
107
108 break;
109 }
110 default:
111 abort ();
112 }
113
114 str_ret = str;
115 str = NULL;
116
117 end:
118 free(str);
119 return str_ret;
120 }
121
122 LTTNG_HIDDEN
123 enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
124 const struct argpar_item **item, int argc_offset,
125 const char **argv, bool unknown_opt_is_error,
126 const char *context_fmt, ...)
127 {
128 enum argpar_iter_next_status status;
129 const struct argpar_error *error = NULL;
130 enum parse_next_item_status ret;
131
132 ARGPAR_ITEM_DESTROY_AND_RESET(*item);
133 status = argpar_iter_next(iter, item, &error);
134
135 switch (status) {
136 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
137 ERR("Failed to get next argpar item.");
138 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
139 break;
140 case ARGPAR_ITER_NEXT_STATUS_ERROR:
141 {
142 va_list args;
143 char *err_str;
144
145 if (argpar_error_type(error) == ARGPAR_ERROR_TYPE_UNKNOWN_OPT &&
146 !unknown_opt_is_error) {
147 ret = PARSE_NEXT_ITEM_STATUS_END;
148 break;
149 }
150
151 va_start(args, context_fmt);
152 err_str = format_arg_error_v(error, argc_offset, argv,
153 context_fmt, args);
154 va_end(args);
155
156 if (err_str) {
157 ERR("%s", err_str);
158 free(err_str);
159 } else {
160 ERR("%s", "Failed to format argpar error.");
161 }
162
163 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
164 break;
165 }
166 case ARGPAR_ITER_NEXT_STATUS_END:
167 ret = PARSE_NEXT_ITEM_STATUS_END;
168 break;
169 case ARGPAR_ITER_NEXT_STATUS_OK:
170 ret = PARSE_NEXT_ITEM_STATUS_OK;
171 break;
172 default:
173 abort();
174 }
175
176 argpar_error_destroy(error);
177
178 return ret;
179 }
This page took 0.033645 seconds and 4 git commands to generate.