Fix: file-descriptor: missing include guards
[lttng-tools.git] / src / common / argpar-utils / argpar-utils.cpp
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.hpp"
9
10 #include <common/error.hpp>
11 #include <common/string-utils/string-utils.hpp>
12
13 #include <stdio.h>
14
15 /*
16 * Given argpar error status `status` and error `error`, return a formatted
17 * error message describing the error.
18 *
19 * `argv` is the argument vector that was being parsed.
20 *
21 * `context_fmt`, if non-NULL, is formatted using `args` and prepended to the
22 * error message.
23 *
24 * Add `argc_offset` the the argument index mentioned in the error message.
25 *
26 * The returned string must be freed by the caller.
27 */
28 static ATTR_FORMAT_PRINTF(4, 0) char *format_arg_error_v(const struct argpar_error *error,
29 int argc_offset,
30 const char **argv,
31 const char *context_fmt,
32 va_list args)
33 {
34 char *str = nullptr;
35 char *str_ret = nullptr;
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 = nullptr;
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 case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG:
57 {
58 const int orig_index = argpar_error_orig_index(error);
59 const char *arg = argv[orig_index];
60
61 ret = strutils_appendf(&str,
62 WHILE_PARSING_ARG_N_ARG_FMT
63 "Missing required argument for option `%s`",
64 orig_index + 1 + argc_offset,
65 argv[orig_index],
66 arg);
67 if (ret < 0) {
68 goto end;
69 }
70
71 break;
72 }
73 case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG:
74 {
75 bool is_short;
76 const struct argpar_opt_descr *descr = argpar_error_opt_descr(error, &is_short);
77 int orig_index = argpar_error_orig_index(error);
78 const char *arg = argv[orig_index];
79
80 if (is_short) {
81 ret = strutils_appendf(&str,
82 WHILE_PARSING_ARG_N_ARG_FMT
83 "Unexpected argument for option `-%c`",
84 orig_index + 1 + argc_offset,
85 arg,
86 descr->short_name);
87 } else {
88 ret = strutils_appendf(&str,
89 WHILE_PARSING_ARG_N_ARG_FMT
90 "Unexpected argument for option `--%s`",
91 orig_index + 1 + argc_offset,
92 arg,
93 descr->long_name);
94 }
95
96 if (ret < 0) {
97 goto end;
98 }
99
100 break;
101 }
102 case ARGPAR_ERROR_TYPE_UNKNOWN_OPT:
103 {
104 int orig_index = argpar_error_orig_index(error);
105 const char *unknown_opt = argpar_error_unknown_opt_name(error);
106
107 ret = strutils_appendf(&str,
108 WHILE_PARSING_ARG_N_ARG_FMT "Unknown option `%s`",
109 orig_index + 1 + argc_offset,
110 argv[orig_index],
111 unknown_opt);
112
113 if (ret < 0) {
114 goto end;
115 }
116
117 break;
118 }
119 default:
120 abort();
121 }
122
123 str_ret = str;
124 str = nullptr;
125
126 end:
127 free(str);
128 return str_ret;
129 }
130
131 enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
132 const struct argpar_item **item,
133 int argc_offset,
134 const char **argv,
135 bool unknown_opt_is_error,
136 const struct argpar_error **error_out,
137 const char *context_fmt,
138 ...)
139 {
140 enum argpar_iter_next_status status;
141 const struct argpar_error *error = nullptr;
142 enum parse_next_item_status ret;
143
144 ARGPAR_ITEM_DESTROY_AND_RESET(*item);
145 status = argpar_iter_next(iter, item, &error);
146
147 switch (status) {
148 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
149 ERR("Failed to get next argpar item.");
150 ret = PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY;
151 break;
152 case ARGPAR_ITER_NEXT_STATUS_ERROR:
153 {
154 va_list args;
155 char *err_str;
156
157 if (argpar_error_type(error) == ARGPAR_ERROR_TYPE_UNKNOWN_OPT &&
158 !unknown_opt_is_error) {
159 ret = PARSE_NEXT_ITEM_STATUS_END;
160 break;
161 }
162
163 va_start(args, context_fmt);
164 err_str = format_arg_error_v(error, argc_offset, argv, context_fmt, args);
165 va_end(args);
166
167 if (err_str) {
168 ERR("%s", err_str);
169 free(err_str);
170 } else {
171 ERR("%s", "Failed to format argpar error.");
172 }
173
174 ret = PARSE_NEXT_ITEM_STATUS_ERROR;
175 break;
176 }
177 case ARGPAR_ITER_NEXT_STATUS_END:
178 ret = PARSE_NEXT_ITEM_STATUS_END;
179 break;
180 case ARGPAR_ITER_NEXT_STATUS_OK:
181 ret = PARSE_NEXT_ITEM_STATUS_OK;
182 break;
183 default:
184 abort();
185 }
186
187 if (error_out) {
188 argpar_error_destroy(*error_out);
189 *error_out = error;
190 error = nullptr;
191 }
192
193 argpar_error_destroy(error);
194
195 return ret;
196 }
This page took 0.032472 seconds and 4 git commands to generate.