Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 17 Aug 2018 04:15:51 +0000 (UTC)
From:      Kyle Evans <kevans@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r337956 - in head: . bin/ls
Message-ID:  <201808170415.w7H4Fp7D046775@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kevans
Date: Fri Aug 17 04:15:51 2018
New Revision: 337956
URL: https://svnweb.freebsd.org/changeset/base/337956

Log:
  ls(1): Add --color=when
  
  --color may be set to one of: 'auto', 'always', and 'never'.
  
  'auto' is the default behavior- output colors only if -G or COLORTERM are
  set, and only if stdout is a tty.
  
  'always' is a new behavior- output colors always. termcap(5) will be
  consulted unless TERM is unset or not a recognized terminal, in which case
  ls(1) will fall back to explicitly outputting ANSI escape sequences.
  
  'never' to turn off any environment variable and -G usage.
  
  Reviewed by:	cem, 0mp (both modulo last-minute manpage changes
  Differential Revision:	https://reviews.freebsd.org/D16741

Modified:
  head/UPDATING
  head/bin/ls/extern.h
  head/bin/ls/ls.1
  head/bin/ls/ls.c
  head/bin/ls/print.c
  head/bin/ls/util.c

Modified: head/UPDATING
==============================================================================
--- head/UPDATING	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/UPDATING	Fri Aug 17 04:15:51 2018	(r337956)
@@ -35,9 +35,9 @@ NOTE TO PEOPLE WHO THINK THAT FreeBSD 12.x IS SLOW:
 	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

Modified: head/bin/ls/extern.h
==============================================================================
--- head/bin/ls/extern.h	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/bin/ls/extern.h	Fri Aug 17 04:15:51 2018	(r337956)
@@ -32,6 +32,8 @@
  * $FreeBSD$
  */
 
+#include <stdbool.h>
+
 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_bgcol;
 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;

Modified: head/bin/ls/ls.1
==============================================================================
--- head/bin/ls/ls.1	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/bin/ls/ls.1	Fri Aug 17 04:15:51 2018	(r337956)
@@ -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 @@ This option is not defined in
 .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 @@ Colorization
 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.

Modified: head/bin/ls/ls.c
==============================================================================
--- head/bin/ls/ls.c	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/bin/ls/ls.c	Fri Aug 17 04:15:51 2018	(r337956)
@@ -55,6 +55,7 @@ __FBSDID("$FreeBSD$");
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
+#include <getopt.h>
 #include <grp.h>
 #include <inttypes.h>
 #include <limits.h>
@@ -99,6 +100,16 @@ static void	 display(const FTSENT *, FTSENT *, int);
 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_stream;		/* stream the output, separate w
 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 @@ do_color_from_env(void)
 	    (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 @@ main(int argc, char *argv[])
 #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 @@ main(int argc, char *argv[])
 	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 @@ main(int argc, char *argv[])
 		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 @@ main(int argc, char *argv[])
 	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 @@ main(int argc, char *argv[])
 				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) {

Modified: head/bin/ls/print.c
==============================================================================
--- head/bin/ls/print.c	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/bin/ls/print.c	Fri Aug 17 04:15:51 2018	(r337956)
@@ -73,6 +73,8 @@ static void	printtime(time_t);
 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 @@ writech(int c)
 }
 
 static void
-printcolor(Colors c)
+printcolor_termcap(Colors c)
 {
 	char *ansiseq;
 
@@ -560,10 +562,53 @@ printcolor(Colors c)
 }
 
 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

Modified: head/bin/ls/util.c
==============================================================================
--- head/bin/ls/util.c	Fri Aug 17 04:11:10 2018	(r337955)
+++ head/bin/ls/util.c	Fri Aug 17 04:15:51 2018	(r337956)
@@ -227,7 +227,7 @@ usage(void)
 {
 	(void)fprintf(stderr,
 #ifdef COLORLS
-	"usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]"
+	"usage: ls [-ABCFGHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [--color=when] [-D format]"
 #else
 	"usage: ls [-ABCFHILPRSTUWZabcdfghiklmnopqrstuwxy1,] [-D format]"
 #endif



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201808170415.w7H4Fp7D046775>