changeset 940:a425f97975d3

First pass at ls --color
author Rob Landley <rob@landley.net>
date Sun, 30 Jun 2013 23:52:45 -0500
parents b58e86e366ab
children 62ba5ce62e9d
files toys/posix/ls.c
diffstat 1 files changed, 52 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/toys/posix/ls.c	Sun Jun 30 16:52:57 2013 -0500
+++ b/toys/posix/ls.c	Sun Jun 30 23:52:45 2013 -0500
@@ -5,7 +5,7 @@
  *
  * See http://opengroup.org/onlinepubs/9699919799/utilities/ls.html
 
-USE_LS(NEWTOY(ls, "goACFHLRSacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN))
+USE_LS(NEWTOY(ls, USE_LS_COLOR("(color)")"goACFHLRSacdfiklmnpqrstux1[-1Cglmnox][-cu][-ftS][-HL]", TOYFLAG_BIN))
 
 config LS
   bool "ls"
@@ -31,6 +31,15 @@
 
     sorting (default is alphabetical):
     -f	unsorted	-r  reverse	-t  timestamp	-S  size
+
+config LS_COLOR
+  bool "ls --color"
+  default y
+  help
+    usage: ls --color
+
+    --color  device=yellow  symlink=turquoise/red  dir=blue  socket=purple
+             files: exe=green  suid=red  suidfile=redback  stickydir=greenback
 */
 
 #define FOR_ls
@@ -193,6 +202,20 @@
   return (*xpos*height) + widecols + (ul/(columns-1));
 }
 
+int color_from_mode(mode_t mode)
+{
+  int color = 0;
+
+  if (S_ISDIR(mode)) color = 256+34;
+  else if (S_ISLNK(mode)) color = 256+36;
+  else if (S_ISBLK(mode) || S_ISCHR(mode)) color = 256+33;
+  else if (S_ISREG(mode) && (mode&0111)) color = 256+32;
+  else if (S_ISFIFO(mode)) color = 33;
+  else if (S_ISSOCK(mode)) color = 256+35;
+
+  return color;
+}
+
 // Display a list of dirtree entries, according to current format
 // Output types -1, -l, -C, or stream
 
@@ -290,7 +313,7 @@
   memset(toybuf, ' ', 256);
   width = 0;
   for (ul = 0; ul<dtlen; ul++) {
-    unsigned curcol;
+    unsigned curcol, color = 0;
     unsigned long next = next_column(ul, dtlen, columns, &curcol);
     struct stat *st = &(sort[next]->st);
     mode_t mode = st->st_mode;
@@ -349,12 +372,31 @@
         (int64_t)st->st_size, thyme);
     }
 
+    if ((flags & FLAG_color) && TT.screen_width) {
+      color = color_from_mode(st->st_mode);
+      if (color) printf("\033[%d;%dm", color>>8, color&255);
+    }
+
     if (flags & FLAG_q) {
       char *p;
       for (p=sort[next]->name; *p; p++) xputc(isprint(*p) ? *p : '?');
     } else xprintf("%s", sort[next]->name);
-    if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode))
-      xprintf(" -> %s", sort[next]->symlink);
+    if (color) xprintf("\033[0m");
+
+    if ((flags & (FLAG_l|FLAG_o|FLAG_n|FLAG_g)) && S_ISLNK(mode)) {
+      printf(" -> ");
+      if ((flags & FLAG_color) && TT.screen_width) {
+        struct stat st2;
+
+        if (fstatat(dirfd, sort[next]->symlink, &st2, 0)) color = 256+31;
+        else color = color_from_mode(st2.st_mode);
+
+        if (color) printf("\033[%d;%dm", color>>8, color&255);
+      }
+
+      printf("%s", sort[next]->symlink);
+      if (color) printf("\033[0m");
+    }
 
     if (et) xputc(et);
 
@@ -378,7 +420,7 @@
       listfiles(openat(dirfd, sort[ul]->name, 0), sort[ul]);
   }
   free(sort);
-  if (dirfd != AT_FDCWD) close(indir->data);
+  if (dirfd != AT_FDCWD) close(dirfd);
 }
 
 void ls_main(void)
@@ -386,15 +428,14 @@
   char **s, *noargs[] = {".", 0};
   struct dirtree *dt;
 
+  TT.screen_width = 80;
+  terminal_size(&TT.screen_width, NULL);
+  if (TT.screen_width<2) TT.screen_width = 2;
+
   // Do we have an implied -1
   if (!isatty(1) || (toys.optflags&(FLAG_l|FLAG_o|FLAG_n|FLAG_g)))
     toys.optflags |= FLAG_1;
-  else {
-    TT.screen_width = 80;
-    terminal_size(&TT.screen_width, NULL);
-    if (TT.screen_width<2) TT.screen_width = 2;
-    if (!(toys.optflags&(FLAG_1|FLAG_x|FLAG_m))) toys.optflags |= FLAG_C;
-  }
+  else if (!(toys.optflags&(FLAG_1|FLAG_x|FLAG_m))) toys.optflags |= FLAG_C;
   // The optflags parsing infrastructure should really do this for us,
   // but currently it has "switch off when this is set", so "-dR" and "-Rd"
   // behave differently