Index: bin/ls/Makefile =================================================================== RCS file: /home/netbsd/src/bin/ls/Makefile,v retrieving revision 1.14 diff -p -u -r1.14 Makefile --- bin/ls/Makefile 14 Dec 2006 20:09:36 -0000 1.14 +++ bin/ls/Makefile 14 Feb 2019 15:57:05 -0000 @@ -7,4 +7,11 @@ SRCS= cmp.c ls.c main.c print.c util.c LDADD+= -lutil DPADD+= ${LIBUTIL} +.ifndef SMALLPROG +CPPFLAGS+= -DCOLORLS + +LDADD+= -lterminfo +DPADD+= ${LIBTERMINFO} +.endif + .include Index: bin/ls/extern.h =================================================================== RCS file: /home/netbsd/src/bin/ls/extern.h,v retrieving revision 1.17 diff -p -u -r1.17 extern.h --- bin/ls/extern.h 29 Aug 2011 14:44:21 -0000 1.17 +++ bin/ls/extern.h 14 Feb 2019 14:34:34 -0000 @@ -51,3 +51,14 @@ void printlong(DISPLAY *); void printscol(DISPLAY *); void printstream(DISPLAY *); int safe_print(const char *); + +#ifdef COLORLS +void parsecolors(const char *cs); +void colorquit(int); + +extern char *ansi_fgcol; +extern char *ansi_bgcol; +extern char *ansi_coloff; +extern char *attrs_off; +extern char *enter_bold; +#endif Index: bin/ls/ls.1 =================================================================== RCS file: /home/netbsd/src/bin/ls/ls.1,v retrieving revision 1.80 diff -p -u -r1.80 ls.1 --- bin/ls/ls.1 3 Jul 2017 21:33:23 -0000 1.80 +++ bin/ls/ls.1 15 Feb 2019 01:30:01 -0000 @@ -32,7 +32,7 @@ .\" .\" @(#)ls.1 8.7 (Berkeley) 7/29/94 .\" -.Dd August 10, 2016 +.Dd February 15, 2019 .Dt LS 1 .Os .Sh NAME @@ -40,7 +40,7 @@ .Nd list directory contents .Sh SYNOPSIS .Nm -.Op Fl 1AaBbCcdFfghikLlMmnOoPpqRrSsTtuWwXx +.Op Fl 1AaBbCcdFfGghikLlMmnOoPpqRrSsTtuWwXx .Op Ar .Sh DESCRIPTION For each @@ -129,6 +129,16 @@ after each that is a Output is not sorted. This option implies .Fl a . +.It Fl G +Enable colorized output. +This option is equivalent to defining +.Ev CLICOLOR +in the environment. +(See below.) +This functionality can be compiled out by removing the definition of +.Ev COLORLS . +This option is not defined in +.St -p1003.2 . .It Fl g The same as .Fl l , @@ -470,6 +480,41 @@ option is not specified, the block count and .Fl s ) will be displayed in units of that size block. +.It Ev CLICOLOR +Use +.Tn ANSI +color sequences to distinguish file types. +See +.Ev LSCOLORS +below. +In addition to the file types mentioned in the +.Fl F +option some extra attributes (setuid bit set, etc.) are also displayed. +The colorization is dependent on a terminal type with the proper +.Xr terminfo 5 +capabilities. +To display the colors in +.Xr wsdisplay 4 , +for example, +the +.Ev TERM +variable must be set to +.Dq Li wsvt25 . +Other terminal types may require similar adjustments. +Colorization +is silently disabled if the output is not directed to a terminal +unless the +.Ev CLICOLOR_FORCE +variable is defined. +.It Ev CLICOLOR_FORCE +Color sequences are normally disabled if the output is not directed to +a terminal. +This can be overridden by setting this variable. +The +.Ev TERM +variable still needs to reference a color capable terminal however +otherwise it is not possible to determine which color sequences to +use. .It Ev COLUMNS If this variable contains a string representing a decimal integer, it is used as the @@ -482,6 +527,99 @@ many pathname text columns to display based on the width provided. (See .Fl C . ) +.It Ev LSCOLORS +The value of this variable describes what color to use for which +attribute when colors are enabled with +.Ev CLICOLOR . +This string is a concatenation of pairs of the format +.Ar f Ns Ar b , +where +.Ar f +is the foreground color and +.Ar b +is the background color. +.Pp +The color designators are as follows: +.Pp +.Bl -tag -width 4n -offset indent -compact +.It Sy a +black +.It Sy b +red +.It Sy c +green +.It Sy d +brown +.It Sy e +blue +.It Sy f +magenta +.It Sy g +cyan +.It Sy h +light grey +.It Sy A +bold black, usually shows up as dark grey +.It Sy B +bold red +.It Sy C +bold green +.It Sy D +bold brown, usually shows up as yellow +.It Sy E +bold blue +.It Sy F +bold magenta +.It Sy G +bold cyan +.It Sy H +bold light grey; looks like bright white +.It Sy x +default foreground or background +.El +.Pp +Note that the above are standard +.Tn ANSI +colors. +The actual display may differ +depending on the color capabilities of the terminal in use. +.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 +.Qq "exfxcxdxbxegedabagacad" , +i.e., blue foreground and +default background for regular directories, black foreground and red +background for setuid executables, etc. +.It Ev TERM +The +.Ev CLICOLOR +functionality depends on a terminal type with color capabilities. .It Ev TZ The timezone to use when displaying dates. See @@ -501,6 +639,7 @@ specification. .Xr stat 2 , .Xr dirent 3 , .Xr getbsize 3 , +.Xr terminfo 5 , .Xr sticky 7 , .Xr symlink 7 .Sh STANDARDS Index: bin/ls/ls.c =================================================================== RCS file: /home/netbsd/src/bin/ls/ls.c,v retrieving revision 1.76 diff -p -u -r1.76 ls.c --- bin/ls/ls.c 6 Feb 2017 21:06:04 -0000 1.76 +++ bin/ls/ls.c 15 Feb 2019 00:42:40 -0000 @@ -65,6 +65,11 @@ __RCSID("$NetBSD: ls.c,v 1.76 2017/02/06 #include #include +#ifdef COLORLS +#include +#include +#endif + #include "ls.h" #include "extern.h" @@ -114,12 +119,26 @@ int f_whiteout; /* show whiteout entri int f_fullpath; /* print full pathname, not filename */ int f_leafonly; /* when recursing, print leaf names only */ +#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 */ +char *attrs_off; /* ANSI sequence to turn off attributes */ +char *enter_bold; /* ANSI sequence to set color to bold mode */ +#endif + __dead static void usage(void) { (void)fprintf(stderr, - "usage: %s [-1AaBbCcdFfghikLlMmnOoPpqRrSsTtuWwXx] [file ...]\n", + "usage: %s [-1AaBbCcdFf" +#ifdef COLORLS + "G" +#endif + "ghikLlMmnOoPpqRrSsTtuWwXx] [file ...]\n", getprogname()); exit(EXIT_FAILURE); /* NOTREACHED */ @@ -133,6 +152,11 @@ ls_main(int argc, char *argv[]) int ch, fts_options; int kflag = 0; const char *p; +#ifdef COLORLS + char termcapbuf[1024]; /* termcap definition buffer */ + char tcapbuf[512]; /* capability buffer */ + char *bp = tcapbuf; +#endif setprogname(argv[0]); (void)setlocale(LC_ALL, ""); @@ -151,7 +175,11 @@ ls_main(int argc, char *argv[]) f_listdot = 1; fts_options = FTS_PHYSICAL; - while ((ch = getopt(argc, argv, "1AaBbCcdFfghikLlMmnOoPpqRrSsTtuWwXx")) + while ((ch = getopt(argc, argv, "1AaBbCcdFf" +#ifdef COLORLS + "G" +#endif + "ghikLlMmnOoPpqRrSsTtuWwXx")) != -1) { switch (ch) { /* @@ -301,6 +329,11 @@ ls_main(int argc, char *argv[]) case 'X': fts_options |= FTS_XDEV; break; +#ifdef COLORLS + case 'G': + f_color = 1; + break; +#endif default: case '?': usage(); @@ -320,19 +353,53 @@ ls_main(int argc, char *argv[]) if (f_grouponly == -1) f_grouponly = 0; +#ifdef COLORLS + if ((f_color || getenv("CLICOLOR")) && + (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE")) && + tgetent(termcapbuf, getenv("TERM")) == 1) { + ansi_fgcol = tgetstr("AF", &bp); + ansi_bgcol = tgetstr("AB", &bp); + attrs_off = tgetstr("me", &bp); + enter_bold = tgetstr("md", &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); + } + + f_color = ansi_fgcol && ansi_bgcol && ansi_coloff; + + if (f_color) { + (void)signal(SIGINT, colorquit); + (void)signal(SIGQUIT, colorquit); + parsecolors(getenv("LSCOLORS")); + } +#endif + /* - * If not -F, -i, -l, -p, -S, -s or -t options, don't require stat + * If not -F, -G, -i, -l, -p, -S, -s or -t options, don't require stat * information. */ if (!f_inode && !f_longform && !f_size && !f_type && !f_typedir && +#ifdef COLORLS + !f_color && +#endif sortkey == BY_NAME) fts_options |= FTS_NOSTAT; /* - * If not -F, -d or -l options, follow any symbolic links listed on + * If not -F, -G, -d or -l options, follow any symbolic links listed on * the command line. */ - if (!f_longform && !f_listdir && !f_type) + if (!f_longform && !f_listdir && !f_type +#ifdef COLORLS + && !f_color +#endif + ) fts_options |= FTS_COMFOLLOW; /* Index: bin/ls/ls.h =================================================================== RCS file: /home/netbsd/src/bin/ls/ls.h,v retrieving revision 1.19 diff -p -u -r1.19 ls.h --- bin/ls/ls.h 20 Feb 2014 18:56:36 -0000 1.19 +++ bin/ls/ls.h 14 Feb 2019 16:02:10 -0000 @@ -56,6 +56,10 @@ extern int f_nonprint; /* show unprinta extern int f_fullpath; /* print full pathname, not filename */ extern int f_leafonly; /* when recursing, print leaf names only */ +#ifdef COLORLS +extern int f_color; /* add type in color for non-regular files */ +#endif + typedef struct { FTSENT *list; u_int64_t btotal; Index: bin/ls/print.c =================================================================== RCS file: /home/netbsd/src/bin/ls/print.c,v retrieving revision 1.55 diff -p -u -r1.55 print.c --- bin/ls/print.c 10 May 2014 09:39:18 -0000 1.55 +++ bin/ls/print.c 15 Feb 2019 00:49:16 -0000 @@ -58,6 +58,12 @@ __RCSID("$NetBSD: print.c,v 1.55 2014/05 #include #include +#ifdef COLORLS +#include +#include +#include +#endif + #include "ls.h" #include "extern.h" @@ -69,8 +75,41 @@ static void printtime(time_t); static void printtotal(DISPLAY *dp); static int printtype(u_int); +#ifdef COLORLS +static void endcolor(int); +static int colortype(mode_t); +#endif + static time_t now; +#ifdef COLORLS +/* Most of these are taken from */ +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; + +static const char *defcolors = "exfxcxdxbxegedabagacad"; + +/* colors for file types */ +static struct { + int num[2]; + int bold; +} colors[C_NUMCOLORS]; +#endif + #define IS_NOPRINT(p) ((p)->fts_number == NO_PRINT) static int @@ -126,6 +165,9 @@ printlong(DISPLAY *dp) FTSENT *p; NAMES *np; char buf[20], szbuf[5]; +#ifdef COLORLS + int color_printed = 0; +#endif now = time(NULL); @@ -184,6 +226,12 @@ printlong(DISPLAY *dp) 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)safe_printpath(p); else if (f_nonprint) @@ -191,6 +239,11 @@ printlong(DISPLAY *dp) else (void)printpath(p); +#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)) @@ -361,6 +414,9 @@ printaname(FTSENT *p, int inodefield, in struct stat *sp; int chcnt; char szbuf[5]; +#ifdef COLORLS + int color_printed = 0; +#endif sp = p->fts_statp; chcnt = 0; @@ -379,12 +435,24 @@ printaname(FTSENT *p, int inodefield, in howmany(sp->st_blocks, blocksize)); } } + +#ifdef COLORLS + if (f_color) + color_printed = colortype(sp->st_mode); +#endif + if (f_octal || f_octal_escape) chcnt += safe_printpath(p); else if (f_nonprint) chcnt += printescapedpath(p); else chcnt += printpath(p); + +#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); @@ -495,3 +563,141 @@ printlink(FTSENT *p) else (void)printf("%s", path); } + +#ifdef COLORLS +static int +writech(int c) +{ + char tmp = (char)c; + + (void)write(STDOUT_FILENO, &tmp, 1); + return 0; +} + +static void +printcolor(Colors c) +{ + char *ansiseq; + + if (colors[c].bold) + tputs(enter_bold, 1, putchar); + + if (colors[c].num[0] != -1) { + ansiseq = tgoto(ansi_fgcol, 0, colors[c].num[0]); + if (ansiseq) + tputs(ansiseq, 1, putchar); + } + if (colors[c].num[1] != -1) { + ansiseq = tgoto(ansi_bgcol, 0, colors[c].num[1]); + if (ansiseq) + tputs(ansiseq, 1, putchar); + } +} + +static void +endcolor(int sig) +{ + + tputs(ansi_coloff, 1, sig ? writech : putchar); + tputs(attrs_off, 1, sig ? writech : putchar); +} + +static int +colortype(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; + default: + break; + } + 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(const char *cs) +{ + size_t len, i, j; + int legacy_warn = 0; + char c[2]; + + if (cs == NULL) + cs = ""; /* LSCOLORS not set */ + len = strlen(cs); + for (i = 0; i < (size_t)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) + warnx("LSCOLORS should use " + "characters a-h instead of 0-9 (" + "see the manual page)"); + 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 { + warnx("invalid character '%c' in LSCOLORS" + " env var", c[j]); + colors[i].num[j] = -1; + } + } + } +} + +void +colorquit(int sig) +{ + + endcolor(sig); + + (void)signal(sig, SIG_DFL); + (void)kill(getpid(), sig); +} +#endif