diff --git a/apps/cat.cpp b/apps/cat.cpp index e91e226c..ee506ddc 100644 --- a/apps/cat.cpp +++ b/apps/cat.cpp @@ -35,7 +35,7 @@ int main(int argc, char** argv) { StringView filename; - ArgumentParser parser; + os::ArgumentParser parser; parser.add_positional_argument(filename, "file"_sv, "-"_sv); Vector extra_files = parser.parse(argc, argv).value(); diff --git a/apps/date.cpp b/apps/date.cpp index 2afe6cf0..3019f69d 100644 --- a/apps/date.cpp +++ b/apps/date.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) { StringView date; - ArgumentParser parser; + os::ArgumentParser parser; parser.add_value_argument(date, 'd', "date"_sv, true); parser.parse(argc, argv); diff --git a/apps/edit.cpp b/apps/edit.cpp index ae177cb8..f514a330 100644 --- a/apps/edit.cpp +++ b/apps/edit.cpp @@ -9,7 +9,7 @@ int main(int argc, char** argv) FILE* f; StringView pathname; - ArgumentParser parser; + os::ArgumentParser parser; parser.add_positional_argument(pathname, "file"_sv, true); parser.parse(argc, argv); diff --git a/apps/ls.cpp b/apps/ls.cpp index 7127d142..065772bc 100644 --- a/apps/ls.cpp +++ b/apps/ls.cpp @@ -11,7 +11,7 @@ int main(int argc, char** argv) bool show_all { false }; bool show_almost_all { false }; - ArgumentParser parser; + os::ArgumentParser parser; parser.add_positional_argument(pathname, "directory"_sv, "/"_sv); parser.add_switch_argument(show_all, 'a', "all"_sv); parser.add_switch_argument(show_almost_all, 'A', "almost-all"_sv); diff --git a/libos/include/os/ArgumentParser.h b/libos/include/os/ArgumentParser.h index 8f71024d..8be7aa56 100644 --- a/libos/include/os/ArgumentParser.h +++ b/libos/include/os/ArgumentParser.h @@ -2,47 +2,50 @@ #include #include -class ArgumentParser +namespace os { - public: - ArgumentParser() = default; - - Result add_positional_argument(StringView& out, StringView name, bool required); - 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); - - Result> parse(int argc, char* const* argv); - - private: - struct PositionalArgument + class ArgumentParser { - StringView* out; - StringView name; - bool required; - StringView fallback; - }; + public: + ArgumentParser() = default; - struct SwitchArgument - { - bool* out; - char short_flag; - StringView long_flag; - }; + Result add_positional_argument(StringView& out, StringView name, bool required); + Result add_positional_argument(StringView& out, StringView name, StringView fallback); - struct ValueArgument - { - StringView* out; - char short_flag; - StringView long_flag; - bool required; - StringView fallback; - }; + Result add_switch_argument(bool& out, char short_flag, StringView long_flag); - Vector m_positional_args; - Vector m_switch_args; - Vector m_value_args; -}; + 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); + + Result> parse(int argc, char* const* argv); + + private: + struct PositionalArgument + { + StringView* out; + StringView name; + bool required; + StringView fallback; + }; + + struct SwitchArgument + { + bool* out; + char short_flag; + 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 3e26b8d3..09022fdd 100644 --- a/libos/src/ArgumentParser.cpp +++ b/libos/src/ArgumentParser.cpp @@ -2,148 +2,94 @@ #include #include -Result ArgumentParser::add_positional_argument(StringView& out, StringView name, bool required) +namespace os { - PositionalArgument arg { &out, name, required, {} }; - - return m_positional_args.try_append(move(arg)); -} - -Result ArgumentParser::add_positional_argument(StringView& out, StringView name, StringView fallback) -{ - PositionalArgument arg { &out, name, false, fallback }; - - return m_positional_args.try_append(move(arg)); -} - -Result ArgumentParser::add_switch_argument(bool& out, char short_flag, StringView long_flag) -{ - SwitchArgument arg { &out, short_flag, long_flag }; - - 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] == '-'; -} - -static bool looks_like_long_flag(StringView arg) -{ - return arg.length() > 2 && arg[0] == '-' && arg[1] == '-'; -} - -Result> ArgumentParser::parse(int argc, char* const* argv) -{ - StringView program_name = argv[0]; - - Vector leftovers; - - Option current_value_argument = {}; - bool is_parsing_value_argument = false; - - bool is_still_parsing_flags = true; - - for (int i = 1; i < argc; i++) + Result ArgumentParser::add_positional_argument(StringView& out, StringView name, bool required) { - StringView arg = argv[i]; + PositionalArgument arg { &out, name, required, {} }; - if (is_parsing_value_argument) - { - *current_value_argument->out = arg; - is_parsing_value_argument = false; - continue; - } + return m_positional_args.try_append(move(arg)); + } - if (is_still_parsing_flags) + Result ArgumentParser::add_positional_argument(StringView& out, StringView name, StringView fallback) + { + PositionalArgument arg { &out, name, false, fallback }; + + return m_positional_args.try_append(move(arg)); + } + + Result ArgumentParser::add_switch_argument(bool& out, char short_flag, StringView long_flag) + { + SwitchArgument arg { &out, short_flag, long_flag }; + + 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] == '-'; + } + + static bool looks_like_long_flag(StringView arg) + { + return arg.length() > 2 && arg[0] == '-' && arg[1] == '-'; + } + + Result> ArgumentParser::parse(int argc, char* const* argv) + { + StringView program_name = argv[0]; + + Vector leftovers; + + Option current_value_argument = {}; + bool is_parsing_value_argument = false; + + bool is_still_parsing_flags = true; + + for (int i = 1; i < argc; i++) { - if (arg == "--") + StringView arg = argv[i]; + + if (is_parsing_value_argument) { - is_still_parsing_flags = false; + *current_value_argument->out = arg; + is_parsing_value_argument = false; continue; } - if (looks_like_long_flag(arg)) + if (is_still_parsing_flags) { - StringView flag = &arg[2]; - - bool found = false; - - for (const auto& current : m_switch_args) + if (arg == "--") { - if (current.long_flag == flag) - { - *current.out = true; - found = true; - break; - } + is_still_parsing_flags = false; + continue; } - for (const auto& current : m_value_args) + if (looks_like_long_flag(arg)) { - if (current.long_flag == flag) - { - current_value_argument = current; - is_parsing_value_argument = true; - found = true; - break; - } - } + StringView flag = &arg[2]; - if (found) continue; - - fprintf(stderr, "%s: unrecognized option '%s'\n", program_name.chars(), arg.chars()); - exit(1); - } - else if (looks_like_short_flag(arg)) - { - StringView flags = &arg[1]; - - for (usize j = 0; j < flags.length(); j++) - { - char c = flags[j]; bool found = false; - // Last flag, this could be a value flag - if (j + 1 == flags.length()) - { - for (const auto& current : m_value_args) - { - if (current.short_flag == ' ') continue; - - if (current.short_flag == c) - { - current_value_argument = current; - is_parsing_value_argument = true; - found = true; - break; - } - } - - if (found) continue; - } - for (const auto& current : m_switch_args) { - if (current.short_flag == ' ') continue; - - if (current.short_flag == c) + if (current.long_flag == flag) { *current.out = true; found = true; @@ -151,47 +97,104 @@ Result> 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: invalid option -- '%c'\n", program_name.chars(), c); + fprintf(stderr, "%s: unrecognized option '%s'\n", program_name.chars(), arg.chars()); exit(1); } + else if (looks_like_short_flag(arg)) + { + StringView flags = &arg[1]; + for (usize j = 0; j < flags.length(); j++) + { + char c = flags[j]; + bool found = false; + + // Last flag, this could be a value flag + if (j + 1 == flags.length()) + { + for (const auto& current : m_value_args) + { + if (current.short_flag == ' ') continue; + + if (current.short_flag == c) + { + current_value_argument = current; + is_parsing_value_argument = true; + found = true; + break; + } + } + + if (found) continue; + } + + for (const auto& current : m_switch_args) + { + if (current.short_flag == ' ') continue; + + if (current.short_flag == c) + { + *current.out = true; + found = true; + break; + } + } + + if (found) continue; + + fprintf(stderr, "%s: invalid option -- '%c'\n", program_name.chars(), c); + exit(1); + } + + continue; + } + } + + Option current = m_positional_args.try_dequeue(); + if (!current.has_value()) + { + TRY(leftovers.try_append(arg)); continue; } + + *current->out = arg; } - Option current = m_positional_args.try_dequeue(); - if (!current.has_value()) + if (is_parsing_value_argument) { - TRY(leftovers.try_append(arg)); - continue; + 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; } } - *current->out = arg; - } - - if (is_parsing_value_argument) - { - if (current_value_argument->required) + // Loop through all remaining positional arguments. + for (const auto& arg : m_positional_args) { - fprintf(stderr, "%s: option '--%s' requires an argument\n", program_name.chars(), - current_value_argument->long_flag.chars()); - exit(1); + if (arg.required) + { + fprintf(stderr, "%s: required argument '%s' not provided\n", program_name.chars(), arg.name.chars()); + exit(1); + } + else { *arg.out = arg.fallback; } } - else { *current_value_argument->out = current_value_argument->fallback; } - } - // Loop through all remaining positional arguments. - for (const auto& arg : m_positional_args) - { - if (arg.required) - { - fprintf(stderr, "%s: required argument '%s' not provided\n", program_name.chars(), arg.name.chars()); - exit(1); - } - else { *arg.out = arg.fallback; } + return leftovers; } - - return leftovers; }