2 * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
4 * SPDX-License-Identifier: GPL-2.0-only
8 #include "argpar-utils.hpp"
10 #include <common/error.hpp>
11 #include <common/string-utils/string-utils.hpp>
16 * Given argpar error status `status` and error `error`, return a formatted
17 * error message describing the error.
19 * `argv` is the argument vector that was being parsed.
21 * `context_fmt`, if non-NULL, is formatted using `args` and prepended to the
24 * Add `argc_offset` the the argument index mentioned in the error message.
26 * The returned string must be freed by the caller.
28 static ATTR_FORMAT_PRINTF(4, 0) char *format_arg_error_v(const struct argpar_error
*error
,
31 const char *context_fmt
,
35 char *str_ret
= nullptr;
39 ret
= vasprintf(&str
, context_fmt
, args
);
42 * If vasprintf fails, the content of str is undefined,
43 * and we shouldn't try to free it.
49 ret
= strutils_append_str(&str
, ": ");
55 switch (argpar_error_type(error
)) {
56 case ARGPAR_ERROR_TYPE_MISSING_OPT_ARG
:
58 const int orig_index
= argpar_error_orig_index(error
);
59 const char *arg
= argv
[orig_index
];
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
,
73 case ARGPAR_ERROR_TYPE_UNEXPECTED_OPT_ARG
:
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
];
81 ret
= strutils_appendf(&str
,
82 WHILE_PARSING_ARG_N_ARG_FMT
83 "Unexpected argument for option `-%c`",
84 orig_index
+ 1 + argc_offset
,
88 ret
= strutils_appendf(&str
,
89 WHILE_PARSING_ARG_N_ARG_FMT
90 "Unexpected argument for option `--%s`",
91 orig_index
+ 1 + argc_offset
,
102 case ARGPAR_ERROR_TYPE_UNKNOWN_OPT
:
104 int orig_index
= argpar_error_orig_index(error
);
105 const char *unknown_opt
= argpar_error_unknown_opt_name(error
);
107 ret
= strutils_appendf(&str
,
108 WHILE_PARSING_ARG_N_ARG_FMT
"Unknown option `%s`",
109 orig_index
+ 1 + argc_offset
,
131 enum parse_next_item_status
parse_next_item(struct argpar_iter
*iter
,
132 const struct argpar_item
**item
,
135 bool unknown_opt_is_error
,
136 const struct argpar_error
**error_out
,
137 const char *context_fmt
,
140 enum argpar_iter_next_status status
;
141 const struct argpar_error
*error
= nullptr;
142 enum parse_next_item_status ret
;
144 ARGPAR_ITEM_DESTROY_AND_RESET(*item
);
145 status
= argpar_iter_next(iter
, item
, &error
);
148 case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY
:
149 ERR("Failed to get next argpar item.");
150 ret
= PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY
;
152 case ARGPAR_ITER_NEXT_STATUS_ERROR
:
157 if (argpar_error_type(error
) == ARGPAR_ERROR_TYPE_UNKNOWN_OPT
&&
158 !unknown_opt_is_error
) {
159 ret
= PARSE_NEXT_ITEM_STATUS_END
;
163 va_start(args
, context_fmt
);
164 err_str
= format_arg_error_v(error
, argc_offset
, argv
, context_fmt
, args
);
171 ERR("%s", "Failed to format argpar error.");
174 ret
= PARSE_NEXT_ITEM_STATUS_ERROR
;
177 case ARGPAR_ITER_NEXT_STATUS_END
:
178 ret
= PARSE_NEXT_ITEM_STATUS_END
;
180 case ARGPAR_ITER_NEXT_STATUS_OK
:
181 ret
= PARSE_NEXT_ITEM_STATUS_OK
;
188 argpar_error_destroy(*error_out
);
193 argpar_error_destroy(error
);