Index: head/UPDATING =================================================================== --- head/UPDATING +++ head/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: head/bin/ls/extern.h =================================================================== --- head/bin/ls/extern.h +++ head/bin/ls/extern.h @@ -32,6 +32,8 @@ * $FreeBSD$ */ +#include + int acccmp(const FTSENT *, const FTSENT *); int revacccmp(const FTSENT *, const FTSENT *); int birthcmp(const FTSENT *, const FTSENT *); @@ -64,5 +66,12 @@ extern char *ansi_coloff; extern char *attrs_off; extern char *enter_bold; + +extern int colorflag; +extern bool explicitansi; + +#define COLORFLAG_NEVER 0 +#define COLORFLAG_AUTO 1 +#define COLORFLAG_ALWAYS 2 #endif extern int termwidth; Index: head/bin/ls/ls.1 =================================================================== --- head/bin/ls/ls.1 +++ head/bin/ls/ls.1 @@ -32,7 +32,7 @@ .\" @(#)ls.1 8.7 (Berkeley) 7/29/94 .\" $FreeBSD$ .\" -.Dd August 8, 2018 +.Dd August 16, 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,47 @@ .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 +.Cm always , +.Cm auto +(default), or +.Cm never . +.Pp +.Cm always +will make +.Nm +always output color. +If +.Ev TERM +is unset or set to an invalid terminal, then +.Nm +will fall back to explicit +.Tn ANSI +escape sequences without the help of +.Xr termcap 5 . +.Cm always +is the default if +.Fl -color +is specified without an argument. +.Pp +.Cm 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 +.Cm 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 +662,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: head/bin/ls/ls.c =================================================================== --- head/bin/ls/ls.c +++ head/bin/ls/ls.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -99,6 +100,16 @@ 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[] = +{ +#ifdef COLORLS + {"color", optional_argument, NULL, COLOR_OPT}, +#endif + {NULL, no_argument, NULL, 0} +}; + static void (*printfcn)(const DISPLAY *); static int (*sortfcn)(const FTSENT *, const FTSENT *); @@ -140,10 +151,10 @@ 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 */ - + bool explicitansi; /* Explicit ANSI sequences, no termcap(5) */ 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 */ @@ -176,6 +187,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[]) { @@ -187,7 +211,7 @@ #ifdef COLORLS char termcapbuf[1024]; /* termcap definition buffer */ char tcapbuf[512]; /* capability buffer */ - char *bp = tcapbuf; + char *bp = tcapbuf, *term; #endif (void)setlocale(LC_ALL, ""); @@ -215,8 +239,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 +404,19 @@ case 'y': f_samesort = 1; break; +#ifdef COLORLS + case COLOR_OPT: + if (optarg == NULL || 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 + errx(2, "unsupported --color value '%s' (must be always, auto, or never)", + optarg); + break; +#endif default: case '?': usage(); @@ -391,10 +429,14 @@ if (!f_listdot && getuid() == (uid_t)0 && !f_noautodot) f_listdot = 1; - /* Enabling of colours is conditional on the environment. */ - if (do_color_from_env()) + /* + * Enabling of colours is conditional on the environment in conjunction + * with the --color and -G arguments, if supplied. + */ + if (do_color()) { #ifdef COLORLS - if (tgetent(termcapbuf, getenv("TERM")) == 1) { + if ((term = getenv("TERM")) != NULL && + tgetent(termcapbuf, term) == 1) { ansi_fgcol = tgetstr("AF", &bp); ansi_bgcol = tgetstr("AB", &bp); attrs_off = tgetstr("me", &bp); @@ -408,10 +450,19 @@ ansi_coloff = tgetstr("oc", &bp); if (ansi_fgcol && ansi_bgcol && ansi_coloff) f_color = 1; + } else if (colorflag == COLORFLAG_ALWAYS) { + /* + * If we're *always* doing color but we don't have + * a functional TERM supplied, we'll fallback to + * outputting raw ANSI sequences. + */ + f_color = 1; + explicitansi = true; } #else warnx("color support not compiled in"); #endif /*COLORLS*/ + } #ifdef COLORLS if (f_color) { Index: head/bin/ls/print.c =================================================================== --- head/bin/ls/print.c +++ head/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,53 @@ } 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(";4%d", colors[c].num[1]); + printf("m"); +} + +static void +printcolor(Colors c) +{ + + if (explicitansi) + 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 (explicitansi) + endcolor_ansi(); + else + endcolor_termcap(sig); } static int Index: head/bin/ls/util.c =================================================================== --- head/bin/ls/util.c +++ head/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