patch 9.2.0205: xxd: Cannot NUL terminate the C include file style
Commit:
https://github.com/vim/vim/commit/4d262b4952754f9e14ccf699e26a27dd37435e1a
Author: Lukáš Jiřiště <
ky...@ljiriste.work>
Date: Thu Mar 19 20:33:18 2026 +0000
patch 9.2.0205: xxd: Cannot NUL terminate the C include file style
Problem: xxd: Cannot NUL terminate the C include file style
Solution: Add option -t to end output with terminating null
(Lukáš Jiřiště).
fixes: #14409
closes: #19745
Signed-off-by: Lukáš Jiřiště <
ky...@ljiriste.work>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index 79536bc98..e9a949e37 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.2. Last change: 2026 Mar 18
+*version9.txt* For Vim version 9.2. Last change: 2026 Mar 19
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -52595,7 +52595,7 @@ between them is small (5 bytes or less) and contains only non-word characters.
This prevents fragmented highlighting when only whitespace or punctuation
separates changes.
-Restricted mode~
+Restricted mode ~
---------------
Using external diff mode or setting environment variables is no longer allowed
when Vim is running in |restricted-mode|.
@@ -52610,6 +52610,10 @@ Other ~
- |status-line| can use several lines, see 'statuslineopt'.
- New "leadtab" value for the 'listchars' setting.
+xxd ~
+---
+Add "-t" option to append a terminating NUL byte to C include output (-i).
+
*changed-9.3*
Changed~
-------
diff --git a/runtime/doc/xxd.1 b/runtime/doc/xxd.1
index 2c6d5ad9a..e81d8cdee 100644
--- a/runtime/doc/xxd.1
+++ b/runtime/doc/xxd.1
@@ -1,4 +1,4 @@
-.TH XXD 1 "May 2024" "Manual page for xxd"
+.TH XXD 1 "March 2026" "Manual page for xxd"
.\"
.\" 21st May 1996
.\" Man page author:
@@ -169,6 +169,9 @@ should be that many characters from the end of the input (or if combined with
I+R: before the current stdin file position).
Without \-s option, xxd starts at the current file position.
.TP
+.I \-t
+When outputting in C include file style using \-i include the terminating zero.
+.TP
.I \-u
Use upper-case hex letters. Default is lower-case.
.TP
@@ -363,6 +366,20 @@ Read single characters from a serial line
.br
I% echo \-n foo > /dev/term/bR
.PP
+Output in C style include output with terminating zero
+.br
+I% echo -e \&"0123456789\&" > digitsR
+.br
+I% xxd -i -t digitsR
+.br
+unsigned char digits[] = {
+.br
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x0a, 0x00
+.br
+};
+.br
+unsigned int digits_len = 11;
+.PP
.SH "RETURN VALUES"
The following error values are returned:
.TP
diff --git a/runtime/doc/xxd.man b/runtime/doc/xxd.man
index 38106e1a8..e5c677ec5 100644
--- a/runtime/doc/xxd.man
+++ b/runtime/doc/xxd.man
@@ -119,26 +119,29 @@ OPTIONS
(or if combined with +: before the current stdin file position).
Without -s option, xxd starts at the current file position.
+ -t When outputting in C include file style using -i include the
+ terminating zero.
+
-u Use upper-case hex letters. Default is lower-case.
-v | -version
Show version string.
CAVEATS
- xxd -r has some built-in magic while evaluating line number informa‐
- tion. If the output file is seekable, then the line numbers at the
- start of each hex dump line may be out of order, lines may be missing,
- or overlapping. In these cases xxd will lseek(2) to the next position.
- If the output file is not seekable, only gaps are allowed, which will
+ xxd -r has some built-in magic while evaluating line number informa‐
+ tion. If the output file is seekable, then the line numbers at the
+ start of each hex dump line may be out of order, lines may be missing,
+ or overlapping. In these cases xxd will lseek(2) to the next position.
+ If the output file is not seekable, only gaps are allowed, which will
be filled by null-bytes.
xxd -r never generates parse errors. Garbage is silently skipped.
When editing hex dumps, please note that xxd -r skips everything on the
input line after reading enough columns of hexadecimal data (see option
- -c). This also means that changes to the printable ASCII (or EBCDIC)
+ -c). This also means that changes to the printable ASCII (or EBCDIC)
columns are always ignored. Reverting a plain (or PostScript) style hex
- dump with xxd -r -p does not depend on the correct number of columns.
+ dump with xxd -r -p does not depend on the correct number of columns.
Here, anything that looks like a pair of hex digits is interpreted.
Note the difference between
@@ -146,28 +149,28 @@ CAVEATS
and
% xxd -i < file
- xxd -s +seek may be different from xxd -s seek, as lseek(2) is used to
+ xxd -s +seek may be different from xxd -s seek, as lseek(2) is used to
"rewind" input. A '+' makes a difference if the input source is stdin,
- and if stdin's file position is not at the start of the file by the
- time xxd is started and given its input. The following examples may
+ and if stdin's file position is not at the start of the file by the
+ time xxd is started and given its input. The following examples may
help to clarify (or further confuse!):
- Rewind stdin before reading; needed because the `cat' has already read
+ Rewind stdin before reading; needed because the `cat' has already read
to the end of stdin.
% sh -c "cat > plain_copy; xxd -s 0 > hex_copy" < file
- Hex dump from file position 0x480 (=1024+128) onwards. The `+' sign
+ Hex dump from file position 0x480 (=1024+128) onwards. The `+' sign
means "relative to the current position", thus the `128' adds to the 1k
where dd left off.
- % sh -c "dd of=plain_snippet bs=1k count=1; xxd -s +128 > hex_snippet"
+ % sh -c "dd of=plain_snippet bs=1k count=1; xxd -s +128 > hex_snippet"
< file
Hex dump from file position 0x100 (=1024-768) onwards.
% sh -c "dd of=plain_snippet bs=1k count=1; xxd -s +-768 > hex_snippet"
< file
- However, this is a rare situation and the use of `+' is rarely needed.
- The author prefers to monitor the effect of xxd with strace(1) or
+ However, this is a rare situation and the use of `+' is rarely needed.
+ The author prefers to monitor the effect of xxd with strace(1) or
truss(1), whenever -s is used.
EXAMPLES
@@ -177,7 +180,7 @@ EXAMPLES
Print 3 lines (hex 0x30 bytes) from the end of file.
% xxd -s -0x30 file
- Note: The results of the examples below are relevant to the xxd.1 man
+ Note: The results of the examples below are relevant to the xxd.1 man
page as of May 2024
Print 120 bytes as a continuous hex dump with 20 octets per line.
@@ -214,7 +217,7 @@ EXAMPLES
% xxd -s 0x33 -l 13 -c 13 xxd.1
00000033: 3235 7468 204d 6179 2031 3939 36 25th May 1996
- Create a 65537 byte file with all bytes 0x00, except for the last one
+ Create a 65537 byte file with all bytes 0x00, except for the last one
which is 'A' (hex 0x41).
% echo "010000: 41" | xxd -r > file
@@ -225,11 +228,11 @@ EXAMPLES
0000fffc: 0000 0000 41 ....A
Create a 1 byte file containing a single 'A' character. The number af‐
- ter '-r -s' adds to the line numbers found in the file; in effect, the
+ ter '-r -s' adds to the line numbers found in the file; in effect, the
leading bytes are suppressed.
% echo "010000: 41" | xxd -r -s -0x10000 > file
- Use xxd as a filter within an editor such as vim(1) to hex dump a re‐
+ Use xxd as a filter within an editor such as vim(1) to hex dump a re‐
gion marked between `a' and `z'.
:'a,'z!xxd
@@ -246,6 +249,15 @@ EXAMPLES
% stty < /dev/term/b -echo -opost -isig -icanon min 1
% echo -n foo > /dev/term/b
+ Output in C style include output with terminating zero
+ % echo -e "0123456789" > digits
+ % xxd -i -t digits
+ unsigned char digits[] = {
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x0a,
+ 0x00
+ };
+ unsigned int digits_len = 11;
+
RETURN VALUES
The following error values are returned:
@@ -283,4 +295,4 @@ AUTHOR
<
to...@sctnugen.ppp.gu.edu.au> <
T.Nu...@sct.gu.edu.au>
Small changes by Bram Moolenaar. Edited by Juergen Weigert.
-Manual page for xxd May 2024 XXD(1)
+Manual page for xxd March 2026 XXD(1)
diff --git a/src/testdir/test_xxd.vim b/src/testdir/test_xxd.vim
index 030fdde5b..75dbd8bf6 100644
--- a/src/testdir/test_xxd.vim
+++ b/src/testdir/test_xxd.vim
@@ -284,6 +284,37 @@ func Test_xxd()
call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+ " Test 20: Print C include with terminating null
+ let s:test += 1
+ call writefile(['TESTabcd09'], 'XXDfile')
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -i -t XXDfile'
+ $d
+ let expected =<< trim [CODE]
+ unsigned char XXDfile[] = {
+ 0x54, 0x45, 0x53, 0x54, 0x61, 0x62, 0x63, 0x64, 0x30, 0x39, 0x0a, 0x00
+ };
+ unsigned int XXDfile_len = 11;
+ [CODE]
+
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
+ " Test 21: Print C include in binary format
+ let s:test += 1
+ call writefile(['TESTabcd09'], 'XXDfile')
+ %d
+ exe '0r! ' . s:xxd_cmd . ' -i -b -t XXDfile'
+ $d
+ let expected =<< trim [CODE]
+ unsigned char XXDfile[] = {
+ 0b01010100, 0b01000101, 0b01010011, 0b01010100, 0b01100001, 0b01100010,
+ 0b01100011, 0b01100100, 0b00110000, 0b00111001, 0b00001010, 0b00000000
+ };
+ unsigned int XXDfile_len = 11;
+ [CODE]
+
+ call assert_equal(expected, getline(1,'$'), s:Mess(s:test))
+
%d
bwipe!
diff --git a/src/version.c b/src/version.c
index 1463ac6a6..439cfd26b 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 205,
/**/
204,
/**/
diff --git a/src/xxd/xxd.c b/src/xxd/xxd.c
index 88c30234d..1dc0f383d 100644
--- a/src/xxd/xxd.c
+++ b/src/xxd/xxd.c
@@ -72,6 +72,7 @@
* 20.08.2025 remove external library call for autoconversion on z/OS (MVS)
* 24.08.2025 avoid NULL dereference with autoskip colorless
* 26.11.2025 update indent in exit_with_usage()
+ * 19.03.2026 Add -t option to end output with terminating null
*
* (c) 1990-1998 by Juergen Weigert (
jnwe...@gmail.com)
*
@@ -152,7 +153,7 @@ extern void perror __P((char *));
# endif
#endif
-char version[] = "xxd 2025-11-26 by Juergen Weigert et al.";
+char version[] = "xxd 2026-03-19 by Juergen Weigert et al.";
#ifdef WIN32
char osver[] = " (Win32)";
#else
@@ -285,6 +286,7 @@ exit_with_usage(void)
" -g bytes number of octets per group in normal output. Default 2 (-e: 4).
"
" -h print this summary.
"
" -i output in C include file style.
"
+ " -t append terminating zero to C include output (-i).
"
" -l len stop after <len> octets.
"
" -n name set the variable name used in C include output (-i).
"
" -o off add <off> to the displayed file position.
"
@@ -735,6 +737,7 @@ main(int argc, char *argv[])
int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
int capitalize = 0, decimal_offset = 0;
int ebcdic = 0;
+ int termination = 0;
int octspergrp = -1; /* number of octets grouped in output */
int grplen; /* total chars per octet group excluding colors */
long length = -1, n = 0, seekoff = 0;
@@ -784,6 +787,7 @@ main(int argc, char *argv[])
else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
else if (!STRNCMP(pp, "-r", 2)) revert++;
else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
+ else if (!STRNCMP(pp, "-t", 2)) termination++;
else if (!STRNCMP(pp, "-v", 2))
{
fprintf(stderr, "%s%s
", version, osver);
@@ -1069,8 +1073,13 @@ main(int argc, char *argv[])
}
p = 0;
- while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
+ while ((length < 0 || p < length) && (((c = getc_or_die(fp)) != EOF) || termination))
{
+ if (c == EOF)
+ {
+ c = 0;
+ termination = -1;
+ }
if (hextype & HEX_BITS)
{
if (p == 0)
@@ -1091,6 +1100,11 @@ main(int argc, char *argv[])
(p % cols) ? ", " : (!p ? " " : ",
"), c));
p++;
}
+ if (termination == -1)
+ {
+ --p;
+ break ;
+ }
}
if (p)