MySQL 9.1.0
Source Code Documentation
arg_handler.h
Go to the documentation of this file.
1/*
2 Copyright (c) 2015, 2024, Oracle and/or its affiliates.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is designed to work with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have either included with
14 the program or referenced in the documentation.
15
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24*/
25
26#ifndef HARNESS_ARG_HANDLER_INCLUDED
27#define HARNESS_ARG_HANDLER_INCLUDED
28
29/** @file
30 * @brief Defining the commandline argument handler class CmdArgHandler
31 *
32 * This file defines the commandline argument handler class CmdArgHandler.
33 */
34
35#include "harness_export.h"
36
37#include <cstdint>
38#include <functional>
39#include <map>
40#include <memory>
41#include <string>
42#include <vector>
43
45 none = 0x01,
46 required = 0x02,
47 optional = 0x03,
48};
49
50/** @brief CmdOption stores information about command line options
51 *
52 * The CmdOption structure stores information about command line options.
53 *
54 */
55struct CmdOption {
56 using ActionFunc = std::function<void(const std::string &)>;
57 using AtEndActionFunc = std::function<void(const std::string &)>;
58 using OptionNames = std::vector<std::string>;
59
61 std::string description;
63 std::string value;
64 std::string metavar;
67 bool required{false};
68
70 OptionNames names_, std::string description_,
71 CmdOptionValueReq value_req_, const std::string metavar_,
72 ActionFunc action_,
73 AtEndActionFunc at_end_action_ = [](const std::string &) {})
74 : names(names_),
75 description(description_),
76 value_req(value_req_),
77 metavar(metavar_),
78 action(action_),
79 at_end_action(at_end_action_) {}
80};
81
82/** @brief Definition of a vector holding unique pointers to CmdOption
83 * objects **/
84using OptionContainer = std::vector<CmdOption>;
85
86/** @class CmdArgHandler
87 * @brief Handles command line arguments
88 *
89 * The CmdArgHandler class handles command line arguments. It is a
90 * replacement and supports most of the POSIX GNU getopt library.
91 *
92 * Command line options can have multiple aliases. For example, the
93 * typical `--help` can be also called `-h`, or even `--help-me`. Long
94 * names starting with one dash are not supported.
95 *
96 * Command line options are added through the `add_option()` method
97 * and can be given 1 or more names and a description. It is also
98 * possible to require the option to have a value, or make the value
99 * optional.
100 *
101 * During processing of the command line arguments, actions will be
102 * executed when the option (and it's potential value) was found.
103 *
104 * Usage example:
105 *
106 * #include "arg_handler.h"
107 *
108 * void MyApp::prepare_command_line_options() {
109 * // CmdArgHandler handler_;
110 * handler_.add_option(OptionNames({"-h", "--help", "--sos"}), "Show help
111 * screen", CmdOptionValueReq::none, "", [this](const string &) {
112 * this->show_help(); } handler_.add_option(OptionNames({"--config"}),
113 * "Configuration file", CmdOptionValueReq::none, "", [this](const string
114 * &value) { this->set_config_file(value); },
115 * []{});
116 *
117 * void MyApp::init(const vector<string> arguments) {
118 * prepare_command_line_options();
119 * handler_.process(arguments);
120 * }
121 *
122 * All arguments which are not valid option names are are not values of options
123 * are considered rest arguments. By default, rest arguments are not allowed and
124 * will raise a std::invalid_argument exception. It is possible to allow them
125 * through the constructor.
126 *
127 * The CmdArgHandler class also provides functionality to help creating help
128 * screen or show how to use the the command line application. The method
129 * `usage_lines()` produces a usage line showing all the option names, their
130 * required or optional value with a meta variable. Similar, method
131 * `option_descriptions()` will get all options and their descriptions. All this
132 * is text wrapped at a configurable margin as well as, if needed, indented.
133 *
134 * @internal
135 * The command line argument handling in CmdArgHandler is the bare minimum
136 * needed for MySQL Router. It was needed to make sure that the application
137 * would compile on system where the getopt library is not available.
138 * @endinternal
139 *
140 */
141class HARNESS_EXPORT CmdArgHandler {
142 public:
143 /** @brief Constructor
144 *
145 * @param allow_rest_arguments_ whether we allow rest arguments or not
146 * @param ignore_unknown_arguments_ whether we ignore unknown arguments or
147 * give an error
148 */
149 explicit CmdArgHandler(bool allow_rest_arguments_,
150 bool ignore_unknown_arguments_ = false)
151 : allow_rest_arguments(allow_rest_arguments_),
152 ignore_unknown_arguments(ignore_unknown_arguments_) {}
153
154 /** @brief Default constructor
155 *
156 * By default, rest arguments are not allowed and unknown arguments are not
157 * ignored.
158 */
159 CmdArgHandler() : CmdArgHandler(false, false) {}
160
161 /** @brief Adds a command line option
162 *
163 * Adds a command line option given names, description, value
164 * requirement and optional action.
165 *
166 * `names` is a vector of strings which contains names starting
167 * with either a single or double dash, `-` or `--`. It is possible
168 * to add more than one name for an option.
169 *
170 * The description text will be used in the help output. Note that
171 * this can be a very long as text will be wrapped (and optionally
172 * indented). New lines in the description will be respected.
173 *
174 * The `metavar` argument is used in the usage text as a placeholder
175 * for the (optional) value of the option, for example, when `metavar`
176 * is set to `path`, the usage would show:
177 *
178 * --config=<path>
179 *
180 * The value_req argument should be either:
181 *
182 * * `CmdOptionValueReq::none` : option has no value
183 * * `CmdOptionValueReq::required` : option requires value
184 * * `CmdOptionValueReq::optional` : option has optional value
185 *
186 * The `action` argument should be a `std::function` and is called
187 * with the (optional) value of the option. The function should
188 * accept only a `const std::string`.
189 *
190 * The `at_end_action` argument should be a `std::function`. This is optional
191 * argument, if not provided then []{} is used as at_end_action. The
192 * `at_end_action` is meant to be used for additional validation, if
193 * particular set of options has to be used together, or if particular set of
194 * options cannot be used together.
195 *
196 * Example usage:
197 *
198 * handler_.add_option(OptionNames({"--config"}), "Configuration file",
199 * CmdOptionValueReq::none, "",
200 * [this](const string &value) {
201 * this->set_config_file(value); },
202 * []{});
203 *
204 * @internal
205 * The `add_option` method will assert when `names` is empty,
206 * one of the names is not valid or when a name was already used with
207 * another option.
208 * @endinternal
209 *
210 * @param names vector of string with option names, each starting with - or --
211 * @param description descriptive text explaining the option
212 * @param value_req value requirement of the option
213 * @param metavar for formatting help text when option accepts a value
214 * @param action action to perform when the option was found
215 * @param at_end_action task to perform after all actions have been done
216 */
217 void add_option(
218 const CmdOption::OptionNames &names, const std::string &description,
219 const CmdOptionValueReq &value_req, const std::string &metavar,
221 CmdOption::AtEndActionFunc at_end_action = [](const std::string &) {
222 }) noexcept;
223
224 void add_option(const CmdOption &other) noexcept;
225
226 /** @brief Processes given command line arguments
227 *
228 * Processes given command line argument provided as a vector
229 * of strings. It uses the stored option information added through the
230 * `add_option()` method.
231 *
232 * Typically, the vector passed to process() are the argc and argv
233 * arguments of the main() function:
234 *
235 * process({argv + 1, argv + argc})
236 *
237 * When an option is found which requires an argument, optional or
238 * not, process() will exit the application with an error message.
239 *
240 * If the option has an action defined, the function will be
241 * executed with the (optional) value as argument.
242 *
243 * @param arguments vector of strings
244 */
245 void process(const std::vector<std::string> &arguments);
246
247#ifndef NDEBUG
248 bool debug_check_option_names(const CmdOption::OptionNames &names) const;
249#endif
250
251 /** @brief Checks whether given name is a valid option name
252 *
253 * Checks whether the given name is a valid option name.
254 *
255 * A valid option name should:
256 *
257 * * have at least consist of 2 characters
258 * * start with a dash '-'
259 * * match the reqular expression ^--[A-Za-z]{2}[A-Za-z_-]+$
260 *
261 * It is allowed to use the equal sign when giving value. Following options
262 * are equal:
263 * --config /path/to/mysqlrouter.conf
264 * --config=/path/to/mysqlrouter.conf
265 *
266 * Throws std::invalid_argument when option name is not valid or
267 * option was not registered.
268 *
269 * Examples of valid option names:
270 *
271 * -h
272 * --with-ham
273 * --with_spam
274 *
275 * Example of invalid option names:
276 *
277 * -help
278 * ---spam
279 * --x-ham
280 *
281 * @param name option name to check
282 * @return true if name is valid; false otherwise
283 */
284 bool is_valid_option_name(const std::string &name) const noexcept;
285
286 /** @brief Finds the option by name
287 *
288 * Finds the option by one of its name. The name should include the the dash
289 * prefix.
290 *
291 * Example usage:
292 * // check if option name is already present
293 * assert(end() == find_option(name))
294 *
295 * @param name name of the option as string
296 * @returns iterator object
297 */
298 OptionContainer::const_iterator find_option(
299 const std::string &name) const noexcept;
300
302 std::function<std::pair<bool, CmdOption>(const CmdOption &)>;
303
304 /** @brief Produces lines of text suitable to show usage
305 *
306 * Produces lines of text suitable to show usage of the command line
307 * appliation. Each option is shown with all its names and with optional
308 * or required value.
309 *
310 * The `prefix` argument can be used to add text, usually the name
311 * of the command, in front of the options. The lines are indented
312 * using the size of the prefix.
313 *
314 * The `rest_metavar` can be used to name non-options arguments.
315 *
316 * The `width` argument is used to set the maximum length of the lines.
317 *
318 * Example output when all lines are printed:
319 *
320 * usage: mysqlrouter [-v|--version] [-h|--help] [-c|--config=<path>]
321 * [-a=[<foo>]] [rest..]
322 *
323 *
324 * @param prefix text in front of options (usually command name)
325 * @param rest_metavar name of rest arguments (empty if not needed)
326 * @param width maximum length of each line
327 * @return vector of strings
328 */
329 std::vector<std::string> usage_lines(const std::string &prefix,
330 const std::string &rest_metavar,
331 size_t width) const noexcept {
332 return usage_lines_if(
333 prefix, rest_metavar, width,
334 [](const CmdOption &opt) -> std::pair<bool, CmdOption> {
335 return {true, opt};
336 });
337 }
338
339 std::vector<std::string> usage_lines_if(
340 const std::string &prefix, const std::string &rest_metavar, size_t width,
341 UsagePredicate predicate) const noexcept;
342
343 /** @brief Produces description of all options
344 *
345 * Produces description of all options. The result is typically shown
346 * when the help screen is requested, for example when the `--help`
347 * option is given.
348 *
349 * The `width` argument is used to set the maximum length of the lines. Text
350 * is wrapped accordingly.
351 *
352 * Each description can be indented using space. The amount is given
353 * by `indent` option.
354 *
355 * Example output when lines are printed:
356 *
357 * -v, --version
358 * Show version
359 * -h, --help
360 * Show help
361 * -c <path>, --config <path>
362 * Path to the configuration file
363 *
364 * @param width maximum length of each line
365 * @param indent how much the description should be indented.
366 * @return vector of strings
367 */
368 std::vector<std::string> option_descriptions(
369 const size_t width, const size_t indent) const noexcept;
370
371 /** @brief Returns an iterator to first option
372 *
373 * Returns an iterator to the first option.
374 *
375 * @returns iterator
376 */
377 OptionContainer::const_iterator begin() { return options_.begin(); }
378
379 /** @brief Returns an iterator to end of the option container
380 *
381 * Returns an iterator to the end of the option container.
382 *
383 * @returns iterator
384 */
385 OptionContainer::const_iterator end() { return options_.end(); }
386
387 /** @brief Clears registered options
388 *
389 * Clears the registered options.
390 *
391 */
392 void clear_options() { options_.clear(); }
393
394 /** @brief Gets all registered options
395 *
396 * Returns as a reference to a vector of CmdOption objects.
397 *
398 * @return std::vector<CmdOption>
399 */
400 const std::vector<CmdOption> &get_options() const noexcept {
401 return options_;
402 }
403
404 /** @brief Returns the rest arguments
405 *
406 * Returns the rest arguments.
407 *
408 * If rest arguments are not allow or there were no rest arguments,
409 * an empty vector is returned.
410 *
411 * @return vector of strings
412 */
413 const std::vector<std::string> &get_rest_arguments() const noexcept {
414 return rest_arguments_;
415 }
416
417 /** @brief Whether to allow rest arguments or not **/
419
420 /** @brief Whether to ignore unknown arguments **/
422
423 /** @brief The key is a section identificator (section name and optional
424 * section key), the value is a map of all the overrides for a given section
425 * (option/value pairs) **/
426 using ConfigOverwrites = std::map<std::pair<std::string, std::string>,
427 std::map<std::string, std::string>>;
428 const ConfigOverwrites &get_config_overwrites() const noexcept {
429 return config_overwrites_;
430 }
431
432 private:
433 /** @brief Vector with registered options **/
434 std::vector<CmdOption> options_;
435 /** @brief Vector with arguments as strings not processed as options **/
436 std::vector<std::string> rest_arguments_;
437 /** @brief Keeps configuration options overwrites **/
439};
440
441#endif // HARNESS_ARG_HANDLER_INCLUDED
std::vector< CmdOption > OptionContainer
Definition of a vector holding unique pointers to CmdOption objects.
Definition: arg_handler.h:84
CmdOptionValueReq
Definition: arg_handler.h:44
Handles command line arguments.
Definition: arg_handler.h:141
ConfigOverwrites config_overwrites_
Keeps configuration options overwrites.
Definition: arg_handler.h:438
std::vector< std::string > rest_arguments_
Vector with arguments as strings not processed as options.
Definition: arg_handler.h:436
const std::vector< std::string > & get_rest_arguments() const noexcept
Returns the rest arguments.
Definition: arg_handler.h:413
std::map< std::pair< std::string, std::string >, std::map< std::string, std::string > > ConfigOverwrites
The key is a section identificator (section name and optional section key), the value is a map of all...
Definition: arg_handler.h:427
std::vector< CmdOption > options_
Vector with registered options.
Definition: arg_handler.h:434
void clear_options()
Clears registered options.
Definition: arg_handler.h:392
const ConfigOverwrites & get_config_overwrites() const noexcept
Definition: arg_handler.h:428
OptionContainer::const_iterator begin()
Returns an iterator to first option.
Definition: arg_handler.h:377
bool allow_rest_arguments
Whether to allow rest arguments or not.
Definition: arg_handler.h:418
CmdArgHandler(bool allow_rest_arguments_, bool ignore_unknown_arguments_=false)
Constructor.
Definition: arg_handler.h:149
OptionContainer::const_iterator end()
Returns an iterator to end of the option container.
Definition: arg_handler.h:385
const std::vector< CmdOption > & get_options() const noexcept
Gets all registered options.
Definition: arg_handler.h:400
bool ignore_unknown_arguments
Whether to ignore unknown arguments.
Definition: arg_handler.h:421
std::vector< std::string > usage_lines(const std::string &prefix, const std::string &rest_metavar, size_t width) const noexcept
Produces lines of text suitable to show usage.
Definition: arg_handler.h:329
CmdArgHandler()
Default constructor.
Definition: arg_handler.h:159
std::function< std::pair< bool, CmdOption >(const CmdOption &)> UsagePredicate
Definition: arg_handler.h:302
repeated Action action
Definition: replication_group_member_actions.proto:43
case opt name
Definition: sslopt-case.h:29
CmdOption stores information about command line options.
Definition: arg_handler.h:55
std::function< void(const std::string &)> AtEndActionFunc
Definition: arg_handler.h:57
std::string metavar
Definition: arg_handler.h:64
CmdOptionValueReq value_req
Definition: arg_handler.h:62
CmdOption(OptionNames names_, std::string description_, CmdOptionValueReq value_req_, const std::string metavar_, ActionFunc action_, AtEndActionFunc at_end_action_=[](const std::string &) {})
Definition: arg_handler.h:69
std::function< void(const std::string &)> ActionFunc
Definition: arg_handler.h:56
std::string description
Definition: arg_handler.h:61
std::string value
Definition: arg_handler.h:63
bool required
Definition: arg_handler.h:67
OptionNames names
Definition: arg_handler.h:60
ActionFunc action
Definition: arg_handler.h:65
std::vector< std::string > OptionNames
Definition: arg_handler.h:58
AtEndActionFunc at_end_action
Definition: arg_handler.h:66