mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 22:57:44 +00:00
Userland+AK: Stop using getopt() for ArgsParser
This commit moves the implementation of getopt into AK, and converts its API to understand and use StringView instead of char*. Everything else is caught in the crossfire of making Option::accept_value() take a StringView instead of a char const*. With this, we must now pass a Span<StringView> to ArgsParser::parse(), applications using LibMain are unaffected, but anything not using that or taking its own argc/argv has to construct a Vector<StringView> for this method.
This commit is contained in:
parent
b2b851b361
commit
db886fe18b
43 changed files with 673 additions and 584 deletions
|
@ -31,6 +31,11 @@ using Test::Crash;
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Vector<StringView> arguments;
|
||||
arguments.ensure_capacity(argc);
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
arguments.append({ argv[i], strlen(argv[i]) });
|
||||
|
||||
bool do_all_crash_types = false;
|
||||
bool do_segmentation_violation = false;
|
||||
bool do_division_by_zero = false;
|
||||
|
@ -84,11 +89,11 @@ int main(int argc, char** argv)
|
|||
if (argc == 1) {
|
||||
do_all_crash_types = true;
|
||||
} else if (argc != 2) {
|
||||
args_parser.print_usage(stderr, argv[0]);
|
||||
args_parser.print_usage(stderr, arguments[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
args_parser.parse(argc, argv);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
Crash::RunType run_type = do_all_crash_types ? Crash::RunType::UsingChildProcess
|
||||
: Crash::RunType::UsingCurrentProcess;
|
||||
|
|
|
@ -13,6 +13,11 @@
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Vector<StringView> arguments;
|
||||
arguments.ensure_capacity(argc);
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
arguments.append({ argv[i], strlen(argv[i]) });
|
||||
|
||||
char const* target = nullptr;
|
||||
int max_file_size = 1024 * 1024;
|
||||
int count = 1024;
|
||||
|
@ -21,7 +26,7 @@ int main(int argc, char** argv)
|
|||
args_parser.add_option(max_file_size, "Maximum file size to generate", "max-size", 's', "size");
|
||||
args_parser.add_option(count, "Number of truncations to run", "number", 'n', "number");
|
||||
args_parser.add_positional_argument(target, "Target file path", "target");
|
||||
args_parser.parse(argc, argv);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
int fd = creat(target, 0666);
|
||||
if (fd < 0) {
|
||||
|
|
|
@ -60,6 +60,11 @@ bool write_block(int fd, int seed, off_t block, AK::ByteBuffer& buffer)
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Vector<StringView> arguments;
|
||||
arguments.ensure_capacity(argc);
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
arguments.append({ argv[i], strlen(argv[i]) });
|
||||
|
||||
char const* target = nullptr;
|
||||
int min_block_offset = 0;
|
||||
int block_length = 2048;
|
||||
|
@ -82,7 +87,7 @@ int main(int argc, char** argv)
|
|||
args_parser.add_option(stop_mode, "Stop after first error", "abort-on-error", 'a');
|
||||
args_parser.add_option(uninitialized_mode, "Don't pre-initialize block range", "uninitialized", 'u');
|
||||
args_parser.add_positional_argument(target, "Target device/file path", "target");
|
||||
args_parser.parse(argc, argv);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
auto buffer_result = AK::ByteBuffer::create_zeroed(block_size);
|
||||
if (buffer_result.is_error()) {
|
||||
|
|
|
@ -12,68 +12,44 @@
|
|||
|
||||
class ParserResult {
|
||||
public:
|
||||
ParserResult(Vector<DeprecatedString> const& arguments)
|
||||
ParserResult(Vector<StringView> arguments)
|
||||
: arguments(move(arguments))
|
||||
{
|
||||
argv = new char*[arguments.size() + 1];
|
||||
argc = 0;
|
||||
for (auto& argument : arguments) {
|
||||
auto char_argument = new char[argument.length() + 1];
|
||||
memcpy(char_argument, argument.characters(), argument.length());
|
||||
char_argument[argument.length()] = '\0';
|
||||
argv[argc++] = char_argument;
|
||||
}
|
||||
argv[argc] = nullptr;
|
||||
}
|
||||
|
||||
ParserResult(ParserResult&& other)
|
||||
{
|
||||
arguments = move(other.arguments);
|
||||
result = other.result;
|
||||
argv = other.argv;
|
||||
argc = other.argc;
|
||||
|
||||
other.argv = nullptr;
|
||||
other.argc = 0;
|
||||
}
|
||||
|
||||
ParserResult& operator=(ParserResult&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
arguments = move(other.arguments);
|
||||
result = other.result;
|
||||
argv = other.argv;
|
||||
argc = other.argc;
|
||||
|
||||
other.argv = nullptr;
|
||||
other.argc = 0;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ParserResult()
|
||||
{
|
||||
for (size_t i = 0; i < argc; ++i)
|
||||
delete[] argv[i];
|
||||
delete[] argv;
|
||||
}
|
||||
|
||||
Vector<StringView> arguments;
|
||||
bool result { false };
|
||||
char** argv { nullptr };
|
||||
size_t argc { 0 };
|
||||
};
|
||||
|
||||
static ParserResult run_parser(Vector<DeprecatedString> arguments, Function<void(Core::ArgsParser&)> parser_initialization = {})
|
||||
static ParserResult run_parser(Vector<StringView> arguments, Function<void(Core::ArgsParser&)> parser_initialization = {})
|
||||
{
|
||||
Core::ArgsParser parser;
|
||||
if (parser_initialization)
|
||||
parser_initialization(parser);
|
||||
|
||||
auto parse_result = ParserResult { arguments };
|
||||
parse_result.result = parser.parse(parse_result.argc, parse_result.argv, Core::ArgsParser::FailureBehavior::Ignore);
|
||||
auto parse_result = ParserResult { move(arguments) };
|
||||
parse_result.result = parser.parse(parse_result.arguments, Core::ArgsParser::FailureBehavior::Ignore);
|
||||
return parse_result;
|
||||
}
|
||||
|
||||
TEST_CASE(no_arguments)
|
||||
{
|
||||
auto parser_result = run_parser({ "app" });
|
||||
auto parser_result = run_parser({ "app"sv });
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
}
|
||||
|
||||
|
@ -81,7 +57,7 @@ TEST_CASE(bool_option)
|
|||
{
|
||||
// Short option
|
||||
bool force = false;
|
||||
auto parser_result = run_parser({ "app", "-f" }, [&](auto& parser) {
|
||||
auto parser_result = run_parser({ "app"sv, "-f"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", nullptr, 'f');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -89,7 +65,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Short option, not given
|
||||
force = false;
|
||||
parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", nullptr, 'f');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -97,7 +73,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Long option
|
||||
force = false;
|
||||
parser_result = run_parser({ "app", "--force" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "--force"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", "force", '\0');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -105,7 +81,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Long option, not given
|
||||
force = false;
|
||||
parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", "force", '\0');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -113,7 +89,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Allow both short and long option, provide short
|
||||
force = false;
|
||||
parser_result = run_parser({ "app", "-f" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-f"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", "force", 'f');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -121,7 +97,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Allow both short and long option, provide long
|
||||
force = false;
|
||||
parser_result = run_parser({ "app", "--force" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "--force"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", "force", 'f');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -129,7 +105,7 @@ TEST_CASE(bool_option)
|
|||
|
||||
// Allow both short and long option, provide both
|
||||
force = false;
|
||||
parser_result = run_parser({ "app", "--force", "-f" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "--force"sv, "-f"sv }, [&](auto& parser) {
|
||||
parser.add_option(force, "force", "force", 'f');
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -140,7 +116,7 @@ TEST_CASE(positional_string_argument)
|
|||
{
|
||||
// Single required string argument
|
||||
DeprecatedString name = "";
|
||||
auto parser_result = run_parser({ "app", "buggie" }, [&](auto& parser) {
|
||||
auto parser_result = run_parser({ "app"sv, "buggie"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -148,7 +124,7 @@ TEST_CASE(positional_string_argument)
|
|||
|
||||
// Single required string argument, not given
|
||||
name = "";
|
||||
parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, false);
|
||||
|
@ -156,7 +132,7 @@ TEST_CASE(positional_string_argument)
|
|||
|
||||
// Single optional string argument
|
||||
name = "";
|
||||
parser_result = run_parser({ "app", "buggie" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "buggie"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::No);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -164,7 +140,7 @@ TEST_CASE(positional_string_argument)
|
|||
|
||||
// Single optional string argument, not given
|
||||
name = "";
|
||||
parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(name, "name", "name", Core::ArgsParser::Required::No);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -176,7 +152,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
Vector<StringView> values;
|
||||
|
||||
// Zero or more positional arguments, zero given
|
||||
auto parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
auto parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -184,7 +160,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
|
||||
// Zero or more positional arguments, one given
|
||||
values = {};
|
||||
parser_result = run_parser({ "app", "one" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "one"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -194,7 +170,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
|
||||
// Zero or more positional arguments, two given
|
||||
values = {};
|
||||
parser_result = run_parser({ "app", "one", "two" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::No);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -206,7 +182,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
|
||||
// One or more positional arguments, zero given
|
||||
values = {};
|
||||
parser_result = run_parser({ "app" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, false);
|
||||
|
@ -214,7 +190,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
|
||||
// One or more positional arguments, one given
|
||||
values = {};
|
||||
parser_result = run_parser({ "app", "one" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "one"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -224,7 +200,7 @@ TEST_CASE(positional_vector_string_argument)
|
|||
|
||||
// One or more positional arguments, two given
|
||||
values = {};
|
||||
parser_result = run_parser({ "app", "one", "two" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
|
||||
parser.add_positional_argument(values, "values", "values", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result.result, true);
|
||||
|
@ -242,7 +218,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
// Expected: all arguments fill as given
|
||||
bool bool_opt1 = false;
|
||||
bool bool_opt2 = false;
|
||||
auto parser_result = run_parser({ "app", "-b", "-c", "one", "two" }, [&](auto& parser) {
|
||||
auto parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv, "two"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -261,7 +237,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "one", "two" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "one"sv, "two"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -280,7 +256,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -295,7 +271,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "--", "-b", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "--"sv, "-b"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -314,7 +290,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "--", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "--"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -332,7 +308,7 @@ TEST_CASE(combination_of_bool_options_with_positional_vector_string)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "-d", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "-d"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::No);
|
||||
|
@ -347,7 +323,7 @@ TEST_CASE(stop_on_first_non_option)
|
|||
bool bool_opt1 = false;
|
||||
bool bool_opt2 = false;
|
||||
Vector<StringView> positionals;
|
||||
auto parser_result = run_parser({ "app", "-b", "-c", "one" }, [&](auto& parser) {
|
||||
auto parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv }, [&](auto& parser) {
|
||||
parser.set_stop_on_first_non_option(false);
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
|
@ -365,7 +341,7 @@ TEST_CASE(stop_on_first_non_option)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "one", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "one"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.set_stop_on_first_non_option(false);
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
|
@ -383,7 +359,7 @@ TEST_CASE(stop_on_first_non_option)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "-c", "one" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "-c"sv, "one"sv }, [&](auto& parser) {
|
||||
parser.set_stop_on_first_non_option(true);
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
|
@ -401,7 +377,7 @@ TEST_CASE(stop_on_first_non_option)
|
|||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
parser_result = run_parser({ "app", "-b", "one", "-c" }, [&](auto& parser) {
|
||||
parser_result = run_parser({ "app"sv, "-b"sv, "one"sv, "-c"sv }, [&](auto& parser) {
|
||||
parser.set_stop_on_first_non_option(true);
|
||||
parser.add_option(bool_opt1, "bool_opt1", nullptr, 'b');
|
||||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
|
|
|
@ -589,6 +589,11 @@ constexpr int exit_read_file_failure = 3;
|
|||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
Vector<StringView> arguments;
|
||||
arguments.ensure_capacity(argc);
|
||||
for (auto i = 0; i < argc; ++i)
|
||||
arguments.append({ argv[i], strlen(argv[i]) });
|
||||
|
||||
int timeout = 10;
|
||||
bool enable_debug_printing = false;
|
||||
bool disable_core_dumping = false;
|
||||
|
@ -602,7 +607,7 @@ int main(int argc, char** argv)
|
|||
args_parser.add_option(timeout, "Seconds before test should timeout", "timeout", 't', "seconds");
|
||||
args_parser.add_option(enable_debug_printing, "Enable debug printing", "debug", 'd');
|
||||
args_parser.add_option(disable_core_dumping, "Disable core dumping", "disable-core-dump", 0);
|
||||
args_parser.parse(argc, argv);
|
||||
args_parser.parse(arguments);
|
||||
|
||||
#if !defined(AK_OS_MACOS) && !defined(AK_OS_EMSCRIPTEN)
|
||||
if (disable_core_dumping && prctl(PR_SET_DUMPABLE, 0, 0) < 0) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue