Index: ls.c
===================================================================
RCS file: /usr/cvs/src/bin/ls/ls.c,v
retrieving revision 1.32
retrieving revision 1.40
diff -u -r1.32 -r1.40
--- ls.c	2000/02/05 18:42:27	1.32
+++ ls.c	2000/06/06 13:02:52	1.40
@@ -63,7 +63,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
 #include <locale.h>
+#ifdef COLORLS
+#include <termcap.h>
+#include <signal.h>
+#endif
 
 #include "ls.h"
 #include "extern.h"
@@ -111,6 +115,13 @@
 int f_timesort;			/* sort by time vice name */
 int f_type;			/* add type character for non-regular files */
 int f_whiteout;			/* show whiteout entries */
+#ifdef COLORLS
+int f_color;			/* add type in color for non-regular files */
+
+char *ansi_bgcol;		/* ANSI sequence to set background colour */
+char *ansi_fgcol;		/* ANSI sequence to set foreground colour */
+char *ansi_coloff;		/* ANSI sequence to reset colours */
+#endif
 
 int rval;
 
@@ -124,6 +135,12 @@
 	int ch, fts_options, notused;
 	char *p;
 
+#ifdef COLORLS
+	char termcapbuf[1024];		/* termcap definition buffer */
+	char tcapbuf[512];		/* capability buffer */
+	char *bp = tcapbuf;
+#endif
+
 	(void) setlocale(LC_ALL, "");
 
 	/* Terminal defaults to -Cq, non-terminal defaults to -1. */
@@ -148,7 +165,7 @@
 		f_listdot = 1;
 
 	fts_options = FTS_PHYSICAL;
-	while ((ch = getopt(argc, argv, "1ABCFHLPRTWabcdfgikloqrstu")) != -1) {
+	while ((ch = getopt(argc, argv, "1ABCFGHLPRTWabcdfgikloqrstu")) != -1) {
 		switch (ch) {
 		/*
 		 * The -1, -C and -l options all override each other so shell
@@ -186,6 +203,26 @@
 		case 'H':
 		        fts_options |= FTS_COMFOLLOW;
 			break;
+		case 'G':
+			if (isatty(STDOUT_FILENO))
+#ifdef COLORLS
+				if (tgetent(termcapbuf, getenv("TERM")) == 1) {
+					ansi_fgcol = tgetstr("AF", &bp);
+					ansi_bgcol = tgetstr("AB", &bp);
+
+					/* To switch colours off use 'op' if
+					 * available, otherwise use 'oc', or
+					 * don't do colours at all. */
+					ansi_coloff = tgetstr("op", &bp);
+					if (!ansi_coloff)
+						ansi_coloff = tgetstr("oc", &bp);
+					if (ansi_fgcol && ansi_bgcol && ansi_coloff)
+						f_color = 1;
+				}
+#else
+				(void)fprintf(stderr, "Color support not compiled in.\n");
+#endif
+			break;
 		case 'L':
 			fts_options &= ~FTS_PHYSICAL;
 			fts_options |= FTS_LOGICAL;
@@ -259,11 +296,30 @@
 	argc -= optind;
 	argv += optind;
 
+#ifdef COLORLS
+	if (f_color) {
+		/*
+		 * We can't put tabs and color sequences together:
+		 * column number will be incremented incorrectly
+		 * for "stty oxtabs" mode.
+		 */
+		f_notabs = 1;
+		(void) signal(SIGINT, colorquit);
+		(void) signal(SIGQUIT, colorquit);
+		parsecolors(getenv("LSCOLORS"));
+	}
+#endif
+
 	/*
 	 * If not -F, -i, -l, -s or -t options, don't require stat
-	 * information.
+	 * information, unless in color mode in which case we do
+	 * need this to determine which colors to display.
 	 */
-	if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type)
+	if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type
+#ifdef COLORLS
+	    && !f_color
+#endif
+	   )
 		fts_options |= FTS_NOSTAT;
 
 	/*
@@ -471,7 +527,11 @@
 		 case 4: maxgroup = 0;
 		 case 5: maxflags = 0;
 		 case 6: maxsize  = 0;
-		 case 7: maxlen   = 0, f_notabs = 0;
+		 case 7: maxlen   = 0;
+#ifdef COLORLS
+		 if (!f_color)
+#endif
+			 f_notabs = 0;
 		}
 		maxinode = makenines(maxinode);
 		maxblock = makenines(maxblock);
Index: ls.h
===================================================================
RCS file: /usr/cvs/src/bin/ls/ls.h,v
retrieving revision 1.11
retrieving revision 1.13
diff -u -r1.11 -r1.13
--- ls.h	1999/08/27 23:14:32	1.11
+++ ls.h	2000/06/05 02:14:01	1.13
@@ -53,6 +53,9 @@
 extern int f_statustime;	/* use time of last mode change */
 extern int f_notabs;		/* don't use tab-separated multi-col output */
 extern int f_type;		/* add type character for non-regular files */
+#ifdef COLORLS
+extern int f_color;		/* add type in color for non-regular files */
+#endif
 
 typedef struct {
 	FTSENT *list;
Index: extern.h
===================================================================
RCS file: /usr/cvs/src/bin/ls/extern.h,v
retrieving revision 1.7
retrieving revision 1.12
diff -u -r1.7 -r1.12
--- extern.h	1999/08/27 23:14:31	1.7
+++ extern.h	2000/06/06 07:14:01	1.12
@@ -51,3 +51,11 @@
 void	 usage __P((void));
 int	 len_octal __P((char *, int));
 int	 prn_octal __P((char *));
+#ifdef COLORLS
+void	 parsecolors __P((char *cs));
+void     colorquit __P((int));
+
+extern  char    *ansi_fgcol;
+extern  char    *ansi_bgcol;
+extern  char    *ansi_coloff;
+#endif
Index: print.c
===================================================================
RCS file: /usr/cvs/src/bin/ls/print.c,v
retrieving revision 1.19
retrieving revision 1.33
diff -u -r1.19 -r1.33
--- print.c	2000/01/06 14:40:10	1.19
+++ print.c	2000/06/06 16:39:24	1.33
@@ -56,6 +56,11 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#ifdef COLORLS
+#include <ctype.h>
+#include <termcap.h>
+#include <signal.h>
+#endif
 
 #include "ls.h"
 #include "extern.h"
@@ -64,9 +69,35 @@
 static void	printlink __P((FTSENT *));
 static void	printtime __P((time_t));
 static int	printtype __P((u_int));
+#ifdef COLORLS
+static void     endcolor __P((int));
+static int      colortype __P((mode_t));
+#endif
 
 #define	IS_NOPRINT(p)	((p)->fts_number == NO_PRINT)
 
+#ifdef COLORLS
+/* Most of these are taken from <sys/stat.h> */
+typedef enum Colors {
+    C_DIR,     /* directory */
+    C_LNK,     /* symbolic link */
+    C_SOCK,    /* socket */
+    C_FIFO,    /* pipe */
+    C_EXEC,    /* executable */
+    C_BLK,     /* block special */
+    C_CHR,     /* character special */
+    C_SUID,    /* setuid executable */
+    C_SGID,    /* setgid executable */
+    C_WSDIR,   /* directory writeble to others, with sticky bit */
+    C_WDIR,    /* directory writeble to others, without sticky bit */
+    C_NUMCOLORS        /* just a place-holder */
+} Colors ;
+
+char *defcolors = "4x5x2x3x1x464301060203";
+
+static int colors[C_NUMCOLORS][2];
+#endif
+
 void
 printscol(dp)
 	DISPLAY *dp;
@@ -89,6 +120,9 @@
 	FTSENT *p;
 	NAMES *np;
 	char buf[20];
+#ifdef COLORLS
+	int color_printed = 0;
+#endif
 
 	if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
 		(void)printf("total %lu\n", howmany(dp->btotal, blocksize));
@@ -128,8 +162,16 @@
 			printtime(sp->st_ctime);
 		else
 			printtime(sp->st_mtime);
+#ifdef COLORLS
+		if (f_color)
+			color_printed = colortype(sp->st_mode);
+#endif
 		if (f_octal || f_octal_escape) (void)prn_octal(p->fts_name);
 		else (void)printf("%s", p->fts_name);
+#ifdef COLORLS
+		if (f_color && color_printed)
+			endcolor(0);
+#endif
 		if (f_type)
 			(void)printtype(sp->st_mode);
 		if (S_ISLNK(sp->st_mode))
@@ -221,6 +263,9 @@
 {
 	struct stat *sp;
 	int chcnt;
+#ifdef COLORLS
+	int color_printed = 0;
+#endif
 
 	sp = p->fts_statp;
 	chcnt = 0;
@@ -229,8 +274,16 @@
 	if (f_size)
 		chcnt += printf("%*qd ",
 		    (int)sizefield, howmany(sp->st_blocks, blocksize));
+#ifdef COLORLS
+	if (f_color)
+		color_printed = colortype(sp->st_mode);
+#endif
 	chcnt += (f_octal || f_octal_escape) ? prn_octal(p->fts_name)
 	                                     : printf("%s", p->fts_name);
+#ifdef COLORLS
+	if (f_color && color_printed)
+		endcolor(0);
+#endif
 	if (f_type)
 		chcnt += printtype(sp->st_mode);
 	return (chcnt);
@@ -294,6 +347,138 @@
 	return (0);
 }
 
+#ifdef COLORLS
+static int
+putch(c)
+	int c;
+{
+	(void) putchar(c);
+	return 0;
+}
+
+static int
+writech(c)
+	int c;
+{
+	char tmp = c;
+
+	(void) write(STDOUT_FILENO, &tmp, 1);
+	return 0;
+}
+
+static void
+printcolor(c)
+       Colors c;
+{
+	char *ansiseq;
+
+	if (colors[c][0] != -1) {
+		ansiseq = tgoto(ansi_fgcol, 0, colors[c][0]);
+		if (ansiseq)
+			tputs(ansiseq, 1, putch);
+	}
+
+	if (colors[c][1] != -1) {
+		ansiseq = tgoto(ansi_bgcol, 0, colors[c][1]);
+		if (ansiseq)
+			tputs(ansiseq, 1, putch);
+	}
+}
+
+static void
+endcolor(sig)
+	int sig;
+{
+	tputs(ansi_coloff, 1, sig ? writech : putch);
+}
+
+static int
+colortype(mode)
+       mode_t mode;
+{
+	switch(mode & S_IFMT) {
+	      case S_IFDIR:
+		if (mode & S_IWOTH)
+		    if (mode & S_ISTXT)
+			printcolor(C_WSDIR);
+		    else
+			printcolor(C_WDIR);
+		else
+		    printcolor(C_DIR);
+		return(1);
+	      case S_IFLNK:
+		printcolor(C_LNK);
+		return(1);
+	      case S_IFSOCK:
+		printcolor(C_SOCK);
+		return(1);
+	      case S_IFIFO:
+		printcolor(C_FIFO);
+		return(1);
+	      case S_IFBLK:
+		printcolor(C_BLK);
+		return(1);
+	      case S_IFCHR:
+		printcolor(C_CHR);
+		return(1);
+	}
+	if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+		if (mode & S_ISUID)
+		    printcolor(C_SUID);
+		else if (mode & S_ISGID)
+		    printcolor(C_SGID);
+		else
+		    printcolor(C_EXEC);
+		return(1);
+	}
+	return(0);
+}
+
+void
+parsecolors(cs)
+char *cs;
+{
+	int i, j, len;
+	char c[2];
+
+	if (cs == NULL)    cs = ""; /* LSCOLORS not set */
+	len = strlen(cs);
+	for (i = 0 ; i < C_NUMCOLORS ; i++) {
+		if (len <= 2*i) {
+			c[0] = defcolors[2*i];
+			c[1] = defcolors[2*i+1];
+		}
+		else {
+			c[0] = cs[2*i];
+			c[1] = cs[2*i+1];
+		}
+		for (j = 0 ; j < 2 ; j++) {
+			if ((c[j] < '0' || c[j] > '7') &&
+			    tolower((unsigned char)c[j]) != 'x') {
+				fprintf(stderr,
+					"error: invalid character '%c' in LSCOLORS env var\n",
+					c[j]);
+				c[j] = defcolors[2*i+j];
+			}
+			if (tolower((unsigned char)c[j]) == 'x')
+			    colors[i][j] = -1;
+			else
+			    colors[i][j] = c[j]-'0';
+		}
+	}
+}
+
+void
+colorquit(sig)
+	int sig;
+{
+	endcolor(sig);
+
+	(void) signal(sig, SIG_DFL);
+	(void) kill(getpid(), sig);
+}
+#endif /*COLORLS*/
+ 
 static void
 printlink(p)
 	FTSENT *p;
Index: util.c
===================================================================
RCS file: /usr/cvs/src/bin/ls/util.c,v
retrieving revision 1.20
retrieving revision 1.21
diff -u -r1.20 -r1.21
--- util.c	1999/08/27 23:14:33	1.20
+++ util.c	2000/06/06 07:29:43	1.21
@@ -158,7 +158,12 @@
 void
 usage()
 {
-	(void)fprintf(stderr, "usage: ls [-ACFHLPRTWacdfgikloqrstu1]"
+	(void)fprintf(stderr,
+#ifdef COLORLS
+	"usage: ls [-ACFGHLPRTWacdfgikloqrstu1]"
+#else
+	"usage: ls [-ACFHLPRTWacdfgikloqrstu1]"
+#endif
 		      " [file ...]\n");
 	exit(1);
 }
Index: Makefile
===================================================================
RCS file: /usr/cvs/src/bin/ls/Makefile,v
retrieving revision 1.9
retrieving revision 1.12
diff -u -r1.9 -r1.12
--- Makefile	2000/02/05 18:42:27	1.9
+++ Makefile	2000/06/05 19:34:31	1.12
@@ -4,5 +4,13 @@

-PROG=	ls
+PROG=	colorls
 SRCS=	cmp.c stat_flags.c ls.c print.c util.c
+BINDIR=	${PREFIX}/bin
+MANDIR= ${PREFIX}/man/man
 
+.if !defined(RELEASE_BUILD_FIXIT)
+CFLAGS+= -DCOLORLS
+LDADD+= -ltermcap
+DPADD+= ${LIBTERMCAP}
+.endif
+
 .include <bsd.prog.mk>
Index: colorls.1
===================================================================
RCS file: /usr/cvs/src/bin/ls/ls.1,v
retrieving revision 1.33
retrieving revision 1.35
diff -u -r1.33 -r1.35
--- colorls.1	2000/03/02 14:53:20	1.33
+++ colorls.1	2000/06/06 00:42:24	1.35
@@ -43,7 +43,15 @@
 .Nd list directory contents
 .Sh SYNOPSIS
 .Nm ls
-.Op Fl ABCFHLPRTWabcdfgikloqrstu1
+.Op Fl ABCFGHLPRTWabcdfgikloqrstu1
 .Op Ar file ...
 .Sh DESCRIPTION
+(Note: This man page describes the color version of the program.  To
+minimize the differences from the original, the program is referred to
+as
+.Nm ls
+in this manual.  The new option
+.Fl G
+is for color display.)
+.Pp
 For each operand that names a
@@ -90,6 +90,12 @@
 a percent sign (%) after each whiteout,
 and a vertical bar (|) after each that is a
 .Tn FIFO .
+.It Fl G
+Use termcap color sequences to distinguish file types. (See
+.Ev LSCOLORS
+below.) In addition to those mentioned above in
+.Fl F ,
+some extra attributes (setuid bit set, etc.) are also displayed.
 .It Fl H
 Symbolic links on the command line are followed.  This option is assumed if
 none of the
@@ -386,6 +392,74 @@
 See
 .Xr environ 7
 for more information.
+.It LSCOLORS
+The value of this variable describes what color to use for which
+attribute when the color output
+.Pq Fl G
+is specified.  This string is a concatenation of pairs of the format
+.Sy fb ,
+where
+.Sy f
+is the foreground color and
+.Sy b
+is the background color.
+.Pp
+The color designators are as follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It Sy 0
+black
+.It Sy 1
+red
+.It Sy 2
+green
+.It Sy 3
+brown
+.It Sy 4
+blue
+.It Sy 5
+magenta
+.It Sy 6
+cyan
+.It Sy 7
+light grey
+.It Sy x
+default foreground or background
+.El
+.Pp
+(Note: the above are standard ANSI colors.  The actual display may
+differ depending on the color capabilities of your terminal.)
+.Pp
+The order of the attributes are as follows:
+.Pp
+.Bl -enum -offset indent -compact
+.It
+directory
+.It
+symbolic link
+.It
+socket
+.It
+pipe
+.It
+executable
+.It
+block special
+.It
+character special
+.It
+executable with setuid bit set
+.It
+executable with setgid bit set
+.It
+directory writable to others, with sticky bit
+.It
+directory writable to others, without sticky bit
+.El
+.Pp
+The default is "4x5x2x3x1x464301060203", i.e., blue foreground and
+default background for regular directories, black foreground and red
+background for setuid executables, etc.
 .It Ev LS_COLWIDTHS
 If this variable is set, it is considered to be a
 colon-delimited list of minimum column widths.  Unreasonable
