$OpenBSD: patch-print_c,v 1.2 2002/01/23 01:27:32 naddy Exp $
--- print.c.orig	Mon Oct 15 22:12:15 2001
+++ print.c	Wed Jan 23 02:11:39 2002
@@ -60,6 +60,11 @@ static char rcsid[] = "$OpenBSD: print.c
 #include <tzfile.h>
 #include <unistd.h>
 #include <utmp.h>
+#ifdef COLORLS
+#include <ctype.h>
+#include <termcap.h>
+#include <signal.h>
+#endif
 
 #include "ls.h"
 #include "extern.h"
@@ -69,9 +74,40 @@ static void	printlink __P((FTSENT *));
 static void	printtime __P((time_t));
 static int	printtype __P((u_int));
 static int	compute_columns __P((DISPLAY *, 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 ;
+
+const char *defcolors = "exfxcxdxbxegedabagacad";
+
+/* colors for file types */
+static struct {
+	int num[2];
+	int bold;
+} colors[C_NUMCOLORS];
+#endif
+
 void
 printscol(dp)
 	DISPLAY *dp;
@@ -94,6 +130,9 @@ printlong(dp)
 	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,7 +167,15 @@ printlong(dp)
 			printtime(sp->st_ctime);
 		else
 			printtime(sp->st_mtime);
+#ifdef COLORLS
+		if (f_color)
+			color_printed = colortype(sp->st_mode);
+#endif
 		(void)putname(p->fts_name);
+#ifdef COLORLS
+		if (f_color && color_printed)
+			endcolor(0);
+#endif
 		if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
 			(void)printtype(sp->st_mode);
 		if (S_ISLNK(sp->st_mode))
@@ -229,6 +276,9 @@ printaname(p, inodefield, sizefield)
 {
 	struct stat *sp;
 	int chcnt;
+#ifdef COLORLS
+	int color_printed = 0;
+#endif
 
 	sp = p->fts_statp;
 	chcnt = 0;
@@ -237,7 +287,15 @@ printaname(p, inodefield, sizefield)
 	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 += putname(p->fts_name);
+#ifdef COLORLS
+	if (f_color && color_printed)
+		endcolor(0);
+#endif
 	if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
 		chcnt += printtype(sp->st_mode);
 	return (chcnt);
@@ -359,6 +417,155 @@ printtype(mode)
 	}
 	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].bold)
+		tputs(enter_bold, 1, putch);
+
+	if (colors[c].num[0] != -1) {
+		ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]);
+		if (ansiseq)
+			tputs(ansiseq, 1, putch);
+	}
+	if (colors[c].num[1] != -1) {
+		ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]);
+		if (ansiseq)
+			tputs(ansiseq, 1, putch);
+	}
+}
+
+static void
+endcolor(sig)
+	int sig;
+{
+	tputs(attrs_off, 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)
+	const char *cs;
+{
+	int i, j, len;
+	char c[2];
+	short legacy_warn = 0;
+
+	if (cs == NULL)
+		cs = "";	/* LSCOLORS not set */
+	len = strlen(cs);
+	for (i = 0; i < C_NUMCOLORS ; i++) {
+		colors[i].bold = 0;
+
+		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++) {
+			/* Legacy colours used 0-7 */
+			if (c[j] >= '0' && c[j] <= '7') {
+				colors[i].num[j] = c[j] - '0';
+				if (!legacy_warn) {
+					fprintf(stderr,
+					    "warn: LSCOLORS should use "
+					    "characters a-h instead of 0-9 ("
+					    "see the manual page)\n");
+				}
+				legacy_warn = 1;
+			} else if (c[j] >= 'a' && c[j] <= 'h')
+				colors[i].num[j] = c[j] - 'a';
+			else if (c[j] >= 'A' && c[j] <= 'H') {
+				colors[i].num[j] = c[j] - 'A';
+				colors[i].bold = 1;
+			} else if (tolower((unsigned char)c[j] == 'x'))
+				colors[i].num[j] = -1;
+			else {
+				fprintf(stderr,
+				    "error: invalid character '%c' in LSCOLORS"
+				    " env var\n", c[j]);
+				colors[i].num[j] = -1;
+			}
+		}
+	}
+}
+
+void
+colorquit(sig)
+	int sig;
+{
+	endcolor(sig);
+
+	(void)signal(sig, SIG_DFL);
+	(void)kill(getpid(), sig);
+}
+#endif /*COLORLS*/
 
 static void
 printlink(p)
