blob: 63f516c12b7eeff3e6f488432acd2cb5f3425cdb [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
Bram Moolenaar4b96df52020-01-26 22:00:26 +010038 * 18.07.96 gcc -Wall @ SunOS4 is now silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +000039 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaard8c56a02019-01-30 23:02:25 +010055 * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
Bram Moolenaar363d6142020-05-30 20:50:25 +020056 * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen
Erik Auerswaldc0a1d372022-01-14 11:58:48 +000057 * 14.01.2022 Disable extra newlines with -c0 -p by Erik Auerswald.
David Gow83e11802022-06-29 20:24:49 +010058 * 20.06.2022 Permit setting the variable names used by -i by David Gow
Christian Brabandt0ffa97e2023-08-31 21:03:02 +020059 * 31.08.2023 -R never/auto/always prints colored output
tristhaus85f45212023-10-06 19:51:13 +020060 * 06.10.2023 enable -r -b to reverse bit dumps
Igor Todorovski48a75f32024-01-09 21:05:48 +000061 * 12.01.2024 disable auto-conversion for z/OS (MVS)
Kuratius7062be12024-01-17 18:37:32 +010062 * 17.01.2024 use size_t instead of usigned int for code-generation (-i), #13876
Christian Brabandtfa8c9712024-01-25 20:50:49 +010063 * 25.01.2024 revert the previous patch (size_t instead of unsigned int)
Goffredo Baroncelli00221482024-02-10 13:31:06 +010064 * 10.02.2024 fix buffer-overflow when writing color output to buffer, #14003
Lennard Hofmann67797192024-05-10 14:17:26 +020065 * 10.05.2024 fix another buffer-overflow when writing colored output to buffer, #14738
Andre Chang15022722024-09-15 20:03:05 +020066 * 10.09.2024 Support -b and -i together, #15661
Bram Moolenaar071d4272004-06-13 20:20:40 +000067 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020068 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000069 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020070 * I hereby grant permission to distribute and use xxd
71 * under X11-MIT or GPL-2.0 (at the user's choice).
72 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020073 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000074 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000075
76/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
77#if _MSC_VER >= 1400
78# define _CRT_SECURE_NO_DEPRECATE
79# define _CRT_NONSTDC_NO_DEPRECATE
80#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010081#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000082# define CYGWIN
83#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000084
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000085#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
86# define _XOPEN_SOURCE 700 /* for fdopen() */
87#endif
88
Bram Moolenaar071d4272004-06-13 20:20:40 +000089#include <stdio.h>
90#ifdef VAXC
91# include <file.h>
92#else
93# include <fcntl.h>
94#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020095#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000096# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +020097#endif
98#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +020099# include <windows.h>
100#endif
101#ifdef UNIX
102# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000103#endif
104#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100105#include <string.h>
106#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100107#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000108#if __MWERKS__ && !defined(BEBOX)
109# include <unix.h> /* for fdopen() on MAC */
110#endif
111
Bram Moolenaar071d4272004-06-13 20:20:40 +0000112
113/* This corrects the problem of missing prototypes for certain functions
114 * in some GNU installations (e.g. SunOS 4.1.x).
115 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
116 */
117#if defined(__GNUC__) && defined(__STDC__)
118# ifndef __USE_FIXED_PROTOTYPES__
119# define __USE_FIXED_PROTOTYPES__
120# endif
121#endif
122
123#ifndef __USE_FIXED_PROTOTYPES__
124/*
125 * This is historic and works only if the compiler really has no prototypes:
126 *
127 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
128 * FILE is defined on OS 4.x, not on 5.x (Solaris).
129 * if __SVR4 is defined (some Solaris versions), don't include this.
130 */
131#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
132# define __P(a) a
133/* excerpt from my sun_stdlib.h */
134extern int fprintf __P((FILE *, char *, ...));
135extern int fputs __P((char *, FILE *));
136extern int _flsbuf __P((unsigned char, FILE *));
137extern int _filbuf __P((FILE *));
138extern int fflush __P((FILE *));
139extern int fclose __P((FILE *));
140extern int fseek __P((FILE *, long, int));
141extern int rewind __P((FILE *));
142
143extern void perror __P((char *));
144# endif
145#endif
146
Andre Chang15022722024-09-15 20:03:05 +0200147char version[] = "xxd 2024-09-15 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148#ifdef WIN32
149char osver[] = " (Win32)";
150#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152#endif
153
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200154#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155# define BIN_READ(yes) ((yes) ? "rb" : "rt")
156# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
157# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
158# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000159# define PATH_SEP '\\'
160#elif defined(CYGWIN)
161# define BIN_READ(yes) ((yes) ? "rb" : "rt")
162# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
163# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
164# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
165# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000166#else
167# ifdef VMS
168# define BIN_READ(dummy) "r"
169# define BIN_WRITE(dummy) "w"
170# define BIN_CREAT(dummy) O_CREAT
171# define BIN_ASSIGN(fp, dummy) fp
172# define PATH_SEP ']'
173# define FILE_SEP '.'
174# else
175# define BIN_READ(dummy) "r"
176# define BIN_WRITE(dummy) "w"
177# define BIN_CREAT(dummy) O_CREAT
178# define BIN_ASSIGN(fp, dummy) fp
179# define PATH_SEP '/'
180# endif
181#endif
182
183/* open has only to arguments on the Mac */
184#if __MWERKS__
185# define OPEN(name, mode, umask) open(name, mode)
186#else
187# define OPEN(name, mode, umask) open(name, mode, umask)
188#endif
189
190#ifdef AMIGA
191# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
192#else
193# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
194#endif
195
196#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200197# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000198# define __P(a) a
199# else
200# define __P(a) ()
201# endif
202#endif
203
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
205#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100206
207/*
208 * LLEN is the maximum length of a line; other than the visible characters
209 * we need to consider also the escape color sequence prologue/epilogue ,
Lennard Hofmann67797192024-05-10 14:17:26 +0200210 * (11 bytes for each character).
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100211 */
Lennard Hofmann67797192024-05-10 14:17:26 +0200212#define LLEN \
213 (39 /* addr: ⌈log10(ULONG_MAX)⌉ if "-d" flag given. We assume ULONG_MAX = 2**128 */ \
214 + 2 /* ": " */ \
215 + 13 * COLS /* hex dump with colors */ \
216 + (COLS - 1) /* whitespace between groups if "-g1" option given and "-c" maxed out */ \
217 + 2 /* whitespace */ \
218 + 12 * COLS /* ASCII dump with colors */ \
219 + 2) /* "\n\0" */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220
221char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
222
223/* the different hextypes known by this program: */
Andre Chang15022722024-09-15 20:03:05 +0200224#define HEX_NORMAL 0x00 /* no flags set */
225#define HEX_POSTSCRIPT 0x01
226#define HEX_CINCLUDE 0x02
227#define HEX_BITS 0x04 /* not hex a dump, but bits: 01111001 */
228#define HEX_LITTLEENDIAN 0x08
Bram Moolenaar071d4272004-06-13 20:20:40 +0000229
Keith Thompson184f71c2024-01-04 21:19:04 +0100230#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200231
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200232#define COLOR_PROLOGUE \
233l[c++] = '\033'; \
234l[c++] = '['; \
235l[c++] = '1'; \
236l[c++] = ';'; \
237l[c++] = '3';
238
239#define COLOR_EPILOGUE \
240l[c++] = '\033'; \
241l[c++] = '['; \
242l[c++] = '0'; \
243l[c++] = 'm';
244#define COLOR_RED '1'
245#define COLOR_GREEN '2'
246#define COLOR_YELLOW '3'
247#define COLOR_BLUE '4'
248#define COLOR_WHITE '7'
249
Bram Moolenaare0659a62011-04-01 19:14:40 +0200250static char *pname;
251
252 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100253exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000254{
255 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
256 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
257 fprintf(stderr, "Options:\n");
258 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Andre Chang15022722024-09-15 20:03:05 +0200259 fprintf(stderr, " -b binary digit dump (incompatible with -ps). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200260 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
262 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100263 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100264 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265 fprintf(stderr, " -h print this summary.\n");
266 fprintf(stderr, " -i output in C include file style.\n");
267 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100268 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100269 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
271 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
272 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200273 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
275#ifdef TRY_SEEK
276 "[+][-]", "(or +: rel.) ");
277#else
278 "", "");
279#endif
280 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200281 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000282 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
283 exit(1);
284}
285
Bram Moolenaare0659a62011-04-01 19:14:40 +0200286 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100287perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200288{
289 fprintf(stderr, "%s: ", pname);
290 perror(NULL);
291 exit(ret);
292}
293
DungSagaa2ffb432021-10-22 15:55:31 +0100294 static void
295error_exit(int ret, char *msg)
296{
297 fprintf(stderr, "%s: %s\n", pname, msg);
298 exit(ret);
299}
300
DungSagad1d8a592021-11-26 13:59:27 +0000301 static int
302getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000303{
DungSagad1d8a592021-11-26 13:59:27 +0000304 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000305 if (c == EOF && ferror(fpi))
306 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000307 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000308}
309
310 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000311putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000312{
313 if (putc(c, fpo) == EOF)
314 perror_exit(3);
315}
316
317 static void
318fputs_or_die(char *s, FILE *fpo)
319{
320 if (fputs(s, fpo) == EOF)
321 perror_exit(3);
322}
323
DungSaga7e5503c2021-12-01 11:24:52 +0000324/* Use a macro to allow for different arguments. */
325#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000326
327 static void
328fclose_or_die(FILE *fpi, FILE *fpo)
329{
330 if (fclose(fpo) != 0)
331 perror_exit(3);
332 if (fclose(fpi) != 0)
333 perror_exit(2);
334}
335
Bram Moolenaar071d4272004-06-13 20:20:40 +0000336/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000337 * If "c" is a hex digit, return the value.
338 * Otherwise return -1.
339 */
340 static int
341parse_hex_digit(int c)
342{
343 return (c >= '0' && c <= '9') ? c - '0'
344 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
345 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
346 : -1;
347}
348
349/*
tristhaus85f45212023-10-06 19:51:13 +0200350 * If "c" is a bin digit, return the value.
351 * Otherwise return -1.
352 */
353 static int
354parse_bin_digit(int c)
355{
356 return (c >= '0' && c <= '1') ? c - '0'
357 : -1;
358}
359
360/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000361 * Ignore text on "fpi" until end-of-line or end-of-file.
362 * Return the '\n' or EOF character.
363 * When an error is encountered exit with an error message.
364 */
365 static int
366skip_to_eol(FILE *fpi, int c)
367{
368 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000369 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000370 return c;
371}
372
373/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 * Max. cols binary characters are decoded from the input stream per line.
375 * Two adjacent garbage characters after evaluated data delimit valid data.
376 * Everything up to the next newline is discarded.
377 *
378 * The name is historic and came from 'undo type opt h'.
379 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200380 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100381huntype(
382 FILE *fpi,
383 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100384 int cols,
385 int hextype,
386 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200388 int c, ign_garb = 1, n1 = -1, n2 = 0, n3 = 0, p = cols, bt = 0, b = 0, bcnt = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 long have_off = 0, want_off = 0;
390
391 rewind(fpi);
392
393 while ((c = getc(fpi)) != EOF)
394 {
395 if (c == '\r') /* Doze style input file? */
396 continue;
397
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100398 /* Allow multiple spaces. This doesn't work when there is normal text
399 * after the hex codes in the last line that looks like hex, thus only
400 * use it for PostScript format. */
401 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000402 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000403
tristhaus85f45212023-10-06 19:51:13 +0200404 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
405 {
406 n3 = n2;
407 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408
tristhaus85f45212023-10-06 19:51:13 +0200409 n1 = parse_hex_digit(c);
410 if (n1 == -1 && ign_garb)
411 continue;
412 }
413 else /* HEX_BITS */
414 {
415 n1 = parse_hex_digit(c);
416 if (n1 == -1 && ign_garb)
417 continue;
418
419 bt = parse_bin_digit(c);
420 if (bt != -1)
421 {
422 b = ((b << 1) | bt);
423 ++bcnt;
424 }
425 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000426
427 ign_garb = 0;
428
tristhaus85f45212023-10-06 19:51:13 +0200429 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000430 {
tristhaus85f45212023-10-06 19:51:13 +0200431 if (hextype == HEX_NORMAL)
432 {
433 if (n1 < 0)
434 {
435 p = 0;
436 continue;
437 }
438 want_off = (want_off << 4) | n1;
439 }
440 else /* HEX_BITS */
441 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200442 if (n1 < 0)
443 {
444 p = 0;
tristhaus85f45212023-10-06 19:51:13 +0200445 bcnt = 0;
OldWorldOrdr1c140302023-10-25 20:57:30 +0200446 continue;
447 }
448 want_off = (want_off << 4) | n1;
tristhaus85f45212023-10-06 19:51:13 +0200449 }
450 continue;
451 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452
453 if (base_off + want_off != have_off)
454 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200455 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100456 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000458 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459 have_off = base_off + want_off;
460#endif
461 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000462 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000464 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465 }
466
tristhaus85f45212023-10-06 19:51:13 +0200467 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
468 {
469 if (n2 >= 0 && n1 >= 0)
470 {
471 putc_or_die((n2 << 4) | n1, fpo);
472 have_off++;
473 want_off++;
474 n1 = -1;
475 if (!hextype && (++p >= cols))
476 /* skip the rest of the line as garbage */
477 c = skip_to_eol(fpi, c);
478 }
479 else if (n1 < 0 && n2 < 0 && n3 < 0)
480 /* already stumbled into garbage, skip line, wait and see */
481 c = skip_to_eol(fpi, c);
482 }
483 else /* HEX_BITS */
484 {
485 if (bcnt == 8)
486 {
487 putc_or_die(b, fpo);
488 have_off++;
489 want_off++;
490 b = 0;
491 bcnt = 0;
492 if (++p >= cols)
493 /* skip the rest of the line as garbage */
494 c = skip_to_eol(fpi, c);
495 }
496 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000497
DungSaga47810462021-10-22 12:55:42 +0100498 if (c == '\n')
499 {
tristhaus85f45212023-10-06 19:51:13 +0200500 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100501 want_off = 0;
502 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000503 ign_garb = 1;
504 }
505 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200506 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100507 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000509 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000511 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512 return 0;
513}
514
515/*
516 * Print line l. If nz is false, xxdline regards the line a line of
517 * zeroes. If there are three or more consecutive lines of zeroes,
518 * they are replaced by a single '*' character.
519 *
520 * If the output ends with more than two lines of zeroes, you
521 * should call xxdline again with l being the last line and nz
522 * negative. This ensures that the last line is shown even when
523 * it is all zeroes.
524 *
525 * If nz is always positive, lines are never suppressed.
526 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200527 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100528xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529{
530 static char z[LLEN+1];
531 static int zero_seen = 0;
532
533 if (!nz && zero_seen == 1)
534 strcpy(z, l);
535
536 if (nz || !zero_seen++)
537 {
538 if (nz)
539 {
540 if (nz < 0)
541 zero_seen--;
542 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000543 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000545 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 }
547 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000548 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 if (nz)
550 zero_seen = 0;
551 }
552}
553
554/* This is an EBCDIC to ASCII conversion table */
555/* from a proposed BTL standard April 16, 1979 */
556static unsigned char etoa64[] =
557{
558 0040,0240,0241,0242,0243,0244,0245,0246,
559 0247,0250,0325,0056,0074,0050,0053,0174,
560 0046,0251,0252,0253,0254,0255,0256,0257,
561 0260,0261,0041,0044,0052,0051,0073,0176,
562 0055,0057,0262,0263,0264,0265,0266,0267,
563 0270,0271,0313,0054,0045,0137,0076,0077,
564 0272,0273,0274,0275,0276,0277,0300,0301,
565 0302,0140,0072,0043,0100,0047,0075,0042,
566 0303,0141,0142,0143,0144,0145,0146,0147,
567 0150,0151,0304,0305,0306,0307,0310,0311,
568 0312,0152,0153,0154,0155,0156,0157,0160,
569 0161,0162,0136,0314,0315,0316,0317,0320,
570 0321,0345,0163,0164,0165,0166,0167,0170,
571 0171,0172,0322,0323,0324,0133,0326,0327,
572 0330,0331,0332,0333,0334,0335,0336,0337,
573 0340,0341,0342,0343,0344,0135,0346,0347,
574 0173,0101,0102,0103,0104,0105,0106,0107,
575 0110,0111,0350,0351,0352,0353,0354,0355,
576 0175,0112,0113,0114,0115,0116,0117,0120,
577 0121,0122,0356,0357,0360,0361,0362,0363,
578 0134,0237,0123,0124,0125,0126,0127,0130,
579 0131,0132,0364,0365,0366,0367,0370,0371,
580 0060,0061,0062,0063,0064,0065,0066,0067,
581 0070,0071,0372,0373,0374,0375,0376,0377
582};
583
K.Takataf6fc2552023-09-01 18:41:04 +0200584 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200585begin_coloring_char (char *l, int *c, int e, int ebcdic)
586{
587 if (ebcdic)
588 {
589 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
590 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
591 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
592 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
593 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
594 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
595 (e == 173) || (e == 224) )
596 l[(*c)++] = COLOR_GREEN;
597
598 else if (e == 37 || e == 13 || e == 5)
599 l[(*c)++] = COLOR_YELLOW;
600 else if (e == 0)
601 l[(*c)++] = COLOR_WHITE;
602 else if (e == 255)
603 l[(*c)++] = COLOR_BLUE;
604 else
605 l[(*c)++] = COLOR_RED;
606 }
607 else /* ASCII */
608 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000609 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200610 if (e >= 64)
611 l[(*c)++] = COLOR_GREEN;
612 #else
613 if (e > 31 && e < 127)
614 l[(*c)++] = COLOR_GREEN;
615 #endif
616
617 else if (e == 9 || e == 10 || e == 13)
618 l[(*c)++] = COLOR_YELLOW;
619 else if (e == 0)
620 l[(*c)++] = COLOR_WHITE;
621 else if (e == 255)
622 l[(*c)++] = COLOR_BLUE;
623 else
624 l[(*c)++] = COLOR_RED;
625 }
626 l[(*c)++] = 'm';
627}
628
K.Takataf6fc2552023-09-01 18:41:04 +0200629 static int
630enable_color(void)
631{
632#ifdef WIN32
633 DWORD mode;
634 HANDLE out;
635
636 if (!isatty(1))
637 return 0;
638
639 out = GetStdHandle(STD_OUTPUT_HANDLE);
640 GetConsoleMode(out, &mode);
641 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
642 return (int)SetConsoleMode(out, mode);
643#elif defined(UNIX)
644 return isatty(STDOUT_FILENO);
645#else
646 return 0;
647#endif
648}
649
Bram Moolenaare0659a62011-04-01 19:14:40 +0200650 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100651main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652{
653 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200654 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000655 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200656 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000657 int ebcdic = 0;
658 int octspergrp = -1; /* number of octets grouped in output */
659 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100660 long length = -1, n = 0, seekoff = 0;
661 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200662 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200663 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100664 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100665 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200666 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200667 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200668
K.Takataf6fc2552023-09-01 18:41:04 +0200669 no_color = getenv("NO_COLOR");
670 if (no_color == NULL || no_color[0] == '\0')
671 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000672
673#ifdef AMIGA
674 /* This program doesn't work when started from the Workbench */
675 if (argc == 0)
676 exit(1);
677#endif
678
679 pname = argv[0];
680 for (pp = pname; *pp; )
681 if (*pp++ == PATH_SEP)
682 pname = pp;
683#ifdef FILE_SEP
684 for (pp = pname; *pp; pp++)
685 if (*pp == FILE_SEP)
686 {
687 *pp = '\0';
688 break;
689 }
690#endif
691
692 while (argc >= 2)
693 {
694 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
695 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
Andre Chang15022722024-09-15 20:03:05 +0200696 else if (!STRNCMP(pp, "-b", 2)) hextype |= HEX_BITS;
697 else if (!STRNCMP(pp, "-e", 2)) hextype |= HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000698 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
Andre Chang15022722024-09-15 20:03:05 +0200699 else if (!STRNCMP(pp, "-p", 2)) hextype |= HEX_POSTSCRIPT;
700 else if (!STRNCMP(pp, "-i", 2)) hextype |= HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200701 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200702 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000703 else if (!STRNCMP(pp, "-r", 2)) revert++;
704 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
705 else if (!STRNCMP(pp, "-v", 2))
706 {
707 fprintf(stderr, "%s%s\n", version, osver);
708 exit(0);
709 }
710 else if (!STRNCMP(pp, "-c", 2))
711 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100712 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200713 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100714 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000715 {
716 colsgiven = 1;
717 cols = (int)strtol(pp + 2, NULL, 0);
718 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 else
720 {
721 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200722 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000723 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 cols = (int)strtol(argv[2], NULL, 0);
725 argv++;
726 argc--;
727 }
728 }
729 else if (!STRNCMP(pp, "-g", 2))
730 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100731 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732 octspergrp = (int)strtol(pp + 2, NULL, 0);
733 else
734 {
735 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200736 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 octspergrp = (int)strtol(argv[2], NULL, 0);
738 argv++;
739 argc--;
740 }
741 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100742 else if (!STRNCMP(pp, "-o", 2))
743 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100744 int reloffset = 0;
745 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100746 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100747 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100748 else
749 {
750 if (!argv[2])
751 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100752
753 if (argv[2][0] == '+')
754 reloffset++;
755 if (argv[2][reloffset] == '-')
756 negoffset++;
757
758 if (negoffset)
759 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
760 else
761 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
762
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100763 argv++;
764 argc--;
765 }
766 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 else if (!STRNCMP(pp, "-s", 2))
768 {
769 relseek = 0;
770 negseek = 0;
771 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
772 {
773#ifdef TRY_SEEK
774 if (pp[2] == '+')
775 relseek++;
776 if (pp[2+relseek] == '-')
777 negseek++;
778#endif
779 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
780 }
781 else
782 {
783 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200784 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785#ifdef TRY_SEEK
786 if (argv[2][0] == '+')
787 relseek++;
788 if (argv[2][relseek] == '-')
789 negseek++;
790#endif
791 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
792 argv++;
793 argc--;
794 }
795 }
796 else if (!STRNCMP(pp, "-l", 2))
797 {
798 if (pp[2] && STRNCMP("en", pp + 2, 2))
799 length = strtol(pp + 2, (char **)NULL, 0);
800 else
801 {
802 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200803 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 length = strtol(argv[2], (char **)NULL, 0);
805 argv++;
806 argc--;
807 }
808 }
David Gow83e11802022-06-29 20:24:49 +0100809 else if (!STRNCMP(pp, "-n", 2))
810 {
811 if (pp[2] && STRNCMP("ame", pp + 2, 3))
812 varname = pp + 2;
813 else
814 {
815 if (!argv[2])
816 exit_with_usage();
817 varname = argv[2];
818 argv++;
819 argc--;
820 }
821 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200822 else if (!STRNCMP(pp, "-R", 2))
823 {
K.Takataf6fc2552023-09-01 18:41:04 +0200824 char *pw = pp + 2;
825 if (!pw[0])
826 {
827 pw = argv[2];
828 argv++;
829 argc--;
830 }
831 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200832 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200833 if (!STRNCMP(pw, "always", 6))
834 {
835 (void)enable_color();
836 color = 1;
837 }
838 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200839 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200840 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200841 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200842 else
843 exit_with_usage();
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200844 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845 else if (!strcmp(pp, "--")) /* end of options */
846 {
847 argv++;
848 argc--;
849 break;
850 }
851 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200852 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 else
854 break; /* not an option */
855
856 argv++; /* advance to next argument */
857 argc--;
858 }
859
Andre Chang15022722024-09-15 20:03:05 +0200860 if (hextype != (HEX_CINCLUDE | HEX_BITS))
861 {
862 /* Allow at most one bit to be set in hextype */
863 if (hextype & (hextype - 1))
864 error_exit(1, "only one of -b, -e, -u, -p, -i can be used");
865 }
866
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000867 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 switch (hextype)
869 {
870 case HEX_POSTSCRIPT: cols = 30; break;
871 case HEX_CINCLUDE: cols = 12; break;
Andre Chang15022722024-09-15 20:03:05 +0200872 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 case HEX_BITS: cols = 6; break;
874 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100875 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 default: cols = 16; break;
877 }
878
879 if (octspergrp < 0)
880 switch (hextype)
881 {
Andre Chang15022722024-09-15 20:03:05 +0200882 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000883 case HEX_BITS: octspergrp = 1; break;
884 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100885 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000886 case HEX_POSTSCRIPT:
887 case HEX_CINCLUDE:
888 default: octspergrp = 0; break;
889 }
890
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000891 if ((hextype == HEX_POSTSCRIPT && cols < 0) ||
892 (hextype != HEX_POSTSCRIPT && cols < 1) ||
893 ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000894 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000895 {
896 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
897 exit(1);
898 }
899
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100900 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000901 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100902 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100903 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000904
905 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200906 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000907
908 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
909 BIN_ASSIGN(fp = stdin, !revert);
910 else
911 {
912 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
913 {
914 fprintf(stderr,"%s: ", pname);
915 perror(argv[1]);
916 return 2;
917 }
918 }
919
920 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
921 BIN_ASSIGN(fpo = stdout, revert);
922 else
923 {
924 int fd;
925 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
926
927 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
928 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
929 {
930 fprintf(stderr, "%s: ", pname);
931 perror(argv[2]);
932 return 3;
933 }
934 rewind(fpo);
935 }
Igor Todorovski48a75f32024-01-09 21:05:48 +0000936#ifdef __MVS__
937 // Disable auto-conversion on input file descriptors
938 __disableautocvt(fileno(fp));
939#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000940
941 if (revert)
tristhaus85f45212023-10-06 19:51:13 +0200942 switch (hextype)
943 {
944 case HEX_NORMAL:
945 case HEX_POSTSCRIPT:
946 case HEX_BITS:
947 return huntype(fp, fpo, cols, hextype,
948 negseek ? -seekoff : seekoff);
949 break;
950 default:
951 error_exit(-1, "Sorry, cannot revert this type of hexdump");
952 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000953
954 if (seekoff || negseek || !relseek)
955 {
956#ifdef TRY_SEEK
957 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000958 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000959 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000960 e = fseek(fp, negseek ? -seekoff : seekoff,
961 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000962 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000963 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 if (e >= 0)
965 seekoff = ftell(fp);
966 else
967#endif
968 {
969 long s = seekoff;
970
971 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000972 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200973 {
DungSaga7e5503c2021-12-01 11:24:52 +0000974 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200975 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000976 }
977 }
978
Andre Chang15022722024-09-15 20:03:05 +0200979 if (hextype & HEX_CINCLUDE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000980 {
David Gow83e11802022-06-29 20:24:49 +0100981 /* A user-set variable name overrides fp == stdin */
982 if (varname == NULL && fp != stdin)
983 varname = argv[1];
984
985 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000986 {
Keith Thompson184f71c2024-01-04 21:19:04 +0100987 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100988 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100989 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000990 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000991 }
992
993 p = 0;
DungSagad1d8a592021-11-26 13:59:27 +0000994 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Andre Chang15022722024-09-15 20:03:05 +0200995 {
996 if (hextype & HEX_BITS)
997 {
998 if (p == 0)
999 fputs_or_die(" ", fpo);
1000 else if (p % cols == 0)
1001 fputs_or_die(",\n ", fpo);
1002 else
1003 fputs_or_die(", ", fpo);
1004
1005 FPRINTF_OR_DIE((fpo, "0b"));
1006 for (int j = 7; j >= 0; j--)
1007 putc_or_die((c & (1 << j)) ? '1' : '0', fpo);
1008 p++;
1009 }
1010 else
1011 {
1012 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
DungSaga7e5503c2021-12-01 11:24:52 +00001013 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Andre Chang15022722024-09-15 20:03:05 +02001014 p++;
1015 }
1016 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001017
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001018 if (p)
1019 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020
David Gow83e11802022-06-29 20:24:49 +01001021 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022 {
DungSagad1d8a592021-11-26 13:59:27 +00001023 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +01001024 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +01001025 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +01001026 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001027 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 }
1029
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001030 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001031 return 0;
1032 }
1033
1034 if (hextype == HEX_POSTSCRIPT)
1035 {
1036 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +00001037 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001038 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001039 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1040 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001041 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001042 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001044 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 p = cols;
1046 }
1047 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001048 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001049 putc_or_die('\n', fpo);
1050 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 return 0;
1052 }
1053
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001054 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001056 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001057 {
1058 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1059 if (color)
1060 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
1061 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 else /* hextype == HEX_BITS */
1063 grplen = 8 * octspergrp + 1;
1064
DungSagad1d8a592021-11-26 13:59:27 +00001065 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001066 {
1067 if (p == 0)
1068 {
DungSaga581f41a2021-11-22 11:57:31 +00001069 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001070 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001071 for (c = addrlen; c < LLEN; l[c++] = ' ')
1072 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001073 }
DungSaga48608b42021-11-24 11:18:07 +00001074 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1075 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001076 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001077 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001078 if (color)
1079 {
1080 COLOR_PROLOGUE
1081 begin_coloring_char(l,&c,e,ebcdic);
1082 l[c++] = hexx[(e >> 4) & 0xf];
1083 l[c++] = hexx[e & 0xf];
1084 COLOR_EPILOGUE
1085 }
1086 else /*No colors*/
1087 {
1088 l[c] = hexx[(e >> 4) & 0xf];
1089 l[++c] = hexx[e & 0xf];
1090 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001091 }
1092 else /* hextype == HEX_BITS */
1093 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001094 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001095 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001097 if (e)
1098 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001099 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001100 if (hextype == HEX_LITTLEENDIAN)
1101 /* last group will be fully used, round up */
1102 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1103 else
1104 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001105
1106 if (color)
1107 {
1108 if (hextype == HEX_BITS)
1109 c += addrlen + 3 + p*12;
1110 else
1111 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
1112
1113 if (hextype == HEX_LITTLEENDIAN)
1114 c += 1;
1115
1116 COLOR_PROLOGUE
1117 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001118#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001119 if (e >= 64)
1120 l[c++] = e;
1121 else
1122 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001123#else
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001124 if (ebcdic)
1125 e = (e < 64) ? '.' : etoa64[e-64];
1126 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001127#endif
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001128 COLOR_EPILOGUE
1129 n++;
1130 if (++p == cols)
1131 {
1132 l[c++] = '\n';
1133 l[c++] = '\0';
1134 xxdline(fpo, l, autoskip ? nonzero : 1);
1135 nonzero = 0;
1136 p = 0;
1137 }
1138 }
1139 else /*no colors*/
1140 {
1141 if (ebcdic)
1142 e = (e < 64) ? '.' : etoa64[e-64];
1143
1144 c += addrlen + 3 + p;
1145 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001146#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001147 (e >= 64)
1148#else
1149 (e > 31 && e < 127)
1150#endif
1151 ? e : '.';
1152 n++;
1153 if (++p == cols)
1154 {
1155 l[c++] = '\n';
1156 l[c] = '\0';
1157 xxdline(fpo, l, autoskip ? nonzero : 1);
1158 nonzero = 0;
1159 p = 0;
1160 }
1161 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001162 }
1163 if (p)
1164 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001165 l[c++] = '\n';
1166 l[c] = '\0';
1167 if (color)
1168 {
1169 c++;
1170
1171 x = p;
1172 if (hextype == HEX_LITTLEENDIAN)
1173 {
1174 int fill = octspergrp - (p % octspergrp);
1175 if (fill == octspergrp) fill = 0;
1176
1177 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
1178
1179 for (i = 0; i < fill;i++)
1180 {
1181 COLOR_PROLOGUE
1182 l[c++] = COLOR_RED;
1183 l[c++] = 'm';
1184 l[c++] = ' '; /* empty space */
1185 COLOR_EPILOGUE
1186 x++;
1187 p++;
1188 }
1189 }
1190
1191 if (hextype != HEX_BITS)
1192 {
1193 c = addrlen + 1 + (grplen * x) / octspergrp;
1194 c += cols - p;
1195 c += (cols - p) / octspergrp;
1196
1197 for (i = cols - p; i > 0;i--)
1198 {
1199 COLOR_PROLOGUE
1200 l[c++] = COLOR_RED;
1201 l[c++] = 'm';
1202 l[c++] = ' '; /* empty space */
1203 COLOR_EPILOGUE
1204 }
1205 }
1206 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001207 xxdline(fpo, l, 1);
1208 }
1209 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001210 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001211
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001212 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001213 return 0;
1214}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001215
1216/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */