patch 9.0.1827: xxd: no color support
Problem: xxd: no color support
Solution: Add color support using xxd -R
Add some basic color support for xxd
The hex-value and value are both colored with the same color depending
on the hex-value, e.g.:
0x00 = white
0xff = blue
printable = green
non-printable = red
tabs and linebreaks = yellow
Each character needs 11 more bytes to contain color. (Same color in a
row could contain only one overhead but the logic how xxd creates colums
must be then changed.) Size of colored output is increased by factor of
~6. Also grepping the output will break when colors is used.
Flag for color is "-R", because less uses "-R".
Color uses parameters auto,always,never same as less and grep (among
others).
E.g.
xxd -R always $FILE | less -R
Add some screen-tests (that currently on work on linux) to verify the
feature works as expected.
closes: #12131
Signed-off-by: Christian Brabandt <cb@256bit.org>
Co-authored-by: Aapo Rantalainen <aapo.rantalainen@gmail.com>
diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c
index e2fc9df..a3827a4 100644
--- a/src/xxd/xxd.c
+++ b/src/xxd/xxd.c
@@ -206,6 +206,24 @@
#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
+#define COLOR_PROLOGUE \
+l[c++] = '\033'; \
+l[c++] = '['; \
+l[c++] = '1'; \
+l[c++] = ';'; \
+l[c++] = '3';
+
+#define COLOR_EPILOGUE \
+l[c++] = '\033'; \
+l[c++] = '['; \
+l[c++] = '0'; \
+l[c++] = 'm';
+#define COLOR_RED '1'
+#define COLOR_GREEN '2'
+#define COLOR_YELLOW '3'
+#define COLOR_BLUE '4'
+#define COLOR_WHITE '7'
+
static char *pname;
static void
@@ -237,6 +255,7 @@
"", "");
#endif
fprintf(stderr, " -u use upper case hex letters.\n");
+ fprintf(stderr, " -R [WHEN] colorize the output; WHEN can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
exit(1);
}
@@ -482,11 +501,56 @@
0070,0071,0372,0373,0374,0375,0376,0377
};
+ static void
+begin_coloring_char (char *l, int *c, int e, int ebcdic)
+{
+ if (ebcdic)
+ {
+ if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
+ (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
+ (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
+ (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
+ (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
+ (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
+ (e == 173) || (e == 224) )
+ l[(*c)++] = COLOR_GREEN;
+
+ else if (e == 37 || e == 13 || e == 5)
+ l[(*c)++] = COLOR_YELLOW;
+ else if (e == 0)
+ l[(*c)++] = COLOR_WHITE;
+ else if (e == 255)
+ l[(*c)++] = COLOR_BLUE;
+ else
+ l[(*c)++] = COLOR_RED;
+ }
+ else /* ASCII */
+ {
+ #ifdef __MVS__
+ if (e >= 64)
+ l[(*c)++] = COLOR_GREEN;
+ #else
+ if (e > 31 && e < 127)
+ l[(*c)++] = COLOR_GREEN;
+ #endif
+
+ else if (e == 9 || e == 10 || e == 13)
+ l[(*c)++] = COLOR_YELLOW;
+ else if (e == 0)
+ l[(*c)++] = COLOR_WHITE;
+ else if (e == 255)
+ l[(*c)++] = COLOR_BLUE;
+ else
+ l[(*c)++] = COLOR_RED;
+ }
+ l[(*c)++] = 'm';
+}
+
int
main(int argc, char *argv[])
{
FILE *fp, *fpo;
- int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
+ int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
int capitalize = 0, decimal_offset = 0;
int ebcdic = 0;
@@ -498,6 +562,11 @@
char *pp;
char *varname = NULL;
int addrlen = 9;
+ int color = 0;
+
+#ifdef UNIX
+ color = isatty(STDOUT_FILENO);
+#endif
#ifdef AMIGA
/* This program doesn't work when started from the Workbench */
@@ -648,6 +717,17 @@
argc--;
}
}
+ else if (!STRNCMP(pp, "-R", 2))
+ {
+ if (!argv[2])
+ exit_with_usage();
+ if (!STRNCMP(argv[2], "always", 2))
+ color = 1;
+ else if (!STRNCMP(argv[2], "never", 1))
+ color = 0;
+ argv++;
+ argc--;
+ }
else if (!strcmp(pp, "--")) /* end of options */
{
argv++;
@@ -825,14 +905,16 @@
/* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
if (hextype != HEX_BITS)
- grplen = octspergrp + octspergrp + 1; /* chars per octet group */
+ {
+ grplen = octspergrp + octspergrp + 1; /* chars per octet group */
+ if (color)
+ grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
+ }
else /* hextype == HEX_BITS */
grplen = 8 * octspergrp + 1;
while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
{
- int x;
-
if (p == 0)
{
addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
@@ -844,47 +926,135 @@
c = addrlen + 1 + (grplen * x) / octspergrp;
if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
{
- l[c] = hexx[(e >> 4) & 0xf];
- l[++c] = hexx[e & 0xf];
+ if (color)
+ {
+ COLOR_PROLOGUE
+ begin_coloring_char(l,&c,e,ebcdic);
+ l[c++] = hexx[(e >> 4) & 0xf];
+ l[c++] = hexx[e & 0xf];
+ COLOR_EPILOGUE
+ }
+ else /*No colors*/
+ {
+ l[c] = hexx[(e >> 4) & 0xf];
+ l[++c] = hexx[e & 0xf];
+ }
}
else /* hextype == HEX_BITS */
{
- int i;
for (i = 7; i >= 0; i--)
l[c++] = (e & (1 << i)) ? '1' : '0';
}
if (e)
nonzero++;
- if (ebcdic)
- e = (e < 64) ? '.' : etoa64[e-64];
/* When changing this update definition of LLEN above. */
if (hextype == HEX_LITTLEENDIAN)
/* last group will be fully used, round up */
c = grplen * ((cols + octspergrp - 1) / octspergrp);
else
c = (grplen * cols - 1) / octspergrp;
- c += addrlen + 3 + p;
- l[c++] =
+
+ if (color)
+ {
+ if (hextype == HEX_BITS)
+ c += addrlen + 3 + p*12;
+ else
+ c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
+
+ if (hextype == HEX_LITTLEENDIAN)
+ c += 1;
+
+ COLOR_PROLOGUE
+ begin_coloring_char(l,&c,e,ebcdic);
#ifdef __MVS__
- (e >= 64)
+ if (e >= 64)
+ l[c++] = e;
+ else
+ l[c++] = '.';
#else
- (e > 31 && e < 127)
+ if (ebcdic)
+ e = (e < 64) ? '.' : etoa64[e-64];
+ l[c++] = (e > 31 && e < 127) ? e : '.';
#endif
- ? e : '.';
- n++;
- if (++p == cols)
- {
- l[c] = '\n';
- l[++c] = '\0';
- xxdline(fpo, l, autoskip ? nonzero : 1);
- nonzero = 0;
- p = 0;
- }
+ COLOR_EPILOGUE
+ n++;
+ if (++p == cols)
+ {
+ l[c++] = '\n';
+ l[c++] = '\0';
+ xxdline(fpo, l, autoskip ? nonzero : 1);
+ nonzero = 0;
+ p = 0;
+ }
+ }
+ else /*no colors*/
+ {
+ if (ebcdic)
+ e = (e < 64) ? '.' : etoa64[e-64];
+
+ c += addrlen + 3 + p;
+ l[c++] =
+#ifdef __MVS__
+ (e >= 64)
+#else
+ (e > 31 && e < 127)
+#endif
+ ? e : '.';
+ n++;
+ if (++p == cols)
+ {
+ l[c++] = '\n';
+ l[c] = '\0';
+ xxdline(fpo, l, autoskip ? nonzero : 1);
+ nonzero = 0;
+ p = 0;
+ }
+ }
}
if (p)
{
- l[c] = '\n';
- l[++c] = '\0';
+ l[c++] = '\n';
+ l[c] = '\0';
+ if (color)
+ {
+ c++;
+
+ x = p;
+ if (hextype == HEX_LITTLEENDIAN)
+ {
+ int fill = octspergrp - (p % octspergrp);
+ if (fill == octspergrp) fill = 0;
+
+ c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
+
+ for (i = 0; i < fill;i++)
+ {
+ COLOR_PROLOGUE
+ l[c++] = COLOR_RED;
+ l[c++] = 'm';
+ l[c++] = ' '; /* empty space */
+ COLOR_EPILOGUE
+ x++;
+ p++;
+ }
+ }
+
+ if (hextype != HEX_BITS)
+ {
+ c = addrlen + 1 + (grplen * x) / octspergrp;
+ c += cols - p;
+ c += (cols - p) / octspergrp;
+
+ for (i = cols - p; i > 0;i--)
+ {
+ COLOR_PROLOGUE
+ l[c++] = COLOR_RED;
+ l[c++] = 'm';
+ l[c++] = ' '; /* empty space */
+ COLOR_EPILOGUE
+ }
+ }
+ }
xxdline(fpo, l, 1);
}
else if (autoskip)