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