]> Sergey Matveev's repositories - nnn.git/commitdiff
Show file details
authorArun Prakash Jana <engineerarun@gmail.com>
Sun, 2 Apr 2017 23:35:14 +0000 (05:05 +0530)
committerArun Prakash Jana <engineerarun@gmail.com>
Sun, 2 Apr 2017 23:35:14 +0000 (05:05 +0530)
We closely follow the output for stat(1).

README.md
config.def.h
nnn.1
nnn.c

index b8f7d92b47eb19558a29672739c4445be91e627d..35a2c833c0b72a2ef7189402d7f3b1459968ab11 100644 (file)
--- a/README.md
+++ b/README.md
@@ -54,6 +54,7 @@ I chose to fork because:
     - current item in reverse video
     - number of items in current directory
     - full name of currently selected file
+  - Show details of the currently selected file
   - Directories first
   - Sort numeric names in numeric order
   - Case-insensitive alphabetic content listing instead of upper case first
@@ -120,6 +121,7 @@ Start nnn (default: current directory):
 | `/`, `&` | filter dir contents |
 | `c` | show change dir prompt |
 | `d` | toggle detail view |
+| `D` | show details of selected file |
 | `.` | toggle hide dot files |
 | `s` | toggle sort by file size |
 | `t` | toggle sort by modified time |
index cb52960fd63fcd7c4e2ab0f9fa5bf7c0d1517a53..9ef50c3a6e7eed8e908590d806ee63609abb7a1c 100644 (file)
@@ -66,6 +66,8 @@ struct key bindings[] = {
        { '.',            SEL_TOGGLEDOT, "\0",  "\0" },
        /* Detailed listing */
        { 'd',            SEL_DETAIL,    "\0",  "\0" },
+       /* File details */
+       { 'D',            SEL_STATS,     "\0",  "\0" },
        /* Toggle sort by size */
        { 's',            SEL_FSIZE,     "\0",  "\0" },
        /* Toggle sort by time */
diff --git a/nnn.1 b/nnn.1
index 136ac58444f24195af316925f00a37f5aee9f2ee..4f78f8b768ab0c55de856f8ac0c38c9e588c8428 100644 (file)
--- a/nnn.1
+++ b/nnn.1
@@ -46,6 +46,8 @@ Change filter (more information below)
 Change into the given directory
 .It Ic d
 Toggle detail view
+.It Ic D
+Show details of selected file
 .It Ic \&.
 Toggle hide .dot files
 .It Ic s
diff --git a/nnn.c b/nnn.c
index 6641a112792c1fedaf8bf9ab57f54f6108f4e3cc..9f18584d6c7ce49bdd2be58ef23ef2edb34adeb7 100644 (file)
--- a/nnn.c
+++ b/nnn.c
@@ -17,6 +17,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <time.h>
+#include <pwd.h>
+#include <grp.h>
 
 #ifdef DEBUG
 #define DEBUG_FD 8
@@ -62,6 +64,7 @@ enum action {
        SEL_CDHOME,
        SEL_TOGGLEDOT,
        SEL_DETAIL,
+       SEL_STATS,
        SEL_FSIZE,
        SEL_MTIME,
        SEL_REDRAW,
@@ -164,7 +167,7 @@ xstrlcpy(char *dest, const char *src, size_t n)
 }
 
 /*
- * The poor man's implementation of memrchr().
+ * The poor man's implementation of memrchr(3).
  * We are only looking for '/' in this program.
  */
 static void *
@@ -204,7 +207,7 @@ xdirname(const char *path)
 #endif
 
 /*
- * The following dirname() implementation does not
+ * The following dirname(3) implementation does not
  * change the input. We use a copy of the original.
  *
  * Modified from the glibc (GNU LGPL) version.
@@ -594,10 +597,7 @@ static void
 printent_long(struct entry *ent, int active)
 {
        static char buf[18];
-       static const struct tm *p;
-
-       p = localtime(&ent->t);
-       strftime(buf, 18, "%b %d %H:%M %Y", p);
+       strftime(buf, 18, "%b %d %H:%M %Y", localtime(&ent->t));
 
        if (active)
                attron(A_REVERSE);
@@ -631,6 +631,140 @@ printent_long(struct entry *ent, int active)
                attroff(A_REVERSE);
 }
 
+static char
+get_fileind(mode_t mode, char *desc)
+{
+       char c;
+
+       if (S_ISREG(mode)) {
+               c = '-';
+               sprintf(desc, "%s", "regular file");
+       } else if (S_ISDIR(mode)) {
+               c = 'd';
+               sprintf(desc, "%s", "directory");
+       } else if (S_ISBLK(mode)) {
+               c = 'b';
+               sprintf(desc, "%s", "block special device");
+       } else if (S_ISCHR(mode)) {
+               c = 'c';
+               sprintf(desc, "%s", "character special device");
+#ifdef S_ISFIFO
+       } else if (S_ISFIFO(mode)) {
+               c = 'p';
+               sprintf(desc, "%s", "FIFO");
+#endif  /* S_ISFIFO */
+#ifdef S_ISLNK
+       } else if (S_ISLNK(mode)) {
+               c = 'l';
+               sprintf(desc, "%s", "symbolic link");
+#endif  /* S_ISLNK */
+#ifdef S_ISSOCK
+       } else if (S_ISSOCK(mode)) {
+               c = 's';
+               sprintf(desc, "%s", "socket");
+#endif  /* S_ISSOCK */
+#ifdef S_ISDOOR
+    /* Solaris 2.6, etc. */
+       } else if (S_ISDOOR(mode)) {
+               c = 'D';
+               desc[0] = '\0';
+#endif  /* S_ISDOOR */
+       } else {
+               /* Unknown type -- possibly a regular file? */
+               c = '?';
+               desc[0] = '\0';
+       }
+
+       return(c);
+}
+
+/* Convert a mode field into "ls -l" type perms field. */
+static char *
+get_lsperms(mode_t mode, char *desc)
+{
+       static const char *rwx[] = {"---", "--x", "-w-", "-wx",
+                                   "r--", "r-x", "rw-", "rwx"};
+       static char bits[11];
+
+       bits[0] = get_fileind(mode, desc);
+       strcpy(&bits[1], rwx[(mode >> 6) & 7]);
+       strcpy(&bits[4], rwx[(mode >> 3) & 7]);
+       strcpy(&bits[7], rwx[(mode & 7)]);
+
+       if (mode & S_ISUID)
+               bits[3] = (mode & S_IXUSR) ? 's' : 'S';
+       if (mode & S_ISGID)
+               bits[6] = (mode & S_IXGRP) ? 's' : 'l';
+       if (mode & S_ISVTX)
+               bits[9] = (mode & S_IXOTH) ? 't' : 'T';
+
+       bits[10] = '\0';
+
+       return(bits);
+}
+
+/*
+ * Follows the stat(1) output closely
+ */
+void
+show_stats(char* fpath, char* fname, struct stat *sb)
+{
+       char buf[40];
+       char *perms = get_lsperms(sb->st_mode, buf);
+
+       clear();
+
+       /* Show file name or 'symlink' -> 'target' */
+       if (perms[0] == 'l') {
+               char symtgt[PATH_MAX];
+               ssize_t len = readlink(fpath, symtgt, PATH_MAX);
+               if (len == -1)
+                       printerr(1, "readlink");
+               printw("\n\n    File: '%s' -> '%s'", fname, symtgt);
+       } else
+               printw("\n\n    File: '%s'", fname);
+
+       /* Show size, blocks, file type */
+       printw("\n    Size: %-15llu Blocks: %-10llu IO Block: %-6llu %s",
+              sb->st_size, sb->st_blocks, sb->st_blksize, buf);
+
+       /* Show containing device, inode, hardlink count */
+       sprintf(buf, "%lxh/%lud", sb->st_dev, sb->st_dev);
+       printw("\n  Device: %-15s Inode: %-11lu Links: %-9lu",
+              buf, sb->st_ino, sb->st_nlink);
+
+       /* Show major, minor number for block or char device */
+       if (perms[0] == 'b' || perms[0] == 'c')
+               printw(" Device type: %lx,%lx",
+                      major(sb->st_rdev), minor(sb->st_rdev));
+
+       /* Show permissions, owner, group */
+       printw("\n  Access: 0%d%d%d/%s Uid: (%lu/%s)  Gid: (%lu/%s)",
+              (sb->st_mode >> 6) & 7, (sb->st_mode >> 3) & 7, sb->st_mode & 7,
+              perms,
+              sb->st_uid, (getpwuid(sb->st_uid))->pw_name,
+              sb->st_gid, (getgrgid(sb->st_gid))->gr_name);
+
+       /* Show last access time */
+       strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_atime));
+       printw("\n\n  Access: %s", buf);
+
+       /* Show last modification time */
+       strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_mtime));
+       printw("\n  Modify: %s", buf);
+
+       /* Show last status change time */
+       strftime(buf, 40, "%a %d-%b-%Y %T %z,%Z", localtime(&sb->st_ctime));
+       printw("\n  Change: %s", buf);
+
+       /* Show exit keys */
+       printw("\n\n\n\n  < (q/Esc)");
+
+       while (*buf = getch())
+               if (*buf == 'q' || *buf == 27)
+                       return;
+}
+
 static int
 dentfill(char *path, struct entry **dents,
         int (*filter)(regex_t *, char *), regex_t *re)
@@ -1036,6 +1170,21 @@ nochange:
                        if (ndents > 0)
                                mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
                        goto begin;
+               case SEL_STATS:
+               {
+                       struct stat sb;
+
+                       if (ndents > 0)
+                               mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
+
+                       r = lstat(oldpath, &sb);
+                       if (r == -1)
+                               printerr(1, "lstat");
+                       else
+                               show_stats(oldpath, dents[cur].name, &sb);
+
+                       goto begin;
+               }
                case SEL_FSIZE:
                        sizeorder = !sizeorder;
                        mtimeorder = 0;