2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @file ArgumentParser.h
|
|
|
|
* @author apio (cloudapio.eu)
|
|
|
|
* @brief Command-line argument parser.
|
|
|
|
*
|
|
|
|
* @copyright Copyright (c) 2023, the Luna authors.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2023-03-29 16:27:02 +00:00
|
|
|
#pragma once
|
|
|
|
#include <luna/StringView.h>
|
|
|
|
#include <luna/Vector.h>
|
|
|
|
|
2023-04-07 08:40:46 +00:00
|
|
|
namespace os
|
2023-03-29 16:27:02 +00:00
|
|
|
{
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief A simple command-line argument parser.
|
|
|
|
*/
|
2023-04-07 08:40:46 +00:00
|
|
|
class ArgumentParser
|
2023-03-29 19:46:07 +00:00
|
|
|
{
|
2023-04-07 08:40:46 +00:00
|
|
|
public:
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Construct a new ArgumentParser object.
|
|
|
|
*/
|
2023-04-28 14:33:05 +00:00
|
|
|
ArgumentParser();
|
2023-04-19 17:16:45 +00:00
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Add a description for this command-line utility (shown in the help text).
|
|
|
|
*
|
|
|
|
* @param description The description to use.
|
|
|
|
*/
|
2023-04-19 17:16:45 +00:00
|
|
|
void add_description(StringView description);
|
2023-04-07 08:40:46 +00:00
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Register a new positional argument.
|
|
|
|
*
|
|
|
|
* @param out The variable where the argument's value will be stored.
|
|
|
|
* @param name The positional argument's name.
|
|
|
|
* @param fallback The value to use if the user does not provide one.
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
2023-04-07 08:40:46 +00:00
|
|
|
Result<void> add_positional_argument(StringView& out, StringView name, StringView fallback);
|
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Register a new positional argument.
|
|
|
|
*
|
|
|
|
* @param out The variable where the argument's value will be stored.
|
|
|
|
* @param name The positional argument's name.
|
|
|
|
* @param required Whether the user must enter a value for this argument. If this is false and the user does not
|
|
|
|
* enter a value, out will be set to an empty string.
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
|
|
|
Result<void> add_positional_argument(StringView& out, StringView name, bool required);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Register a new switch argument.
|
|
|
|
*
|
|
|
|
* @param out This variable will be set to true if the user provides the switch argument on the command
|
|
|
|
* line.
|
|
|
|
* @param short_flag The short flag to use for this argument, excluding the '-' prefix: an option '-c' would be
|
|
|
|
* passed as 'c'. Can only be a single ASCII character. If you do not wish this argument to have a short flag,
|
|
|
|
* use the space character: ' '.
|
|
|
|
* @param long_flag The long flag to use for this argument, excluding the '--' prefix: an option '--example'
|
|
|
|
* would be passed as 'example'. Can be a string of any length. If you do not wish this argument to have a long
|
|
|
|
* flag, use an empty string: "".
|
|
|
|
* @param help The help text to show for this argument (optional).
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
2023-04-19 17:16:45 +00:00
|
|
|
Result<void> add_switch_argument(bool& out, char short_flag, StringView long_flag, StringView help = {});
|
2023-04-07 08:40:46 +00:00
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Register a new value argument.
|
|
|
|
*
|
|
|
|
* @param out The variable where the argument's value will be stored.
|
|
|
|
* @param short_flag The short flag to use for this argument, excluding the '-' prefix: an option '-c' would be
|
|
|
|
* passed as 'c'. Can only be a single ASCII character. If you do not wish this argument to have a short flag,
|
|
|
|
* use the space character: ' '.
|
|
|
|
* @param long_flag The long flag to use for this argument, excluding the '--' prefix: an option '--example'
|
|
|
|
* would be passed as 'example'. Can be a string of any length. If you do not wish this argument to have a long
|
|
|
|
* flag, use an empty string: "".
|
|
|
|
* @param fallback The value to use if the user uses the argument but does not provide a value. If, however, the
|
|
|
|
* user does not specify this argument at all, out WILL NOT BE MODIFIED!
|
|
|
|
* @param help The help text to show for this argument (optional).
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
2023-04-19 17:16:45 +00:00
|
|
|
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView fallback,
|
|
|
|
StringView help = {});
|
2023-04-07 08:40:46 +00:00
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Register a new value argument.
|
|
|
|
*
|
|
|
|
* @param out The variable where the argument's value will be stored.
|
|
|
|
* @param short_flag The short flag to use for this argument, excluding the '-' prefix: an option '-c' would be
|
|
|
|
* passed as 'c'. Can only be a single ASCII character. If you do not wish this argument to have a short flag,
|
|
|
|
* use the space character: ' '.
|
|
|
|
* @param long_flag The long flag to use for this argument, excluding the '--' prefix: an option '--example'
|
|
|
|
* would be passed as 'example'. Can be a string of any length. If you do not wish this argument to have a long
|
|
|
|
* flag, use an empty string: "".
|
|
|
|
* @param value_required Whether the user is required to pass a value when using this argument. If this is
|
|
|
|
* false and the user does not enter a value along with the argument, out will be set to an empty string. If,
|
|
|
|
* however, the user does not specify this argument at all, out WILL NOT BE MODIFIED!
|
|
|
|
* @param help The help text to show for this argument (optional).
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
|
|
|
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, bool value_required,
|
|
|
|
StringView help = {});
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @brief Set the vector to append extra unregistered positional arguments to, after all
|
|
|
|
* registered positional arguments have been parsed. (If no vector is set, these values will instead be
|
|
|
|
* discarded!)
|
|
|
|
*
|
|
|
|
* @param out The vector of StringViews to use.
|
|
|
|
* @param allow_no_more_flags If set, after starting to append values into the vector, no more flags (switch and
|
|
|
|
* value arguments) will be parsed, and will instead be treated as regular positional arguments, as if '--' had
|
|
|
|
* been specified on the command line.
|
|
|
|
*/
|
2023-05-13 11:22:10 +00:00
|
|
|
void set_vector_argument(Vector<StringView>& out, bool allow_no_more_flags = false);
|
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Parse the given command-line using this ArgumentParser's registered arguments.
|
|
|
|
*
|
|
|
|
* @param argc The argc value passed to main() or luna_main().
|
|
|
|
* @param argv The argv value passed to main() or luna_main().
|
|
|
|
* @return Result<void> Whether the operation succeeded.
|
|
|
|
*/
|
2023-05-13 11:22:10 +00:00
|
|
|
Result<void> parse(int argc, char* const* argv);
|
2023-04-07 08:40:46 +00:00
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief A program's copyright and version information.
|
|
|
|
*/
|
2023-04-28 14:33:05 +00:00
|
|
|
struct ProgramInfo
|
|
|
|
{
|
2023-06-09 20:45:06 +00:00
|
|
|
StringView name; // The program's name.
|
|
|
|
StringView version; // The program's version/release.
|
|
|
|
StringView copyright; // The program's copyright statement.
|
|
|
|
StringView license; // The program's licensing information.
|
|
|
|
StringView authors; // The program's authors (optional).
|
|
|
|
StringView package; // The package the program is a part of (optional).
|
2023-04-28 14:33:05 +00:00
|
|
|
};
|
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Set this program's copyright and version information (shown in the version text).
|
|
|
|
*
|
|
|
|
* @param info The program information to use.
|
|
|
|
*/
|
2023-04-28 14:33:05 +00:00
|
|
|
void add_program_info(ProgramInfo info);
|
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief For programs that are part of the Luna source tree, set the version information using Luna's own
|
|
|
|
* version and copyright info and the program name.
|
|
|
|
*
|
|
|
|
* @param name The program name to show in the version information.
|
|
|
|
*/
|
2023-04-28 14:33:05 +00:00
|
|
|
void add_system_program_info(StringView name);
|
|
|
|
|
2023-06-09 20:45:06 +00:00
|
|
|
/**
|
|
|
|
* @brief Show a short message describing how to find usage information (usually "<program> --help").
|
|
|
|
*
|
|
|
|
* The actual message shown is:
|
|
|
|
* "Try running '<program> --help' for more information." if --help has not been overridden.
|
|
|
|
* "Try running '<program> -h' for more information." if -h has not been overridden.
|
|
|
|
* If both have been overridden, no output is shown.
|
|
|
|
*
|
|
|
|
* Then, the program exits with a non-zero exit code.
|
|
|
|
* This function is designed to be used when the program detects an invalid argument value after parse() has run
|
|
|
|
* successfully.
|
|
|
|
*
|
|
|
|
* @param program_name The program name to show (usually argv[0]).
|
|
|
|
*/
|
2023-05-28 19:57:04 +00:00
|
|
|
void short_usage(StringView program_name);
|
|
|
|
|
2023-04-07 08:40:46 +00:00
|
|
|
private:
|
|
|
|
struct PositionalArgument
|
|
|
|
{
|
|
|
|
StringView* out;
|
|
|
|
StringView name;
|
|
|
|
bool required;
|
|
|
|
StringView fallback;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct SwitchArgument
|
|
|
|
{
|
|
|
|
bool* out;
|
|
|
|
char short_flag;
|
|
|
|
StringView long_flag;
|
2023-04-19 17:16:45 +00:00
|
|
|
StringView help;
|
2023-04-07 08:40:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct ValueArgument
|
|
|
|
{
|
|
|
|
StringView* out;
|
|
|
|
char short_flag;
|
|
|
|
StringView long_flag;
|
|
|
|
bool required;
|
|
|
|
StringView fallback;
|
2023-04-19 17:16:45 +00:00
|
|
|
StringView help;
|
2023-04-07 08:40:46 +00:00
|
|
|
};
|
|
|
|
|
2023-04-19 17:16:45 +00:00
|
|
|
Result<void> usage(StringView program_name);
|
|
|
|
|
2023-04-28 14:33:05 +00:00
|
|
|
void version();
|
|
|
|
|
2023-04-07 08:40:46 +00:00
|
|
|
Vector<PositionalArgument> m_positional_args;
|
|
|
|
Vector<SwitchArgument> m_switch_args;
|
|
|
|
Vector<ValueArgument> m_value_args;
|
2023-05-13 11:22:10 +00:00
|
|
|
Vector<StringView>* m_vector_argument { nullptr };
|
|
|
|
bool m_allow_no_more_flags_after_vector_argument_start { false };
|
2023-04-28 14:33:05 +00:00
|
|
|
ProgramInfo m_program_info;
|
2023-04-19 17:16:45 +00:00
|
|
|
StringView m_description = {};
|
|
|
|
bool m_add_short_help_flag { false };
|
|
|
|
bool m_add_long_help_flag { false };
|
2023-04-28 14:33:05 +00:00
|
|
|
bool m_add_short_version_flag { false };
|
|
|
|
bool m_add_long_version_flag { false };
|
2023-03-29 19:46:07 +00:00
|
|
|
};
|
2023-04-07 08:40:46 +00:00
|
|
|
}
|