changeset 459:1dbe91079950

Second drop of ls from Andre, adds -l.
author Rob Landley <rob@landley.net>
date Mon, 13 Feb 2012 21:27:50 -0600
parents 9786a697d5aa
children 55d815926c5c
files toys/ls.c
diffstat 1 files changed, 80 insertions(+), 20 deletions(-) [+]
line wrap: on
line diff
--- a/toys/ls.c	Mon Feb 13 21:26:27 2012 -0600
+++ b/toys/ls.c	Mon Feb 13 21:27:50 2012 -0600
@@ -4,20 +4,21 @@
  *
  * Copyright 2012 Andre Renaud <andre@bluewatersys.com>
  *
- * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.htm
+ * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html
 
-USE_LS(NEWTOY(ls, "F1a", TOYFLAG_USR|TOYFLAG_BIN))
+USE_LS(NEWTOY(ls, "lF1a", TOYFLAG_BIN))
 
 config LS
 	bool "ls"
 	default y
 	help
-	  usage: ls [-F] [-a] [-1] [directory...]
+	  usage: ls [-l] [-F] [-a] [-1] [directory...]
 	  list files
 
           -F    append a character as a file type indicator
           -a    list all files
           -1    list one file per line
+          -l    show full details for each file
 */
 
 #include "toys.h"
@@ -25,6 +26,7 @@
 #define FLAG_a 1
 #define FLAG_1 2
 #define FLAG_F 4
+#define FLAG_l 8
 
 static int dir_filter(const struct dirent *d)
 {
@@ -41,11 +43,12 @@
     int nentries;
     int i;
     int maxwidth = -1;
-    int ncolumns;
+    int ncolumns = 1;
 
-    if (strcmp(name, "-") == 0)
+    if (!name || strcmp(name, "-") == 0)
         name = ".";
 
+    /* Get all the files in this directory */
     nentries = scandir(name, &entries, dir_filter, alphasort);
     if (nentries < 0)
         perror_exit("ls: cannot access %s'", name);
@@ -71,43 +74,100 @@
 
         columns_str = getenv("COLUMNS");
         columns = columns_str ? atoi(columns_str) : 80;
-        ncolumns = columns / maxwidth;
+        ncolumns = maxwidth ? columns / maxwidth : 1;
     }
 
     for (i = 0; i < nentries; i++) {
         struct dirent *ent = entries[i];
         int len = strlen(ent->d_name);
+        struct stat st;
+        int stat_valid = 0;
 
-        printf("%s", ent->d_name);
+        /* Provide the ls -l long output */
+        if (toys.optflags & FLAG_l) {
+            char type;
+            char timestamp[64];
+            struct tm mtime;
+
+            if (lstat(ent->d_name, &st))
+                perror_exit("Can't stat %s", ent->d_name);
+            stat_valid = 1;
+            if (S_ISDIR(st.st_mode))
+                type = 'd';
+            else if (S_ISCHR(st.st_mode))
+                type = 'c';
+            else if (S_ISBLK(st.st_mode))
+                type = 'b';
+            else if (S_ISLNK(st.st_mode))
+                type = 'l';
+            else
+                type = '-';
+
+            xprintf("%c%c%c%c%c%c%c%c%c%c ", type,
+                (st.st_mode & S_IRUSR) ? 'r' : '-',
+                (st.st_mode & S_IWUSR) ? 'w' : '-',
+                (st.st_mode & S_IXUSR) ? 'x' : '-',
+                (st.st_mode & S_IRGRP) ? 'r' : '-',
+                (st.st_mode & S_IWGRP) ? 'w' : '-',
+                (st.st_mode & S_IXGRP) ? 'x' : '-',
+                (st.st_mode & S_IROTH) ? 'r' : '-',
+                (st.st_mode & S_IWOTH) ? 'w' : '-',
+                (st.st_mode & S_IXOTH) ? 'x' : '-');
+
+            xprintf("%2d ", st.st_nlink);
+            /* FIXME: We're never looking up uid/gid numbers */
+            xprintf("%4d ", st.st_uid);
+            xprintf("%4d ", st.st_gid);
+            if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode))
+                xprintf("%3d, %3d ", major(st.st_rdev), minor(st.st_rdev));
+            else
+                xprintf("%8ld ", st.st_size);
+
+            localtime_r(&st.st_mtime, &mtime);
+
+            strftime(timestamp, sizeof(timestamp), "%b %e %H:%M", &mtime);
+            xprintf("%s ", timestamp);
+        }
+
+        xprintf("%s", ent->d_name);
+
+        /* Append the file-type indicator character */
         if (toys.optflags & FLAG_F) {
-            struct stat st;
-            if (stat(ent->d_name, &st))
-                perror_exit("Can't stat %s", ent->d_name);
+            if (!stat_valid) {
+                if (lstat(ent->d_name, &st))
+                    perror_exit("Can't stat %s", ent->d_name);
+                stat_valid = 1;
+            }
             if (S_ISDIR(st.st_mode)) {
-                printf("/");
+                xprintf("/");
                 len++;
-            }
-            if (S_ISREG(st.st_mode) &&
+            } else if (S_ISREG(st.st_mode) &&
                 (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
-                printf("*");
+                xprintf("*");
+                len++;
+            } else if (S_ISLNK(st.st_mode)) {
+                xprintf("@");
                 len++;
             }
         }
-        if (toys.optflags & FLAG_1)
-            printf("\n");
-        else {
+        if (toys.optflags & FLAG_1) {
+            xprintf("\n");
+        } else {
             if (i % ncolumns == ncolumns - 1)
-                printf("\n");
+                xprintf("\n");
             else
-                printf("%*s", maxwidth - len, "");
+                xprintf("%*s", maxwidth - len, "");
         }
     }
     /* Make sure we put at a trailing new line in */
     if (!(toys.optflags & FLAG_1) && (i % ncolumns))
-        printf("\n");
+        xprintf("\n");
 }
 
 void ls_main(void)
 {
+    /* Long output must be one-file per line */
+    if (toys.optflags & FLAG_l)
+        toys.optflags |= FLAG_1;
     loopfiles(toys.optargs, do_ls);
 }