Index: UPDATING =================================================================== --- UPDATING +++ UPDATING @@ -35,9 +35,9 @@ ls(1) now respects the COLORTERM environment variable used in other systems and software to indicate that a colored terminal is both supported and desired. If ls(1) is suddenly emitting colors, they may - be disabled again by removing the unwanted COLORTERM from your - environment. The ls(1) specific CLICOLOR may not be observed in a - future release. + be disabled again by either removing the unwanted COLORTERM from your + environment, or using `ls --color=never`. The ls(1) specific CLICOLOR + may not be observed in a future release. 20180808: The default pager for most commands has been changed to "less". To Index: bin/ls/extern.h =================================================================== --- bin/ls/extern.h +++ bin/ls/extern.h @@ -64,5 +64,11 @@ extern char *ansi_coloff; extern char *attrs_off; extern char *enter_bold; + +extern int colorflag; + +#define COLORFLAG_NEVER 0 +#define COLORFLAG_AUTO 1 +#define COLORFLAG_ALWAYS 2 #endif extern int termwidth; Index: bin/ls/ls.1 =================================================================== --- bin/ls/ls.1 +++ bin/ls/ls.1 @@ -32,7 +32,7 @@ .\" @(#)ls.1 8.7 (Berkeley) 7/29/94 .\" $FreeBSD$ .\" -.Dd August 8, 2018 +.Dd August 15, 2018 .Dt LS 1 .Os .Sh NAME @@ -41,6 +41,7 @@ .Sh SYNOPSIS .Nm .Op Fl ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1, +.Op Fl -color Ns = Ns Ar when .Op Fl D Ar format .Op Ar .Sh DESCRIPTION @@ -210,6 +211,37 @@ .St -p1003.1-2001 . .It Fl c Use time when file status was last changed for sorting or printing. +. +.It Fl -color Ns = Ns Ar when +Output colored escape sequences based on +.Ar when , +which may be set to either +.Dq always , +.Dq auto +(default), or +.Dq never . +.Dq always +will make +.Nm +always output +.Tn ANSI +color sequences. +.Pp +.Dq auto +will make +.Nm +output escape sequences based on +.Xr termcap 5 , +but only if +.Dv stdout +is a tty and either the +.Fl G +flag is specified or the +.Ev COLORTERM +environment variable is set and not empty. +.Pp +.Dq never +will disable color regardless of environment variables. .It Fl d Directories are listed as plain files (not searched recursively). .It Fl f @@ -620,7 +652,10 @@ is silently disabled if the output is not directed to a terminal unless the .Ev CLICOLOR_FORCE -variable is defined. +variable is defined or +.Fl -color +is set to +.Dq always . .It Ev CLICOLOR_FORCE Color sequences are normally disabled if the output is not directed to a terminal. Index: bin/ls/ls.c =================================================================== --- bin/ls/ls.c +++ bin/ls/ls.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,14 @@ static int mastercmp(const FTSENT * const *, const FTSENT * const *); static void traverse(int, char **, int); +#define COLOR_OPT (CHAR_MAX + 1) + +static const struct option long_opts[] = +{ + {"color", required_argument, NULL, COLOR_OPT}, + {NULL, no_argument, NULL, 0} +}; + static void (*printfcn)(const DISPLAY *); static int (*sortfcn)(const FTSENT *, const FTSENT *); @@ -140,8 +149,8 @@ static int f_timesort; /* sort by time vice name */ int f_type; /* add type character for non-regular files */ static int f_whiteout; /* show whiteout entries */ - #ifdef COLORLS + int colorflag = COLORFLAG_AUTO; /* passed in colorflag */ int f_color; /* add type in color for non-regular files */ char *ansi_bgcol; /* ANSI sequence to set background colour */ @@ -176,6 +185,19 @@ (isatty(STDOUT_FILENO) || getenv("CLICOLOR_FORCE"))); } +static bool +do_color(void) +{ + +#ifdef COLORLS + if (colorflag == COLORFLAG_NEVER) + return (false); + else if (colorflag == COLORFLAG_ALWAYS) + return (true); +#endif + return (do_color_from_env()); +} + int main(int argc, char *argv[]) { @@ -215,8 +237,9 @@ fts_options = FTS_PHYSICAL; if (getenv("LS_SAMESORT")) f_samesort = 1; - while ((ch = getopt(argc, argv, - "1ABCD:FGHILPRSTUWXZabcdfghiklmnopqrstuwxy,")) != -1) { + while ((ch = getopt_long(argc, argv, + "+1ABCD:FGHILPRSTUWXZabcdfghiklmnopqrstuwxy,", long_opts, + NULL)) != -1) { switch (ch) { /* * The -1, -C, -x and -l options all override each other so @@ -379,6 +402,19 @@ case 'y': f_samesort = 1; break; +#ifdef COLORLS + case COLOR_OPT: + /* optarg is 'when': always, auto, or never */ + if (strcmp(optarg, "always") == 0) + colorflag = COLORFLAG_ALWAYS; + else if (strcmp(optarg, "auto") == 0) + colorflag = COLORFLAG_AUTO; + else if (strcmp(optarg, "never") == 0) + colorflag = COLORFLAG_NEVER; + else + warnx("unsupported --color value '%s'", optarg); + break; +#endif default: case '?': usage(); @@ -392,9 +428,16 @@ f_listdot = 1; /* Enabling of colours is conditional on the environment. */ - if (do_color_from_env()) + if (do_color()) { #ifdef COLORLS - if (tgetent(termcapbuf, getenv("TERM")) == 1) { + /* + * We can skip the termcaps calls if we're always coloring, + * anyways. We implement the always coloring directly with + * ANSI escape sequences, rather than relying on the terminal + * capabilities. */ + if (colorflag == COLORFLAG_ALWAYS) + f_color = 1; + else if (tgetent(termcapbuf, getenv("TERM")) == 1) { ansi_fgcol = tgetstr("AF", &bp); ansi_bgcol = tgetstr("AB", &bp); attrs_off = tgetstr("me", &bp); @@ -412,6 +455,7 @@ #else warnx("color support not compiled in"); #endif /*COLORLS*/ + } #ifdef COLORLS if (f_color) { Index: bin/ls/print.c =================================================================== --- bin/ls/print.c +++ bin/ls/print.c @@ -73,6 +73,8 @@ static int printtype(u_int); static void printsize(size_t, off_t); #ifdef COLORLS +static void endcolor_termcap(int); +static void endcolor_ansi(void); static void endcolor(int); static int colortype(mode_t); #endif @@ -540,7 +542,7 @@ } static void -printcolor(Colors c) +printcolor_termcap(Colors c) { char *ansiseq; @@ -560,10 +562,56 @@ } static void -endcolor(int sig) +printcolor_ansi(Colors c) { + + printf("\033["); + + if (colors[c].bold) + printf("1;"); + if (colors[c].num[0] != -1) { + printf("3%d", colors[c].num[0]); + if (colors[c].num[1] != -1) + printf(";"); + } + if (colors[c].num[1] != -1) + printf("4%d", colors[c].num[1]); + printf("m"); +} + +static void +printcolor(Colors c) +{ + + if (colorflag == COLORFLAG_ALWAYS) + printcolor_ansi(c); + else + printcolor_termcap(c); +} + +static void +endcolor_termcap(int sig) +{ + tputs(ansi_coloff, 1, sig ? writech : putch); tputs(attrs_off, 1, sig ? writech : putch); +} + +static void +endcolor_ansi(void) +{ + + printf("\33[m"); +} + +static void +endcolor(int sig) +{ + + if (colorflag == COLORFLAG_ALWAYS) + endcolor_ansi(); + else + endcolor_termcap(sig); } static int Index: bin/ls/util.c =================================================================== --- bin/ls/util.c +++ bin/ls/util.c @@ -227,7 +227,7 @@ { (void)fprintf(stderr, #ifdef COLORLS - "usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]" + "usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [--color=when] [-D format]" #else "usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]" #endif