diff --git a/apps/ls.cpp b/apps/ls.cpp index c9050b7d..5589fd6c 100644 --- a/apps/ls.cpp +++ b/apps/ls.cpp @@ -8,9 +8,13 @@ int main(int argc, char** argv) { StringView pathname; + bool show_all; + bool show_almost_all; ArgumentParser parser; parser.add_positional_argument(pathname, "directory", false, "/"); + parser.add_switch_argument(show_all, 'a', "all"); + parser.add_switch_argument(show_almost_all, 'A', "almost-all"); parser.parse(argc, argv); DIR* dp = opendir(pathname.chars()); @@ -24,6 +28,8 @@ int main(int argc, char** argv) do { struct dirent* ent = readdir(dp); if (!ent) break; + if (show_almost_all && (!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, ".."))) continue; + if (!show_all && !show_almost_all && *ent->d_name == '.') continue; printf(first_ent ? "%s" : " %s", ent->d_name); first_ent = 0; } while (1); diff --git a/libluna/include/luna/String.h b/libluna/include/luna/String.h index 219e4e2f..6fd22e94 100644 --- a/libluna/include/luna/String.h +++ b/libluna/include/luna/String.h @@ -4,6 +4,9 @@ class String { + typedef char* Iterator; + typedef const char* ConstIterator; + public: String(char* c_str); String(char* c_str, usize length); @@ -43,6 +46,26 @@ class String const char& operator[](usize) const; + Iterator begin() + { + return m_inline ? m_inline_storage : m_string; + } + + ConstIterator begin() const + { + return chars(); + } + + Iterator end() + { + return begin() + m_length; + } + + ConstIterator end() const + { + return begin() + m_length; + } + private: union { char* m_string { nullptr }; diff --git a/libluna/include/luna/StringView.h b/libluna/include/luna/StringView.h index 68c4885b..790ace6e 100644 --- a/libluna/include/luna/StringView.h +++ b/libluna/include/luna/StringView.h @@ -5,6 +5,8 @@ class String; class StringView { + typedef const char* Iterator; + public: StringView(const char* c_str); StringView(const char* c_str, usize length); @@ -32,6 +34,19 @@ class StringView const char& operator[](usize) const; + bool operator==(const char* other) const; + bool operator==(StringView other) const; + + Iterator begin() const + { + return m_string; + } + + Iterator end() const + { + return m_string + m_length; + } + private: const char* m_string { nullptr }; diff --git a/libluna/src/StringView.cpp b/libluna/src/StringView.cpp index 40161b7a..054f0ebd 100644 --- a/libluna/src/StringView.cpp +++ b/libluna/src/StringView.cpp @@ -36,6 +36,16 @@ const char& StringView::operator[](usize index) const return m_string[index]; } +bool StringView::operator==(const char* other) const +{ + return !strcmp(m_string, other); +} + +bool StringView::operator==(StringView other) const +{ + return !strcmp(m_string, other.m_string); +} + Result StringView::to_string() { return String::from_cstring(m_string); diff --git a/libos/include/os/ArgumentParser.h b/libos/include/os/ArgumentParser.h index f1655e44..034f9d8d 100644 --- a/libos/include/os/ArgumentParser.h +++ b/libos/include/os/ArgumentParser.h @@ -10,6 +10,8 @@ class ArgumentParser Result add_positional_argument(StringView& out, StringView name, bool required); Result add_positional_argument(StringView& out, StringView name, bool required, StringView fallback); + Result add_switch_argument(bool& out, char short_flag, StringView long_flag); + void parse(int argc, char* const* argv); private: @@ -21,5 +23,13 @@ class ArgumentParser StringView fallback; }; + struct SwitchArgument + { + bool* out; + char short_flag; + StringView long_flag; + }; + Vector m_positional_args; + Vector m_switch_args; }; diff --git a/libos/src/ArgumentParser.cpp b/libos/src/ArgumentParser.cpp index 91b672c7..4d2274c3 100644 --- a/libos/src/ArgumentParser.cpp +++ b/libos/src/ArgumentParser.cpp @@ -17,13 +17,92 @@ Result ArgumentParser::add_positional_argument(StringView& out, StringView 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)); +} + +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] == '-'; +} + void ArgumentParser::parse(int argc, char* const* argv) { StringView program_name = argv[0]; + bool is_still_parsing_flags = true; + for (int i = 1; i < argc; i++) { StringView arg = argv[i]; + + if (is_still_parsing_flags) + { + if (arg == "--") + { + is_still_parsing_flags = false; + continue; + } + + if (looks_like_long_flag(arg)) + { + StringView flag = &arg[2]; + + bool found = false; + + for (const auto& current : m_switch_args) + { + if (current.long_flag == flag) + { + *current.out = true; + found = true; + break; + } + } + + 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 (char c : flags) + { + bool found = false; + + 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()) {