changeset 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 7ff767f84630
children e9d9d0e4fc40
files runtime/doc/xxd.1 src/testdir/dumps/Test_xxd_color_0.dump src/testdir/dumps/Test_xxd_color_1.dump src/testdir/term_util.vim src/testdir/test_xxd.vim src/version.c src/xxd/xxd.c
diffstat 7 files changed, 428 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/xxd.1
+++ b/runtime/doc/xxd.1
@@ -135,6 +135,12 @@ to read plain hexadecimal dumps without 
 particular column layout. Additional whitespace and line breaks are allowed
 anywhere.
 .TP
+.IR \-R " "[WHEN]
+In output the hex-value and the value are both colored with the same color depending on the hex-value. Mostly helping to differentiate printable and non-printable characters.
+.I WHEN
+is
+.BR never ", " always ", or " auto .
+.TP
 .I \-seek offset
 When used after
 .IR \-r :
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xxd_color_0.dump
@@ -0,0 +1,20 @@
+|$+0&#ffffff0| |.@1|/|x@1|d|/|x@1|d| |-|R| |n|e|v|e|r| @1|<| |X@1|D|f|i|l|e|_|c|o|l|o|r|s| @35
+|0@7|:| |0@2|1| |0|2|0|3| |0|4|0|5| |0|6|0|7| |0|8|0|9| |0|a|0|b| |0|c|0|d| |0|e|0|f| @1|.@15| @7
+|0@5|1|0|:| |1|0|1@1| |1|2|1|3| |1|4|1|5| |1|6|1|7| |1|8|1|9| |1|a|1|b| |1|c|1|d| |1|e|1|f| @1|.@15| @7
+|0@5|2|0|:| |2|0|2|1| |2@2|3| |2|4|2|5| |2|6|0@1| |2|8|2|9| |2|a|2|b| |2|c|2|d| |2|e|2|f| @2|!|"|#|$|%|&|.|(|)|*|+|,|-|.|/| @7
+|0@5|3|0|:| |3|0|3|1| |3|2|3@1| |3|4|3|5| |3|6|3|7| |3|8|3|9| |3|a|3|b| |3|c|3|d| |3|e|3|f| @1|0|1|2|3|4|5|6|7|8|9|:|;|<|=|>|?| @7
+|0@5|4|0|:| |4|0|4|1| |4|2|4|3| |4@2|5| |4|6|4|7| |4|8|4|9| |4|a|4|b| |4|c|4|d| |4|e|4|f| @1|@|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O| @7
+|0@5|5|0|:| |5|0|5|1| |5|2|5|3| |5|4|5@1| |5|6|5|7| |5|8|5|9| |5|a|5|b| |0@1|5|d| |5|e|5|f| @1|P|Q|R|S|T|U|V|W|X|Y|Z|[|.|]|^|_| @7
+|0@5|6|0|:| |6|0|6|1| |6|2|6|3| |6|4|6|5| |6@2|7| |6|8|6|9| |6|a|6|b| |6|c|6|d| |6|e|6|f| @1|`|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o| @7
+|0@5|7|0|:| |7|0|7|1| |7|2|7|3| |7|4|7|5| |7|6|7@1| |7|8|7|9| |7|a|7|b| |7|c|7|d| |7|e|7|f| @1|p|q|r|s|t|u|v|w|x|y|z|{|||}|~|.| @7
+|0@5|8|0|:| |8|0|8|1| |8|2|8|3| |8|4|8|5| |8|6|8|7| |8@2|9| |8|a|8|b| |8|c|8|d| |8|e|8|f| @1|.@15| @7
+|0@5|9|0|:| |9|0|9|1| |9|2|9|3| |9|4|9|5| |9|6|9|7| |9|8|9@1| |9|a|9|b| |9|c|9|d| |9|e|9|f| @1|.@15| @7
+|0@5|a|0|:| |a|0|a|1| |a|2|a|3| |a|4|a|5| |a|6|a|7| |a|8|a|9| |a@2|b| |a|c|a|d| |a|e|a|f| @1|.@15| @7
+|0@5|b|0|:| |b|0|b|1| |b|2|b|3| |b|4|b|5| |b|6|b|7| |b|8|b|9| |b|a|b@1| |b|c|b|d| |b|e|b|f| @1|.@15| @7
+|0@5|c|0|:| |c|0|c|1| |c|2|c|3| |c|4|c|5| |c|6|c|7| |c|8|c|9| |c|a|c|b| |c@2|d| |c|e|c|f| @1|.@15| @7
+|0@5|d|0|:| |d|0|d|1| |d|2|d|3| |d|4|d|5| |d|6|d|7| |d|8|d|9| |d|a|d|b| |d|c|d@1| |d|e|d|f| @1|.@15| @7
+|0@5|e|0|:| |e|0|e|1| |e|2|e|3| |e|4|e|5| |e|6|e|7| |e|8|e|9| |e|a|e|b| |e|c|e|d| |e@2|f| @1|.@15| @7
+|0@5|f|0|:| |f|0|f|1| |f|2|f|3| |f|4|f|5| |f|6|f|7| |f|8|f|9| |f|a|f|b| |f|c|f|d| |f|e|f@1| @1|.@15| @7
+|$| > @72
+@75
+@75
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_xxd_color_1.dump
@@ -0,0 +1,20 @@
+|$+0&#ffffff0| |0@7|:| |0+2#e0e0e08&@1|0+2#e000002&|1| +0#0000000&|0+2#e000002&|2|0|3| +0#0000000&|0+2#e000002&|4|0|5| +0#0000000&|0+2#e000002&|6|0|7| +0#0000000&|0+2#e000002&|8|0+2#e0e0004&|9| +0#0000000&|0+2#e0e0004&|a|0+2#e000002&|b| +0#0000000&|0+2#e000002&|c|0+2#e0e0004&|d| +0#0000000&|0+2#e000002&|e|0|f| +0#0000000&@1|.+2#e0e0e08&|.+2#e000002&@7|.+2#e0e0004&@1|.+2#e000002&@1|.+2#e0e0004&|.+2#e000002&@1| +0#0000000&@5
+|0@5|1|0|:| |1+2#e000002&|0|1@1| +0#0000000&|1+2#e000002&|2|1|3| +0#0000000&|1+2#e000002&|4|1|5| +0#0000000&|1+2#e000002&|6|1|7| +0#0000000&|1+2#e000002&|8|1|9| +0#0000000&|1+2#e000002&|a|1|b| +0#0000000&|1+2#e000002&|c|1|d| +0#0000000&|1+2#e000002&|e|1|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|2|0|:| |2+2#00e0003&|0|2|1| +0#0000000&|2+2#00e0003&@2|3| +0#0000000&|2+2#00e0003&|4|2|5| +0#0000000&|2+2#00e0003&|6|0+2#e0e0e08&@1| +0#0000000&|2+2#00e0003&|8|2|9| +0#0000000&|2+2#00e0003&|a|2|b| +0#0000000&|2+2#00e0003&|c|2|d| +0#0000000&|2+2#00e0003&|e|2|f| +0#0000000&@1| +2#00e0003&|!|"|#|$|%|&|.+2#e0e0e08&|(+2#00e0003&|)|*|+|,|-|.|/| +0#0000000&@7
+|0@5|3|0|:| |3+2#00e0003&|0|3|1| +0#0000000&|3+2#00e0003&|2|3@1| +0#0000000&|3+2#00e0003&|4|3|5| +0#0000000&|3+2#00e0003&|6|3|7| +0#0000000&|3+2#00e0003&|8|3|9| +0#0000000&|3+2#00e0003&|a|3|b| +0#0000000&|3+2#00e0003&|c|3|d| +0#0000000&|3+2#00e0003&|e|3|f| +0#0000000&@1|0+2#00e0003&|1|2|3|4|5|6|7|8|9|:|;|<|=|>|?| +0#0000000&@7
+|0@5|4|0|:| |4+2#00e0003&|0|4|1| +0#0000000&|4+2#00e0003&|2|4|3| +0#0000000&|4+2#00e0003&@2|5| +0#0000000&|4+2#00e0003&|6|4|7| +0#0000000&|4+2#00e0003&|8|4|9| +0#0000000&|4+2#00e0003&|a|4|b| +0#0000000&|4+2#00e0003&|c|4|d| +0#0000000&|4+2#00e0003&|e|4|f| +0#0000000&@1|@+2#00e0003&|A|B|C|D|E|F|G|H|I|J|K|L|M|N|O| +0#0000000&@7
+|0@5|5|0|:| |5+2#00e0003&|0|5|1| +0#0000000&|5+2#00e0003&|2|5|3| +0#0000000&|5+2#00e0003&|4|5@1| +0#0000000&|5+2#00e0003&|6|5|7| +0#0000000&|5+2#00e0003&|8|5|9| +0#0000000&|5+2#00e0003&|a|5|b| +0#0000000&|0+2#e0e0e08&@1|5+2#00e0003&|d| +0#0000000&|5+2#00e0003&|e|5|f| +0#0000000&@1|P+2#00e0003&|Q|R|S|T|U|V|W|X|Y|Z|[|.+2#e0e0e08&|]+2#00e0003&|^|_| +0#0000000&@7
+|0@5|6|0|:| |6+2#00e0003&|0|6|1| +0#0000000&|6+2#00e0003&|2|6|3| +0#0000000&|6+2#00e0003&|4|6|5| +0#0000000&|6+2#00e0003&@2|7| +0#0000000&|6+2#00e0003&|8|6|9| +0#0000000&|6+2#00e0003&|a|6|b| +0#0000000&|6+2#00e0003&|c|6|d| +0#0000000&|6+2#00e0003&|e|6|f| +0#0000000&@1|`+2#00e0003&|a|b|c|d|e|f|g|h|i|j|k|l|m|n|o| +0#0000000&@7
+|0@5|7|0|:| |7+2#00e0003&|0|7|1| +0#0000000&|7+2#00e0003&|2|7|3| +0#0000000&|7+2#00e0003&|4|7|5| +0#0000000&|7+2#00e0003&|6|7@1| +0#0000000&|7+2#00e0003&|8|7|9| +0#0000000&|7+2#00e0003&|a|7|b| +0#0000000&|7+2#00e0003&|c|7|d| +0#0000000&|7+2#00e0003&|e|7+2#e000002&|f| +0#0000000&@1|p+2#00e0003&|q|r|s|t|u|v|w|x|y|z|{|||}|~|.+2#e000002&| +0#0000000&@7
+|0@5|8|0|:| |8+2#e000002&|0|8|1| +0#0000000&|8+2#e000002&|2|8|3| +0#0000000&|8+2#e000002&|4|8|5| +0#0000000&|8+2#e000002&|6|8|7| +0#0000000&|8+2#e000002&@2|9| +0#0000000&|8+2#e000002&|a|8|b| +0#0000000&|8+2#e000002&|c|8|d| +0#0000000&|8+2#e000002&|e|8|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|9|0|:| |9+2#e000002&|0|9|1| +0#0000000&|9+2#e000002&|2|9|3| +0#0000000&|9+2#e000002&|4|9|5| +0#0000000&|9+2#e000002&|6|9|7| +0#0000000&|9+2#e000002&|8|9@1| +0#0000000&|9+2#e000002&|a|9|b| +0#0000000&|9+2#e000002&|c|9|d| +0#0000000&|9+2#e000002&|e|9|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|a|0|:| |a+2#e000002&|0|a|1| +0#0000000&|a+2#e000002&|2|a|3| +0#0000000&|a+2#e000002&|4|a|5| +0#0000000&|a+2#e000002&|6|a|7| +0#0000000&|a+2#e000002&|8|a|9| +0#0000000&|a+2#e000002&@2|b| +0#0000000&|a+2#e000002&|c|a|d| +0#0000000&|a+2#e000002&|e|a|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|b|0|:| |b+2#e000002&|0|b|1| +0#0000000&|b+2#e000002&|2|b|3| +0#0000000&|b+2#e000002&|4|b|5| +0#0000000&|b+2#e000002&|6|b|7| +0#0000000&|b+2#e000002&|8|b|9| +0#0000000&|b+2#e000002&|a|b@1| +0#0000000&|b+2#e000002&|c|b|d| +0#0000000&|b+2#e000002&|e|b|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|c|0|:| |c+2#e000002&|0|c|1| +0#0000000&|c+2#e000002&|2|c|3| +0#0000000&|c+2#e000002&|4|c|5| +0#0000000&|c+2#e000002&|6|c|7| +0#0000000&|c+2#e000002&|8|c|9| +0#0000000&|c+2#e000002&|a|c|b| +0#0000000&|c+2#e000002&@2|d| +0#0000000&|c+2#e000002&|e|c|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|d|0|:| |d+2#e000002&|0|d|1| +0#0000000&|d+2#e000002&|2|d|3| +0#0000000&|d+2#e000002&|4|d|5| +0#0000000&|d+2#e000002&|6|d|7| +0#0000000&|d+2#e000002&|8|d|9| +0#0000000&|d+2#e000002&|a|d|b| +0#0000000&|d+2#e000002&|c|d@1| +0#0000000&|d+2#e000002&|e|d|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|e|0|:| |e+2#e000002&|0|e|1| +0#0000000&|e+2#e000002&|2|e|3| +0#0000000&|e+2#e000002&|4|e|5| +0#0000000&|e+2#e000002&|6|e|7| +0#0000000&|e+2#e000002&|8|e|9| +0#0000000&|e+2#e000002&|a|e|b| +0#0000000&|e+2#e000002&|c|e|d| +0#0000000&|e+2#e000002&@2|f| +0#0000000&@1|.+2#e000002&@15| +0#0000000&@7
+|0@5|f|0|:| |f+2#e000002&|0|f|1| +0#0000000&|f+2#e000002&|2|f|3| +0#0000000&|f+2#e000002&|4|f|5| +0#0000000&|f+2#e000002&|6|f|7| +0#0000000&|f+2#e000002&|8|f|9| +0#0000000&|f+2#e000002&|a|f|b| +0#0000000&|f+2#e000002&|c|f|d| +0#0000000&|f+2#e000002&|e|f+2#0000e05&@1| +0#0000000&@1|.+2#e000002&@14|.+2#0000e05&| +0#0000000&@7
+|$| > @72
+@75
+@75
+@75
--- a/src/testdir/term_util.vim
+++ b/src/testdir/term_util.vim
@@ -56,6 +56,7 @@ endfunc
 " "statusoff" - number of lines the status is offset from default
 " "wait_for_ruler" - if zero then don't wait for ruler to show
 " "no_clean" - if non-zero then remove "--clean" from the command
+" "cmd"  - run any other command, e.g. "xxd" (used in xxd test)
 func RunVimInTerminal(arguments, options)
   " If Vim doesn't exit a swap file remains, causing other tests to fail.
   " Remove it here.
@@ -90,7 +91,11 @@ func RunVimInTerminal(arguments, options
     let reset_u7 = ' --cmd "set t_u7=" '
   endif
 
-  let cmd = GetVimCommandCleanTerm() .. reset_u7 .. a:arguments
+  if empty(get(a:options, 'cmd', ''))
+    let cmd = GetVimCommandCleanTerm() .. reset_u7 .. a:arguments
+  else
+    let cmd = get(a:options, 'cmd')
+  endif
 
   if get(a:options, 'no_clean', 0)
     let cmd = substitute(cmd, '--clean', '', '')
@@ -120,7 +125,7 @@ func RunVimInTerminal(arguments, options
 
   call TermWait(buf)
 
-  if get(a:options, 'wait_for_ruler', 1)
+  if get(a:options, 'wait_for_ruler', 1) && empty(get(a:options, 'cmd', ''))
     " Wait for "All" or "Top" of the ruler to be shown in the last line or in
     " the status line of the last window. This can be quite slow (e.g. when
     " using valgrind).
--- a/src/testdir/test_xxd.vim
+++ b/src/testdir/test_xxd.vim
@@ -1,5 +1,8 @@
 " Test for the xxd command
 
+source check.vim
+source screendump.vim
+
 if empty($XXD) && executable('..\xxd\xxd.exe')
   let s:xxd_cmd = '..\xxd\xxd.exe'
 elseif empty($XXD) || !executable($XXD)
@@ -311,7 +314,7 @@ endfunc
 
 " Various ways with wrong arguments that trigger the usage output.
 func Test_xxd_usage()
-  for arg in ['-h', '-c', '-g', '-o', '-s', '-l', '-X', 'one two three']
+  for arg in ['-h', '-c', '-g', '-o', '-s', '-l', '-X', '-R', 'one two three']
     new
     exe 'r! ' . s:xxd_cmd . ' ' . arg
     call assert_match("Usage:", join(getline(1, 3)))
@@ -415,4 +418,178 @@ func Test_xxd_little_endian_with_cols()
   bwipe!
 endfunc
 
+func Test_xxd_color()
+"Test: color=never
+let s:test = 1
+
+"Note Quotation mark escaped
+"Note Aposhpere vaihdettu apostrophe replaced with 0x00
+"Note Backslash replaced with 0x00
+let data = [
+    \ "00000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................",
+    \ "00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................",
+    \ "00000020: 2021 2223 2425 2600 2829 2a2b 2c2d 2e2f   !\"#$%&.()*+,-./",
+    \ "00000030: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f  0123456789:;<=>?",
+    \ "00000040: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f  @ABCDEFGHIJKLMNO",
+    \ "00000050: 5051 5253 5455 5657 5859 5a5b 005d 5e5f  PQRSTUVWXYZ[.]^_",
+    \ "00000060: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f  `abcdefghijklmno",
+    \ "00000070: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f  pqrstuvwxyz{|}~.",
+    \ "00000080: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f  ................",
+    \ "00000090: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f  ................",
+    \ "000000a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf  ................",
+    \ "000000b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf  ................",
+    \ "000000c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf  ................",
+    \ "000000d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf  ................",
+    \ "000000e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef  ................",
+    \ "000000f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff  ................"]
+call writefile(data,'Xinput')
+
+  silent exe '!' . s:xxd_cmd . ' -r < Xinput > XXDfile'
+
+  %d
+  exe '0r! ' . s:xxd_cmd . ' -R never ' . ' XXDfile'
+  $d
+  let expected = [
+      \ "00000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................",
+      \ "00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................",
+      \ "00000020: 2021 2223 2425 2600 2829 2a2b 2c2d 2e2f   !\"#$%&.()*+,-./",
+      \ "00000030: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f  0123456789:;<=>?",
+      \ "00000040: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f  @ABCDEFGHIJKLMNO",
+      \ "00000050: 5051 5253 5455 5657 5859 5a5b 005d 5e5f  PQRSTUVWXYZ[.]^_",
+      \ "00000060: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f  `abcdefghijklmno",
+      \ "00000070: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f  pqrstuvwxyz{|}~.",
+      \ "00000080: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f  ................",
+      \ "00000090: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f  ................",
+      \ "000000a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf  ................",
+      \ "000000b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf  ................",
+      \ "000000c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf  ................",
+      \ "000000d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf  ................",
+      \ "000000e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef  ................",
+      \ "000000f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff  ................"]
+
+  call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+  "Test: color=always
+  let s:test += 1
+
+  %d
+  exe '0r! ' . s:xxd_cmd . ' -R always -c 4 ' . ' XXDfile'
+  $d
+  let expected = [
+      \ "00000000: \e[1;37m00\e[0m\e[1;31m01\e[0m \e[1;31m02\e[0m\e[1;31m03\e[0m  \e[1;37m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000004: \e[1;31m04\e[0m\e[1;31m05\e[0m \e[1;31m06\e[0m\e[1;31m07\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000008: \e[1;31m08\e[0m\e[1;33m09\e[0m \e[1;33m0a\e[0m\e[1;31m0b\e[0m  \e[1;31m.\e[0m\e[1;33m.\e[0m\e[1;33m.\e[0m\e[1;31m.\e[0m",
+      \ "0000000c: \e[1;31m0c\e[0m\e[1;33m0d\e[0m \e[1;31m0e\e[0m\e[1;31m0f\e[0m  \e[1;31m.\e[0m\e[1;33m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000010: \e[1;31m10\e[0m\e[1;31m11\e[0m \e[1;31m12\e[0m\e[1;31m13\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000014: \e[1;31m14\e[0m\e[1;31m15\e[0m \e[1;31m16\e[0m\e[1;31m17\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000018: \e[1;31m18\e[0m\e[1;31m19\e[0m \e[1;31m1a\e[0m\e[1;31m1b\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "0000001c: \e[1;31m1c\e[0m\e[1;31m1d\e[0m \e[1;31m1e\e[0m\e[1;31m1f\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000020: \e[1;32m20\e[0m\e[1;32m21\e[0m \e[1;32m22\e[0m\e[1;32m23\e[0m  \e[1;32m \e[0m\e[1;32m!\e[0m\e[1;32m\"\e[0m\e[1;32m#\e[0m",
+      \ "00000024: \e[1;32m24\e[0m\e[1;32m25\e[0m \e[1;32m26\e[0m\e[1;37m00\e[0m  \e[1;32m$\e[0m\e[1;32m%\e[0m\e[1;32m&\e[0m\e[1;37m.\e[0m",
+      \ "00000028: \e[1;32m28\e[0m\e[1;32m29\e[0m \e[1;32m2a\e[0m\e[1;32m2b\e[0m  \e[1;32m(\e[0m\e[1;32m)\e[0m\e[1;32m*\e[0m\e[1;32m+\e[0m",
+      \ "0000002c: \e[1;32m2c\e[0m\e[1;32m2d\e[0m \e[1;32m2e\e[0m\e[1;32m2f\e[0m  \e[1;32m,\e[0m\e[1;32m-\e[0m\e[1;32m.\e[0m\e[1;32m/\e[0m",
+      \ "00000030: \e[1;32m30\e[0m\e[1;32m31\e[0m \e[1;32m32\e[0m\e[1;32m33\e[0m  \e[1;32m0\e[0m\e[1;32m1\e[0m\e[1;32m2\e[0m\e[1;32m3\e[0m",
+      \ "00000034: \e[1;32m34\e[0m\e[1;32m35\e[0m \e[1;32m36\e[0m\e[1;32m37\e[0m  \e[1;32m4\e[0m\e[1;32m5\e[0m\e[1;32m6\e[0m\e[1;32m7\e[0m",
+      \ "00000038: \e[1;32m38\e[0m\e[1;32m39\e[0m \e[1;32m3a\e[0m\e[1;32m3b\e[0m  \e[1;32m8\e[0m\e[1;32m9\e[0m\e[1;32m:\e[0m\e[1;32m;\e[0m",
+      \ "0000003c: \e[1;32m3c\e[0m\e[1;32m3d\e[0m \e[1;32m3e\e[0m\e[1;32m3f\e[0m  \e[1;32m<\e[0m\e[1;32m=\e[0m\e[1;32m>\e[0m\e[1;32m?\e[0m",
+      \ "00000040: \e[1;32m40\e[0m\e[1;32m41\e[0m \e[1;32m42\e[0m\e[1;32m43\e[0m  \e[1;32m@\e[0m\e[1;32mA\e[0m\e[1;32mB\e[0m\e[1;32mC\e[0m",
+      \ "00000044: \e[1;32m44\e[0m\e[1;32m45\e[0m \e[1;32m46\e[0m\e[1;32m47\e[0m  \e[1;32mD\e[0m\e[1;32mE\e[0m\e[1;32mF\e[0m\e[1;32mG\e[0m",
+      \ "00000048: \e[1;32m48\e[0m\e[1;32m49\e[0m \e[1;32m4a\e[0m\e[1;32m4b\e[0m  \e[1;32mH\e[0m\e[1;32mI\e[0m\e[1;32mJ\e[0m\e[1;32mK\e[0m",
+      \ "0000004c: \e[1;32m4c\e[0m\e[1;32m4d\e[0m \e[1;32m4e\e[0m\e[1;32m4f\e[0m  \e[1;32mL\e[0m\e[1;32mM\e[0m\e[1;32mN\e[0m\e[1;32mO\e[0m",
+      \ "00000050: \e[1;32m50\e[0m\e[1;32m51\e[0m \e[1;32m52\e[0m\e[1;32m53\e[0m  \e[1;32mP\e[0m\e[1;32mQ\e[0m\e[1;32mR\e[0m\e[1;32mS\e[0m",
+      \ "00000054: \e[1;32m54\e[0m\e[1;32m55\e[0m \e[1;32m56\e[0m\e[1;32m57\e[0m  \e[1;32mT\e[0m\e[1;32mU\e[0m\e[1;32mV\e[0m\e[1;32mW\e[0m",
+      \ "00000058: \e[1;32m58\e[0m\e[1;32m59\e[0m \e[1;32m5a\e[0m\e[1;32m5b\e[0m  \e[1;32mX\e[0m\e[1;32mY\e[0m\e[1;32mZ\e[0m\e[1;32m[\e[0m",
+      \ "0000005c: \e[1;37m00\e[0m\e[1;32m5d\e[0m \e[1;32m5e\e[0m\e[1;32m5f\e[0m  \e[1;37m.\e[0m\e[1;32m]\e[0m\e[1;32m^\e[0m\e[1;32m_\e[0m",
+      \ "00000060: \e[1;32m60\e[0m\e[1;32m61\e[0m \e[1;32m62\e[0m\e[1;32m63\e[0m  \e[1;32m`\e[0m\e[1;32ma\e[0m\e[1;32mb\e[0m\e[1;32mc\e[0m",
+      \ "00000064: \e[1;32m64\e[0m\e[1;32m65\e[0m \e[1;32m66\e[0m\e[1;32m67\e[0m  \e[1;32md\e[0m\e[1;32me\e[0m\e[1;32mf\e[0m\e[1;32mg\e[0m",
+      \ "00000068: \e[1;32m68\e[0m\e[1;32m69\e[0m \e[1;32m6a\e[0m\e[1;32m6b\e[0m  \e[1;32mh\e[0m\e[1;32mi\e[0m\e[1;32mj\e[0m\e[1;32mk\e[0m",
+      \ "0000006c: \e[1;32m6c\e[0m\e[1;32m6d\e[0m \e[1;32m6e\e[0m\e[1;32m6f\e[0m  \e[1;32ml\e[0m\e[1;32mm\e[0m\e[1;32mn\e[0m\e[1;32mo\e[0m",
+      \ "00000070: \e[1;32m70\e[0m\e[1;32m71\e[0m \e[1;32m72\e[0m\e[1;32m73\e[0m  \e[1;32mp\e[0m\e[1;32mq\e[0m\e[1;32mr\e[0m\e[1;32ms\e[0m",
+      \ "00000074: \e[1;32m74\e[0m\e[1;32m75\e[0m \e[1;32m76\e[0m\e[1;32m77\e[0m  \e[1;32mt\e[0m\e[1;32mu\e[0m\e[1;32mv\e[0m\e[1;32mw\e[0m",
+      \ "00000078: \e[1;32m78\e[0m\e[1;32m79\e[0m \e[1;32m7a\e[0m\e[1;32m7b\e[0m  \e[1;32mx\e[0m\e[1;32my\e[0m\e[1;32mz\e[0m\e[1;32m{\e[0m",
+      \ "0000007c: \e[1;32m7c\e[0m\e[1;32m7d\e[0m \e[1;32m7e\e[0m\e[1;31m7f\e[0m  \e[1;32m|\e[0m\e[1;32m}\e[0m\e[1;32m~\e[0m\e[1;31m.\e[0m",
+      \ "00000080: \e[1;31m80\e[0m\e[1;31m81\e[0m \e[1;31m82\e[0m\e[1;31m83\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000084: \e[1;31m84\e[0m\e[1;31m85\e[0m \e[1;31m86\e[0m\e[1;31m87\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000088: \e[1;31m88\e[0m\e[1;31m89\e[0m \e[1;31m8a\e[0m\e[1;31m8b\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "0000008c: \e[1;31m8c\e[0m\e[1;31m8d\e[0m \e[1;31m8e\e[0m\e[1;31m8f\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000090: \e[1;31m90\e[0m\e[1;31m91\e[0m \e[1;31m92\e[0m\e[1;31m93\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000094: \e[1;31m94\e[0m\e[1;31m95\e[0m \e[1;31m96\e[0m\e[1;31m97\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "00000098: \e[1;31m98\e[0m\e[1;31m99\e[0m \e[1;31m9a\e[0m\e[1;31m9b\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "0000009c: \e[1;31m9c\e[0m\e[1;31m9d\e[0m \e[1;31m9e\e[0m\e[1;31m9f\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000a0: \e[1;31ma0\e[0m\e[1;31ma1\e[0m \e[1;31ma2\e[0m\e[1;31ma3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000a4: \e[1;31ma4\e[0m\e[1;31ma5\e[0m \e[1;31ma6\e[0m\e[1;31ma7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000a8: \e[1;31ma8\e[0m\e[1;31ma9\e[0m \e[1;31maa\e[0m\e[1;31mab\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000ac: \e[1;31mac\e[0m\e[1;31mad\e[0m \e[1;31mae\e[0m\e[1;31maf\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000b0: \e[1;31mb0\e[0m\e[1;31mb1\e[0m \e[1;31mb2\e[0m\e[1;31mb3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000b4: \e[1;31mb4\e[0m\e[1;31mb5\e[0m \e[1;31mb6\e[0m\e[1;31mb7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000b8: \e[1;31mb8\e[0m\e[1;31mb9\e[0m \e[1;31mba\e[0m\e[1;31mbb\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000bc: \e[1;31mbc\e[0m\e[1;31mbd\e[0m \e[1;31mbe\e[0m\e[1;31mbf\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000c0: \e[1;31mc0\e[0m\e[1;31mc1\e[0m \e[1;31mc2\e[0m\e[1;31mc3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000c4: \e[1;31mc4\e[0m\e[1;31mc5\e[0m \e[1;31mc6\e[0m\e[1;31mc7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000c8: \e[1;31mc8\e[0m\e[1;31mc9\e[0m \e[1;31mca\e[0m\e[1;31mcb\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000cc: \e[1;31mcc\e[0m\e[1;31mcd\e[0m \e[1;31mce\e[0m\e[1;31mcf\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000d0: \e[1;31md0\e[0m\e[1;31md1\e[0m \e[1;31md2\e[0m\e[1;31md3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000d4: \e[1;31md4\e[0m\e[1;31md5\e[0m \e[1;31md6\e[0m\e[1;31md7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000d8: \e[1;31md8\e[0m\e[1;31md9\e[0m \e[1;31mda\e[0m\e[1;31mdb\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000dc: \e[1;31mdc\e[0m\e[1;31mdd\e[0m \e[1;31mde\e[0m\e[1;31mdf\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000e0: \e[1;31me0\e[0m\e[1;31me1\e[0m \e[1;31me2\e[0m\e[1;31me3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000e4: \e[1;31me4\e[0m\e[1;31me5\e[0m \e[1;31me6\e[0m\e[1;31me7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000e8: \e[1;31me8\e[0m\e[1;31me9\e[0m \e[1;31mea\e[0m\e[1;31meb\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000ec: \e[1;31mec\e[0m\e[1;31med\e[0m \e[1;31mee\e[0m\e[1;31mef\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000f0: \e[1;31mf0\e[0m\e[1;31mf1\e[0m \e[1;31mf2\e[0m\e[1;31mf3\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000f4: \e[1;31mf4\e[0m\e[1;31mf5\e[0m \e[1;31mf6\e[0m\e[1;31mf7\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000f8: \e[1;31mf8\e[0m\e[1;31mf9\e[0m \e[1;31mfa\e[0m\e[1;31mfb\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m",
+      \ "000000fc: \e[1;31mfc\e[0m\e[1;31mfd\e[0m \e[1;31mfe\e[0m\e[1;34mff\e[0m  \e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;31m.\e[0m\e[1;34m.\e[0m"]
+  call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+  call delete('Xinput')
+  call delete('XXDfile')
+
+endfunc
+
+func Test_xxd_color2()
+  CheckScreendump
+  CheckUnix
+  CheckNotMac
+  CheckNotBSD
+
+  "Note Quotation mark escaped
+  "Note Aposhpere vaihdettu apostrophe replaced with 0x00
+  "Note Backslash replaced with 0x00
+  let data = [
+      \ "00000000: 0001 0203 0405 0607 0809 0a0b 0c0d 0e0f  ................",
+      \ "00000010: 1011 1213 1415 1617 1819 1a1b 1c1d 1e1f  ................",
+      \ "00000020: 2021 2223 2425 2600 2829 2a2b 2c2d 2e2f   !\"#$%&.()*+,-./",
+      \ "00000030: 3031 3233 3435 3637 3839 3a3b 3c3d 3e3f  0123456789:;<=>?",
+      \ "00000040: 4041 4243 4445 4647 4849 4a4b 4c4d 4e4f  @ABCDEFGHIJKLMNO",
+      \ "00000050: 5051 5253 5455 5657 5859 5a5b 005d 5e5f  PQRSTUVWXYZ[.]^_",
+      \ "00000060: 6061 6263 6465 6667 6869 6a6b 6c6d 6e6f  `abcdefghijklmno",
+      \ "00000070: 7071 7273 7475 7677 7879 7a7b 7c7d 7e7f  pqrstuvwxyz{|}~.",
+      \ "00000080: 8081 8283 8485 8687 8889 8a8b 8c8d 8e8f  ................",
+      \ "00000090: 9091 9293 9495 9697 9899 9a9b 9c9d 9e9f  ................",
+      \ "000000a0: a0a1 a2a3 a4a5 a6a7 a8a9 aaab acad aeaf  ................",
+      \ "000000b0: b0b1 b2b3 b4b5 b6b7 b8b9 babb bcbd bebf  ................",
+      \ "000000c0: c0c1 c2c3 c4c5 c6c7 c8c9 cacb cccd cecf  ................",
+      \ "000000d0: d0d1 d2d3 d4d5 d6d7 d8d9 dadb dcdd dedf  ................",
+      \ "000000e0: e0e1 e2e3 e4e5 e6e7 e8e9 eaeb eced eeef  ................",
+      \ "000000f0: f0f1 f2f3 f4f5 f6f7 f8f9 fafb fcfd feff  ................"]
+  call writefile(data, 'Xinput', 'D')
+
+  call system(s:xxd_cmd .. ' -r < Xinput > XXDfile_colors')
+
+  let buf = RunVimInTerminal('', #{rows: 20, cmd: 'sh'})
+  call term_sendkeys(buf,  s:xxd_cmd .. " -R never  < XXDfile_colors\<cr>")
+  call TermWait(buf)
+  call VerifyScreenDump(buf, 'Test_xxd_color_0', {})
+
+  call TermWait(buf)
+  call term_sendkeys(buf,  "clear\<CR>")
+  call term_sendkeys(buf,  s:xxd_cmd .. " -R always  < XXDfile_colors\<cr>")
+  call TermWait(buf)
+  call VerifyScreenDump(buf, 'Test_xxd_color_1', {})
+
+  call term_sendkeys(buf,  "exit\<CR>")
+
+  call delete('XXDfile_colors')
+endfunc
 " vim: shiftwidth=2 sts=2 expandtab
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1827,
+/**/
     1826,
 /**/
     1825,
--- 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)