Newsgroups: comp.os.linux.announce
From: marcel@duteca.et.tudelft.nl (Marcel Mol)
Subject: ANNOUNCE: color ls patches for fileutils 3.5
Message-ID: <1993Jun1.231554.16271@klaava.Helsinki.FI>
Date: Tue, 1 Jun 1993 23:15:54 GMT
Approved: linux-announce@tc.cornell.edu (Lars Wirzenius)

Below follows a patch to get color output from ls in 
GNU fileutils 3.5.
It is based on previous patches for color ls for fileutils 3.4
including the one setting colors based on filename extensions.
BTW, the option to switch on color is changed from -f to -e
(extended-display :-) cause the GNU guys use the -f option for
something else.

Color-ls gives ansi color support and works great on for example
the color xterm or on aixterm (oops).
I also update the Usage() function to show the options for the
new ls functions in fileutils 3.5 ...

Wonder when color support will make it into the distributed 
fileutils code ... 
Who maintains the fileutils anyway, so I can mail the patches
to them/him/her?

Have fun with it!

-Marcel
---------------------------------------------------------------------------
*** src/ls.c.org	Sun May 30 18:22:03 1993
--- src/ls.c	Mon May 31 01:43:42 1993
***************
*** 32,37 ****
--- 32,63 ----
  
  /* Written by Richard Stallman and David MacKenzie. */
  
+ /* 8-bit and color support by Peter Anvin <hpa@nwu.edu>
+ 
+    Color support based on original patches by Greg Lee
+                                               <lee@uhunix.uhcc.hawaii.edu>
+ 
+    Display attributes support, auto-disable for pipes, and colors according to
+    file suffixes added by Patrick Volkerding (volkerdi@mhd1.moorhead.msus.edu)
+ 
+    Cleanup of color code. Can now separtely set attributes and foreground
+    and background color.  Had to change the command line option to -e
+    because -f is now user for 'full-time' option. When will color support
+    become part of the GNU distribution ????
+    By Marcel Mol 30May93 <marcel@duteca.et.tudelft.nl>
+ 
+    These features are conditionalized.  To enable them, add the following
+    to the DEFS statement in the main level Makefile:
+ 
+    -DEIGHTBIT=0     To enable 8-bit support (default OFF, activate with -8)
+    -DEIGHTBIT=1     To enable 8-bit support (default ON, deactivate with -7)
+ 
+    -DCOLOR=0        To enable color support (default OFF, activate with -e)
+    -DCOLOR=1        To enable color support (default ON, deactivate with -e)
+    -DCOLOR_FILETYPE To enable color support based on filename extensions
+                     (obnly works when COLOR is defined)
+ */
+ 
  #ifdef _AIX
   #pragma alloca
  #endif
***************
*** 51,56 ****
--- 77,97 ----
  #define S_IEXEC S_IXUSR
  #endif
  
+ /* The following handles the conditionalizations of the 8-bit and
+    color options */
+ 
+ #ifndef COLOR
+ #define COLOR_DEFAULT 0
+ #else
+ #define COLOR_DEFAULT COLOR
+ #endif
+ 
+ #ifndef EIGHTBIT
+ #define EIGHTBIT_DEFAULT 0
+ #else
+ #define EIGHTBIT_DEFAULT EIGHTBIT
+ #endif
+ 
  /* Return an int indicating the result of comparing two longs. */
  #ifdef INT_16_BITS
  #define longdiff(a, b) ((a) < (b) ? -1 : (a) > (b) ? 1 : 0)
***************
*** 106,111 ****
--- 147,156 ----
  static void print_many_per_line ();
  static void print_name_with_quoting ();
  static void print_type_indicator ();
+ #ifdef COLOR
+ static char match_suffix();
+ static void print_colorized_name ();
+ #endif
  static void print_with_commas ();
  static void queue_directory ();
  static void sort_files ();
***************
*** 252,257 ****
--- 297,308 ----
  
  static int print_block_size;
  
+ #ifdef COLOR
+ /* Nonzero means use color for types.  -e toggles. */
+ 
+ static int print_with_color;
+ #endif
+ 
  /* Nonzero means show file sizes in kilobytes instead of blocks
     (the size of which is system-dependant).  -k */
  
***************
*** 352,357 ****
--- 403,416 ----
  
  static int format_needs_stat;
  
+ #ifdef EIGHTBIT
+ /* If zero, we consider all characters above 0x7E as nongraphic chars.
+    Default is to consider 0xA1 to 0xFF as graphic (ISO 8859).
+    -7 disables, -8 enables. */
+ 
+ static int bit8_ok;
+ #endif
+ 
  /* The exit status to use if we don't get any fatal errors. */
  
  static int exit_status;
***************
*** 391,396 ****
--- 450,468 ----
    {"time", required_argument, 0, 11},
    {"help", no_argument, &flag_help, 1},
    {"version", no_argument, &flag_version, 1},
+ 
+ #ifdef COLOR
+   /* Retain these (as dummy options) even if disabled */
+   {"color", 0, 0, 20},
+   {"colour", 0, 0, 20},
+   {"no-color", 0, 0, 21},
+   {"no-colour", 0, 0, 21},
+ #endif
+ #ifdef EIGHTBIT
+   {"7bit", 0, 0, '7'},
+   {"8bit", 0, 0, '8'},
+ #endif
+ 
    {0, 0, 0, 0}
  };
  
***************
*** 453,459 ****
    format_needs_stat = sort_type == sort_time || sort_type == sort_size
      || format == long_format
      || trace_links || trace_dirs || indicator_style != none
!     || print_block_size || print_inode;
  
    nfiles = 100;
    files = (struct file *) xmalloc (sizeof (struct file) * nfiles);
--- 525,535 ----
    format_needs_stat = sort_type == sort_time || sort_type == sort_size
      || format == long_format
      || trace_links || trace_dirs || indicator_style != none
!     || print_block_size || print_inode
! #ifdef COLOR
!     || print_with_color
! #endif
!     ;
  
    nfiles = 100;
    files = (struct file *) xmalloc (sizeof (struct file) * nfiles);
***************
*** 562,567 ****
--- 638,649 ----
    really_all_files = 0;
    ignore_patterns = 0;
    quote_as_string = 0;
+ #ifdef COLOR
+   print_with_color = COLOR_DEFAULT;
+ #endif
+ #ifdef EIGHTBIT
+   bit8_ok = EIGHTBIT_DEFAULT;
+ #endif
  
    p = getenv ("COLUMNS");
    line_length = p ? atoi (p) : 80;
***************
*** 578,585 ****
    p = getenv ("TABSIZE");
    tabsize = p ? atoi (p) : 8;
  
!   while ((c = getopt_long (argc, argv, "abcdfgiklmnpqrstuw:xABCFGI:LNQRST:UX1",
  			   long_options, (int *) 0)) != EOF)
      {
        switch (c)
  	{
--- 660,677 ----
    p = getenv ("TABSIZE");
    tabsize = p ? atoi (p) : 8;
  
! /* while ((c = getopt_long (argc, argv, "abcdefgiklmnpqrstuw:xABCFGI:LNQRST:UX178", */
!   while ((c = getopt_long (argc, argv, "abcd" 
! #ifdef COLOR
! 			"e"
! #endif
! 			"fgiklmnpqrstuw:xABCFGI:LNQRST:UX1"
! #ifdef EIGHTBIT
! 			"78"
! #endif
!                         ,
  			   long_options, (int *) 0)) != EOF)
+ 
      {
        switch (c)
  	{
***************
*** 604,609 ****
--- 696,708 ----
  	  immediate_dirs = 1;
  	  break;
  
+ #ifdef COLOR
+         case 'e':
+           /* No effect if color is disabled */
+           print_with_color = !COLOR_DEFAULT;
+         break;
+ #endif
+ 
  	case 'f':
  	  full_time = 1;
  	  break;
***************
*** 733,738 ****
--- 832,849 ----
  	  format = one_per_line;
  	  break;
  
+ #ifdef EIGHTBIT
+         case '7':
+           /* Dummy option if EIGHTBIT is not defined */
+           bit8_ok = 0;
+           break;
+ 
+         case '8':
+           /* Dummy option if EIGHTBIT is not defined */
+           bit8_ok = 1;
+           break;
+ #endif
+ 
  	case 10:		/* +sort */
  	  i = argmatch (optarg, sort_args);
  	  if (i < 0)
***************
*** 763,768 ****
--- 874,889 ----
  	  format = formats[i];
  	  break;
  	  
+ #ifdef COLOR
+         case 20:                /* --color */
+           print_with_color = 1;
+           break;
+ 
+         case 21:                /* --no-color */
+           print_with_color = 0;
+           break;
+ #endif
+ 
  	default:
  	  usage ();
  	}
***************
*** 1380,1385 ****
--- 1501,1512 ----
      }
  }
  
+ #ifdef COLOR
+ #define PRINT_COLORIZED(NAME,MODE) print_colorized_name (NAME,MODE)
+ #else
+ #define PRINT_COLORIZED(NAME,MODE) print_name_with_quoting (NAME)
+ #endif
+ 
  static void
  print_long_format (f)
       struct file *f;
***************
*** 1456,1462 ****
  
    printf ("%s ", full_time ? timebuf : timebuf + 4);
  
!   print_name_with_quoting (f->name);
  
    if (f->filetype == symbolic_link)
      {
--- 1583,1589 ----
  
    printf ("%s ", full_time ? timebuf : timebuf + 4);
  
!   PRINT_COLORIZED (f->name, f->stat.st_mode);
  
    if (f->filetype == symbolic_link)
      {
***************
*** 1463,1469 ****
        if (f->linkname)
  	{
  	  fputs (" -> ", stdout);
! 	  print_name_with_quoting (f->linkname);
  	  if (indicator_style != none)
  	    print_type_indicator (f->linkmode);
  	}
--- 1590,1596 ----
        if (f->linkname)
  	{
  	  fputs (" -> ", stdout);
!           PRINT_COLORIZED (f->linkname, f->linkmode);
  	  if (indicator_style != none)
  	    print_type_indicator (f->linkmode);
  	}
***************
*** 1520,1526 ****
  	      break;
  
  	    default:
! 	      if (c > 040 && c < 0177)
  		putchar (c);
  	      else
  		printf ("\\%03o", (unsigned int) c);
--- 1647,1658 ----
  	      break;
  
  	    default:
! #ifdef EIGHTBIT
!               if ( (c >= 0x20 && c <= 0x7E) || (bit8_ok && c >= 0xA1 && c <= 0xFF) )
! #else
!               if (c >= 040 && c < 0177)
! /*	      if (c > 040 && c < 0177) */
! #endif
  		putchar (c);
  	      else
  		printf ("\\%03o", (unsigned int) c);
***************
*** 1528,1534 ****
  	}
        else
  	{
! 	  if (c >= 040 && c < 0177)
  	    putchar (c);
  	  else if (!qmark_funny_chars)
  	    putchar (c);
--- 1660,1670 ----
  	}
        else
  	{
! #ifdef EIGHTBIT
!           if ( (c >= 0x20 && c <= 0x7E) || (bit8_ok && c >= 0xA1 && c <= 0xFF) )
! #else
!           if (c >= 040 && c < 0177)
! #endif
  	    putchar (c);
  	  else if (!qmark_funny_chars)
  	    putchar (c);
***************
*** 1556,1562 ****
      printf ("%*u ", block_size_size,
  	    convert_blocks (ST_NBLOCKS (f->stat), kilobyte_blocks));
  
!   print_name_with_quoting (f->name);
  
    if (indicator_style != none)
      print_type_indicator (f->stat.st_mode);
--- 1692,1698 ----
      printf ("%*u ", block_size_size,
  	    convert_blocks (ST_NBLOCKS (f->stat), kilobyte_blocks));
  
!   PRINT_COLORIZED (f->name, f->stat.st_mode);
  
    if (indicator_style != none)
      print_type_indicator (f->stat.st_mode);
***************
*** 1589,1600 ****
      putchar ('*');
  }
  
  static int
  length_of_file_name_and_frills (f)
       struct file *f;
  {
    register char *p = f->name;
!   register char c;
    register int len = 0;
  
    if (print_inode)
--- 1725,1940 ----
      putchar ('*');
  }
  
+ #ifdef COLOR
+ 
+ /*
+  * Colors
+  */
+ #define BLACK		'0'
+ #define RED		'1'
+ #define GREEN		'2'
+ #define YELLOW		'3'
+ #define BLUE		'4'
+ #define MAGENTA		'5'
+ #define CYAN		'6'
+ #define WHITE		'7'
+ 
+ /*
+  * Attributes
+  *
+  * As both forground and background colors can be specified, REVERSE
+  * is not a useful attribute. 
+  * LOWGRAY makes the foreground low intensity white on a color screen.
+  * UNDERSCORE makes the foreground high intensity white on a color screen.
+  * Don't know what happens on a monochrome screen. Anyone?
+  * CONCELED doesn't seem to do anything on a color screen.
+  */
+ #define NORMAL		'0'
+ #define INTENS		'1'
+ #define LOWGRAY		'2'	/* fg colors is low intens gray, monochrome? */
+ #define UNDERSCORE	'4'	/* fg colors intens white, monochrome? */
+ #define BLINK		'5'
+ #define REVERSE		'7'	/* not useful on color screen, use fg+bg cols */
+ #define CONCELED	'8'	/* ??? */
+ 
+ /*
+  * The actual settings for the different file types
+  * 
+  * xxx_FGCOLOR is the foreground color
+  * xxx_BGCOLOR is the background color
+  * xxx_ATT is the attribute
+  */
+ #define DIR_FGCOLOR	GREEN         /* blue */
+ #define DIR_BGCOLOR	BLACK
+ #define DIR_ATT		NORMAL
+ 
+ #define LINK_FGCOLOR	RED          /* -cyan */
+ #define LINK_BGCOLOR	BLACK
+ #define LINK_ATT	NORMAL
+ 
+ #define FIFO_FGCOLOR	BLUE           /* -red yellow*/
+ #define FIFO_BGCOLOR	BLACK
+ #define FIFO_ATT	NORMAL
+ 
+ #define SOCK_FGCOLOR	YELLOW       /* magenta */
+ #define SOCK_BGCOLOR	BLACK
+ #define SOCK_ATT	INTENS
+ 
+ #define BLK_FGCOLOR	MAGENTA          /* -blue yellow */
+ #define BLK_BGCOLOR	BLACK
+ #define BLK_ATT		INTENS
+ 
+ #define CHR_FGCOLOR	MAGENTA          /* -blue yellow */
+ #define CHR_BGCOLOR	BLACK
+ #define CHR_ATT		NORMAL
+ 
+ #define EXEC_FGCOLOR	CYAN       /* -magenta green */
+ #define EXEC_BGCOLOR	BLACK
+ #define EXEC_ATT	NORMAL
+ 
+ #ifdef COLOR_FILETYPE
+ /*
+  * This function sees if the second argument matches the last characters of the
+  * first one. It is used to see whether we should colorize-by-file-suffix 
+  */
+ static char
+ match_suffix (name, suffix)
+      char *name;
+      char *suffix;
+ {
+     int offset;
+ 
+     offset = strlen(name) - strlen(suffix);
+     if ( offset >= 0 ) {
+         if (!strcmp(name+offset, suffix))
+             return 1;
+     }
+     return 0;
+ 
+ } /* match_suffix */
+ #endif
+ 
+ static void
+ print_colorized_name (name, mode)
+      char *name;
+      unsigned int mode;
+ {
+   register char c;
+   register char b;
+   register char a;
+ 
+   c = b = a = 0;
+ 
+   if ( print_with_color  && isatty(1) ) {
+       if (S_ISDIR (mode)) {
+           c = DIR_FGCOLOR;
+           b = DIR_BGCOLOR;
+           a = DIR_ATT;
+       }
+ 
+ #ifdef S_ISLNK
+       else if (S_ISLNK (mode)) {
+           c = LINK_FGCOLOR;
+           b = LINK_BGCOLOR;
+           a = LINK_ATT;
+       }
+ #endif
+ 
+ #ifdef S_ISFIFO
+       else if (S_ISFIFO (mode)) {
+           c = FIFO_FGCOLOR;
+           b = FIFO_BGCOLOR;
+           a = FIFO_ATT;
+       }
+ #endif
+ 
+ #ifdef S_ISSOCK
+       else if (S_ISSOCK (mode)) {
+           c = SOCK_FGCOLOR;
+           b = SOCK_BGCOLOR;
+           a = SOCK_ATT;
+       }
+ #endif
+ 
+ #ifdef S_ISBLK
+       else if (S_ISBLK (mode)) {
+           c = BLK_FGCOLOR;
+           b = BLK_BGCOLOR;
+           a = BLK_ATT;
+       }
+ #endif
+ 
+ #ifdef S_ISCHR
+       else if (S_ISCHR (mode)) {
+           c = CHR_FGCOLOR;
+           b = CHR_BGCOLOR;
+           a = CHR_ATT;
+       }
+ #endif
+ 
+       else if ( S_ISREG (mode) &&
+                 (mode & (S_IEXEC | S_IEXEC >> 3 | S_IEXEC >> 6))) {
+           c = EXEC_FGCOLOR;
+           b = EXEC_BGCOLOR;
+           a = EXEC_ATT;
+       }
+ 
+ #ifdef COLOR_FILETYPE
+       /*
+        * Let's use a 'standard': use colored backgrounds for 
+        * extension based settings and colored foreground for 
+        * above detected unix filetypes.
+        */
+       if ( S_ISREG (mode) ) {
+           if (match_suffix(name,".cmd") || match_suffix(name,".com") ||
+               match_suffix(name,".btm") || match_suffix(name,".exe") ||
+               match_suffix(name,".bat")) {
+               b = EXEC_FGCOLOR; /* swich bg fg color, cause these are */
+               c = EXEC_BGCOLOR; /* not really executables */
+               a = EXEC_ATT;
+           } else if (match_suffix(name,".tar") || match_suffix(name,".tgz") ||
+                      match_suffix(name,".zoo") || match_suffix(name,".arj") ||
+                      match_suffix(name,".taz") || match_suffix(name,".lzh") ||
+                      match_suffix(name,".zip") || match_suffix(name,".z")   ||
+                      match_suffix(name,".Z")) {
+               c = BLACK;
+               b = GREEN;
+               a = NORMAL;
+           } else if (match_suffix(name,".jpg") || match_suffix(name,".gif") ||
+                      match_suffix(name,".bmp")) {
+               c = BLACK;
+               b = YELLOW;
+               a = INTENS; /* make it really yellow */
+           } else if (match_suffix(name,".dll") || match_suffix(name,".txt") ||
+                      match_suffix(name,".doc") || match_suffix(name,".sys") ||
+                      match_suffix(name,".drv") || match_suffix(name,".ini")) {
+               c = BLACK;
+               b = WHITE;
+               a = NORMAL;
+           }
+       }
+ #endif
+ 
+       if (c)
+           printf("\33[0%c;4%c;3%cm", a, b, c);
+ 
+     }
+ 
+     print_name_with_quoting(name);
+ 
+     if (c || b || a)   /* check for 'c' should be enough... */
+         printf("\33[0m"); 
+ 
+ } /* print_colorized_name */
+ #endif /* COLOR */
+ 
+ 
  static int
  length_of_file_name_and_frills (f)
       struct file *f;
  {
    register char *p = f->name;
!   register unsigned char c;
    register int len = 0;
  
    if (print_inode)
***************
*** 1630,1636 ****
  	      break;
  
  	    default:
! 	      if (c >= 040 && c < 0177)
  		len += 1;
  	      else
  		len += 4;
--- 1970,1980 ----
  	      break;
  
  	    default:
! #ifdef EIGHTBIT
!               if ( (c >= 0x20 && c <= 0x7E) || (bit8_ok && c >= 0xA1 && c <= 0xFF) )
! #else
!               if (c >= 040 && c < 0177)
! #endif
  		len += 1;
  	      else
  		len += 4;
***************
*** 1851,1866 ****
  usage ()
  {
    fprintf (stderr, "\
! Usage: %s [-abcdgiklmnpqrstuxABCFGLNQRSUX1] [-w cols] [-T cols] [-I pattern]\n\
         [--all] [--escape] [--directory] [--inode] [--kilobytes] [--literal]\n\
         [--numeric-uid-gid] [--hide-control-chars] [--reverse] [--size]\n\
         [--width=cols] [--tabsize=cols] [--almost-all] [--ignore-backups]\n",
! 	   program_name);
    fprintf (stderr, "\
         [--classify] [--file-type] [--ignore=pattern] [--dereference]\n\
         [--quote-name] [--recursive] [--sort={none,time,size,extension}]\n\
         [--format={long,verbose,commas,across,vertical,single-column}]\n\
!        [--time={atime,access,use,ctime,status}] [--no-group]\n\
!        [--help] [--version] [path...]\n");
    exit (1);
  }
--- 2195,2234 ----
  usage ()
  {
    fprintf (stderr, "\
! Usage: %s [-abcd%sfgiklmnpqrstuxABCFGLNQRSUX1%s] [-w cols] [-T cols] [-I pattern]\n\
         [--all] [--escape] [--directory] [--inode] [--kilobytes] [--literal]\n\
         [--numeric-uid-gid] [--hide-control-chars] [--reverse] [--size]\n\
         [--width=cols] [--tabsize=cols] [--almost-all] [--ignore-backups]\n",
! 	   program_name,
! #ifdef COLOR
!            "e",
! #else
!            "",
! #endif
! #ifdef EIGHTBIT
!            "78"
! #else
!            ""
! #endif
! 
!           );
    fprintf (stderr, "\
         [--classify] [--file-type] [--ignore=pattern] [--dereference]\n\
         [--quote-name] [--recursive] [--sort={none,time,size,extension}]\n\
         [--format={long,verbose,commas,across,vertical,single-column}]\n\
!        [--time={atime,access,use,ctime,status}] [--no-group] [--full-time]\n\
!        %s%s[--help] [--version] [path...]\n",
! #ifdef COLOR
!            COLOR_DEFAULT ? "[--no-color] " : "[--color] ",
! #else
!            "",
! #endif
! #ifdef EIGHTBIT
!            EIGHTBIT_DEFAULT ? "[--7bit] " : "[--8bit] "
! #else
!            ""
! #endif
!           );
! 
    exit (1);
  }
-- 
#########################################
# Marcel J.E. Mol                       ######################################
# Delft University of Technology        # Pink Elephant B.V.                 #
# Electrotechnical Engineering          # System management services         #
# The Netherlands                       # Voorburg                           #
# inet: marcel@duteca.et.tudelft.nl     # Phone: 070-3694231                 #
#                      	  (Phone private: (+31) 070-3361515)                 #
##############################################################################
 They couldn't think of a number, so they gave me a name!
                                -- Rupert Hine
