ls: don't output any colors with TERM=dumb

The TERM variable is usually set to "dumb" to indicate that the terminal
does not support any ANSI escape sequences. Presently, ls does not honor
this variable and outputs colors anyhow which results in unreadable
output, unless the user explicitly disables colors using `ls
--color=never`. The rational behind this change is that ls should "just
work" by default, even on dumb terminals.

For this reason, this patch adds a check which additionally consults the
TERM variable before printing any colors. This is analogous to the
existing check for ensuring that standard output is a tty. As such,
colors can still be forced with `--color=force`, even if TERM is set to
dumb.

function                                             old     new   delta
is_TERM_dumb                                           -      40     +40
ls_main                                              579     598     +19
.rodata                                           103246  103251      +5
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 2/0 up/down: 64/0)               Total: 64 bytes

Signed-off-by: Sören Tempel <soeren+git@soeren-tempel.net>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Sören Tempel 2021-05-23 14:14:10 +02:00 committed by Denys Vlasenko
parent 5a3d3b8055
commit 3d9c649158
3 changed files with 15 additions and 4 deletions

View File

@ -1145,12 +1145,16 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
#if ENABLE_FEATURE_LS_COLOR #if ENABLE_FEATURE_LS_COLOR
/* set G_show_color = 1/0 */ /* set G_show_color = 1/0 */
if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) { if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) {
char *p = getenv("LS_COLORS"); char *p = getenv("LS_COLORS");
/* LS_COLORS is unset, or (not empty && not "none") ? */ /* LS_COLORS is unset, or (not empty && not "none") ? */
if (!p || (p[0] && strcmp(p, "none") != 0)) if (!p || (p[0] && strcmp(p, "none") != 0)) {
if (isatty(STDOUT_FILENO)) {
/* check isatty() last because it's expensive (syscall) */
G_show_color = 1; G_show_color = 1;
} }
}
}
if (opt & OPT_color) { if (opt & OPT_color) {
if (color_opt[0] == 'n') if (color_opt[0] == 'n')
G_show_color = 0; G_show_color = 0;
@ -1158,7 +1162,7 @@ int ls_main(int argc UNUSED_PARAM, char **argv)
case 3: case 3:
case 4: case 4:
case 5: case 5:
if (isatty(STDOUT_FILENO)) { if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) {
case 0: case 0:
case 1: case 1:
case 2: case 2:

View File

@ -1773,6 +1773,7 @@ extern void print_login_issue(const char *issue_file, const char *tty) FAST_FUNC
extern void print_login_prompt(void) FAST_FUNC; extern void print_login_prompt(void) FAST_FUNC;
char *xmalloc_ttyname(int fd) FAST_FUNC RETURNS_MALLOC; char *xmalloc_ttyname(int fd) FAST_FUNC RETURNS_MALLOC;
int is_TERM_dumb(void) FAST_FUNC;
/* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */ /* NB: typically you want to pass fd 0, not 1. Think 'applet | grep something' */
int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FUNC; int get_terminal_width_height(int fd, unsigned *width, unsigned *height) FAST_FUNC;
int get_terminal_width(int fd) FAST_FUNC; int get_terminal_width(int fd) FAST_FUNC;

View File

@ -303,6 +303,12 @@ int FAST_FUNC get_terminal_width(int fd)
return width; return width;
} }
int FAST_FUNC is_dumb_term(void)
{
char *term = getenv("TERM");
return term && strcmp(term, "dumb") == 0;
}
int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp)
{ {
return tcsetattr(STDIN_FILENO, TCSANOW, tp); return tcsetattr(STDIN_FILENO, TCSANOW, tp);