summaryrefslogtreecommitdiff
path: root/sdn.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'sdn.cpp')
-rw-r--r--sdn.cpp88
1 files 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<string, chtype> 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 = {};