blob: 072ef630a205a9c8fc0c9e6b59966f07b6aa3536 [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
Aapo Rantalainenc73fc862024-10-19 15:54:57 +020067 * 19.10.2024 -e did add an extra space #15899
DungSaga4b9fa952024-11-11 22:19:50 +010068 * 11.11.2024 improve end-of-options argument parser #9285
sendittothenewts6e6aff02024-12-07 16:27:22 +010069 * 07.12.2024 fix overflow with xxd --autoskip and large sparse files #16175
Bram Moolenaar071d4272004-06-13 20:20:40 +000070 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020071 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000072 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020073 * I hereby grant permission to distribute and use xxd
74 * under X11-MIT or GPL-2.0 (at the user's choice).
75 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020076 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000077 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000078
79/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
80#if _MSC_VER >= 1400
81# define _CRT_SECURE_NO_DEPRECATE
82# define _CRT_NONSTDC_NO_DEPRECATE
83#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010084#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000085# define CYGWIN
86#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000087
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000088#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
89# define _XOPEN_SOURCE 700 /* for fdopen() */
90#endif
91
Bram Moolenaar071d4272004-06-13 20:20:40 +000092#include <stdio.h>
93#ifdef VAXC
94# include <file.h>
95#else
96# include <fcntl.h>
97#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020098#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000099# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +0200100#endif
101#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +0200102# include <windows.h>
103#endif
104#ifdef UNIX
105# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106#endif
107#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100108#include <string.h>
109#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100110#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111#if __MWERKS__ && !defined(BEBOX)
112# include <unix.h> /* for fdopen() on MAC */
113#endif
114
Bram Moolenaar071d4272004-06-13 20:20:40 +0000115
116/* This corrects the problem of missing prototypes for certain functions
117 * in some GNU installations (e.g. SunOS 4.1.x).
118 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
119 */
120#if defined(__GNUC__) && defined(__STDC__)
121# ifndef __USE_FIXED_PROTOTYPES__
122# define __USE_FIXED_PROTOTYPES__
123# endif
124#endif
125
126#ifndef __USE_FIXED_PROTOTYPES__
127/*
128 * This is historic and works only if the compiler really has no prototypes:
129 *
130 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
131 * FILE is defined on OS 4.x, not on 5.x (Solaris).
132 * if __SVR4 is defined (some Solaris versions), don't include this.
133 */
134#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
135# define __P(a) a
136/* excerpt from my sun_stdlib.h */
137extern int fprintf __P((FILE *, char *, ...));
138extern int fputs __P((char *, FILE *));
139extern int _flsbuf __P((unsigned char, FILE *));
140extern int _filbuf __P((FILE *));
141extern int fflush __P((FILE *));
142extern int fclose __P((FILE *));
143extern int fseek __P((FILE *, long, int));
144extern int rewind __P((FILE *));
145
146extern void perror __P((char *));
147# endif
148#endif
149
sendittothenewts6e6aff02024-12-07 16:27:22 +0100150char version[] = "xxd 2024-12-07 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151#ifdef WIN32
152char osver[] = " (Win32)";
153#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000155#endif
156
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200157#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158# define BIN_READ(yes) ((yes) ? "rb" : "rt")
159# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
160# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
161# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000162# define PATH_SEP '\\'
163#elif defined(CYGWIN)
164# define BIN_READ(yes) ((yes) ? "rb" : "rt")
165# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
166# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
167# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
168# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169#else
170# ifdef VMS
171# define BIN_READ(dummy) "r"
172# define BIN_WRITE(dummy) "w"
173# define BIN_CREAT(dummy) O_CREAT
174# define BIN_ASSIGN(fp, dummy) fp
175# define PATH_SEP ']'
176# define FILE_SEP '.'
177# else
178# define BIN_READ(dummy) "r"
179# define BIN_WRITE(dummy) "w"
180# define BIN_CREAT(dummy) O_CREAT
181# define BIN_ASSIGN(fp, dummy) fp
182# define PATH_SEP '/'
183# endif
184#endif
185
186/* open has only to arguments on the Mac */
187#if __MWERKS__
188# define OPEN(name, mode, umask) open(name, mode)
189#else
190# define OPEN(name, mode, umask) open(name, mode, umask)
191#endif
192
193#ifdef AMIGA
194# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
195#else
196# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
197#endif
198
199#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200200# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201# define __P(a) a
202# else
203# define __P(a) ()
204# endif
205#endif
206
Bram Moolenaar071d4272004-06-13 20:20:40 +0000207#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
208#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100209
210/*
211 * LLEN is the maximum length of a line; other than the visible characters
212 * we need to consider also the escape color sequence prologue/epilogue ,
Lennard Hofmann67797192024-05-10 14:17:26 +0200213 * (11 bytes for each character).
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100214 */
Lennard Hofmann67797192024-05-10 14:17:26 +0200215#define LLEN \
216 (39 /* addr: ⌈log10(ULONG_MAX)⌉ if "-d" flag given. We assume ULONG_MAX = 2**128 */ \
217 + 2 /* ": " */ \
218 + 13 * COLS /* hex dump with colors */ \
219 + (COLS - 1) /* whitespace between groups if "-g1" option given and "-c" maxed out */ \
220 + 2 /* whitespace */ \
221 + 12 * COLS /* ASCII dump with colors */ \
222 + 2) /* "\n\0" */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000223
224char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
225
226/* the different hextypes known by this program: */
Andre Chang15022722024-09-15 20:03:05 +0200227#define HEX_NORMAL 0x00 /* no flags set */
228#define HEX_POSTSCRIPT 0x01
229#define HEX_CINCLUDE 0x02
230#define HEX_BITS 0x04 /* not hex a dump, but bits: 01111001 */
231#define HEX_LITTLEENDIAN 0x08
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232
Keith Thompson184f71c2024-01-04 21:19:04 +0100233#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200234
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200235#define COLOR_PROLOGUE \
236l[c++] = '\033'; \
237l[c++] = '['; \
238l[c++] = '1'; \
239l[c++] = ';'; \
240l[c++] = '3';
241
242#define COLOR_EPILOGUE \
243l[c++] = '\033'; \
244l[c++] = '['; \
245l[c++] = '0'; \
246l[c++] = 'm';
247#define COLOR_RED '1'
248#define COLOR_GREEN '2'
249#define COLOR_YELLOW '3'
250#define COLOR_BLUE '4'
251#define COLOR_WHITE '7'
252
Bram Moolenaare0659a62011-04-01 19:14:40 +0200253static char *pname;
254
255 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100256exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257{
258 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
259 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
260 fprintf(stderr, "Options:\n");
261 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Andre Chang15022722024-09-15 20:03:05 +0200262 fprintf(stderr, " -b binary digit dump (incompatible with -ps). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200263 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
265 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100266 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100267 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268 fprintf(stderr, " -h print this summary.\n");
269 fprintf(stderr, " -i output in C include file style.\n");
270 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100271 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100272 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
274 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
275 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200276 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000277 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
278#ifdef TRY_SEEK
279 "[+][-]", "(or +: rel.) ");
280#else
281 "", "");
282#endif
283 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200284 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000285 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
286 exit(1);
287}
288
Bram Moolenaare0659a62011-04-01 19:14:40 +0200289 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100290perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200291{
292 fprintf(stderr, "%s: ", pname);
293 perror(NULL);
294 exit(ret);
295}
296
DungSagaa2ffb432021-10-22 15:55:31 +0100297 static void
298error_exit(int ret, char *msg)
299{
300 fprintf(stderr, "%s: %s\n", pname, msg);
301 exit(ret);
302}
303
DungSagad1d8a592021-11-26 13:59:27 +0000304 static int
305getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000306{
DungSagad1d8a592021-11-26 13:59:27 +0000307 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000308 if (c == EOF && ferror(fpi))
309 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000310 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000311}
312
313 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000314putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000315{
316 if (putc(c, fpo) == EOF)
317 perror_exit(3);
318}
319
320 static void
321fputs_or_die(char *s, FILE *fpo)
322{
323 if (fputs(s, fpo) == EOF)
324 perror_exit(3);
325}
326
DungSaga7e5503c2021-12-01 11:24:52 +0000327/* Use a macro to allow for different arguments. */
328#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000329
330 static void
331fclose_or_die(FILE *fpi, FILE *fpo)
332{
333 if (fclose(fpo) != 0)
334 perror_exit(3);
335 if (fclose(fpi) != 0)
336 perror_exit(2);
337}
338
Bram Moolenaar071d4272004-06-13 20:20:40 +0000339/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000340 * If "c" is a hex digit, return the value.
341 * Otherwise return -1.
342 */
343 static int
344parse_hex_digit(int c)
345{
346 return (c >= '0' && c <= '9') ? c - '0'
347 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
348 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
349 : -1;
350}
351
352/*
tristhaus85f45212023-10-06 19:51:13 +0200353 * If "c" is a bin digit, return the value.
354 * Otherwise return -1.
355 */
356 static int
357parse_bin_digit(int c)
358{
359 return (c >= '0' && c <= '1') ? c - '0'
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200360 : -1;
tristhaus85f45212023-10-06 19:51:13 +0200361}
362
363/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000364 * Ignore text on "fpi" until end-of-line or end-of-file.
365 * Return the '\n' or EOF character.
366 * When an error is encountered exit with an error message.
367 */
368 static int
369skip_to_eol(FILE *fpi, int c)
370{
371 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000372 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000373 return c;
374}
375
376/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 * Max. cols binary characters are decoded from the input stream per line.
378 * Two adjacent garbage characters after evaluated data delimit valid data.
379 * Everything up to the next newline is discarded.
380 *
381 * The name is historic and came from 'undo type opt h'.
382 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200383 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100384huntype(
385 FILE *fpi,
386 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100387 int cols,
388 int hextype,
389 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200391 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 +0000392 long have_off = 0, want_off = 0;
393
394 rewind(fpi);
395
396 while ((c = getc(fpi)) != EOF)
397 {
398 if (c == '\r') /* Doze style input file? */
399 continue;
400
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100401 /* Allow multiple spaces. This doesn't work when there is normal text
402 * after the hex codes in the last line that looks like hex, thus only
403 * use it for PostScript format. */
404 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000405 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000406
tristhaus85f45212023-10-06 19:51:13 +0200407 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200408 {
tristhaus85f45212023-10-06 19:51:13 +0200409 n3 = n2;
410 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411
tristhaus85f45212023-10-06 19:51:13 +0200412 n1 = parse_hex_digit(c);
413 if (n1 == -1 && ign_garb)
414 continue;
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200415 }
tristhaus85f45212023-10-06 19:51:13 +0200416 else /* HEX_BITS */
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200417 {
tristhaus85f45212023-10-06 19:51:13 +0200418 n1 = parse_hex_digit(c);
419 if (n1 == -1 && ign_garb)
420 continue;
421
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200422 bt = parse_bin_digit(c);
423 if (bt != -1)
424 {
425 b = ((b << 1) | bt);
426 ++bcnt;
427 }
428 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429
430 ign_garb = 0;
431
tristhaus85f45212023-10-06 19:51:13 +0200432 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000433 {
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200434 if (hextype == HEX_NORMAL)
435 {
tristhaus85f45212023-10-06 19:51:13 +0200436 if (n1 < 0)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200437 {
438 p = 0;
439 continue;
440 }
tristhaus85f45212023-10-06 19:51:13 +0200441 want_off = (want_off << 4) | n1;
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200442 }
443 else /* HEX_BITS */
444 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200445 if (n1 < 0)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200446 {
447 p = 0;
448 bcnt = 0;
449 continue;
450 }
OldWorldOrdr1c140302023-10-25 20:57:30 +0200451 want_off = (want_off << 4) | n1;
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200452 }
453 continue;
454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455
456 if (base_off + want_off != have_off)
457 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200458 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100459 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000461 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 have_off = base_off + want_off;
463#endif
464 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000465 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000467 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468 }
469
tristhaus85f45212023-10-06 19:51:13 +0200470 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200471 {
472 if (n2 >= 0 && n1 >= 0)
473 {
474 putc_or_die((n2 << 4) | n1, fpo);
475 have_off++;
476 want_off++;
477 n1 = -1;
478 if (!hextype && (++p >= cols))
479 /* skip the rest of the line as garbage */
480 c = skip_to_eol(fpi, c);
481 }
482 else if (n1 < 0 && n2 < 0 && n3 < 0)
483 /* already stumbled into garbage, skip line, wait and see */
484 c = skip_to_eol(fpi, c);
485 }
tristhaus85f45212023-10-06 19:51:13 +0200486 else /* HEX_BITS */
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200487 {
488 if (bcnt == 8)
489 {
490 putc_or_die(b, fpo);
491 have_off++;
492 want_off++;
493 b = 0;
494 bcnt = 0;
495 if (++p >= cols)
496 /* skip the rest of the line as garbage */
497 c = skip_to_eol(fpi, c);
498 }
499 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000500
DungSaga47810462021-10-22 12:55:42 +0100501 if (c == '\n')
502 {
tristhaus85f45212023-10-06 19:51:13 +0200503 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100504 want_off = 0;
505 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 ign_garb = 1;
507 }
508 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200509 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100510 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000512 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000514 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515 return 0;
516}
517
518/*
sendittothenewts6e6aff02024-12-07 16:27:22 +0100519 * Print line l. If nz is false, xxdline regards the line as a line of
Bram Moolenaar071d4272004-06-13 20:20:40 +0000520 * zeroes. If there are three or more consecutive lines of zeroes,
521 * they are replaced by a single '*' character.
522 *
523 * If the output ends with more than two lines of zeroes, you
524 * should call xxdline again with l being the last line and nz
525 * negative. This ensures that the last line is shown even when
526 * it is all zeroes.
527 *
528 * If nz is always positive, lines are never suppressed.
529 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200530 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100531xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532{
533 static char z[LLEN+1];
sendittothenewts6e6aff02024-12-07 16:27:22 +0100534 static signed char zero_seen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535
536 if (!nz && zero_seen == 1)
537 strcpy(z, l);
538
539 if (nz || !zero_seen++)
540 {
541 if (nz)
542 {
543 if (nz < 0)
544 zero_seen--;
545 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000546 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000548 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000549 }
550 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000551 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000552 if (nz)
553 zero_seen = 0;
554 }
sendittothenewts6e6aff02024-12-07 16:27:22 +0100555
556 /* If zero_seen > 3, then its exact value doesn't matter, so long as it
557 * remains >3 and incrementing it will not cause overflow. */
558 if (zero_seen >= 0x7F)
559 zero_seen = 4;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560}
561
562/* This is an EBCDIC to ASCII conversion table */
563/* from a proposed BTL standard April 16, 1979 */
564static unsigned char etoa64[] =
565{
566 0040,0240,0241,0242,0243,0244,0245,0246,
567 0247,0250,0325,0056,0074,0050,0053,0174,
568 0046,0251,0252,0253,0254,0255,0256,0257,
569 0260,0261,0041,0044,0052,0051,0073,0176,
570 0055,0057,0262,0263,0264,0265,0266,0267,
571 0270,0271,0313,0054,0045,0137,0076,0077,
572 0272,0273,0274,0275,0276,0277,0300,0301,
573 0302,0140,0072,0043,0100,0047,0075,0042,
574 0303,0141,0142,0143,0144,0145,0146,0147,
575 0150,0151,0304,0305,0306,0307,0310,0311,
576 0312,0152,0153,0154,0155,0156,0157,0160,
577 0161,0162,0136,0314,0315,0316,0317,0320,
578 0321,0345,0163,0164,0165,0166,0167,0170,
579 0171,0172,0322,0323,0324,0133,0326,0327,
580 0330,0331,0332,0333,0334,0335,0336,0337,
581 0340,0341,0342,0343,0344,0135,0346,0347,
582 0173,0101,0102,0103,0104,0105,0106,0107,
583 0110,0111,0350,0351,0352,0353,0354,0355,
584 0175,0112,0113,0114,0115,0116,0117,0120,
585 0121,0122,0356,0357,0360,0361,0362,0363,
586 0134,0237,0123,0124,0125,0126,0127,0130,
587 0131,0132,0364,0365,0366,0367,0370,0371,
588 0060,0061,0062,0063,0064,0065,0066,0067,
589 0070,0071,0372,0373,0374,0375,0376,0377
590};
591
K.Takataf6fc2552023-09-01 18:41:04 +0200592 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200593begin_coloring_char (char *l, int *c, int e, int ebcdic)
594{
595 if (ebcdic)
596 {
597 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200598 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
599 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
600 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
601 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
602 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
603 (e == 173) || (e == 224) )
604 l[(*c)++] = COLOR_GREEN;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200605
606 else if (e == 37 || e == 13 || e == 5)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200607 l[(*c)++] = COLOR_YELLOW;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200608 else if (e == 0)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200609 l[(*c)++] = COLOR_WHITE;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200610 else if (e == 255)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200611 l[(*c)++] = COLOR_BLUE;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200612 else
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200613 l[(*c)++] = COLOR_RED;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200614 }
615 else /* ASCII */
616 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000617 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200618 if (e >= 64)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200619 l[(*c)++] = COLOR_GREEN;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200620 #else
621 if (e > 31 && e < 127)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200622 l[(*c)++] = COLOR_GREEN;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200623 #endif
624
625 else if (e == 9 || e == 10 || e == 13)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200626 l[(*c)++] = COLOR_YELLOW;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200627 else if (e == 0)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200628 l[(*c)++] = COLOR_WHITE;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200629 else if (e == 255)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200630 l[(*c)++] = COLOR_BLUE;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200631 else
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200632 l[(*c)++] = COLOR_RED;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200633 }
634 l[(*c)++] = 'm';
635}
636
K.Takataf6fc2552023-09-01 18:41:04 +0200637 static int
638enable_color(void)
639{
640#ifdef WIN32
641 DWORD mode;
642 HANDLE out;
643
644 if (!isatty(1))
645 return 0;
646
647 out = GetStdHandle(STD_OUTPUT_HANDLE);
648 GetConsoleMode(out, &mode);
649 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
650 return (int)SetConsoleMode(out, mode);
651#elif defined(UNIX)
652 return isatty(STDOUT_FILENO);
653#else
654 return 0;
655#endif
656}
657
Bram Moolenaare0659a62011-04-01 19:14:40 +0200658 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100659main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660{
661 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200662 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000663 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200664 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000665 int ebcdic = 0;
666 int octspergrp = -1; /* number of octets grouped in output */
667 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100668 long length = -1, n = 0, seekoff = 0;
669 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200670 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200671 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100672 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100673 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200674 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200675 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200676
K.Takataf6fc2552023-09-01 18:41:04 +0200677 no_color = getenv("NO_COLOR");
678 if (no_color == NULL || no_color[0] == '\0')
679 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680
681#ifdef AMIGA
682 /* This program doesn't work when started from the Workbench */
683 if (argc == 0)
684 exit(1);
685#endif
686
687 pname = argv[0];
688 for (pp = pname; *pp; )
689 if (*pp++ == PATH_SEP)
690 pname = pp;
691#ifdef FILE_SEP
692 for (pp = pname; *pp; pp++)
693 if (*pp == FILE_SEP)
694 {
695 *pp = '\0';
696 break;
697 }
698#endif
699
700 while (argc >= 2)
701 {
702 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
703 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
Andre Chang15022722024-09-15 20:03:05 +0200704 else if (!STRNCMP(pp, "-b", 2)) hextype |= HEX_BITS;
705 else if (!STRNCMP(pp, "-e", 2)) hextype |= HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000706 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
Andre Chang15022722024-09-15 20:03:05 +0200707 else if (!STRNCMP(pp, "-p", 2)) hextype |= HEX_POSTSCRIPT;
708 else if (!STRNCMP(pp, "-i", 2)) hextype |= HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200709 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200710 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000711 else if (!STRNCMP(pp, "-r", 2)) revert++;
712 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
713 else if (!STRNCMP(pp, "-v", 2))
714 {
715 fprintf(stderr, "%s%s\n", version, osver);
716 exit(0);
717 }
718 else if (!STRNCMP(pp, "-c", 2))
719 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100720 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200721 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100722 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000723 {
724 colsgiven = 1;
725 cols = (int)strtol(pp + 2, NULL, 0);
726 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 else
728 {
729 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200730 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000731 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732 cols = (int)strtol(argv[2], NULL, 0);
733 argv++;
734 argc--;
735 }
736 }
737 else if (!STRNCMP(pp, "-g", 2))
738 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100739 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 octspergrp = (int)strtol(pp + 2, NULL, 0);
741 else
742 {
743 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 octspergrp = (int)strtol(argv[2], NULL, 0);
746 argv++;
747 argc--;
748 }
749 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100750 else if (!STRNCMP(pp, "-o", 2))
751 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100752 int reloffset = 0;
753 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100754 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100755 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100756 else
757 {
758 if (!argv[2])
759 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100760
761 if (argv[2][0] == '+')
762 reloffset++;
763 if (argv[2][reloffset] == '-')
764 negoffset++;
765
766 if (negoffset)
767 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
768 else
769 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
770
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100771 argv++;
772 argc--;
773 }
774 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 else if (!STRNCMP(pp, "-s", 2))
776 {
777 relseek = 0;
778 negseek = 0;
779 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
780 {
781#ifdef TRY_SEEK
782 if (pp[2] == '+')
783 relseek++;
784 if (pp[2+relseek] == '-')
785 negseek++;
786#endif
787 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
788 }
789 else
790 {
791 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200792 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000793#ifdef TRY_SEEK
794 if (argv[2][0] == '+')
795 relseek++;
796 if (argv[2][relseek] == '-')
797 negseek++;
798#endif
799 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
800 argv++;
801 argc--;
802 }
803 }
804 else if (!STRNCMP(pp, "-l", 2))
805 {
806 if (pp[2] && STRNCMP("en", pp + 2, 2))
807 length = strtol(pp + 2, (char **)NULL, 0);
808 else
809 {
810 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200811 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 length = strtol(argv[2], (char **)NULL, 0);
813 argv++;
814 argc--;
815 }
816 }
David Gow83e11802022-06-29 20:24:49 +0100817 else if (!STRNCMP(pp, "-n", 2))
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200818 {
819 if (pp[2] && STRNCMP("ame", pp + 2, 3))
820 varname = pp + 2;
821 else
822 {
823 if (!argv[2])
824 exit_with_usage();
825 varname = argv[2];
826 argv++;
827 argc--;
828 }
829 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200830 else if (!STRNCMP(pp, "-R", 2))
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200831 {
K.Takataf6fc2552023-09-01 18:41:04 +0200832 char *pw = pp + 2;
833 if (!pw[0])
834 {
835 pw = argv[2];
836 argv++;
837 argc--;
838 }
839 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200840 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200841 if (!STRNCMP(pw, "always", 6))
842 {
843 (void)enable_color();
844 color = 1;
845 }
846 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200847 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200848 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200849 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200850 else
851 exit_with_usage();
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200852 }
DungSaga4b9fa952024-11-11 22:19:50 +0100853 else if (!strcmp(argv[1], "--")) /* end of options */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 {
855 argv++;
856 argc--;
857 break;
858 }
859 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200860 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000861 else
862 break; /* not an option */
863
864 argv++; /* advance to next argument */
865 argc--;
866 }
867
Andre Chang15022722024-09-15 20:03:05 +0200868 if (hextype != (HEX_CINCLUDE | HEX_BITS))
869 {
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200870 /* Allow at most one bit to be set in hextype */
871 if (hextype & (hextype - 1))
872 error_exit(1, "only one of -b, -e, -u, -p, -i can be used");
Andre Chang15022722024-09-15 20:03:05 +0200873 }
874
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000875 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 switch (hextype)
877 {
878 case HEX_POSTSCRIPT: cols = 30; break;
879 case HEX_CINCLUDE: cols = 12; break;
Andre Chang15022722024-09-15 20:03:05 +0200880 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881 case HEX_BITS: cols = 6; break;
882 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100883 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 default: cols = 16; break;
885 }
886
887 if (octspergrp < 0)
888 switch (hextype)
889 {
Andre Chang15022722024-09-15 20:03:05 +0200890 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891 case HEX_BITS: octspergrp = 1; break;
892 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100893 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894 case HEX_POSTSCRIPT:
895 case HEX_CINCLUDE:
896 default: octspergrp = 0; break;
897 }
898
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000899 if ((hextype == HEX_POSTSCRIPT && cols < 0) ||
900 (hextype != HEX_POSTSCRIPT && cols < 1) ||
901 ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000902 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 {
904 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
905 exit(1);
906 }
907
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100908 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100910 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100911 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000912
913 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200914 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915
916 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
917 BIN_ASSIGN(fp = stdin, !revert);
918 else
919 {
920 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
921 {
922 fprintf(stderr,"%s: ", pname);
923 perror(argv[1]);
924 return 2;
925 }
926 }
927
928 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
929 BIN_ASSIGN(fpo = stdout, revert);
930 else
931 {
932 int fd;
933 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
934
935 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
936 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
937 {
938 fprintf(stderr, "%s: ", pname);
939 perror(argv[2]);
940 return 3;
941 }
942 rewind(fpo);
943 }
Igor Todorovski48a75f32024-01-09 21:05:48 +0000944#ifdef __MVS__
945 // Disable auto-conversion on input file descriptors
946 __disableautocvt(fileno(fp));
947#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000948
949 if (revert)
tristhaus85f45212023-10-06 19:51:13 +0200950 switch (hextype)
951 {
952 case HEX_NORMAL:
953 case HEX_POSTSCRIPT:
954 case HEX_BITS:
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200955 return huntype(fp, fpo, cols, hextype,
956 negseek ? -seekoff : seekoff);
957 break;
tristhaus85f45212023-10-06 19:51:13 +0200958 default:
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200959 error_exit(-1, "Sorry, cannot revert this type of hexdump");
tristhaus85f45212023-10-06 19:51:13 +0200960 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961
962 if (seekoff || negseek || !relseek)
963 {
964#ifdef TRY_SEEK
965 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000966 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000967 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000968 e = fseek(fp, negseek ? -seekoff : seekoff,
969 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000970 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000971 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000972 if (e >= 0)
973 seekoff = ftell(fp);
974 else
975#endif
976 {
977 long s = seekoff;
978
979 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000980 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200981 {
DungSaga7e5503c2021-12-01 11:24:52 +0000982 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200983 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000984 }
985 }
986
Andre Chang15022722024-09-15 20:03:05 +0200987 if (hextype & HEX_CINCLUDE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 {
David Gow83e11802022-06-29 20:24:49 +0100989 /* A user-set variable name overrides fp == stdin */
990 if (varname == NULL && fp != stdin)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +0200991 varname = argv[1];
David Gow83e11802022-06-29 20:24:49 +0100992
993 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000994 {
Keith Thompson184f71c2024-01-04 21:19:04 +0100995 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100996 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100997 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000998 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000999 }
1000
1001 p = 0;
DungSagad1d8a592021-11-26 13:59:27 +00001002 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001003 {
1004 if (hextype & HEX_BITS)
Andre Chang15022722024-09-15 20:03:05 +02001005 {
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001006 if (p == 0)
1007 fputs_or_die(" ", fpo);
1008 else if (p % cols == 0)
1009 fputs_or_die(",\n ", fpo);
1010 else
1011 fputs_or_die(", ", fpo);
Andre Chang15022722024-09-15 20:03:05 +02001012
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001013 FPRINTF_OR_DIE((fpo, "0b"));
1014 for (int j = 7; j >= 0; j--)
1015 putc_or_die((c & (1 << j)) ? '1' : '0', fpo);
1016 p++;
Andre Chang15022722024-09-15 20:03:05 +02001017 }
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001018 else
Andre Chang15022722024-09-15 20:03:05 +02001019 {
1020 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
DungSaga7e5503c2021-12-01 11:24:52 +00001021 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Andre Chang15022722024-09-15 20:03:05 +02001022 p++;
1023 }
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001024 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001025
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001026 if (p)
1027 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028
David Gow83e11802022-06-29 20:24:49 +01001029 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 {
DungSagad1d8a592021-11-26 13:59:27 +00001031 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +01001032 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +01001033 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +01001034 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001035 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 }
1037
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001038 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 return 0;
1040 }
1041
1042 if (hextype == HEX_POSTSCRIPT)
1043 {
1044 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +00001045 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001047 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1048 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001049 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001050 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001052 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 p = cols;
1054 }
1055 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001056 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001057 putc_or_die('\n', fpo);
1058 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001059 return 0;
1060 }
1061
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001062 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001064 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001065 {
1066 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1067 if (color)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001068 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001069 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001070 else /* hextype == HEX_BITS */
1071 grplen = 8 * octspergrp + 1;
1072
DungSagad1d8a592021-11-26 13:59:27 +00001073 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 {
1075 if (p == 0)
1076 {
DungSaga581f41a2021-11-22 11:57:31 +00001077 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001078 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001079 for (c = addrlen; c < LLEN; l[c++] = ' ')
1080 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 }
DungSaga48608b42021-11-24 11:18:07 +00001082 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1083 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001084 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001085 {
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001086 if (color)
1087 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001088 COLOR_PROLOGUE
1089 begin_coloring_char(l,&c,e,ebcdic);
1090 l[c++] = hexx[(e >> 4) & 0xf];
1091 l[c++] = hexx[e & 0xf];
1092 COLOR_EPILOGUE
1093 }
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001094 else /*No colors*/
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001095 {
1096 l[c] = hexx[(e >> 4) & 0xf];
1097 l[++c] = hexx[e & 0xf];
1098 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001099 }
1100 else /* hextype == HEX_BITS */
1101 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001102 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001103 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001104 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001105 if (e)
1106 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001107 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001108 if (hextype == HEX_LITTLEENDIAN)
1109 /* last group will be fully used, round up */
1110 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1111 else
1112 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001113
1114 if (color)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001115 {
1116 if (hextype == HEX_BITS)
1117 c += addrlen + 3 + p*12;
1118 else
1119 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001120
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001121 COLOR_PROLOGUE
1122 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001123#if defined(__MVS__) && __CHARSET_LIB == 0
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001124 if (e >= 64)
1125 l[c++] = e;
1126 else
1127 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001128#else
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001129 if (ebcdic)
1130 e = (e < 64) ? '.' : etoa64[e-64];
1131 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001132#endif
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001133 COLOR_EPILOGUE
1134 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001135 else /*no colors*/
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001136 {
1137 if (ebcdic)
1138 e = (e < 64) ? '.' : etoa64[e-64];
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001139
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001140 if (hextype == HEX_LITTLEENDIAN)
1141 c -= 1;
Aapo Rantalainenc73fc862024-10-19 15:54:57 +02001142
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001143 c += addrlen + 3 + p;
1144 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001145#if defined(__MVS__) && __CHARSET_LIB == 0
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001146 (e >= 64)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001147#else
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001148 (e > 31 && e < 127)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001149#endif
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001150 ? e : '.';
1151 }
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 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001161 }
1162 if (p)
1163 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001164 l[c++] = '\n';
1165 l[c] = '\0';
1166 if (color)
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001167 {
1168 x = p;
1169 if (hextype == HEX_LITTLEENDIAN)
1170 {
1171 int fill = octspergrp - (p % octspergrp);
1172 if (fill == octspergrp) fill = 0;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001173
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001174 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001175
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001176 for (i = 0; i < fill;i++)
1177 {
1178 COLOR_PROLOGUE
1179 l[c++] = COLOR_RED;
1180 l[c++] = 'm';
1181 l[c++] = ' '; /* empty space */
1182 COLOR_EPILOGUE
1183 x++;
1184 p++;
1185 }
1186 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001187
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001188 if (hextype != HEX_BITS)
1189 {
1190 c = addrlen + 1 + (grplen * x) / octspergrp;
1191 c += cols - p;
1192 c += (cols - p) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001193
Naruhiko Nishinoc2a90002025-05-04 20:05:47 +02001194 for (i = cols - p; i > 0;i--)
1195 {
1196 COLOR_PROLOGUE
1197 l[c++] = COLOR_RED;
1198 l[c++] = 'm';
1199 l[c++] = ' '; /* empty space */
1200 COLOR_EPILOGUE
1201 }
1202 }
1203 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 xxdline(fpo, l, 1);
1205 }
1206 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001207 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001208
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001209 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001210 return 0;
1211}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001212
1213/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */