On Tue, Oct 10, 2017 at 08:37:24AM -0500, Eric Blake wrote:
> On 10/10/2017 03:43 AM, Pádraig Brady wrote:
> > This idea has some merit, though I'd prefer not to have
> > cat needing to deal with CAT_COLORS etc.
>
> I also like the idea, but detest the environment variable.  When we
> recently added coloring to 'diff' (see diffutils 3.4), we chose --color
> to turn things on, but --palette to specify which colors to use rather
> than an environment variable.
>
> In fact, if we want to add 'cat --palette', it might be nice to retrofit
> 'ls --color --palette' where the command line takes precedence over the
> environment variable LS_COLORS.

I finally implemented a version of this (patch attached). The
implementation uses hard-coded sequences for making text bold and also
for sgr0. I would be willing to modify the patch to make it more
flexible by implementing a "--palette" option as suggested and renaming
the option to something like "--highlight-escapes" or "--color-escapes".
Since I don't personally need that flexibility, I wanted to follow-up to
see if the change would be accepted upstream so I don't make the changes
for naught.

Eric
Add support for a new _cat(1)_ option, "--bold-escapes", that makes escape
sequences generated by "-E", "-v" and "-T" bold making it easy to determine
which strings are literal sequences in the input and which strings represent
escaped characters. The "--bold-escapes" option is ignored if "-v" is not
specified since it may conflict with escape sequences present in the input.

--- src/cat.c	2019-12-22 10:15:43.126764549 -0800
+++ src/cat.c	2019-12-22 21:39:36.413294479 -0800
@@ -40,6 +40,7 @@
 #include "full-write.h"
 #include "safe-read.h"
 #include "xbinary-io.h"
+#include "argmatch.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "cat"
@@ -48,6 +49,9 @@
   proper_name ("Torbjorn Granlund"), \
   proper_name ("Richard M. Stallman")
 
+#define TTY_BOLD "\033[1m"
+#define TTY_SGR0 "\033[0m"
+
 /* Name of input file.  May be "-".  */
 static char const *infile;
 
@@ -78,6 +82,24 @@
 /* Preserves the 'cat' function's local 'newlines' between invocations.  */
 static int newlines2 = 0;
 
+enum bold_type
+  {
+    bold_never,
+    bold_always,
+    bold_auto,
+  };
+
+static char const *const bold_args[] =
+  {
+    "always", "never", "auto", NULL
+  };
+
+static enum bold_type const bold_types[] =
+  {
+    bold_always, bold_never, bold_auto
+  };
+ARGMATCH_VERIFY (bold_args, bold_types);
+
 void
 usage (int status)
 {
@@ -99,6 +121,11 @@
 \n\
   -A, --show-all           equivalent to -vET\n\
   -b, --number-nonblank    number nonempty output lines, overrides -n\n\
+  --bold-escapes[=WHEN]    make escape sequences generated by -E, -v and -T\n\
+                           bold. WHEN can be 'always' (default if omitted),\n\
+                           'auto' or 'never'. This option is ignored if -v\n\
+                           is not specified since it may conflict with\n\
+                           escape sequences present in the input.\n\
   -e                       equivalent to -vE\n\
   -E, --show-ends          display $ at end of each line\n\
   -n, --number             number all output lines\n\
@@ -227,6 +254,7 @@
      size_t outsize,
 
      /* Variables that have values according to the specified options.  */
+     bool bold_escapes,
      bool show_nonprinting,
      bool show_tabs,
      bool number,
@@ -399,7 +427,15 @@
               /* Output a currency symbol if requested (-e).  */
 
               if (show_ends)
-                *bpout++ = '$';
+                {
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_BOLD);
+
+                  *bpout++ = '$';
+
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_SGR0);
+                }
 
               /* Output the newline.  */
 
@@ -427,13 +463,19 @@
          scan for chars that need conversion.  */
       if (show_nonprinting)
         {
-          while (true)
+          for (;; ch = *bpin++)
             {
               if (ch >= 32)
                 {
-                  if (ch < 127)
+                  if (ch < 127) {
                     *bpout++ = ch;
-                  else if (ch == 127)
+                    continue;
+                  }
+
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_BOLD);
+
+                  if (ch == 127)
                     {
                       *bpout++ = '^';
                       *bpout++ = '?';
@@ -458,6 +500,9 @@
                           *bpout++ = ch - 128 + 64;
                         }
                     }
+
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_SGR0);
                 }
               else if (ch == '\t' && !show_tabs)
                 *bpout++ = '\t';
@@ -468,11 +513,15 @@
                 }
               else
                 {
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_BOLD);
+
                   *bpout++ = '^';
                   *bpout++ = ch + 64;
-                }
 
-              ch = *bpin++;
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_SGR0);
+                }
             }
         }
       else
@@ -482,8 +531,14 @@
             {
               if (ch == '\t' && show_tabs)
                 {
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_BOLD);
+
                   *bpout++ = '^';
                   *bpout++ = ch + 64;
+
+                  if (bold_escapes)
+                    bpout = stpcpy(bpout, TTY_SGR0);
                 }
               else if (ch != '\n')
                 *bpout++ = ch;
@@ -518,6 +573,8 @@
 
   bool ok = true;
   int c;
+  int bold;
+  size_t inflation = 4;
 
   /* Index in argv to processed argument.  */
   int argind;
@@ -543,6 +600,7 @@
   bool show_ends = false;
   bool show_nonprinting = false;
   bool show_tabs = false;
+  bool bold_escapes = false;
   int file_open_mode = O_RDONLY;
 
   static struct option const long_options[] =
@@ -554,6 +612,7 @@
     {"show-ends", no_argument, NULL, 'E'},
     {"show-tabs", no_argument, NULL, 'T'},
     {"show-all", no_argument, NULL, 'A'},
+    {"bold-escapes", optional_argument, NULL, 'B'},
     {GETOPT_HELP_OPTION_DECL},
     {GETOPT_VERSION_OPTION_DECL},
     {NULL, 0, NULL, 0}
@@ -573,7 +632,7 @@
 
   /* Parse command line options.  */
 
-  while ((c = getopt_long (argc, argv, "benstuvAET", long_options, NULL))
+  while ((c = getopt_long (argc, argv, "benstuvABET", long_options, NULL))
          != -1)
     {
       switch (c)
@@ -623,6 +682,19 @@
           show_tabs = true;
           break;
 
+        case 'B':
+          if (optarg)
+            {
+              bold = XARGMATCH ("--bold-escapes", optarg, bold_args,
+                                bold_types);
+              bold_escapes = bold == bold_always ||
+                             (bold == bold_auto && isatty(STDOUT_FILENO));
+            }
+          else
+            bold_escapes = true;
+
+          break;
+
         case_GETOPT_HELP_CHAR;
 
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -632,6 +704,9 @@
         }
     }
 
+  if (bold_escapes && !show_nonprinting)
+    bold_escapes = false;
+
   /* Get device, i-node number, and optimal blocksize of output.  */
 
   if (fstat (STDOUT_FILENO, &stat_buf) < 0)
@@ -738,13 +813,16 @@
              on some paging implementations, so add PAGE_SIZE - 1 bytes to the
              request to make room for the alignment.  */
 
-          outbuf = xmalloc (outsize - 1 + insize * 4 + LINE_COUNTER_BUF_LEN
-                            + page_size - 1);
+          if (bold_escapes)
+            inflation += strlen(TTY_BOLD) + strlen(TTY_SGR0);
+
+          outbuf = xmalloc (outsize - 1 + insize * inflation
+                            + LINE_COUNTER_BUF_LEN + page_size - 1);
 
           ok &= cat (ptr_align (inbuf, page_size), insize,
-                     ptr_align (outbuf, page_size), outsize, show_nonprinting,
-                     show_tabs, number, number_nonblank, show_ends,
-                     squeeze_blank);
+                     ptr_align (outbuf, page_size), outsize, bold_escapes,
+                     show_nonprinting, show_tabs, number, number_nonblank,
+                     show_ends, squeeze_blank);
 
           free (outbuf);
         }

Reply via email to