blob: c222885455f12d145b30efb8b7f63d42df8fbf1d [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
Bram Moolenaar4b96df52020-01-26 22:00:26 +010038 * 18.07.96 gcc -Wall @ SunOS4 is now silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +000039 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaard8c56a02019-01-30 23:02:25 +010055 * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
Bram Moolenaar363d6142020-05-30 20:50:25 +020056 * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen
Erik Auerswaldc0a1d372022-01-14 11:58:48 +000057 * 14.01.2022 Disable extra newlines with -c0 -p by Erik Auerswald.
David Gow83e11802022-06-29 20:24:49 +010058 * 20.06.2022 Permit setting the variable names used by -i by David Gow
Christian Brabandt0ffa97e2023-08-31 21:03:02 +020059 * 31.08.2023 -R never/auto/always prints colored output
tristhaus85f45212023-10-06 19:51:13 +020060 * 06.10.2023 enable -r -b to reverse bit dumps
Igor Todorovski48a75f32024-01-09 21:05:48 +000061 * 12.01.2024 disable auto-conversion for z/OS (MVS)
Kuratius7062be12024-01-17 18:37:32 +010062 * 17.01.2024 use size_t instead of usigned int for code-generation (-i), #13876
Christian Brabandtfa8c9712024-01-25 20:50:49 +010063 * 25.01.2024 revert the previous patch (size_t instead of unsigned int)
Goffredo Baroncelli00221482024-02-10 13:31:06 +010064 * 10.02.2024 fix buffer-overflow when writing color output to buffer, #14003
Lennard Hofmann67797192024-05-10 14:17:26 +020065 * 10.05.2024 fix another buffer-overflow when writing colored output to buffer, #14738
Andre Chang15022722024-09-15 20:03:05 +020066 * 10.09.2024 Support -b and -i together, #15661
Aapo Rantalainenc73fc862024-10-19 15:54:57 +020067 * 19.10.2024 -e did add an extra space #15899
DungSaga4b9fa952024-11-11 22:19:50 +010068 * 11.11.2024 improve end-of-options argument parser #9285
Bram Moolenaar071d4272004-06-13 20:20:40 +000069 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020070 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000071 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020072 * I hereby grant permission to distribute and use xxd
73 * under X11-MIT or GPL-2.0 (at the user's choice).
74 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020075 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000076 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000077
78/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
79#if _MSC_VER >= 1400
80# define _CRT_SECURE_NO_DEPRECATE
81# define _CRT_NONSTDC_NO_DEPRECATE
82#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010083#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000084# define CYGWIN
85#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000086
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000087#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
88# define _XOPEN_SOURCE 700 /* for fdopen() */
89#endif
90
Bram Moolenaar071d4272004-06-13 20:20:40 +000091#include <stdio.h>
92#ifdef VAXC
93# include <file.h>
94#else
95# include <fcntl.h>
96#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020097#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000098# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +020099#endif
100#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +0200101# include <windows.h>
102#endif
103#ifdef UNIX
104# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000105#endif
106#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100107#include <string.h>
108#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100109#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000110#if __MWERKS__ && !defined(BEBOX)
111# include <unix.h> /* for fdopen() on MAC */
112#endif
113
Bram Moolenaar071d4272004-06-13 20:20:40 +0000114
115/* This corrects the problem of missing prototypes for certain functions
116 * in some GNU installations (e.g. SunOS 4.1.x).
117 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
118 */
119#if defined(__GNUC__) && defined(__STDC__)
120# ifndef __USE_FIXED_PROTOTYPES__
121# define __USE_FIXED_PROTOTYPES__
122# endif
123#endif
124
125#ifndef __USE_FIXED_PROTOTYPES__
126/*
127 * This is historic and works only if the compiler really has no prototypes:
128 *
129 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
130 * FILE is defined on OS 4.x, not on 5.x (Solaris).
131 * if __SVR4 is defined (some Solaris versions), don't include this.
132 */
133#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
134# define __P(a) a
135/* excerpt from my sun_stdlib.h */
136extern int fprintf __P((FILE *, char *, ...));
137extern int fputs __P((char *, FILE *));
138extern int _flsbuf __P((unsigned char, FILE *));
139extern int _filbuf __P((FILE *));
140extern int fflush __P((FILE *));
141extern int fclose __P((FILE *));
142extern int fseek __P((FILE *, long, int));
143extern int rewind __P((FILE *));
144
145extern void perror __P((char *));
146# endif
147#endif
148
DungSaga4b9fa952024-11-11 22:19:50 +0100149char version[] = "xxd 2024-11-11 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000150#ifdef WIN32
151char osver[] = " (Win32)";
152#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000154#endif
155
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200156#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157# define BIN_READ(yes) ((yes) ? "rb" : "rt")
158# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
159# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
160# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000161# define PATH_SEP '\\'
162#elif defined(CYGWIN)
163# define BIN_READ(yes) ((yes) ? "rb" : "rt")
164# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
165# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
166# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
167# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000168#else
169# ifdef VMS
170# define BIN_READ(dummy) "r"
171# define BIN_WRITE(dummy) "w"
172# define BIN_CREAT(dummy) O_CREAT
173# define BIN_ASSIGN(fp, dummy) fp
174# define PATH_SEP ']'
175# define FILE_SEP '.'
176# else
177# define BIN_READ(dummy) "r"
178# define BIN_WRITE(dummy) "w"
179# define BIN_CREAT(dummy) O_CREAT
180# define BIN_ASSIGN(fp, dummy) fp
181# define PATH_SEP '/'
182# endif
183#endif
184
185/* open has only to arguments on the Mac */
186#if __MWERKS__
187# define OPEN(name, mode, umask) open(name, mode)
188#else
189# define OPEN(name, mode, umask) open(name, mode, umask)
190#endif
191
192#ifdef AMIGA
193# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
194#else
195# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
196#endif
197
198#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200199# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200# define __P(a) a
201# else
202# define __P(a) ()
203# endif
204#endif
205
Bram Moolenaar071d4272004-06-13 20:20:40 +0000206#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
207#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100208
209/*
210 * LLEN is the maximum length of a line; other than the visible characters
211 * we need to consider also the escape color sequence prologue/epilogue ,
Lennard Hofmann67797192024-05-10 14:17:26 +0200212 * (11 bytes for each character).
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100213 */
Lennard Hofmann67797192024-05-10 14:17:26 +0200214#define LLEN \
215 (39 /* addr: ⌈log10(ULONG_MAX)⌉ if "-d" flag given. We assume ULONG_MAX = 2**128 */ \
216 + 2 /* ": " */ \
217 + 13 * COLS /* hex dump with colors */ \
218 + (COLS - 1) /* whitespace between groups if "-g1" option given and "-c" maxed out */ \
219 + 2 /* whitespace */ \
220 + 12 * COLS /* ASCII dump with colors */ \
221 + 2) /* "\n\0" */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222
223char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
224
225/* the different hextypes known by this program: */
Andre Chang15022722024-09-15 20:03:05 +0200226#define HEX_NORMAL 0x00 /* no flags set */
227#define HEX_POSTSCRIPT 0x01
228#define HEX_CINCLUDE 0x02
229#define HEX_BITS 0x04 /* not hex a dump, but bits: 01111001 */
230#define HEX_LITTLEENDIAN 0x08
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231
Keith Thompson184f71c2024-01-04 21:19:04 +0100232#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200233
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200234#define COLOR_PROLOGUE \
235l[c++] = '\033'; \
236l[c++] = '['; \
237l[c++] = '1'; \
238l[c++] = ';'; \
239l[c++] = '3';
240
241#define COLOR_EPILOGUE \
242l[c++] = '\033'; \
243l[c++] = '['; \
244l[c++] = '0'; \
245l[c++] = 'm';
246#define COLOR_RED '1'
247#define COLOR_GREEN '2'
248#define COLOR_YELLOW '3'
249#define COLOR_BLUE '4'
250#define COLOR_WHITE '7'
251
Bram Moolenaare0659a62011-04-01 19:14:40 +0200252static char *pname;
253
254 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100255exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000256{
257 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
258 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
259 fprintf(stderr, "Options:\n");
260 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Andre Chang15022722024-09-15 20:03:05 +0200261 fprintf(stderr, " -b binary digit dump (incompatible with -ps). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200262 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
264 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100265 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100266 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000267 fprintf(stderr, " -h print this summary.\n");
268 fprintf(stderr, " -i output in C include file style.\n");
269 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100270 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100271 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
273 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
274 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200275 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
277#ifdef TRY_SEEK
278 "[+][-]", "(or +: rel.) ");
279#else
280 "", "");
281#endif
282 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200283 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
285 exit(1);
286}
287
Bram Moolenaare0659a62011-04-01 19:14:40 +0200288 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100289perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200290{
291 fprintf(stderr, "%s: ", pname);
292 perror(NULL);
293 exit(ret);
294}
295
DungSagaa2ffb432021-10-22 15:55:31 +0100296 static void
297error_exit(int ret, char *msg)
298{
299 fprintf(stderr, "%s: %s\n", pname, msg);
300 exit(ret);
301}
302
DungSagad1d8a592021-11-26 13:59:27 +0000303 static int
304getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000305{
DungSagad1d8a592021-11-26 13:59:27 +0000306 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000307 if (c == EOF && ferror(fpi))
308 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000309 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000310}
311
312 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000313putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000314{
315 if (putc(c, fpo) == EOF)
316 perror_exit(3);
317}
318
319 static void
320fputs_or_die(char *s, FILE *fpo)
321{
322 if (fputs(s, fpo) == EOF)
323 perror_exit(3);
324}
325
DungSaga7e5503c2021-12-01 11:24:52 +0000326/* Use a macro to allow for different arguments. */
327#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000328
329 static void
330fclose_or_die(FILE *fpi, FILE *fpo)
331{
332 if (fclose(fpo) != 0)
333 perror_exit(3);
334 if (fclose(fpi) != 0)
335 perror_exit(2);
336}
337
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000339 * If "c" is a hex digit, return the value.
340 * Otherwise return -1.
341 */
342 static int
343parse_hex_digit(int c)
344{
345 return (c >= '0' && c <= '9') ? c - '0'
346 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
347 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
348 : -1;
349}
350
351/*
tristhaus85f45212023-10-06 19:51:13 +0200352 * If "c" is a bin digit, return the value.
353 * Otherwise return -1.
354 */
355 static int
356parse_bin_digit(int c)
357{
358 return (c >= '0' && c <= '1') ? c - '0'
359 : -1;
360}
361
362/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000363 * Ignore text on "fpi" until end-of-line or end-of-file.
364 * Return the '\n' or EOF character.
365 * When an error is encountered exit with an error message.
366 */
367 static int
368skip_to_eol(FILE *fpi, int c)
369{
370 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000371 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000372 return c;
373}
374
375/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 * Max. cols binary characters are decoded from the input stream per line.
377 * Two adjacent garbage characters after evaluated data delimit valid data.
378 * Everything up to the next newline is discarded.
379 *
380 * The name is historic and came from 'undo type opt h'.
381 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200382 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100383huntype(
384 FILE *fpi,
385 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100386 int cols,
387 int hextype,
388 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200390 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 +0000391 long have_off = 0, want_off = 0;
392
393 rewind(fpi);
394
395 while ((c = getc(fpi)) != EOF)
396 {
397 if (c == '\r') /* Doze style input file? */
398 continue;
399
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100400 /* Allow multiple spaces. This doesn't work when there is normal text
401 * after the hex codes in the last line that looks like hex, thus only
402 * use it for PostScript format. */
403 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000404 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000405
tristhaus85f45212023-10-06 19:51:13 +0200406 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
407 {
408 n3 = n2;
409 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410
tristhaus85f45212023-10-06 19:51:13 +0200411 n1 = parse_hex_digit(c);
412 if (n1 == -1 && ign_garb)
413 continue;
414 }
415 else /* HEX_BITS */
416 {
417 n1 = parse_hex_digit(c);
418 if (n1 == -1 && ign_garb)
419 continue;
420
421 bt = parse_bin_digit(c);
422 if (bt != -1)
423 {
424 b = ((b << 1) | bt);
425 ++bcnt;
426 }
427 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428
429 ign_garb = 0;
430
tristhaus85f45212023-10-06 19:51:13 +0200431 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 {
tristhaus85f45212023-10-06 19:51:13 +0200433 if (hextype == HEX_NORMAL)
434 {
435 if (n1 < 0)
436 {
437 p = 0;
438 continue;
439 }
440 want_off = (want_off << 4) | n1;
441 }
442 else /* HEX_BITS */
443 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200444 if (n1 < 0)
445 {
446 p = 0;
tristhaus85f45212023-10-06 19:51:13 +0200447 bcnt = 0;
OldWorldOrdr1c140302023-10-25 20:57:30 +0200448 continue;
449 }
450 want_off = (want_off << 4) | n1;
tristhaus85f45212023-10-06 19:51:13 +0200451 }
452 continue;
453 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000454
455 if (base_off + want_off != have_off)
456 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200457 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100458 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000460 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461 have_off = base_off + want_off;
462#endif
463 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000464 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000466 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467 }
468
tristhaus85f45212023-10-06 19:51:13 +0200469 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
470 {
471 if (n2 >= 0 && n1 >= 0)
472 {
473 putc_or_die((n2 << 4) | n1, fpo);
474 have_off++;
475 want_off++;
476 n1 = -1;
477 if (!hextype && (++p >= cols))
478 /* skip the rest of the line as garbage */
479 c = skip_to_eol(fpi, c);
480 }
481 else if (n1 < 0 && n2 < 0 && n3 < 0)
482 /* already stumbled into garbage, skip line, wait and see */
483 c = skip_to_eol(fpi, c);
484 }
485 else /* HEX_BITS */
486 {
487 if (bcnt == 8)
488 {
489 putc_or_die(b, fpo);
490 have_off++;
491 want_off++;
492 b = 0;
493 bcnt = 0;
494 if (++p >= cols)
495 /* skip the rest of the line as garbage */
496 c = skip_to_eol(fpi, c);
497 }
498 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000499
DungSaga47810462021-10-22 12:55:42 +0100500 if (c == '\n')
501 {
tristhaus85f45212023-10-06 19:51:13 +0200502 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100503 want_off = 0;
504 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 ign_garb = 1;
506 }
507 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200508 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100509 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000510#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000511 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000512#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000513 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514 return 0;
515}
516
517/*
518 * Print line l. If nz is false, xxdline regards the line a line of
519 * zeroes. If there are three or more consecutive lines of zeroes,
520 * they are replaced by a single '*' character.
521 *
522 * If the output ends with more than two lines of zeroes, you
523 * should call xxdline again with l being the last line and nz
524 * negative. This ensures that the last line is shown even when
525 * it is all zeroes.
526 *
527 * If nz is always positive, lines are never suppressed.
528 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200529 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100530xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531{
532 static char z[LLEN+1];
533 static int zero_seen = 0;
534
535 if (!nz && zero_seen == 1)
536 strcpy(z, l);
537
538 if (nz || !zero_seen++)
539 {
540 if (nz)
541 {
542 if (nz < 0)
543 zero_seen--;
544 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000545 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000546 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000547 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 }
549 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000550 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 if (nz)
552 zero_seen = 0;
553 }
554}
555
556/* This is an EBCDIC to ASCII conversion table */
557/* from a proposed BTL standard April 16, 1979 */
558static unsigned char etoa64[] =
559{
560 0040,0240,0241,0242,0243,0244,0245,0246,
561 0247,0250,0325,0056,0074,0050,0053,0174,
562 0046,0251,0252,0253,0254,0255,0256,0257,
563 0260,0261,0041,0044,0052,0051,0073,0176,
564 0055,0057,0262,0263,0264,0265,0266,0267,
565 0270,0271,0313,0054,0045,0137,0076,0077,
566 0272,0273,0274,0275,0276,0277,0300,0301,
567 0302,0140,0072,0043,0100,0047,0075,0042,
568 0303,0141,0142,0143,0144,0145,0146,0147,
569 0150,0151,0304,0305,0306,0307,0310,0311,
570 0312,0152,0153,0154,0155,0156,0157,0160,
571 0161,0162,0136,0314,0315,0316,0317,0320,
572 0321,0345,0163,0164,0165,0166,0167,0170,
573 0171,0172,0322,0323,0324,0133,0326,0327,
574 0330,0331,0332,0333,0334,0335,0336,0337,
575 0340,0341,0342,0343,0344,0135,0346,0347,
576 0173,0101,0102,0103,0104,0105,0106,0107,
577 0110,0111,0350,0351,0352,0353,0354,0355,
578 0175,0112,0113,0114,0115,0116,0117,0120,
579 0121,0122,0356,0357,0360,0361,0362,0363,
580 0134,0237,0123,0124,0125,0126,0127,0130,
581 0131,0132,0364,0365,0366,0367,0370,0371,
582 0060,0061,0062,0063,0064,0065,0066,0067,
583 0070,0071,0372,0373,0374,0375,0376,0377
584};
585
K.Takataf6fc2552023-09-01 18:41:04 +0200586 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200587begin_coloring_char (char *l, int *c, int e, int ebcdic)
588{
589 if (ebcdic)
590 {
591 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
592 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
593 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
594 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
595 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
596 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
597 (e == 173) || (e == 224) )
598 l[(*c)++] = COLOR_GREEN;
599
600 else if (e == 37 || e == 13 || e == 5)
601 l[(*c)++] = COLOR_YELLOW;
602 else if (e == 0)
603 l[(*c)++] = COLOR_WHITE;
604 else if (e == 255)
605 l[(*c)++] = COLOR_BLUE;
606 else
607 l[(*c)++] = COLOR_RED;
608 }
609 else /* ASCII */
610 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000611 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200612 if (e >= 64)
613 l[(*c)++] = COLOR_GREEN;
614 #else
615 if (e > 31 && e < 127)
616 l[(*c)++] = COLOR_GREEN;
617 #endif
618
619 else if (e == 9 || e == 10 || e == 13)
620 l[(*c)++] = COLOR_YELLOW;
621 else if (e == 0)
622 l[(*c)++] = COLOR_WHITE;
623 else if (e == 255)
624 l[(*c)++] = COLOR_BLUE;
625 else
626 l[(*c)++] = COLOR_RED;
627 }
628 l[(*c)++] = 'm';
629}
630
K.Takataf6fc2552023-09-01 18:41:04 +0200631 static int
632enable_color(void)
633{
634#ifdef WIN32
635 DWORD mode;
636 HANDLE out;
637
638 if (!isatty(1))
639 return 0;
640
641 out = GetStdHandle(STD_OUTPUT_HANDLE);
642 GetConsoleMode(out, &mode);
643 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
644 return (int)SetConsoleMode(out, mode);
645#elif defined(UNIX)
646 return isatty(STDOUT_FILENO);
647#else
648 return 0;
649#endif
650}
651
Bram Moolenaare0659a62011-04-01 19:14:40 +0200652 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100653main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654{
655 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200656 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000657 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200658 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659 int ebcdic = 0;
660 int octspergrp = -1; /* number of octets grouped in output */
661 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100662 long length = -1, n = 0, seekoff = 0;
663 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200664 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200665 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100666 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100667 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200668 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200669 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200670
K.Takataf6fc2552023-09-01 18:41:04 +0200671 no_color = getenv("NO_COLOR");
672 if (no_color == NULL || no_color[0] == '\0')
673 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000674
675#ifdef AMIGA
676 /* This program doesn't work when started from the Workbench */
677 if (argc == 0)
678 exit(1);
679#endif
680
681 pname = argv[0];
682 for (pp = pname; *pp; )
683 if (*pp++ == PATH_SEP)
684 pname = pp;
685#ifdef FILE_SEP
686 for (pp = pname; *pp; pp++)
687 if (*pp == FILE_SEP)
688 {
689 *pp = '\0';
690 break;
691 }
692#endif
693
694 while (argc >= 2)
695 {
696 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
697 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
Andre Chang15022722024-09-15 20:03:05 +0200698 else if (!STRNCMP(pp, "-b", 2)) hextype |= HEX_BITS;
699 else if (!STRNCMP(pp, "-e", 2)) hextype |= HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
Andre Chang15022722024-09-15 20:03:05 +0200701 else if (!STRNCMP(pp, "-p", 2)) hextype |= HEX_POSTSCRIPT;
702 else if (!STRNCMP(pp, "-i", 2)) hextype |= HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200703 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200704 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000705 else if (!STRNCMP(pp, "-r", 2)) revert++;
706 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
707 else if (!STRNCMP(pp, "-v", 2))
708 {
709 fprintf(stderr, "%s%s\n", version, osver);
710 exit(0);
711 }
712 else if (!STRNCMP(pp, "-c", 2))
713 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100714 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200715 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100716 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000717 {
718 colsgiven = 1;
719 cols = (int)strtol(pp + 2, NULL, 0);
720 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 else
722 {
723 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200724 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000725 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000726 cols = (int)strtol(argv[2], NULL, 0);
727 argv++;
728 argc--;
729 }
730 }
731 else if (!STRNCMP(pp, "-g", 2))
732 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100733 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 octspergrp = (int)strtol(pp + 2, NULL, 0);
735 else
736 {
737 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 octspergrp = (int)strtol(argv[2], NULL, 0);
740 argv++;
741 argc--;
742 }
743 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100744 else if (!STRNCMP(pp, "-o", 2))
745 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100746 int reloffset = 0;
747 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100748 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100749 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100750 else
751 {
752 if (!argv[2])
753 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100754
755 if (argv[2][0] == '+')
756 reloffset++;
757 if (argv[2][reloffset] == '-')
758 negoffset++;
759
760 if (negoffset)
761 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
762 else
763 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
764
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100765 argv++;
766 argc--;
767 }
768 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 else if (!STRNCMP(pp, "-s", 2))
770 {
771 relseek = 0;
772 negseek = 0;
773 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
774 {
775#ifdef TRY_SEEK
776 if (pp[2] == '+')
777 relseek++;
778 if (pp[2+relseek] == '-')
779 negseek++;
780#endif
781 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
782 }
783 else
784 {
785 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200786 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787#ifdef TRY_SEEK
788 if (argv[2][0] == '+')
789 relseek++;
790 if (argv[2][relseek] == '-')
791 negseek++;
792#endif
793 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
794 argv++;
795 argc--;
796 }
797 }
798 else if (!STRNCMP(pp, "-l", 2))
799 {
800 if (pp[2] && STRNCMP("en", pp + 2, 2))
801 length = strtol(pp + 2, (char **)NULL, 0);
802 else
803 {
804 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200805 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 length = strtol(argv[2], (char **)NULL, 0);
807 argv++;
808 argc--;
809 }
810 }
David Gow83e11802022-06-29 20:24:49 +0100811 else if (!STRNCMP(pp, "-n", 2))
812 {
813 if (pp[2] && STRNCMP("ame", pp + 2, 3))
814 varname = pp + 2;
815 else
816 {
817 if (!argv[2])
818 exit_with_usage();
819 varname = argv[2];
820 argv++;
821 argc--;
822 }
823 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200824 else if (!STRNCMP(pp, "-R", 2))
825 {
K.Takataf6fc2552023-09-01 18:41:04 +0200826 char *pw = pp + 2;
827 if (!pw[0])
828 {
829 pw = argv[2];
830 argv++;
831 argc--;
832 }
833 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200834 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200835 if (!STRNCMP(pw, "always", 6))
836 {
837 (void)enable_color();
838 color = 1;
839 }
840 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200841 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200842 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200843 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200844 else
845 exit_with_usage();
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200846 }
DungSaga4b9fa952024-11-11 22:19:50 +0100847 else if (!strcmp(argv[1], "--")) /* end of options */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 {
849 argv++;
850 argc--;
851 break;
852 }
853 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200854 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000855 else
856 break; /* not an option */
857
858 argv++; /* advance to next argument */
859 argc--;
860 }
861
Andre Chang15022722024-09-15 20:03:05 +0200862 if (hextype != (HEX_CINCLUDE | HEX_BITS))
863 {
864 /* Allow at most one bit to be set in hextype */
865 if (hextype & (hextype - 1))
866 error_exit(1, "only one of -b, -e, -u, -p, -i can be used");
867 }
868
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000869 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 switch (hextype)
871 {
872 case HEX_POSTSCRIPT: cols = 30; break;
873 case HEX_CINCLUDE: cols = 12; break;
Andre Chang15022722024-09-15 20:03:05 +0200874 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 case HEX_BITS: cols = 6; break;
876 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100877 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 default: cols = 16; break;
879 }
880
881 if (octspergrp < 0)
882 switch (hextype)
883 {
Andre Chang15022722024-09-15 20:03:05 +0200884 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 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
Andre Chang15022722024-09-15 20:03:05 +0200981 if (hextype & HEX_CINCLUDE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000982 {
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)
Andre Chang15022722024-09-15 20:03:05 +0200997 {
998 if (hextype & HEX_BITS)
999 {
1000 if (p == 0)
1001 fputs_or_die(" ", fpo);
1002 else if (p % cols == 0)
1003 fputs_or_die(",\n ", fpo);
1004 else
1005 fputs_or_die(", ", fpo);
1006
1007 FPRINTF_OR_DIE((fpo, "0b"));
1008 for (int j = 7; j >= 0; j--)
1009 putc_or_die((c & (1 << j)) ? '1' : '0', fpo);
1010 p++;
1011 }
1012 else
1013 {
1014 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
DungSaga7e5503c2021-12-01 11:24:52 +00001015 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Andre Chang15022722024-09-15 20:03:05 +02001016 p++;
1017 }
1018 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001019
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001020 if (p)
1021 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001022
David Gow83e11802022-06-29 20:24:49 +01001023 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001024 {
DungSagad1d8a592021-11-26 13:59:27 +00001025 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +01001026 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +01001027 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +01001028 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001029 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001030 }
1031
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001032 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001033 return 0;
1034 }
1035
1036 if (hextype == HEX_POSTSCRIPT)
1037 {
1038 p = cols;
DungSagad1d8a592021-11-26 13:59:27 +00001039 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001040 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001041 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1042 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001043 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001044 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001045 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001046 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001047 p = cols;
1048 }
1049 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001050 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001051 putc_or_die('\n', fpo);
1052 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001053 return 0;
1054 }
1055
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001056 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001058 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001059 {
1060 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1061 if (color)
1062 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
1063 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001064 else /* hextype == HEX_BITS */
1065 grplen = 8 * octspergrp + 1;
1066
DungSagad1d8a592021-11-26 13:59:27 +00001067 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001068 {
1069 if (p == 0)
1070 {
DungSaga581f41a2021-11-22 11:57:31 +00001071 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001072 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001073 for (c = addrlen; c < LLEN; l[c++] = ' ')
1074 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001075 }
DungSaga48608b42021-11-24 11:18:07 +00001076 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1077 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001078 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001079 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001080 if (color)
1081 {
1082 COLOR_PROLOGUE
1083 begin_coloring_char(l,&c,e,ebcdic);
1084 l[c++] = hexx[(e >> 4) & 0xf];
1085 l[c++] = hexx[e & 0xf];
1086 COLOR_EPILOGUE
1087 }
1088 else /*No colors*/
1089 {
1090 l[c] = hexx[(e >> 4) & 0xf];
1091 l[++c] = hexx[e & 0xf];
1092 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001093 }
1094 else /* hextype == HEX_BITS */
1095 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001096 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001097 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001098 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001099 if (e)
1100 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001101 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001102 if (hextype == HEX_LITTLEENDIAN)
1103 /* last group will be fully used, round up */
1104 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1105 else
1106 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001107
1108 if (color)
1109 {
1110 if (hextype == HEX_BITS)
1111 c += addrlen + 3 + p*12;
1112 else
1113 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
1114
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001115 COLOR_PROLOGUE
1116 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001117#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001118 if (e >= 64)
1119 l[c++] = e;
1120 else
1121 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001122#else
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001123 if (ebcdic)
1124 e = (e < 64) ? '.' : etoa64[e-64];
1125 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001126#endif
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001127 COLOR_EPILOGUE
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001128 }
1129 else /*no colors*/
1130 {
1131 if (ebcdic)
1132 e = (e < 64) ? '.' : etoa64[e-64];
1133
Aapo Rantalainenc73fc862024-10-19 15:54:57 +02001134 if (hextype == HEX_LITTLEENDIAN)
1135 c -= 1;
1136
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001137 c += addrlen + 3 + p;
1138 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001139#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001140 (e >= 64)
1141#else
1142 (e > 31 && e < 127)
1143#endif
1144 ? e : '.';
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001145 }
Aapo Rantalainenc73fc862024-10-19 15:54:57 +02001146 n++;
1147 if (++p == cols)
1148 {
1149 l[c++] = '\n';
1150 l[c] = '\0';
1151 xxdline(fpo, l, autoskip ? nonzero : 1);
1152 nonzero = 0;
1153 p = 0;
1154 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001155 }
1156 if (p)
1157 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001158 l[c++] = '\n';
1159 l[c] = '\0';
1160 if (color)
1161 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001162 x = p;
1163 if (hextype == HEX_LITTLEENDIAN)
1164 {
1165 int fill = octspergrp - (p % octspergrp);
1166 if (fill == octspergrp) fill = 0;
1167
1168 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
1169
1170 for (i = 0; i < fill;i++)
1171 {
1172 COLOR_PROLOGUE
1173 l[c++] = COLOR_RED;
1174 l[c++] = 'm';
1175 l[c++] = ' '; /* empty space */
1176 COLOR_EPILOGUE
1177 x++;
1178 p++;
1179 }
1180 }
1181
1182 if (hextype != HEX_BITS)
1183 {
1184 c = addrlen + 1 + (grplen * x) / octspergrp;
1185 c += cols - p;
1186 c += (cols - p) / octspergrp;
1187
1188 for (i = cols - p; i > 0;i--)
1189 {
1190 COLOR_PROLOGUE
1191 l[c++] = COLOR_RED;
1192 l[c++] = 'm';
1193 l[c++] = ' '; /* empty space */
1194 COLOR_EPILOGUE
1195 }
1196 }
1197 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001198 xxdline(fpo, l, 1);
1199 }
1200 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001201 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001202
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001203 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001204 return 0;
1205}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001206
1207/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */