From 0cf63744a754b1c03efc50f53cbfc13fa53a2d77 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C5=99emysl=20Janouch?= Date: Sat, 15 Jul 2017 22:18:45 +0200 Subject: Factor out ls_format(), comments --- sdn.cpp | 88 +++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 50 insertions(+), 38 deletions(-) diff --git a/sdn.cpp b/sdn.cpp index cb841c8..1ba094e 100644 --- a/sdn.cpp +++ b/sdn.cpp @@ -318,44 +318,11 @@ static struct { map ls_exts; // LS_COLORS file extensions } g; -// XXX: this will probably have to be changed to make_entry and run lstat itself -fun make_row (const string &filename, const struct stat &info) -> row { - row r; - auto mode = decode_mode (info.st_mode); - // This is a Linux-only extension - if (acl_extended_file_nofollow (filename.c_str ()) > 0) - mode += L"+"; - r.cols[row::MODES] = apply_attrs (mode, 0); - - auto user = to_wstring (info.st_uid); - if (auto u = getpwuid (info.st_uid)) - user = to_wide (u->pw_name); - r.cols[row::USER] = apply_attrs (user, 0); - - auto group = to_wstring (info.st_gid); - if (auto g = getgrgid (info.st_gid)) - group = to_wide (g->gr_name); - r.cols[row::GROUP] = apply_attrs (group, 0); - - auto size = to_wstring (info.st_size); - if (info.st_size >> 40) size = to_wstring (info.st_size >> 40) + L"T"; - else if (info.st_size >> 30) size = to_wstring (info.st_size >> 30) + L"G"; - else if (info.st_size >> 20) size = to_wstring (info.st_size >> 20) + L"M"; - else if (info.st_size >> 10) size = to_wstring (info.st_size >> 10) + L"K"; - r.cols[row::SIZE] = apply_attrs (size, 0); - - auto now = time (NULL); - auto now_year = localtime (&now)->tm_year; - - char buf[32] = ""; - auto tm = localtime (&info.st_mtime); - strftime (buf, sizeof buf, - (tm->tm_year == now_year) ? "%b %e %H:%M" : "%b %e %Y", tm); - r.cols[row::MTIME] = apply_attrs (to_wide (buf), 0); - +fun ls_format (const string &filename, const struct stat &info) -> chtype { int type = LS_ORPHAN; auto set = [&](int t) { if (g.ls_colors.count (t)) type = t; }; - // TODO: LS_MISSING + // TODO: LS_MISSING if available and this is a missing symlink target + // TODO: go by readdir() information when stat() isn't available yet if (S_ISREG (info.st_mode)) { type = LS_FILE; if (info.st_nlink > 1) @@ -377,7 +344,9 @@ fun make_row (const string &filename, const struct stat &info) -> row { if ((info.st_mode & S_ISVTX) && (info.st_mode & S_IWOTH)) set (LS_STICKY_OTHER_WRITABLE); } else if (S_ISLNK (info.st_mode)) { - // TODO: LS_ORPHAN + // TODO: LS_ORPHAN when symlink target is missing and either + // a/ "li" is "target", or + // b/ LS_ORPHAN is available type = LS_SYMLINK; } else if (S_ISFIFO (info.st_mode)) { type = LS_FIFO; @@ -400,8 +369,46 @@ fun make_row (const string &filename, const struct stat &info) -> row { if (x != g.ls_exts.end ()) format = x->second; } + return format; +} + +// XXX: this will probably have to be changed to make_entry and run lstat itself +fun make_row (const string &filename, const struct stat &info) -> row { + row r; + auto mode = decode_mode (info.st_mode); + // This is a Linux-only extension + if (acl_extended_file_nofollow (filename.c_str ()) > 0) + mode += L"+"; + r.cols[row::MODES] = apply_attrs (mode, 0); + + auto user = to_wstring (info.st_uid); + if (auto u = getpwuid (info.st_uid)) + user = to_wide (u->pw_name); + r.cols[row::USER] = apply_attrs (user, 0); + + auto group = to_wstring (info.st_gid); + if (auto g = getgrgid (info.st_gid)) + group = to_wide (g->gr_name); + r.cols[row::GROUP] = apply_attrs (group, 0); + + auto size = to_wstring (info.st_size); + if (info.st_size >> 40) size = to_wstring (info.st_size >> 40) + L"T"; + else if (info.st_size >> 30) size = to_wstring (info.st_size >> 30) + L"G"; + else if (info.st_size >> 20) size = to_wstring (info.st_size >> 20) + L"M"; + else if (info.st_size >> 10) size = to_wstring (info.st_size >> 10) + L"K"; + r.cols[row::SIZE] = apply_attrs (size, 0); + + auto now = time (NULL); + auto now_year = localtime (&now)->tm_year; + + char buf[32] = ""; + auto tm = localtime (&info.st_mtime); + strftime (buf, sizeof buf, + (tm->tm_year == now_year) ? "%b %e %H:%M" : "%b %e %Y", tm); + r.cols[row::MTIME] = apply_attrs (to_wide (buf), 0); - // TODO: show symlink target + // TODO: show symlink target: check st_mode/DT_*, readlink + auto format = ls_format (filename, info); r.cols[row::FILENAME] = apply_attrs (to_wide (filename), format); return r; } @@ -462,6 +469,10 @@ fun reload () { if (f->d_name == string (".")) continue; + // TODO: check lstat() return value + // TODO: benchmark just readdir() vs. lstat(), also on dead mounts; + // it might make sense to stat asynchronously in threads + // http://lkml.iu.edu/hypermail//linux/kernel/0804.3/1616.html struct stat sb = {}; lstat (f->d_name, &sb); g.entries.push_back ({ f->d_name, sb, make_row (f->d_name, sb) }); @@ -527,6 +538,7 @@ fun handle_editor (wint_t c, bool is_char) { fun choose (const entry &entry) -> bool { bool is_dir = S_ISDIR (entry.info.st_mode) != 0; // Dive into directories and accessible symlinks to them + // TODO: we probably want to use a preread readlink value if (S_ISLNK (entry.info.st_mode)) { char buf[PATH_MAX]; struct stat sb = {}; -- cgit v1.2.3