diff src/xxd/xxd.c @ 33083:79b2eb83f2df v9.0.1827

patch 9.0.1827: xxd: no color support Commit: https://github.com/vim/vim/commit/e2528ae11134cdf35c312754b124aba4963d8054 Author: Aapo Rantalainen <aapo.rantalainen@gmail.com> Date: Thu Aug 31 17:58:13 2023 +0200 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>
author Christian Brabandt <cb@256bit.org>
date Thu, 31 Aug 2023 18:15:03 +0200
parents 5a1113ece237
children e1a219f47e3a
line wrap: on
line diff
--- a/src/xxd/xxd.c
+++ b/src/xxd/xxd.c
@@ -206,6 +206,24 @@ char hexxa[] = "0123456789abcdef01234567
 
 #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 @@ exit_with_usage(void)
 	  "", "");
 #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 @@ static unsigned char etoa64[] =
     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 @@ main(int argc, char *argv[])
   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 @@ main(int argc, char *argv[])
               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 @@ main(int argc, char *argv[])
   /* 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 @@ main(int argc, char *argv[])
       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)