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 ATTR_FORMAT_PRINTF(4, 0)
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 const 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 enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
123 const struct argpar_item **item, int argc_offset,
124 const char **argv, bool unknown_opt_is_error,
125 const char *context_fmt, ...)
126 {
127 enum argpar_iter_next_status status;
128 const struct argpar_error *error = NULL;
129 enum parse_next_item_status ret;
130
131 ARGPAR_ITEM_DESTROY_AND_RESET(*item);
132 status = argpar_iter_next(iter, item, &error);
133
134 switch (status) {
135 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
136 ERR("Failed to get next argpar item.");
137 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
138 break;
139 case ARGPAR_ITER_NEXT_STATUS_ERROR:
140 {
141 va_list args;
142 char *err_str;
143
144 if (argpar_error_type(error) == ARGPAR_ERROR_TYPE_UNKNOWN_OPT &&
145 !unknown_opt_is_error) {
146 ret = PARSE_NEXT_ITEM_STATUS_END;
147 break;
148 }
149
150 va_start(args, context_fmt);
151 err_str = format_arg_error_v(error, argc_offset, argv,
152 context_fmt, args);
153 va_end(args);
154
155 if (err_str) {
156 ERR("%s", err_str);
157 free(err_str);
158 } else {
159 ERR("%s", "Failed to format argpar error.");
160 }
161
162 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
163 break;
164 }
165 case ARGPAR_ITER_NEXT_STATUS_END:
166 ret = PARSE_NEXT_ITEM_STATUS_END;
167 break;
168 case ARGPAR_ITER_NEXT_STATUS_OK:
169 ret = PARSE_NEXT_ITEM_STATUS_OK;
170 break;
171 default:
172 abort();
173 }
174
175 argpar_error_destroy(error);
176
177 return ret;
178 }
This page took 0.031938 seconds and 4 git commands to generate.