libos: Make long value arguments use '=' and make value arguments' values always required
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
266fa4a0d4
commit
2f08e0f5b0
@ -11,8 +11,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Display the current (or another) date and time."_sv);
|
||||
parser.add_system_program_info("date"_sv);
|
||||
parser.add_value_argument(date, 'd', "date"_sv, true,
|
||||
"the UNIX timestamp to display instead of the current time"_sv);
|
||||
parser.add_value_argument(date, 'd', "date"_sv, "the UNIX timestamp to display instead of the current time"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
time_t now;
|
||||
|
@ -96,7 +96,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
"follow symbolic links listed as arguments"_sv);
|
||||
parser.add_switch_argument(one_per_line, '1', ""_sv, "list one file per line"_sv);
|
||||
parser.add_switch_argument(list_directories, 'd', "directory"_sv, "list directories instead of their contents"_sv);
|
||||
parser.add_value_argument(sort_type, ' ', "sort"_sv, true, "sort by name, size or time"_sv);
|
||||
parser.add_value_argument(sort_type, ' ', "sort"_sv, "sort by name, size or time"_sv);
|
||||
parser.add_switch_argument(reverse_sort, 'r', "reverse"_sv, "reverse order while sorting"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
|
@ -41,7 +41,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
parser.add_description("Create directories."_sv);
|
||||
parser.add_system_program_info("mkdir"_sv);
|
||||
parser.add_positional_argument(path, "path"_sv, true);
|
||||
parser.add_value_argument(mode_string, 'm', "mode"_sv, true, "set the mode for the newly created directory");
|
||||
parser.add_value_argument(mode_string, 'm', "mode"_sv, "set the mode for the newly created directory");
|
||||
parser.add_switch_argument(recursive, 'p', "parents"_sv,
|
||||
"if parent directories do not exist, create them as well"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
@ -5,13 +5,13 @@
|
||||
Result<int> luna_main(int argc, char** argv)
|
||||
{
|
||||
StringView target;
|
||||
StringView fstype;
|
||||
StringView fstype { "auto" };
|
||||
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("Mount a file system.");
|
||||
parser.add_system_program_info("mount"_sv);
|
||||
parser.add_positional_argument(target, "mountpoint"_sv, true);
|
||||
parser.add_value_argument(fstype, 't', "type"_sv, "auto"_sv, "the file system type to use");
|
||||
parser.add_value_argument(fstype, 't', "type"_sv, "the file system type to use");
|
||||
parser.parse(argc, argv);
|
||||
|
||||
if (mount(target.chars(), fstype.chars()) < 0)
|
||||
|
@ -48,7 +48,7 @@ Result<int> luna_main(int argc, char** argv)
|
||||
parser.add_description("The Luna system's command shell."_sv);
|
||||
parser.add_system_program_info("sh"_sv);
|
||||
parser.add_positional_argument(path, "path"_sv, "-"_sv);
|
||||
parser.add_value_argument(command, 'c', "command"_sv, true, "execute a single command and then exit"_sv);
|
||||
parser.add_value_argument(command, 'c', "command"_sv, "execute a single command and then exit"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
if (!command.is_empty()) TRY(execute_command(command));
|
||||
|
@ -40,8 +40,8 @@ int main(int argc, char** argv)
|
||||
os::ArgumentParser parser;
|
||||
parser.add_description("System call fuzzer (invokes system calls with random arguments to test system stability)");
|
||||
parser.add_system_program_info("sysfuzz"_sv);
|
||||
parser.add_value_argument(times_sv, 't', "times"_sv, true, "the number of syscalls to invoke"_sv);
|
||||
parser.add_value_argument(interval_sv, 'i', "interval"_sv, true,
|
||||
parser.add_value_argument(times_sv, 't', "times"_sv, "the number of syscalls to invoke"_sv);
|
||||
parser.add_value_argument(interval_sv, 'i', "interval"_sv,
|
||||
"the interval between system calls (in milliseconds)"_sv);
|
||||
parser.parse(argc, argv);
|
||||
|
||||
|
@ -42,6 +42,9 @@ class StringView
|
||||
|
||||
Result<Vector<String>> split(StringView delim) const;
|
||||
Result<Vector<String>> split_once(char delim) const;
|
||||
Result<Vector<StringView>> split_view(char delim) const;
|
||||
|
||||
bool contains(char v) const;
|
||||
|
||||
static StringView from_fixed_size_cstring(const char* string, usize max);
|
||||
|
||||
|
@ -50,12 +50,12 @@ const char& StringView::operator[](usize index) const
|
||||
|
||||
bool StringView::operator==(const char* other) const
|
||||
{
|
||||
return !strcmp(m_string, other);
|
||||
return !strncmp(m_string, other, m_length);
|
||||
}
|
||||
|
||||
bool StringView::operator==(StringView other) const
|
||||
{
|
||||
return !strcmp(m_string, other.m_string);
|
||||
return !strncmp(m_string, other.m_string, m_length);
|
||||
}
|
||||
|
||||
Result<Vector<String>> StringView::split(StringView delim) const
|
||||
@ -110,6 +110,32 @@ Result<Vector<String>> StringView::split_once(char delim) const
|
||||
return result;
|
||||
}
|
||||
|
||||
Result<Vector<StringView>> StringView::split_view(char delim) const
|
||||
{
|
||||
Vector<StringView> result;
|
||||
|
||||
char* middle = strchr(m_string, delim);
|
||||
if (!middle)
|
||||
{
|
||||
TRY(result.try_append(*this));
|
||||
return result;
|
||||
}
|
||||
|
||||
// begin will not contain a null terminator.
|
||||
auto begin = StringView::from_fixed_size_cstring(m_string, middle - m_string);
|
||||
auto end = StringView { middle + 1 };
|
||||
|
||||
TRY(result.try_append(begin));
|
||||
TRY(result.try_append(end));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringView::contains(char v) const
|
||||
{
|
||||
return strchr(m_string, v);
|
||||
}
|
||||
|
||||
Result<usize> StringView::to_uint() const
|
||||
{
|
||||
const char* endptr = nullptr;
|
||||
|
@ -78,32 +78,10 @@ namespace os
|
||||
* @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.
|
||||
*/
|
||||
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView fallback,
|
||||
StringView help = {});
|
||||
|
||||
/**
|
||||
* @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 = {});
|
||||
Result<void> add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView help = {});
|
||||
|
||||
/**
|
||||
* @brief Set the vector to append extra unregistered positional arguments to, after all
|
||||
@ -192,8 +170,6 @@ namespace os
|
||||
StringView* out;
|
||||
char short_flag;
|
||||
StringView long_flag;
|
||||
bool required;
|
||||
StringView fallback;
|
||||
StringView help;
|
||||
};
|
||||
|
||||
|
@ -8,6 +8,7 @@
|
||||
*/
|
||||
|
||||
#include <luna/StringBuilder.h>
|
||||
#include <luna/TypeTraits.h>
|
||||
#include <os/ArgumentParser.h>
|
||||
#include <os/File.h>
|
||||
#include <stdio.h>
|
||||
@ -52,22 +53,9 @@ namespace os
|
||||
}
|
||||
|
||||
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
|
||||
bool value_required, StringView help)
|
||||
StringView help)
|
||||
{
|
||||
ValueArgument arg { &out, short_flag, long_flag, value_required, {}, help };
|
||||
|
||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||
if (short_flag == 'v') m_add_short_version_flag = false;
|
||||
if (long_flag == "version"_sv) m_add_long_version_flag = false;
|
||||
|
||||
return m_value_args.try_append(move(arg));
|
||||
}
|
||||
|
||||
Result<void> ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag,
|
||||
StringView fallback, StringView help)
|
||||
{
|
||||
ValueArgument arg { &out, short_flag, long_flag, false, fallback, help };
|
||||
ValueArgument arg { &out, short_flag, long_flag, help };
|
||||
|
||||
if (short_flag == 'h') m_add_short_help_flag = false;
|
||||
if (long_flag == "help"_sv) m_add_long_help_flag = false;
|
||||
@ -130,6 +118,8 @@ namespace os
|
||||
|
||||
bool is_still_parsing_flags = true;
|
||||
|
||||
Vector<PositionalArgument> positional_args = TRY(m_positional_args.deep_copy());
|
||||
|
||||
for (int i = 1; i < argc; i++)
|
||||
{
|
||||
StringView arg = argv[i];
|
||||
@ -168,16 +158,21 @@ namespace os
|
||||
}
|
||||
}
|
||||
|
||||
if (flag.contains('='))
|
||||
{
|
||||
auto v = TRY(flag.split_view('='));
|
||||
StringView actual_flag = v[0];
|
||||
StringView data = v[1];
|
||||
for (const auto& current : m_value_args)
|
||||
{
|
||||
if (current.long_flag == flag)
|
||||
if (current.long_flag == actual_flag)
|
||||
{
|
||||
current_value_argument = current;
|
||||
is_parsing_value_argument = true;
|
||||
*current.out = data;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (found) continue;
|
||||
|
||||
@ -237,7 +232,7 @@ namespace os
|
||||
}
|
||||
}
|
||||
|
||||
Option<PositionalArgument> current = m_positional_args.try_dequeue();
|
||||
Option<PositionalArgument> current = positional_args.try_dequeue();
|
||||
if (!current.has_value())
|
||||
{
|
||||
if (m_vector_argument)
|
||||
@ -253,17 +248,13 @@ namespace os
|
||||
|
||||
if (is_parsing_value_argument)
|
||||
{
|
||||
if (current_value_argument->required)
|
||||
{
|
||||
os::eprintln("%s: option '--%s' requires an argument", program_name.chars(),
|
||||
current_value_argument->long_flag.chars());
|
||||
os::eprintln("%s: option '-%c' requires an argument", program_name.chars(),
|
||||
current_value_argument->short_flag);
|
||||
short_usage(program_name);
|
||||
}
|
||||
else { *current_value_argument->out = current_value_argument->fallback; }
|
||||
}
|
||||
|
||||
// Loop through all remaining positional arguments.
|
||||
for (const auto& arg : m_positional_args)
|
||||
for (const auto& arg : positional_args)
|
||||
{
|
||||
if (arg.required)
|
||||
{
|
||||
@ -317,10 +308,7 @@ namespace os
|
||||
|
||||
for (const auto& arg : m_value_args)
|
||||
{
|
||||
StringView value_name;
|
||||
if (arg.required) value_name = "VALUE"_sv;
|
||||
else
|
||||
value_name = "[VALUE]"_sv;
|
||||
StringView value_name = "VALUE"_sv;
|
||||
|
||||
int field_size = 20 - (int)(arg.long_flag.length() + 1);
|
||||
if (field_size < 0) field_size = 0;
|
||||
@ -333,11 +321,11 @@ namespace os
|
||||
}
|
||||
else if (arg.short_flag == ' ')
|
||||
{
|
||||
printf(" --%s %-*s %s\n", arg.long_flag.chars(), field_size, value_name.chars(), arg.help.chars());
|
||||
printf(" --%s=%-*s %s\n", arg.long_flag.chars(), field_size, value_name.chars(), arg.help.chars());
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" -%c, --%s %-*s %s\n", arg.short_flag, arg.long_flag.chars(), field_size, value_name.chars(),
|
||||
printf(" -%c, --%s=%-*s %s\n", arg.short_flag, arg.long_flag.chars(), field_size, value_name.chars(),
|
||||
arg.help.chars());
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user