Mercurial > vim
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)