]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
dircolors: add --print-ls-colors to display colored entries
authorPádraig Brady <P@draigBrady.com>
Sun, 13 Feb 2022 18:19:04 +0000 (18:19 +0000)
committerPádraig Brady <P@draigBrady.com>
Sun, 13 Feb 2022 18:25:59 +0000 (18:25 +0000)
* 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
doc/coreutils.texi
src/dircolors.c
tests/misc/dircolors.pl

diff --git a/NEWS b/NEWS
index d58be88637aba23644e792e3ba1a74b7fe3f23a6..e14501e7786ff7248aa4ea25d638114933167088 100644 (file)
--- 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.
index d1ad85865e9acdba05b833921a25d75390173a8b..7ae5ab8e33acde89d468e8058188e321ff2994fa 100644 (file)
@@ -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
index b8cd203762ddb528865437ec1a29e93bb502c2ad..8bb4abfc4ef10456b0e18a2b6237ceca478db526 100644 (file)
@@ -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);
         }
     }
 
index 942505e905c15877c8593768ac2afcafbadc38f8..27fa2c5b6863bb58b312ff7df253d8e58b2b664f 100755 (executable)
@@ -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};