From abc4533fe4b7eba1c92263f49145713ff5fc0c3c Mon Sep 17 00:00:00 2001 From: =?utf8?q?P=C3=A1draig=20Brady?=
Date: Sun, 13 Feb 2022 18:19:04 +0000 Subject: [PATCH] dircolors: add --print-ls-colors to display colored entries * NEWS: Mention the new feature. * doc/coreutils.texi (dircolors invocation): Describe the new --print-ls-colors option. * src/dircolors.c (print_ls_colors): A new global to select between shell or terminal output. (append_entry): A new function refactored from dc_parse_stream() to append the entry in the appropriate format. (dc_parse_stream): Adjust to call append_entry(). * tests/misc/dircolors.pl: Add test cases. --- NEWS | 5 ++ doc/coreutils.texi | 6 ++ src/dircolors.c | 149 +++++++++++++++++++++++----------------- tests/misc/dircolors.pl | 16 ++++- 4 files changed, 112 insertions(+), 64 deletions(-) diff --git a/NEWS b/NEWS index d58be88637..e14501e778 100644 --- a/NEWS +++ b/NEWS @@ -62,6 +62,11 @@ GNU coreutils NEWS -*- outline -*- when the --foreground option is not specified. This allows users to distinguish if the command was more forcefully terminated. +** New Features + + dircolors takes a new --print-ls-colors option to display LS_COLORS + entries, on separate lines, colored according to the entry color code. + ** Improvements cp, mv, and install now use openat-like syscalls when copying to a directory. diff --git a/doc/coreutils.texi b/doc/coreutils.texi index d1ad85865e..7ae5ab8e33 100644 --- a/doc/coreutils.texi +++ b/doc/coreutils.texi @@ -8625,6 +8625,12 @@ Print the (compiled-in) default color configuration database. This output is itself a valid configuration file, and is fairly descriptive of the possibilities. +@item --print-ls-colors +@opindex --print-ls-colors +@cindex printing ls colors +Print the LS_COLORS entries on separate lines, +each colored as per the color they represent. + @end table @exitstatus diff --git a/src/dircolors.c b/src/dircolors.c index b8cd203762..8bb4abfc4e 100644 --- a/src/dircolors.c +++ b/src/dircolors.c @@ -46,13 +46,6 @@ enum Shell_syntax }; #define APPEND_CHAR(C) obstack_1grow (&lsc_obstack, C) -#define APPEND_TWO_CHAR_STRING(S) \ - do \ - { \ - APPEND_CHAR (S[0]); \ - APPEND_CHAR (S[1]); \ - } \ - while (0) /* Accumulate in this obstack the value for the LS_COLORS environment variable. */ @@ -76,6 +69,16 @@ static char const *const ls_codes[] = }; verify (ARRAY_CARDINALITY (slack_codes) == ARRAY_CARDINALITY (ls_codes)); +/* Whether to output escaped ls color codes for display. */ +static bool print_ls_colors; + +/* For long options that have no equivalent short option, use a + non-character as a pseudo short option, starting with CHAR_MAX + 1. */ +enum +{ + PRINT_LS_COLORS_OPTION = CHAR_MAX + 1, +}; + static struct option const long_options[] = { {"bourne-shell", no_argument, NULL, 'b'}, @@ -83,6 +86,7 @@ static struct option const long_options[] = {"csh", no_argument, NULL, 'c'}, {"c-shell", no_argument, NULL, 'c'}, {"print-database", no_argument, NULL, 'p'}, + {"print-ls-colors", no_argument, NULL, PRINT_LS_COLORS_OPTION}, {GETOPT_HELP_OPTION_DECL}, {GETOPT_VERSION_OPTION_DECL}, {NULL, 0, NULL, 0} @@ -103,6 +107,7 @@ Determine format of output:\n\ -b, --sh, --bourne-shell output Bourne shell code to set LS_COLORS\n\ -c, --csh, --c-shell output C shell code to set LS_COLORS\n\ -p, --print-database output defaults\n\ + --print-ls-colors output fully escaped colors for display\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -187,8 +192,8 @@ parse_line (char const *line, char **keyword, char **arg) *arg = ximemdup0 (arg_start, p - arg_start); } -/* FIXME: Write a string to standard out, while watching for "dangerous" - sequences like unescaped : and = characters. */ +/* Accumulate STR to LS_COLORS data. + If outputting shell syntax, then escape appropriately. */ static void append_quoted (char const *str) @@ -197,36 +202,59 @@ append_quoted (char const *str) while (*str != '\0') { - switch (*str) - { - case '\'': - APPEND_CHAR ('\''); - APPEND_CHAR ('\\'); - APPEND_CHAR ('\''); - need_backslash = true; - break; - - case '\\': - case '^': - need_backslash = !need_backslash; - break; - - case ':': - case '=': - if (need_backslash) + if (! print_ls_colors) + switch (*str) + { + case '\'': + APPEND_CHAR ('\''); APPEND_CHAR ('\\'); - FALLTHROUGH; + APPEND_CHAR ('\''); + need_backslash = true; + break; - default: - need_backslash = true; - break; - } + case '\\': + case '^': + need_backslash = !need_backslash; + break; + + case ':': + case '=': + if (need_backslash) + APPEND_CHAR ('\\'); + FALLTHROUGH; + + default: + need_backslash = true; + break; + } APPEND_CHAR (*str); ++str; } } +/* Accumulate entry to LS_COLORS data. + Use shell syntax unless PRINT_LS_COLORS is set. */ + +static void +append_entry (char prefix, char const *item, char const *arg) +{ + if (print_ls_colors) + { + append_quoted ("\x1B["); + append_quoted (arg); + APPEND_CHAR ('m'); + } + if (prefix) + APPEND_CHAR (prefix); + append_quoted (item); + APPEND_CHAR (print_ls_colors ? '\t' : '='); + append_quoted (arg); + if (print_ls_colors) + append_quoted ("\x1B[0m"); + APPEND_CHAR (print_ls_colors ? '\n' : ':'); +} + /* Read the file open on FP (with name FILENAME). First, look for a 'TERM name' directive where name matches the current terminal type. Once found, translate and accumulate the associated directives onto @@ -307,20 +335,9 @@ dc_parse_stream (FILE *fp, char const *filename) if (state != ST_TERMNO) { if (keywd[0] == '.') - { - APPEND_CHAR ('*'); - append_quoted (keywd); - APPEND_CHAR ('='); - append_quoted (arg); - APPEND_CHAR (':'); - } + append_entry ('*', keywd, arg); else if (keywd[0] == '*') - { - append_quoted (keywd); - APPEND_CHAR ('='); - append_quoted (arg); - APPEND_CHAR (':'); - } + append_entry (0, keywd, arg); else if (c_strcasecmp (keywd, "OPTIONS") == 0 || c_strcasecmp (keywd, "COLOR") == 0 || c_strcasecmp (keywd, "EIGHTBIT") == 0) @@ -336,22 +353,13 @@ dc_parse_stream (FILE *fp, char const *filename) break; if (slack_codes[i] != NULL) - { - APPEND_TWO_CHAR_STRING (ls_codes[i]); - APPEND_CHAR ('='); - append_quoted (arg); - APPEND_CHAR (':'); - } + append_entry (0, ls_codes[i], arg); else - { - unrecognized = true; - } + unrecognized = true; } } else - { - unrecognized = true; - } + unrecognized = true; } if (unrecognized && (state == ST_TERMSURE || state == ST_TERMYES)) @@ -422,6 +430,10 @@ main (int argc, char **argv) print_database = true; break; + case PRINT_LS_COLORS_OPTION: + print_ls_colors = true; + break; + case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -435,17 +447,26 @@ main (int argc, char **argv) /* It doesn't make sense to use --print with either of --bourne or --c-shell. */ - if (print_database && syntax != SHELL_SYNTAX_UNKNOWN) + if ((print_database | print_ls_colors) && syntax != SHELL_SYNTAX_UNKNOWN) + { + error (0, 0, + _("the options to output non shell syntax,\n" + "and to select a shell syntax are mutually exclusive")); + usage (EXIT_FAILURE); + } + + if (print_database && print_ls_colors) { error (0, 0, - _("the options to output dircolors' internal database and\n" - "to select a shell syntax are mutually exclusive")); + _("options --print-database and --print-ls-colors " + "are mutually exclusive")); usage (EXIT_FAILURE); } if ((!print_database) < argc) { - error (0, 0, _("extra operand %s"), quote (argv[!print_database])); + error (0, 0, _("extra operand %s"), + quote (argv[!print_database])); if (print_database) fprintf (stderr, "%s\n", _("file operands cannot be combined with " @@ -465,7 +486,7 @@ main (int argc, char **argv) else { /* If shell syntax was not explicitly specified, try to guess it. */ - if (syntax == SHELL_SYNTAX_UNKNOWN) + if (syntax == SHELL_SYNTAX_UNKNOWN && ! print_ls_colors) { syntax = guess_shell_syntax (); if (syntax == SHELL_SYNTAX_UNKNOWN) @@ -498,9 +519,11 @@ main (int argc, char **argv) prefix = "setenv LS_COLORS '"; suffix = "'\n"; } - fputs (prefix, stdout); + if (! print_ls_colors) + fputs (prefix, stdout); fwrite (s, 1, len, stdout); - fputs (suffix, stdout); + if (! print_ls_colors) + fputs (suffix, stdout); } } diff --git a/tests/misc/dircolors.pl b/tests/misc/dircolors.pl index 942505e905..27fa2c5b68 100755 --- a/tests/misc/dircolors.pl +++ b/tests/misc/dircolors.pl @@ -42,8 +42,22 @@ my @Tests = ['term-4', '-b', {IN => "TERM N*match\nowt 40;33\n"}, {OUT => "LS_COLORS='';\nexport LS_COLORS\n"}], + ['print-clash1', '-p', '--print-ls', + {ERR => "dircolors: options --print-database and --print-ls-colors " . + "are mutually exclusive\n" . + "Try 'dircolors --help' for more information.\n"}, + {EXIT => 1}], + ['print-clash2', '-b', '--print-database', + {ERR => "dircolors: the options to output non shell syntax,\n" . + "and to select a shell syntax are mutually exclusive\n" . + "Try 'dircolors --help' for more information.\n"}, + {EXIT => 1}], + + ['print-ls-colors', '--print-ls-colors', {IN => "OWT 40;33\n"}, + {OUT => "\x1B[40;33mtw\t40;33\x1B[0m\n"}], + # CAREFUL: always specify the -b option, unless explicitly testing - # for csh syntax output. + # for csh syntax output, or --print-ls-color output. ); my $save_temps = $ENV{DEBUG}; -- 2.47.2