On 13/10/2021 14:18, Pádraig Brady wrote:
BTW dircolors(1) should probably also have a mode to print LS_COLORS like:
$ eval $(TERM=xterm dircolors)
$ echo $LS_COLORS | tr : '\n' | sed 's/\(.*\)=\(.*\)/\x1b[\2m\1\t\2\x1b[0m/'
The attached implement the above through: dircolors --print-ls-colors
cheers,
Pádraig
From abc4533fe4b7eba1c92263f49145713ff5fc0c3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <p...@draigbrady.com>
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 d58be8863..e14501e77 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 d1ad85865..7ae5ab8e3 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 b8cd20376..8bb4abfc4 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 942505e90..27fa2c5b6 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.26.2