From 75c48e996a4d217809f075d650bae84998a93b47 Mon Sep 17 00:00:00 2001 From: apio Date: Wed, 29 Mar 2023 21:46:07 +0200 Subject: [PATCH] ArgumentParser+date: Add value arguments --- apps/CMakeLists.txt | 2 ++ apps/date.cpp | 15 +++++++-- apps/ls.cpp | 2 +- libos/include/os/ArgumentParser.h | 15 ++++++++- libos/src/ArgumentParser.cpp | 55 +++++++++++++++++++++++++++++-- 5 files changed, 82 insertions(+), 7 deletions(-) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index f4a131c6..c7d8e823 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -9,7 +9,9 @@ endfunction() luna_app(init.cpp init) luna_app(cat.cpp cat) luna_app(sh.cpp sh) + luna_app(date.cpp date) +target_link_libraries(date PRIVATE os) luna_app(edit.cpp edit) target_link_libraries(edit PRIVATE os) diff --git a/apps/date.cpp b/apps/date.cpp index 6ff4174e..76bc5d79 100644 --- a/apps/date.cpp +++ b/apps/date.cpp @@ -1,10 +1,21 @@ +#include + #include #include +#include #include -int main() +int main(int argc, char** argv) { - time_t now = time(NULL); + StringView date; + + ArgumentParser parser; + parser.add_value_argument(date, 'd', "date", false); + parser.parse(argc, argv); + + time_t now; + if (date.is_empty()) { now = time(NULL); } + else { now = strtol(date.chars(), nullptr, 10); } fputs(ctime(&now), stdout); } diff --git a/apps/ls.cpp b/apps/ls.cpp index 5589fd6c..bed6deed 100644 --- a/apps/ls.cpp +++ b/apps/ls.cpp @@ -12,7 +12,7 @@ int main(int argc, char** argv) bool show_almost_all; ArgumentParser parser; - parser.add_positional_argument(pathname, "directory", false, "/"); + parser.add_positional_argument(pathname, "directory", "/"); parser.add_switch_argument(show_all, 'a', "all"); parser.add_switch_argument(show_almost_all, 'A', "almost-all"); parser.parse(argc, argv); diff --git a/libos/include/os/ArgumentParser.h b/libos/include/os/ArgumentParser.h index 034f9d8d..4bbe91ef 100644 --- a/libos/include/os/ArgumentParser.h +++ b/libos/include/os/ArgumentParser.h @@ -8,10 +8,13 @@ class ArgumentParser ArgumentParser() = default; Result add_positional_argument(StringView& out, StringView name, bool required); - Result add_positional_argument(StringView& out, StringView name, bool required, StringView fallback); + Result add_positional_argument(StringView& out, StringView name, StringView fallback); Result add_switch_argument(bool& out, char short_flag, StringView long_flag); + Result add_value_argument(StringView& out, char short_flag, StringView long_flag, bool value_required); + Result add_value_argument(StringView& out, char short_flag, StringView long_flag, StringView fallback); + void parse(int argc, char* const* argv); private: @@ -30,6 +33,16 @@ class ArgumentParser StringView long_flag; }; + struct ValueArgument + { + StringView* out; + char short_flag; + StringView long_flag; + bool required; + StringView fallback; + }; + Vector m_positional_args; Vector m_switch_args; + Vector m_value_args; }; diff --git a/libos/src/ArgumentParser.cpp b/libos/src/ArgumentParser.cpp index 4d2274c3..c87932d4 100644 --- a/libos/src/ArgumentParser.cpp +++ b/libos/src/ArgumentParser.cpp @@ -9,10 +9,9 @@ Result ArgumentParser::add_positional_argument(StringView& out, StringView return m_positional_args.try_append(move(arg)); } -Result ArgumentParser::add_positional_argument(StringView& out, StringView name, bool required, - StringView fallback) +Result ArgumentParser::add_positional_argument(StringView& out, StringView name, StringView fallback) { - PositionalArgument arg { &out, name, required, fallback }; + PositionalArgument arg { &out, name, false, fallback }; return m_positional_args.try_append(move(arg)); } @@ -24,6 +23,22 @@ Result ArgumentParser::add_switch_argument(bool& out, char short_flag, Str return m_switch_args.try_append(move(arg)); } +Result ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag, + bool value_required) +{ + ValueArgument arg { &out, short_flag, long_flag, value_required, {} }; + + return m_value_args.try_append(move(arg)); +} + +Result ArgumentParser::add_value_argument(StringView& out, char short_flag, StringView long_flag, + StringView fallback) +{ + ValueArgument arg { &out, short_flag, long_flag, false, fallback }; + + return m_value_args.try_append(move(arg)); +} + static bool looks_like_short_flag(StringView arg) { return arg.length() > 1 && arg[0] == '-'; @@ -38,12 +53,22 @@ void ArgumentParser::parse(int argc, char* const* argv) { StringView program_name = argv[0]; + Option current_value_argument = {}; + bool is_parsing_value_argument = false; + bool is_still_parsing_flags = true; for (int i = 1; i < argc; i++) { StringView arg = argv[i]; + if (is_parsing_value_argument) + { + *current_value_argument->out = arg; + is_parsing_value_argument = false; + continue; + } + if (is_still_parsing_flags) { if (arg == "--") @@ -68,6 +93,17 @@ void ArgumentParser::parse(int argc, char* const* argv) } } + for (const auto& current : m_value_args) + { + if (current.long_flag == flag) + { + current_value_argument = current; + is_parsing_value_argument = true; + found = true; + break; + } + } + if (found) continue; fprintf(stderr, "%s: unrecognized option '%s'\n", program_name.chars(), arg.chars()); @@ -81,6 +117,8 @@ void ArgumentParser::parse(int argc, char* const* argv) { bool found = false; + // FIXME: Implement value arguments for short flags. + for (const auto& current : m_switch_args) { if (current.short_flag == ' ') continue; @@ -113,6 +151,17 @@ void ArgumentParser::parse(int argc, char* const* argv) *current->out = arg; } + if (is_parsing_value_argument) + { + if (current_value_argument->required) + { + fprintf(stderr, "%s: option '--%s' requires an argument\n", program_name.chars(), + current_value_argument->long_flag.chars()); + exit(1); + } + else { *current_value_argument->out = current_value_argument->fallback; } + } + // Loop through all remaining positional arguments. for (const auto& arg : m_positional_args) {