blob: 7a3d36a7fe9716e14e339216d508e2ceba977188 [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000066 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020067 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020069 * I hereby grant permission to distribute and use xxd
70 * under X11-MIT or GPL-2.0 (at the user's choice).
71 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020072 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000073 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000074
75/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
76#if _MSC_VER >= 1400
77# define _CRT_SECURE_NO_DEPRECATE
78# define _CRT_NONSTDC_NO_DEPRECATE
79#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010080#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000081# define CYGWIN
82#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000083
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000084#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
85# define _XOPEN_SOURCE 700 /* for fdopen() */
86#endif
87
Bram Moolenaar071d4272004-06-13 20:20:40 +000088#include <stdio.h>
89#ifdef VAXC
90# include <file.h>
91#else
92# include <fcntl.h>
93#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020094#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000095# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +020096#endif
97#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +020098# include <windows.h>
99#endif
100#ifdef UNIX
101# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000102#endif
103#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100104#include <string.h>
105#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100106#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000107#if __MWERKS__ && !defined(BEBOX)
108# include <unix.h> /* for fdopen() on MAC */
109#endif
110
Bram Moolenaar071d4272004-06-13 20:20:40 +0000111
112/* This corrects the problem of missing prototypes for certain functions
113 * in some GNU installations (e.g. SunOS 4.1.x).
114 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
115 */
116#if defined(__GNUC__) && defined(__STDC__)
117# ifndef __USE_FIXED_PROTOTYPES__
118# define __USE_FIXED_PROTOTYPES__
119# endif
120#endif
121
122#ifndef __USE_FIXED_PROTOTYPES__
123/*
124 * This is historic and works only if the compiler really has no prototypes:
125 *
126 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
127 * FILE is defined on OS 4.x, not on 5.x (Solaris).
128 * if __SVR4 is defined (some Solaris versions), don't include this.
129 */
130#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
131# define __P(a) a
132/* excerpt from my sun_stdlib.h */
133extern int fprintf __P((FILE *, char *, ...));
134extern int fputs __P((char *, FILE *));
135extern int _flsbuf __P((unsigned char, FILE *));
136extern int _filbuf __P((FILE *));
137extern int fflush __P((FILE *));
138extern int fclose __P((FILE *));
139extern int fseek __P((FILE *, long, int));
140extern int rewind __P((FILE *));
141
142extern void perror __P((char *));
143# endif
144#endif
145
Lennard Hofmann67797192024-05-10 14:17:26 +0200146char version[] = "xxd 2024-05-10 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147#ifdef WIN32
148char osver[] = " (Win32)";
149#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151#endif
152
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200153#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154# define BIN_READ(yes) ((yes) ? "rb" : "rt")
155# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
156# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
157# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000158# define PATH_SEP '\\'
159#elif defined(CYGWIN)
160# define BIN_READ(yes) ((yes) ? "rb" : "rt")
161# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
162# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
163# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
164# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000165#else
166# ifdef VMS
167# define BIN_READ(dummy) "r"
168# define BIN_WRITE(dummy) "w"
169# define BIN_CREAT(dummy) O_CREAT
170# define BIN_ASSIGN(fp, dummy) fp
171# define PATH_SEP ']'
172# define FILE_SEP '.'
173# else
174# define BIN_READ(dummy) "r"
175# define BIN_WRITE(dummy) "w"
176# define BIN_CREAT(dummy) O_CREAT
177# define BIN_ASSIGN(fp, dummy) fp
178# define PATH_SEP '/'
179# endif
180#endif
181
182/* open has only to arguments on the Mac */
183#if __MWERKS__
184# define OPEN(name, mode, umask) open(name, mode)
185#else
186# define OPEN(name, mode, umask) open(name, mode, umask)
187#endif
188
189#ifdef AMIGA
190# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
191#else
192# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
193#endif
194
195#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200196# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000197# define __P(a) a
198# else
199# define __P(a) ()
200# endif
201#endif
202
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
204#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100205
206/*
207 * LLEN is the maximum length of a line; other than the visible characters
208 * we need to consider also the escape color sequence prologue/epilogue ,
Lennard Hofmann67797192024-05-10 14:17:26 +0200209 * (11 bytes for each character).
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100210 */
Lennard Hofmann67797192024-05-10 14:17:26 +0200211#define LLEN \
212 (39 /* addr: ⌈log10(ULONG_MAX)⌉ if "-d" flag given. We assume ULONG_MAX = 2**128 */ \
213 + 2 /* ": " */ \
214 + 13 * COLS /* hex dump with colors */ \
215 + (COLS - 1) /* whitespace between groups if "-g1" option given and "-c" maxed out */ \
216 + 2 /* whitespace */ \
217 + 12 * COLS /* ASCII dump with colors */ \
218 + 2) /* "\n\0" */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219
220char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
221
222/* the different hextypes known by this program: */
223#define HEX_NORMAL 0
224#define HEX_POSTSCRIPT 1
225#define HEX_CINCLUDE 2
226#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100227#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228
Keith Thompson184f71c2024-01-04 21:19:04 +0100229#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200230
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200231#define COLOR_PROLOGUE \
232l[c++] = '\033'; \
233l[c++] = '['; \
234l[c++] = '1'; \
235l[c++] = ';'; \
236l[c++] = '3';
237
238#define COLOR_EPILOGUE \
239l[c++] = '\033'; \
240l[c++] = '['; \
241l[c++] = '0'; \
242l[c++] = 'm';
243#define COLOR_RED '1'
244#define COLOR_GREEN '2'
245#define COLOR_YELLOW '3'
246#define COLOR_BLUE '4'
247#define COLOR_WHITE '7'
248
Bram Moolenaare0659a62011-04-01 19:14:40 +0200249static char *pname;
250
251 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100252exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000253{
254 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
255 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
256 fprintf(stderr, "Options:\n");
257 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
tristhaus85f45212023-10-06 19:51:13 +0200258 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200259 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000260 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
261 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100262 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100263 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000264 fprintf(stderr, " -h print this summary.\n");
265 fprintf(stderr, " -i output in C include file style.\n");
266 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100267 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100268 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000269 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
270 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
271 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200272 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
274#ifdef TRY_SEEK
275 "[+][-]", "(or +: rel.) ");
276#else
277 "", "");
278#endif
279 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200280 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000281 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
282 exit(1);
283}
284
Bram Moolenaare0659a62011-04-01 19:14:40 +0200285 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100286perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200287{
288 fprintf(stderr, "%s: ", pname);
289 perror(NULL);
290 exit(ret);
291}
292
DungSagaa2ffb432021-10-22 15:55:31 +0100293 static void
294error_exit(int ret, char *msg)
295{
296 fprintf(stderr, "%s: %s\n", pname, msg);
297 exit(ret);
298}
299
DungSagad1d8a592021-11-26 13:59:27 +0000300 static int
301getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000302{
DungSagad1d8a592021-11-26 13:59:27 +0000303 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000304 if (c == EOF && ferror(fpi))
305 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000306 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000307}
308
309 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000310putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000311{
312 if (putc(c, fpo) == EOF)
313 perror_exit(3);
314}
315
316 static void
317fputs_or_die(char *s, FILE *fpo)
318{
319 if (fputs(s, fpo) == EOF)
320 perror_exit(3);
321}
322
DungSaga7e5503c2021-12-01 11:24:52 +0000323/* Use a macro to allow for different arguments. */
324#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000325
326 static void
327fclose_or_die(FILE *fpi, FILE *fpo)
328{
329 if (fclose(fpo) != 0)
330 perror_exit(3);
331 if (fclose(fpi) != 0)
332 perror_exit(2);
333}
334
Bram Moolenaar071d4272004-06-13 20:20:40 +0000335/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000336 * If "c" is a hex digit, return the value.
337 * Otherwise return -1.
338 */
339 static int
340parse_hex_digit(int c)
341{
342 return (c >= '0' && c <= '9') ? c - '0'
343 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
344 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
345 : -1;
346}
347
348/*
tristhaus85f45212023-10-06 19:51:13 +0200349 * If "c" is a bin digit, return the value.
350 * Otherwise return -1.
351 */
352 static int
353parse_bin_digit(int c)
354{
355 return (c >= '0' && c <= '1') ? c - '0'
356 : -1;
357}
358
359/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000360 * Ignore text on "fpi" until end-of-line or end-of-file.
361 * Return the '\n' or EOF character.
362 * When an error is encountered exit with an error message.
363 */
364 static int
365skip_to_eol(FILE *fpi, int c)
366{
367 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000368 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000369 return c;
370}
371
372/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 * Max. cols binary characters are decoded from the input stream per line.
374 * Two adjacent garbage characters after evaluated data delimit valid data.
375 * Everything up to the next newline is discarded.
376 *
377 * The name is historic and came from 'undo type opt h'.
378 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200379 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100380huntype(
381 FILE *fpi,
382 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100383 int cols,
384 int hextype,
385 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200387 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 +0000388 long have_off = 0, want_off = 0;
389
390 rewind(fpi);
391
392 while ((c = getc(fpi)) != EOF)
393 {
394 if (c == '\r') /* Doze style input file? */
395 continue;
396
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100397 /* Allow multiple spaces. This doesn't work when there is normal text
398 * after the hex codes in the last line that looks like hex, thus only
399 * use it for PostScript format. */
400 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000401 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000402
tristhaus85f45212023-10-06 19:51:13 +0200403 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
404 {
405 n3 = n2;
406 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000407
tristhaus85f45212023-10-06 19:51:13 +0200408 n1 = parse_hex_digit(c);
409 if (n1 == -1 && ign_garb)
410 continue;
411 }
412 else /* HEX_BITS */
413 {
414 n1 = parse_hex_digit(c);
415 if (n1 == -1 && ign_garb)
416 continue;
417
418 bt = parse_bin_digit(c);
419 if (bt != -1)
420 {
421 b = ((b << 1) | bt);
422 ++bcnt;
423 }
424 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425
426 ign_garb = 0;
427
tristhaus85f45212023-10-06 19:51:13 +0200428 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 {
tristhaus85f45212023-10-06 19:51:13 +0200430 if (hextype == HEX_NORMAL)
431 {
432 if (n1 < 0)
433 {
434 p = 0;
435 continue;
436 }
437 want_off = (want_off << 4) | n1;
438 }
439 else /* HEX_BITS */
440 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200441 if (n1 < 0)
442 {
443 p = 0;
tristhaus85f45212023-10-06 19:51:13 +0200444 bcnt = 0;
OldWorldOrdr1c140302023-10-25 20:57:30 +0200445 continue;
446 }
447 want_off = (want_off << 4) | n1;
tristhaus85f45212023-10-06 19:51:13 +0200448 }
449 continue;
450 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000451
452 if (base_off + want_off != have_off)
453 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200454 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100455 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000457 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458 have_off = base_off + want_off;
459#endif
460 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000461 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000463 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464 }
465
tristhaus85f45212023-10-06 19:51:13 +0200466 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
467 {
468 if (n2 >= 0 && n1 >= 0)
469 {
470 putc_or_die((n2 << 4) | n1, fpo);
471 have_off++;
472 want_off++;
473 n1 = -1;
474 if (!hextype && (++p >= cols))
475 /* skip the rest of the line as garbage */
476 c = skip_to_eol(fpi, c);
477 }
478 else if (n1 < 0 && n2 < 0 && n3 < 0)
479 /* already stumbled into garbage, skip line, wait and see */
480 c = skip_to_eol(fpi, c);
481 }
482 else /* HEX_BITS */
483 {
484 if (bcnt == 8)
485 {
486 putc_or_die(b, fpo);
487 have_off++;
488 want_off++;
489 b = 0;
490 bcnt = 0;
491 if (++p >= cols)
492 /* skip the rest of the line as garbage */
493 c = skip_to_eol(fpi, c);
494 }
495 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000496
DungSaga47810462021-10-22 12:55:42 +0100497 if (c == '\n')
498 {
tristhaus85f45212023-10-06 19:51:13 +0200499 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100500 want_off = 0;
501 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 ign_garb = 1;
503 }
504 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200505 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100506 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000508 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000510 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 return 0;
512}
513
514/*
515 * Print line l. If nz is false, xxdline regards the line a line of
516 * zeroes. If there are three or more consecutive lines of zeroes,
517 * they are replaced by a single '*' character.
518 *
519 * If the output ends with more than two lines of zeroes, you
520 * should call xxdline again with l being the last line and nz
521 * negative. This ensures that the last line is shown even when
522 * it is all zeroes.
523 *
524 * If nz is always positive, lines are never suppressed.
525 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200526 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100527xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000528{
529 static char z[LLEN+1];
530 static int zero_seen = 0;
531
532 if (!nz && zero_seen == 1)
533 strcpy(z, l);
534
535 if (nz || !zero_seen++)
536 {
537 if (nz)
538 {
539 if (nz < 0)
540 zero_seen--;
541 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000542 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000543 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000544 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 }
546 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000547 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 if (nz)
549 zero_seen = 0;
550 }
551}
552
553/* This is an EBCDIC to ASCII conversion table */
554/* from a proposed BTL standard April 16, 1979 */
555static unsigned char etoa64[] =
556{
557 0040,0240,0241,0242,0243,0244,0245,0246,
558 0247,0250,0325,0056,0074,0050,0053,0174,
559 0046,0251,0252,0253,0254,0255,0256,0257,
560 0260,0261,0041,0044,0052,0051,0073,0176,
561 0055,0057,0262,0263,0264,0265,0266,0267,
562 0270,0271,0313,0054,0045,0137,0076,0077,
563 0272,0273,0274,0275,0276,0277,0300,0301,
564 0302,0140,0072,0043,0100,0047,0075,0042,
565 0303,0141,0142,0143,0144,0145,0146,0147,
566 0150,0151,0304,0305,0306,0307,0310,0311,
567 0312,0152,0153,0154,0155,0156,0157,0160,
568 0161,0162,0136,0314,0315,0316,0317,0320,
569 0321,0345,0163,0164,0165,0166,0167,0170,
570 0171,0172,0322,0323,0324,0133,0326,0327,
571 0330,0331,0332,0333,0334,0335,0336,0337,
572 0340,0341,0342,0343,0344,0135,0346,0347,
573 0173,0101,0102,0103,0104,0105,0106,0107,
574 0110,0111,0350,0351,0352,0353,0354,0355,
575 0175,0112,0113,0114,0115,0116,0117,0120,
576 0121,0122,0356,0357,0360,0361,0362,0363,
577 0134,0237,0123,0124,0125,0126,0127,0130,
578 0131,0132,0364,0365,0366,0367,0370,0371,
579 0060,0061,0062,0063,0064,0065,0066,0067,
580 0070,0071,0372,0373,0374,0375,0376,0377
581};
582
K.Takataf6fc2552023-09-01 18:41:04 +0200583 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200584begin_coloring_char (char *l, int *c, int e, int ebcdic)
585{
586 if (ebcdic)
587 {
588 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
589 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
590 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
591 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
592 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
593 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
594 (e == 173) || (e == 224) )
595 l[(*c)++] = COLOR_GREEN;
596
597 else if (e == 37 || e == 13 || e == 5)
598 l[(*c)++] = COLOR_YELLOW;
599 else if (e == 0)
600 l[(*c)++] = COLOR_WHITE;
601 else if (e == 255)
602 l[(*c)++] = COLOR_BLUE;
603 else
604 l[(*c)++] = COLOR_RED;
605 }
606 else /* ASCII */
607 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000608 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200609 if (e >= 64)
610 l[(*c)++] = COLOR_GREEN;
611 #else
612 if (e > 31 && e < 127)
613 l[(*c)++] = COLOR_GREEN;
614 #endif
615
616 else if (e == 9 || e == 10 || e == 13)
617 l[(*c)++] = COLOR_YELLOW;
618 else if (e == 0)
619 l[(*c)++] = COLOR_WHITE;
620 else if (e == 255)
621 l[(*c)++] = COLOR_BLUE;
622 else
623 l[(*c)++] = COLOR_RED;
624 }
625 l[(*c)++] = 'm';
626}
627
K.Takataf6fc2552023-09-01 18:41:04 +0200628 static int
629enable_color(void)
630{
631#ifdef WIN32
632 DWORD mode;
633 HANDLE out;
634
635 if (!isatty(1))
636 return 0;
637
638 out = GetStdHandle(STD_OUTPUT_HANDLE);
639 GetConsoleMode(out, &mode);
640 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
641 return (int)SetConsoleMode(out, mode);
642#elif defined(UNIX)
643 return isatty(STDOUT_FILENO);
644#else
645 return 0;
646#endif
647}
648
Bram Moolenaare0659a62011-04-01 19:14:40 +0200649 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100650main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651{
652 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200653 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000654 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200655 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000656 int ebcdic = 0;
657 int octspergrp = -1; /* number of octets grouped in output */
658 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100659 long length = -1, n = 0, seekoff = 0;
660 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200661 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200662 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100663 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100664 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200665 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200666 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200667
K.Takataf6fc2552023-09-01 18:41:04 +0200668 no_color = getenv("NO_COLOR");
669 if (no_color == NULL || no_color[0] == '\0')
670 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000671
672#ifdef AMIGA
673 /* This program doesn't work when started from the Workbench */
674 if (argc == 0)
675 exit(1);
676#endif
677
678 pname = argv[0];
679 for (pp = pname; *pp; )
680 if (*pp++ == PATH_SEP)
681 pname = pp;
682#ifdef FILE_SEP
683 for (pp = pname; *pp; pp++)
684 if (*pp == FILE_SEP)
685 {
686 *pp = '\0';
687 break;
688 }
689#endif
690
691 while (argc >= 2)
692 {
693 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
694 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
695 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100696 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000697 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
698 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
699 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200700 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200701 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 else if (!STRNCMP(pp, "-r", 2)) revert++;
703 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
704 else if (!STRNCMP(pp, "-v", 2))
705 {
706 fprintf(stderr, "%s%s\n", version, osver);
707 exit(0);
708 }
709 else if (!STRNCMP(pp, "-c", 2))
710 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100711 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200712 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100713 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000714 {
715 colsgiven = 1;
716 cols = (int)strtol(pp + 2, NULL, 0);
717 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 else
719 {
720 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200721 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000722 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000723 cols = (int)strtol(argv[2], NULL, 0);
724 argv++;
725 argc--;
726 }
727 }
728 else if (!STRNCMP(pp, "-g", 2))
729 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100730 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 octspergrp = (int)strtol(pp + 2, NULL, 0);
732 else
733 {
734 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200735 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 octspergrp = (int)strtol(argv[2], NULL, 0);
737 argv++;
738 argc--;
739 }
740 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100741 else if (!STRNCMP(pp, "-o", 2))
742 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100743 int reloffset = 0;
744 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100745 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100746 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100747 else
748 {
749 if (!argv[2])
750 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100751
752 if (argv[2][0] == '+')
753 reloffset++;
754 if (argv[2][reloffset] == '-')
755 negoffset++;
756
757 if (negoffset)
758 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
759 else
760 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
761
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100762 argv++;
763 argc--;
764 }
765 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766 else if (!STRNCMP(pp, "-s", 2))
767 {
768 relseek = 0;
769 negseek = 0;
770 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
771 {
772#ifdef TRY_SEEK
773 if (pp[2] == '+')
774 relseek++;
775 if (pp[2+relseek] == '-')
776 negseek++;
777#endif
778 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
779 }
780 else
781 {
782 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200783 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784#ifdef TRY_SEEK
785 if (argv[2][0] == '+')
786 relseek++;
787 if (argv[2][relseek] == '-')
788 negseek++;
789#endif
790 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
791 argv++;
792 argc--;
793 }
794 }
795 else if (!STRNCMP(pp, "-l", 2))
796 {
797 if (pp[2] && STRNCMP("en", pp + 2, 2))
798 length = strtol(pp + 2, (char **)NULL, 0);
799 else
800 {
801 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200802 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 length = strtol(argv[2], (char **)NULL, 0);
804 argv++;
805 argc--;
806 }
807 }
David Gow83e11802022-06-29 20:24:49 +0100808 else if (!STRNCMP(pp, "-n", 2))
809 {
810 if (pp[2] && STRNCMP("ame", pp + 2, 3))
811 varname = pp + 2;
812 else
813 {
814 if (!argv[2])
815 exit_with_usage();
816 varname = argv[2];
817 argv++;
818 argc--;
819 }
820 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200821 else if (!STRNCMP(pp, "-R", 2))
822 {
K.Takataf6fc2552023-09-01 18:41:04 +0200823 char *pw = pp + 2;
824 if (!pw[0])
825 {
826 pw = argv[2];
827 argv++;
828 argc--;
829 }
830 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200831 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200832 if (!STRNCMP(pw, "always", 6))
833 {
834 (void)enable_color();
835 color = 1;
836 }
837 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200838 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200839 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200840 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200841 else
842 exit_with_usage();
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200843 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000844 else if (!strcmp(pp, "--")) /* end of options */
845 {
846 argv++;
847 argc--;
848 break;
849 }
850 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200851 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 else
853 break; /* not an option */
854
855 argv++; /* advance to next argument */
856 argc--;
857 }
858
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000859 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 switch (hextype)
861 {
862 case HEX_POSTSCRIPT: cols = 30; break;
863 case HEX_CINCLUDE: cols = 12; break;
864 case HEX_BITS: cols = 6; break;
865 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100866 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 default: cols = 16; break;
868 }
869
870 if (octspergrp < 0)
871 switch (hextype)
872 {
873 case HEX_BITS: octspergrp = 1; break;
874 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100875 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 case HEX_POSTSCRIPT:
877 case HEX_CINCLUDE:
878 default: octspergrp = 0; break;
879 }
880
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000881 if ((hextype == HEX_POSTSCRIPT && cols < 0) ||
882 (hextype != HEX_POSTSCRIPT && cols < 1) ||
883 ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000884 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 {
886 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
887 exit(1);
888 }
889
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100890 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000891 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100892 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100893 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000894
895 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200896 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000897
898 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
899 BIN_ASSIGN(fp = stdin, !revert);
900 else
901 {
902 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
903 {
904 fprintf(stderr,"%s: ", pname);
905 perror(argv[1]);
906 return 2;
907 }
908 }
909
910 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
911 BIN_ASSIGN(fpo = stdout, revert);
912 else
913 {
914 int fd;
915 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
916
917 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
918 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
919 {
920 fprintf(stderr, "%s: ", pname);
921 perror(argv[2]);
922 return 3;
923 }
924 rewind(fpo);
925 }
Igor Todorovski48a75f32024-01-09 21:05:48 +0000926#ifdef __MVS__
927 // Disable auto-conversion on input file descriptors
928 __disableautocvt(fileno(fp));
929#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000930
931 if (revert)
tristhaus85f45212023-10-06 19:51:13 +0200932 switch (hextype)
933 {
934 case HEX_NORMAL:
935 case HEX_POSTSCRIPT:
936 case HEX_BITS:
937 return huntype(fp, fpo, cols, hextype,
938 negseek ? -seekoff : seekoff);
939 break;
940 default:
941 error_exit(-1, "Sorry, cannot revert this type of hexdump");
942 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000943
944 if (seekoff || negseek || !relseek)
945 {
946#ifdef TRY_SEEK
947 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000948 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000949 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000950 e = fseek(fp, negseek ? -seekoff : seekoff,
951 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000952 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000953 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954 if (e >= 0)
955 seekoff = ftell(fp);
956 else
957#endif
958 {
959 long s = seekoff;
960
961 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000962 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200963 {
DungSaga7e5503c2021-12-01 11:24:52 +0000964 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200965 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000966 }
967 }
968
969 if (hextype == HEX_CINCLUDE)
970 {
David Gow83e11802022-06-29 20:24:49 +0100971 /* A user-set variable name overrides fp == stdin */
972 if (varname == NULL && fp != stdin)
973 varname = argv[1];
974
975 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000976 {
Keith Thompson184f71c2024-01-04 21:19:04 +0100977 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100978 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100979 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000980 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981 }
982
983 p = 0;
DungSagad1d8a592021-11-26 13:59:27 +0000984 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000985 {
DungSaga7e5503c2021-12-01 11:24:52 +0000986 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
987 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000988 p++;
989 }
990
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000991 if (p)
992 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000993
David Gow83e11802022-06-29 20:24:49 +0100994 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000995 {
DungSagad1d8a592021-11-26 13:59:27 +0000996 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +0100997 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100998 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100999 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001000 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001001 }
1002
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001003 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001004 return 0;
1005 }
1006
1007 if (hextype == HEX_POSTSCRIPT)
1008 {
1009 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +00001010 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001011 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001012 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1013 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001014 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001015 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001016 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001017 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018 p = cols;
1019 }
1020 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001021 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001022 putc_or_die('\n', fpo);
1023 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024 return 0;
1025 }
1026
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001027 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001028
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001029 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001030 {
1031 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1032 if (color)
1033 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
1034 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001035 else /* hextype == HEX_BITS */
1036 grplen = 8 * octspergrp + 1;
1037
DungSagad1d8a592021-11-26 13:59:27 +00001038 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001039 {
1040 if (p == 0)
1041 {
DungSaga581f41a2021-11-22 11:57:31 +00001042 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001043 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001044 for (c = addrlen; c < LLEN; l[c++] = ' ')
1045 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 }
DungSaga48608b42021-11-24 11:18:07 +00001047 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1048 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001049 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001050 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001051 if (color)
1052 {
1053 COLOR_PROLOGUE
1054 begin_coloring_char(l,&c,e,ebcdic);
1055 l[c++] = hexx[(e >> 4) & 0xf];
1056 l[c++] = hexx[e & 0xf];
1057 COLOR_EPILOGUE
1058 }
1059 else /*No colors*/
1060 {
1061 l[c] = hexx[(e >> 4) & 0xf];
1062 l[++c] = hexx[e & 0xf];
1063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 }
1065 else /* hextype == HEX_BITS */
1066 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001068 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001069 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001070 if (e)
1071 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001072 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001073 if (hextype == HEX_LITTLEENDIAN)
1074 /* last group will be fully used, round up */
1075 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1076 else
1077 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001078
1079 if (color)
1080 {
1081 if (hextype == HEX_BITS)
1082 c += addrlen + 3 + p*12;
1083 else
1084 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
1085
1086 if (hextype == HEX_LITTLEENDIAN)
1087 c += 1;
1088
1089 COLOR_PROLOGUE
1090 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001091#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001092 if (e >= 64)
1093 l[c++] = e;
1094 else
1095 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096#else
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001097 if (ebcdic)
1098 e = (e < 64) ? '.' : etoa64[e-64];
1099 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001100#endif
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001101 COLOR_EPILOGUE
1102 n++;
1103 if (++p == cols)
1104 {
1105 l[c++] = '\n';
1106 l[c++] = '\0';
1107 xxdline(fpo, l, autoskip ? nonzero : 1);
1108 nonzero = 0;
1109 p = 0;
1110 }
1111 }
1112 else /*no colors*/
1113 {
1114 if (ebcdic)
1115 e = (e < 64) ? '.' : etoa64[e-64];
1116
1117 c += addrlen + 3 + p;
1118 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001119#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001120 (e >= 64)
1121#else
1122 (e > 31 && e < 127)
1123#endif
1124 ? e : '.';
1125 n++;
1126 if (++p == cols)
1127 {
1128 l[c++] = '\n';
1129 l[c] = '\0';
1130 xxdline(fpo, l, autoskip ? nonzero : 1);
1131 nonzero = 0;
1132 p = 0;
1133 }
1134 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001135 }
1136 if (p)
1137 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001138 l[c++] = '\n';
1139 l[c] = '\0';
1140 if (color)
1141 {
1142 c++;
1143
1144 x = p;
1145 if (hextype == HEX_LITTLEENDIAN)
1146 {
1147 int fill = octspergrp - (p % octspergrp);
1148 if (fill == octspergrp) fill = 0;
1149
1150 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
1151
1152 for (i = 0; i < fill;i++)
1153 {
1154 COLOR_PROLOGUE
1155 l[c++] = COLOR_RED;
1156 l[c++] = 'm';
1157 l[c++] = ' '; /* empty space */
1158 COLOR_EPILOGUE
1159 x++;
1160 p++;
1161 }
1162 }
1163
1164 if (hextype != HEX_BITS)
1165 {
1166 c = addrlen + 1 + (grplen * x) / octspergrp;
1167 c += cols - p;
1168 c += (cols - p) / octspergrp;
1169
1170 for (i = cols - p; i > 0;i--)
1171 {
1172 COLOR_PROLOGUE
1173 l[c++] = COLOR_RED;
1174 l[c++] = 'm';
1175 l[c++] = ' '; /* empty space */
1176 COLOR_EPILOGUE
1177 }
1178 }
1179 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001180 xxdline(fpo, l, 1);
1181 }
1182 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001183 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001184
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001185 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001186 return 0;
1187}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001188
1189/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */