blob: cf8b4ea6a0e2acde115d35aff178d7f9f45bdfec [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000065 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020066 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000067 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020068 * I hereby grant permission to distribute and use xxd
69 * under X11-MIT or GPL-2.0 (at the user's choice).
70 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020071 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000072 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000073
74/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
75#if _MSC_VER >= 1400
76# define _CRT_SECURE_NO_DEPRECATE
77# define _CRT_NONSTDC_NO_DEPRECATE
78#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010079#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000080# define CYGWIN
81#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000082
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000083#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
84# define _XOPEN_SOURCE 700 /* for fdopen() */
85#endif
86
Bram Moolenaar071d4272004-06-13 20:20:40 +000087#include <stdio.h>
88#ifdef VAXC
89# include <file.h>
90#else
91# include <fcntl.h>
92#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020093#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000094# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +020095#endif
96#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +020097# include <windows.h>
98#endif
99#ifdef UNIX
100# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000101#endif
102#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100103#include <string.h>
104#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100105#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000106#if __MWERKS__ && !defined(BEBOX)
107# include <unix.h> /* for fdopen() on MAC */
108#endif
109
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110
111/* This corrects the problem of missing prototypes for certain functions
112 * in some GNU installations (e.g. SunOS 4.1.x).
113 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
114 */
115#if defined(__GNUC__) && defined(__STDC__)
116# ifndef __USE_FIXED_PROTOTYPES__
117# define __USE_FIXED_PROTOTYPES__
118# endif
119#endif
120
121#ifndef __USE_FIXED_PROTOTYPES__
122/*
123 * This is historic and works only if the compiler really has no prototypes:
124 *
125 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
126 * FILE is defined on OS 4.x, not on 5.x (Solaris).
127 * if __SVR4 is defined (some Solaris versions), don't include this.
128 */
129#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
130# define __P(a) a
131/* excerpt from my sun_stdlib.h */
132extern int fprintf __P((FILE *, char *, ...));
133extern int fputs __P((char *, FILE *));
134extern int _flsbuf __P((unsigned char, FILE *));
135extern int _filbuf __P((FILE *));
136extern int fflush __P((FILE *));
137extern int fclose __P((FILE *));
138extern int fseek __P((FILE *, long, int));
139extern int rewind __P((FILE *));
140
141extern void perror __P((char *));
142# endif
143#endif
144
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100145char version[] = "xxd 2024-02-10 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146#ifdef WIN32
147char osver[] = " (Win32)";
148#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150#endif
151
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200152#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153# define BIN_READ(yes) ((yes) ? "rb" : "rt")
154# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
155# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
156# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000157# define PATH_SEP '\\'
158#elif defined(CYGWIN)
159# define BIN_READ(yes) ((yes) ? "rb" : "rt")
160# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
161# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
162# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
163# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164#else
165# ifdef VMS
166# define BIN_READ(dummy) "r"
167# define BIN_WRITE(dummy) "w"
168# define BIN_CREAT(dummy) O_CREAT
169# define BIN_ASSIGN(fp, dummy) fp
170# define PATH_SEP ']'
171# define FILE_SEP '.'
172# else
173# define BIN_READ(dummy) "r"
174# define BIN_WRITE(dummy) "w"
175# define BIN_CREAT(dummy) O_CREAT
176# define BIN_ASSIGN(fp, dummy) fp
177# define PATH_SEP '/'
178# endif
179#endif
180
181/* open has only to arguments on the Mac */
182#if __MWERKS__
183# define OPEN(name, mode, umask) open(name, mode)
184#else
185# define OPEN(name, mode, umask) open(name, mode, umask)
186#endif
187
188#ifdef AMIGA
189# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
190#else
191# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
192#endif
193
194#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200195# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196# define __P(a) a
197# else
198# define __P(a) ()
199# endif
200#endif
201
Bram Moolenaar071d4272004-06-13 20:20:40 +0000202#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
203#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100204
205/*
206 * LLEN is the maximum length of a line; other than the visible characters
207 * we need to consider also the escape color sequence prologue/epilogue ,
208 * (11 bytes for each character). The most larger format is the default one:
209 * addr + 1 word for each col/2 + 1 char for each col
210 *
211 * addr 1st group 2nd group
212 * +-------+ +-----------------+ +------+
213 * 01234567: 1234 5678 9abc def0 12345678
214 *
215 * - addr: typically 012345678: -> from 10 up to 18 bytes (including trailing
216 * space)
217 * - 1st group: 1234 5678 9abc ... -> each byte may be colored, so add 11
218 * for each byte
219 * - space -> 1 byte
220 * - 2nd group: 12345678 -> each char may be colore so add 11
221 * for each byte
222 * - new line -> 1 byte
223 * - zero (end line) -> 1 byte
224 */
225#define LLEN (2*(int)sizeof(unsigned long) + 2 + /* addr + ": " */ \
226 (11 * 2 + 4 + 1) * (COLS / 2) + /* 1st group */ \
227 1 + /* space */ \
228 (1 + 11) * COLS + /* 2nd group */ \
229 1 + /* new line */ \
230 1) /* zero */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231
232char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
233
234/* the different hextypes known by this program: */
235#define HEX_NORMAL 0
236#define HEX_POSTSCRIPT 1
237#define HEX_CINCLUDE 2
238#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100239#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240
Keith Thompson184f71c2024-01-04 21:19:04 +0100241#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200242
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200243#define COLOR_PROLOGUE \
244l[c++] = '\033'; \
245l[c++] = '['; \
246l[c++] = '1'; \
247l[c++] = ';'; \
248l[c++] = '3';
249
250#define COLOR_EPILOGUE \
251l[c++] = '\033'; \
252l[c++] = '['; \
253l[c++] = '0'; \
254l[c++] = 'm';
255#define COLOR_RED '1'
256#define COLOR_GREEN '2'
257#define COLOR_YELLOW '3'
258#define COLOR_BLUE '4'
259#define COLOR_WHITE '7'
260
Bram Moolenaare0659a62011-04-01 19:14:40 +0200261static char *pname;
262
263 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100264exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000265{
266 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
267 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
268 fprintf(stderr, "Options:\n");
269 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
tristhaus85f45212023-10-06 19:51:13 +0200270 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200271 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
273 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100274 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100275 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 fprintf(stderr, " -h print this summary.\n");
277 fprintf(stderr, " -i output in C include file style.\n");
278 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100279 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100280 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000281 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
282 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
283 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200284 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000285 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
286#ifdef TRY_SEEK
287 "[+][-]", "(or +: rel.) ");
288#else
289 "", "");
290#endif
291 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200292 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
294 exit(1);
295}
296
Bram Moolenaare0659a62011-04-01 19:14:40 +0200297 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100298perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200299{
300 fprintf(stderr, "%s: ", pname);
301 perror(NULL);
302 exit(ret);
303}
304
DungSagaa2ffb432021-10-22 15:55:31 +0100305 static void
306error_exit(int ret, char *msg)
307{
308 fprintf(stderr, "%s: %s\n", pname, msg);
309 exit(ret);
310}
311
DungSagad1d8a592021-11-26 13:59:27 +0000312 static int
313getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000314{
DungSagad1d8a592021-11-26 13:59:27 +0000315 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000316 if (c == EOF && ferror(fpi))
317 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000318 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000319}
320
321 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000322putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000323{
324 if (putc(c, fpo) == EOF)
325 perror_exit(3);
326}
327
328 static void
329fputs_or_die(char *s, FILE *fpo)
330{
331 if (fputs(s, fpo) == EOF)
332 perror_exit(3);
333}
334
DungSaga7e5503c2021-12-01 11:24:52 +0000335/* Use a macro to allow for different arguments. */
336#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000337
338 static void
339fclose_or_die(FILE *fpi, FILE *fpo)
340{
341 if (fclose(fpo) != 0)
342 perror_exit(3);
343 if (fclose(fpi) != 0)
344 perror_exit(2);
345}
346
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000348 * If "c" is a hex digit, return the value.
349 * Otherwise return -1.
350 */
351 static int
352parse_hex_digit(int c)
353{
354 return (c >= '0' && c <= '9') ? c - '0'
355 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
356 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
357 : -1;
358}
359
360/*
tristhaus85f45212023-10-06 19:51:13 +0200361 * If "c" is a bin digit, return the value.
362 * Otherwise return -1.
363 */
364 static int
365parse_bin_digit(int c)
366{
367 return (c >= '0' && c <= '1') ? c - '0'
368 : -1;
369}
370
371/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000372 * Ignore text on "fpi" until end-of-line or end-of-file.
373 * Return the '\n' or EOF character.
374 * When an error is encountered exit with an error message.
375 */
376 static int
377skip_to_eol(FILE *fpi, int c)
378{
379 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000380 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000381 return c;
382}
383
384/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 * Max. cols binary characters are decoded from the input stream per line.
386 * Two adjacent garbage characters after evaluated data delimit valid data.
387 * Everything up to the next newline is discarded.
388 *
389 * The name is historic and came from 'undo type opt h'.
390 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200391 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100392huntype(
393 FILE *fpi,
394 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100395 int cols,
396 int hextype,
397 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200399 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 +0000400 long have_off = 0, want_off = 0;
401
402 rewind(fpi);
403
404 while ((c = getc(fpi)) != EOF)
405 {
406 if (c == '\r') /* Doze style input file? */
407 continue;
408
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100409 /* Allow multiple spaces. This doesn't work when there is normal text
410 * after the hex codes in the last line that looks like hex, thus only
411 * use it for PostScript format. */
412 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000413 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000414
tristhaus85f45212023-10-06 19:51:13 +0200415 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
416 {
417 n3 = n2;
418 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419
tristhaus85f45212023-10-06 19:51:13 +0200420 n1 = parse_hex_digit(c);
421 if (n1 == -1 && ign_garb)
422 continue;
423 }
424 else /* HEX_BITS */
425 {
426 n1 = parse_hex_digit(c);
427 if (n1 == -1 && ign_garb)
428 continue;
429
430 bt = parse_bin_digit(c);
431 if (bt != -1)
432 {
433 b = ((b << 1) | bt);
434 ++bcnt;
435 }
436 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000437
438 ign_garb = 0;
439
tristhaus85f45212023-10-06 19:51:13 +0200440 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000441 {
tristhaus85f45212023-10-06 19:51:13 +0200442 if (hextype == HEX_NORMAL)
443 {
444 if (n1 < 0)
445 {
446 p = 0;
447 continue;
448 }
449 want_off = (want_off << 4) | n1;
450 }
451 else /* HEX_BITS */
452 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200453 if (n1 < 0)
454 {
455 p = 0;
tristhaus85f45212023-10-06 19:51:13 +0200456 bcnt = 0;
OldWorldOrdr1c140302023-10-25 20:57:30 +0200457 continue;
458 }
459 want_off = (want_off << 4) | n1;
tristhaus85f45212023-10-06 19:51:13 +0200460 }
461 continue;
462 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463
464 if (base_off + want_off != have_off)
465 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200466 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100467 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000469 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470 have_off = base_off + want_off;
471#endif
472 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000473 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000474 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000475 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476 }
477
tristhaus85f45212023-10-06 19:51:13 +0200478 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
479 {
480 if (n2 >= 0 && n1 >= 0)
481 {
482 putc_or_die((n2 << 4) | n1, fpo);
483 have_off++;
484 want_off++;
485 n1 = -1;
486 if (!hextype && (++p >= cols))
487 /* skip the rest of the line as garbage */
488 c = skip_to_eol(fpi, c);
489 }
490 else if (n1 < 0 && n2 < 0 && n3 < 0)
491 /* already stumbled into garbage, skip line, wait and see */
492 c = skip_to_eol(fpi, c);
493 }
494 else /* HEX_BITS */
495 {
496 if (bcnt == 8)
497 {
498 putc_or_die(b, fpo);
499 have_off++;
500 want_off++;
501 b = 0;
502 bcnt = 0;
503 if (++p >= cols)
504 /* skip the rest of the line as garbage */
505 c = skip_to_eol(fpi, c);
506 }
507 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000508
DungSaga47810462021-10-22 12:55:42 +0100509 if (c == '\n')
510 {
tristhaus85f45212023-10-06 19:51:13 +0200511 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100512 want_off = 0;
513 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514 ign_garb = 1;
515 }
516 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200517 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100518 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000520 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000522 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 return 0;
524}
525
526/*
527 * Print line l. If nz is false, xxdline regards the line a line of
528 * zeroes. If there are three or more consecutive lines of zeroes,
529 * they are replaced by a single '*' character.
530 *
531 * If the output ends with more than two lines of zeroes, you
532 * should call xxdline again with l being the last line and nz
533 * negative. This ensures that the last line is shown even when
534 * it is all zeroes.
535 *
536 * If nz is always positive, lines are never suppressed.
537 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200538 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100539xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000540{
541 static char z[LLEN+1];
542 static int zero_seen = 0;
543
544 if (!nz && zero_seen == 1)
545 strcpy(z, l);
546
547 if (nz || !zero_seen++)
548 {
549 if (nz)
550 {
551 if (nz < 0)
552 zero_seen--;
553 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000554 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000555 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000556 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000557 }
558 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000559 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 if (nz)
561 zero_seen = 0;
562 }
563}
564
565/* This is an EBCDIC to ASCII conversion table */
566/* from a proposed BTL standard April 16, 1979 */
567static unsigned char etoa64[] =
568{
569 0040,0240,0241,0242,0243,0244,0245,0246,
570 0247,0250,0325,0056,0074,0050,0053,0174,
571 0046,0251,0252,0253,0254,0255,0256,0257,
572 0260,0261,0041,0044,0052,0051,0073,0176,
573 0055,0057,0262,0263,0264,0265,0266,0267,
574 0270,0271,0313,0054,0045,0137,0076,0077,
575 0272,0273,0274,0275,0276,0277,0300,0301,
576 0302,0140,0072,0043,0100,0047,0075,0042,
577 0303,0141,0142,0143,0144,0145,0146,0147,
578 0150,0151,0304,0305,0306,0307,0310,0311,
579 0312,0152,0153,0154,0155,0156,0157,0160,
580 0161,0162,0136,0314,0315,0316,0317,0320,
581 0321,0345,0163,0164,0165,0166,0167,0170,
582 0171,0172,0322,0323,0324,0133,0326,0327,
583 0330,0331,0332,0333,0334,0335,0336,0337,
584 0340,0341,0342,0343,0344,0135,0346,0347,
585 0173,0101,0102,0103,0104,0105,0106,0107,
586 0110,0111,0350,0351,0352,0353,0354,0355,
587 0175,0112,0113,0114,0115,0116,0117,0120,
588 0121,0122,0356,0357,0360,0361,0362,0363,
589 0134,0237,0123,0124,0125,0126,0127,0130,
590 0131,0132,0364,0365,0366,0367,0370,0371,
591 0060,0061,0062,0063,0064,0065,0066,0067,
592 0070,0071,0372,0373,0374,0375,0376,0377
593};
594
K.Takataf6fc2552023-09-01 18:41:04 +0200595 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200596begin_coloring_char (char *l, int *c, int e, int ebcdic)
597{
598 if (ebcdic)
599 {
600 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
601 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
602 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
603 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
604 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
605 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
606 (e == 173) || (e == 224) )
607 l[(*c)++] = COLOR_GREEN;
608
609 else if (e == 37 || e == 13 || e == 5)
610 l[(*c)++] = COLOR_YELLOW;
611 else if (e == 0)
612 l[(*c)++] = COLOR_WHITE;
613 else if (e == 255)
614 l[(*c)++] = COLOR_BLUE;
615 else
616 l[(*c)++] = COLOR_RED;
617 }
618 else /* ASCII */
619 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000620 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200621 if (e >= 64)
622 l[(*c)++] = COLOR_GREEN;
623 #else
624 if (e > 31 && e < 127)
625 l[(*c)++] = COLOR_GREEN;
626 #endif
627
628 else if (e == 9 || e == 10 || e == 13)
629 l[(*c)++] = COLOR_YELLOW;
630 else if (e == 0)
631 l[(*c)++] = COLOR_WHITE;
632 else if (e == 255)
633 l[(*c)++] = COLOR_BLUE;
634 else
635 l[(*c)++] = COLOR_RED;
636 }
637 l[(*c)++] = 'm';
638}
639
K.Takataf6fc2552023-09-01 18:41:04 +0200640 static int
641enable_color(void)
642{
643#ifdef WIN32
644 DWORD mode;
645 HANDLE out;
646
647 if (!isatty(1))
648 return 0;
649
650 out = GetStdHandle(STD_OUTPUT_HANDLE);
651 GetConsoleMode(out, &mode);
652 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
653 return (int)SetConsoleMode(out, mode);
654#elif defined(UNIX)
655 return isatty(STDOUT_FILENO);
656#else
657 return 0;
658#endif
659}
660
Bram Moolenaare0659a62011-04-01 19:14:40 +0200661 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100662main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663{
664 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200665 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000666 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200667 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 int ebcdic = 0;
669 int octspergrp = -1; /* number of octets grouped in output */
670 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100671 long length = -1, n = 0, seekoff = 0;
672 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200673 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200674 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100675 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100676 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200677 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200678 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200679
K.Takataf6fc2552023-09-01 18:41:04 +0200680 no_color = getenv("NO_COLOR");
681 if (no_color == NULL || no_color[0] == '\0')
682 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000683
684#ifdef AMIGA
685 /* This program doesn't work when started from the Workbench */
686 if (argc == 0)
687 exit(1);
688#endif
689
690 pname = argv[0];
691 for (pp = pname; *pp; )
692 if (*pp++ == PATH_SEP)
693 pname = pp;
694#ifdef FILE_SEP
695 for (pp = pname; *pp; pp++)
696 if (*pp == FILE_SEP)
697 {
698 *pp = '\0';
699 break;
700 }
701#endif
702
703 while (argc >= 2)
704 {
705 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
706 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
707 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100708 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000709 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
710 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
711 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200712 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200713 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000714 else if (!STRNCMP(pp, "-r", 2)) revert++;
715 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
716 else if (!STRNCMP(pp, "-v", 2))
717 {
718 fprintf(stderr, "%s%s\n", version, osver);
719 exit(0);
720 }
721 else if (!STRNCMP(pp, "-c", 2))
722 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100723 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200724 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100725 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000726 {
727 colsgiven = 1;
728 cols = (int)strtol(pp + 2, NULL, 0);
729 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730 else
731 {
732 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200733 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000734 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 cols = (int)strtol(argv[2], NULL, 0);
736 argv++;
737 argc--;
738 }
739 }
740 else if (!STRNCMP(pp, "-g", 2))
741 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100742 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 octspergrp = (int)strtol(pp + 2, NULL, 0);
744 else
745 {
746 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200747 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 octspergrp = (int)strtol(argv[2], NULL, 0);
749 argv++;
750 argc--;
751 }
752 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100753 else if (!STRNCMP(pp, "-o", 2))
754 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100755 int reloffset = 0;
756 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100757 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100758 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100759 else
760 {
761 if (!argv[2])
762 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100763
764 if (argv[2][0] == '+')
765 reloffset++;
766 if (argv[2][reloffset] == '-')
767 negoffset++;
768
769 if (negoffset)
770 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
771 else
772 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
773
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100774 argv++;
775 argc--;
776 }
777 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 else if (!STRNCMP(pp, "-s", 2))
779 {
780 relseek = 0;
781 negseek = 0;
782 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
783 {
784#ifdef TRY_SEEK
785 if (pp[2] == '+')
786 relseek++;
787 if (pp[2+relseek] == '-')
788 negseek++;
789#endif
790 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
791 }
792 else
793 {
794 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200795 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796#ifdef TRY_SEEK
797 if (argv[2][0] == '+')
798 relseek++;
799 if (argv[2][relseek] == '-')
800 negseek++;
801#endif
802 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
803 argv++;
804 argc--;
805 }
806 }
807 else if (!STRNCMP(pp, "-l", 2))
808 {
809 if (pp[2] && STRNCMP("en", pp + 2, 2))
810 length = strtol(pp + 2, (char **)NULL, 0);
811 else
812 {
813 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200814 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 length = strtol(argv[2], (char **)NULL, 0);
816 argv++;
817 argc--;
818 }
819 }
David Gow83e11802022-06-29 20:24:49 +0100820 else if (!STRNCMP(pp, "-n", 2))
821 {
822 if (pp[2] && STRNCMP("ame", pp + 2, 3))
823 varname = pp + 2;
824 else
825 {
826 if (!argv[2])
827 exit_with_usage();
828 varname = argv[2];
829 argv++;
830 argc--;
831 }
832 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200833 else if (!STRNCMP(pp, "-R", 2))
834 {
K.Takataf6fc2552023-09-01 18:41:04 +0200835 char *pw = pp + 2;
836 if (!pw[0])
837 {
838 pw = argv[2];
839 argv++;
840 argc--;
841 }
842 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200843 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200844 if (!STRNCMP(pw, "always", 6))
845 {
846 (void)enable_color();
847 color = 1;
848 }
849 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200850 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200851 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200852 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200853 else
854 exit_with_usage();
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200855 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 else if (!strcmp(pp, "--")) /* end of options */
857 {
858 argv++;
859 argc--;
860 break;
861 }
862 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200863 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864 else
865 break; /* not an option */
866
867 argv++; /* advance to next argument */
868 argc--;
869 }
870
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000871 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 switch (hextype)
873 {
874 case HEX_POSTSCRIPT: cols = 30; break;
875 case HEX_CINCLUDE: cols = 12; break;
876 case HEX_BITS: cols = 6; break;
877 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100878 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 default: cols = 16; break;
880 }
881
882 if (octspergrp < 0)
883 switch (hextype)
884 {
885 case HEX_BITS: octspergrp = 1; break;
886 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100887 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000888 case HEX_POSTSCRIPT:
889 case HEX_CINCLUDE:
890 default: octspergrp = 0; break;
891 }
892
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000893 if ((hextype == HEX_POSTSCRIPT && cols < 0) ||
894 (hextype != HEX_POSTSCRIPT && cols < 1) ||
895 ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000896 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897 {
898 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
899 exit(1);
900 }
901
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100902 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000903 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100904 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100905 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000906
907 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200908 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000909
910 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
911 BIN_ASSIGN(fp = stdin, !revert);
912 else
913 {
914 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
915 {
916 fprintf(stderr,"%s: ", pname);
917 perror(argv[1]);
918 return 2;
919 }
920 }
921
922 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
923 BIN_ASSIGN(fpo = stdout, revert);
924 else
925 {
926 int fd;
927 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
928
929 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
930 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
931 {
932 fprintf(stderr, "%s: ", pname);
933 perror(argv[2]);
934 return 3;
935 }
936 rewind(fpo);
937 }
Igor Todorovski48a75f32024-01-09 21:05:48 +0000938#ifdef __MVS__
939 // Disable auto-conversion on input file descriptors
940 __disableautocvt(fileno(fp));
941#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000942
943 if (revert)
tristhaus85f45212023-10-06 19:51:13 +0200944 switch (hextype)
945 {
946 case HEX_NORMAL:
947 case HEX_POSTSCRIPT:
948 case HEX_BITS:
949 return huntype(fp, fpo, cols, hextype,
950 negseek ? -seekoff : seekoff);
951 break;
952 default:
953 error_exit(-1, "Sorry, cannot revert this type of hexdump");
954 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000955
956 if (seekoff || negseek || !relseek)
957 {
958#ifdef TRY_SEEK
959 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000960 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000961 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000962 e = fseek(fp, negseek ? -seekoff : seekoff,
963 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000964 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000965 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 if (e >= 0)
967 seekoff = ftell(fp);
968 else
969#endif
970 {
971 long s = seekoff;
972
973 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000974 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200975 {
DungSaga7e5503c2021-12-01 11:24:52 +0000976 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200977 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000978 }
979 }
980
981 if (hextype == HEX_CINCLUDE)
982 {
David Gow83e11802022-06-29 20:24:49 +0100983 /* A user-set variable name overrides fp == stdin */
984 if (varname == NULL && fp != stdin)
985 varname = argv[1];
986
987 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 {
Keith Thompson184f71c2024-01-04 21:19:04 +0100989 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100990 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100991 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000992 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993 }
994
995 p = 0;
DungSagad1d8a592021-11-26 13:59:27 +0000996 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000997 {
DungSaga7e5503c2021-12-01 11:24:52 +0000998 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
999 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001000 p++;
1001 }
1002
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001003 if (p)
1004 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005
David Gow83e11802022-06-29 20:24:49 +01001006 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001007 {
DungSagad1d8a592021-11-26 13:59:27 +00001008 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +01001009 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +01001010 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +01001011 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001012 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001013 }
1014
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001015 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 return 0;
1017 }
1018
1019 if (hextype == HEX_POSTSCRIPT)
1020 {
1021 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +00001022 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001024 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1025 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001027 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001029 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 p = cols;
1031 }
1032 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001033 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001034 putc_or_die('\n', fpo);
1035 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001036 return 0;
1037 }
1038
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001039 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001041 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001042 {
1043 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1044 if (color)
1045 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
1046 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047 else /* hextype == HEX_BITS */
1048 grplen = 8 * octspergrp + 1;
1049
DungSagad1d8a592021-11-26 13:59:27 +00001050 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001051 {
1052 if (p == 0)
1053 {
DungSaga581f41a2021-11-22 11:57:31 +00001054 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001055 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001056 for (c = addrlen; c < LLEN; l[c++] = ' ')
1057 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001058 }
DungSaga48608b42021-11-24 11:18:07 +00001059 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1060 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001061 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001062 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001063 if (color)
1064 {
1065 COLOR_PROLOGUE
1066 begin_coloring_char(l,&c,e,ebcdic);
1067 l[c++] = hexx[(e >> 4) & 0xf];
1068 l[c++] = hexx[e & 0xf];
1069 COLOR_EPILOGUE
1070 }
1071 else /*No colors*/
1072 {
1073 l[c] = hexx[(e >> 4) & 0xf];
1074 l[++c] = hexx[e & 0xf];
1075 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001076 }
1077 else /* hextype == HEX_BITS */
1078 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001080 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001081 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001082 if (e)
1083 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001084 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001085 if (hextype == HEX_LITTLEENDIAN)
1086 /* last group will be fully used, round up */
1087 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1088 else
1089 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001090
1091 if (color)
1092 {
1093 if (hextype == HEX_BITS)
1094 c += addrlen + 3 + p*12;
1095 else
1096 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
1097
1098 if (hextype == HEX_LITTLEENDIAN)
1099 c += 1;
1100
1101 COLOR_PROLOGUE
1102 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001103#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001104 if (e >= 64)
1105 l[c++] = e;
1106 else
1107 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001108#else
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001109 if (ebcdic)
1110 e = (e < 64) ? '.' : etoa64[e-64];
1111 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001112#endif
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001113 COLOR_EPILOGUE
1114 n++;
1115 if (++p == cols)
1116 {
1117 l[c++] = '\n';
1118 l[c++] = '\0';
1119 xxdline(fpo, l, autoskip ? nonzero : 1);
1120 nonzero = 0;
1121 p = 0;
1122 }
1123 }
1124 else /*no colors*/
1125 {
1126 if (ebcdic)
1127 e = (e < 64) ? '.' : etoa64[e-64];
1128
1129 c += addrlen + 3 + p;
1130 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001131#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001132 (e >= 64)
1133#else
1134 (e > 31 && e < 127)
1135#endif
1136 ? e : '.';
1137 n++;
1138 if (++p == cols)
1139 {
1140 l[c++] = '\n';
1141 l[c] = '\0';
1142 xxdline(fpo, l, autoskip ? nonzero : 1);
1143 nonzero = 0;
1144 p = 0;
1145 }
1146 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147 }
1148 if (p)
1149 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001150 l[c++] = '\n';
1151 l[c] = '\0';
1152 if (color)
1153 {
1154 c++;
1155
1156 x = p;
1157 if (hextype == HEX_LITTLEENDIAN)
1158 {
1159 int fill = octspergrp - (p % octspergrp);
1160 if (fill == octspergrp) fill = 0;
1161
1162 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
1163
1164 for (i = 0; i < fill;i++)
1165 {
1166 COLOR_PROLOGUE
1167 l[c++] = COLOR_RED;
1168 l[c++] = 'm';
1169 l[c++] = ' '; /* empty space */
1170 COLOR_EPILOGUE
1171 x++;
1172 p++;
1173 }
1174 }
1175
1176 if (hextype != HEX_BITS)
1177 {
1178 c = addrlen + 1 + (grplen * x) / octspergrp;
1179 c += cols - p;
1180 c += (cols - p) / octspergrp;
1181
1182 for (i = cols - p; i > 0;i--)
1183 {
1184 COLOR_PROLOGUE
1185 l[c++] = COLOR_RED;
1186 l[c++] = 'm';
1187 l[c++] = ' '; /* empty space */
1188 COLOR_EPILOGUE
1189 }
1190 }
1191 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001192 xxdline(fpo, l, 1);
1193 }
1194 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001195 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001196
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001197 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198 return 0;
1199}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001200
1201/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */