From 28abfd6290ca8d740ebd8cc2c6893e92bf4c4f0f Mon Sep 17 00:00:00 2001 From: Brendan Coles Date: Tue, 10 Nov 2020 17:42:41 +0000 Subject: [PATCH] Userland: ls: Add `-d` / `--directory` flag --- Base/usr/share/man/man1/ls.md | 3 +- Userland/ls.cpp | 62 ++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 27 deletions(-) diff --git a/Base/usr/share/man/man1/ls.md b/Base/usr/share/man/man1/ls.md index 4bd25515b4713d..0af1c5bec2f297 100644 --- a/Base/usr/share/man/man1/ls.md +++ b/Base/usr/share/man/man1/ls.md @@ -19,7 +19,8 @@ If no *path* argument is provided the current working directory is used. * `--help`: Display this message * `-a`, `--all`: Show dotfiles * `-A`: Do not list implied . and .. directories -* `-B`, --ignore-backups`: Do not list implied entries ending with ~ +* `-B`, `--ignore-backups`: Do not list implied entries ending with ~ +* `-d`, `--directory`: List directories themselves, not their contents * `-l`, `--long`: Display long info * `-t`: Sort files by timestamp * `-r`, `--reverse`: Reverse sort order diff --git a/Userland/ls.cpp b/Userland/ls.cpp index 017e87d89e6ffc..66255632667ace 100644 --- a/Userland/ls.cpp +++ b/Userland/ls.cpp @@ -56,6 +56,7 @@ static bool flag_long = false; static bool flag_show_dotfiles = false; static bool flag_show_almost_all_dotfiles = false; static bool flag_ignore_backups = false; +static bool flag_list_directories_only = false; static bool flag_show_inode = false; static bool flag_print_numeric = false; static bool flag_hide_group = false; @@ -102,6 +103,7 @@ int main(int argc, char** argv) args_parser.add_option(flag_show_dotfiles, "Show dotfiles", "all", 'a'); args_parser.add_option(flag_show_almost_all_dotfiles, "Do not list implied . and .. directories", nullptr, 'A'); args_parser.add_option(flag_ignore_backups, "Do not list implied entries ending with ~", "--ignore-backups", 'B'); + args_parser.add_option(flag_list_directories_only, "List directories themselves, not their contents", "directory", 'd'); args_parser.add_option(flag_long, "Display long info", "long", 'l'); args_parser.add_option(flag_sort_by_timestamp, "Sort files by timestamp", nullptr, 't'); args_parser.add_option(flag_reverse_sort, "Reverse sort order", "reverse", 'r'); @@ -316,7 +318,26 @@ static bool print_filesystem_object(const String& path, const String& name, cons static int do_file_system_object_long(const char* path) { - Core::DirIterator di(path, !flag_show_dotfiles ? Core::DirIterator::SkipDots : Core::DirIterator::Flags::NoFlags); + if (flag_list_directories_only) { + struct stat stat; + int rc = lstat(path, &stat); + if (rc < 0) { + perror("lstat"); + memset(&stat, 0, sizeof(stat)); + } + if (print_filesystem_object(path, path, stat)) + return 0; + return 2; + } + + auto flags = Core::DirIterator::SkipDots; + if (flag_show_dotfiles) + flags = Core::DirIterator::Flags::NoFlags; + if (flag_show_almost_all_dotfiles) + flags = Core::DirIterator::SkipParentAndBaseDir; + + Core::DirIterator di(path, flags); + if (di.has_error()) { if (di.error() == ENOTDIR) { struct stat stat; @@ -345,18 +366,6 @@ static int do_file_system_object_long(const char* path) metadata.name = di.next_path(); ASSERT(!metadata.name.is_empty()); - if (metadata.name[0] == '.') { - if (!flag_show_dotfiles) - continue; - if (flag_show_almost_all_dotfiles) { - // skip '.' and '..' directories - if (metadata.name.length() == 1) - continue; - if (metadata.name.length() == 2 && metadata.name[1] == '.') - continue; - } - } - if (metadata.name.ends_with('~') && flag_ignore_backups && metadata.name != path) continue; @@ -411,7 +420,20 @@ static bool print_filesystem_object_short(const char* path, const char* name, si int do_file_system_object_short(const char* path) { - Core::DirIterator di(path, !flag_show_dotfiles ? Core::DirIterator::SkipDots : Core::DirIterator::Flags::NoFlags); + if (flag_list_directories_only) { + size_t nprinted = 0; + if (print_filesystem_object_short(path, path, &nprinted)) + return 0; + return 2; + } + + auto flags = Core::DirIterator::SkipDots; + if (flag_show_dotfiles) + flags = Core::DirIterator::Flags::NoFlags; + if (flag_show_almost_all_dotfiles) + flags = Core::DirIterator::SkipParentAndBaseDir; + + Core::DirIterator di(path, flags); if (di.has_error()) { if (di.error() == ENOTDIR) { size_t nprinted = 0; @@ -430,18 +452,6 @@ int do_file_system_object_short(const char* path) while (di.has_next()) { String name = di.next_path(); - if (name[0] == '.') { - if (!flag_show_dotfiles) - continue; - if (flag_show_almost_all_dotfiles) { - // skip '.' and '..' directories - if (name.length() == 1) - continue; - if (name.length() == 2 && name[1] == '.') - continue; - } - } - if (name.ends_with('~') && flag_ignore_backups && name != path) continue;