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);
}