blob: b1050e9da4da33622bc8a3f9aa8dbf3575d7a50d [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000068 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020069 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000070 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020071 * I hereby grant permission to distribute and use xxd
72 * under X11-MIT or GPL-2.0 (at the user's choice).
73 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020074 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000075 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000076
77/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
78#if _MSC_VER >= 1400
79# define _CRT_SECURE_NO_DEPRECATE
80# define _CRT_NONSTDC_NO_DEPRECATE
81#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010082#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000083# define CYGWIN
84#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000085
Yegappan Lakshmananef089f52021-12-31 17:33:47 +000086#if (defined(__linux__) && !defined(__ANDROID__)) || defined(__CYGWIN__)
87# define _XOPEN_SOURCE 700 /* for fdopen() */
88#endif
89
Bram Moolenaar071d4272004-06-13 20:20:40 +000090#include <stdio.h>
91#ifdef VAXC
92# include <file.h>
93#else
94# include <fcntl.h>
95#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020096#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000097# include <io.h> /* for setmode() */
Ken Takatac4a40382023-10-25 21:17:35 +020098#endif
99#ifdef WIN32
K.Takataf6fc2552023-09-01 18:41:04 +0200100# include <windows.h>
101#endif
102#ifdef UNIX
103# include <unistd.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000104#endif
105#include <stdlib.h>
Keith Thompson184f71c2024-01-04 21:19:04 +0100106#include <string.h>
107#include <ctype.h>
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100108#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +0000109#if __MWERKS__ && !defined(BEBOX)
110# include <unix.h> /* for fdopen() on MAC */
111#endif
112
Bram Moolenaar071d4272004-06-13 20:20:40 +0000113
114/* This corrects the problem of missing prototypes for certain functions
115 * in some GNU installations (e.g. SunOS 4.1.x).
116 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
117 */
118#if defined(__GNUC__) && defined(__STDC__)
119# ifndef __USE_FIXED_PROTOTYPES__
120# define __USE_FIXED_PROTOTYPES__
121# endif
122#endif
123
124#ifndef __USE_FIXED_PROTOTYPES__
125/*
126 * This is historic and works only if the compiler really has no prototypes:
127 *
128 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
129 * FILE is defined on OS 4.x, not on 5.x (Solaris).
130 * if __SVR4 is defined (some Solaris versions), don't include this.
131 */
132#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
133# define __P(a) a
134/* excerpt from my sun_stdlib.h */
135extern int fprintf __P((FILE *, char *, ...));
136extern int fputs __P((char *, FILE *));
137extern int _flsbuf __P((unsigned char, FILE *));
138extern int _filbuf __P((FILE *));
139extern int fflush __P((FILE *));
140extern int fclose __P((FILE *));
141extern int fseek __P((FILE *, long, int));
142extern int rewind __P((FILE *));
143
144extern void perror __P((char *));
145# endif
146#endif
147
Aapo Rantalainenc73fc862024-10-19 15:54:57 +0200148char version[] = "xxd 2024-10-19 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149#ifdef WIN32
150char osver[] = " (Win32)";
151#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000152char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153#endif
154
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200155#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156# define BIN_READ(yes) ((yes) ? "rb" : "rt")
157# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
158# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
159# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000160# define PATH_SEP '\\'
161#elif defined(CYGWIN)
162# define BIN_READ(yes) ((yes) ? "rb" : "rt")
163# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
164# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
165# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
166# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000167#else
168# ifdef VMS
169# define BIN_READ(dummy) "r"
170# define BIN_WRITE(dummy) "w"
171# define BIN_CREAT(dummy) O_CREAT
172# define BIN_ASSIGN(fp, dummy) fp
173# define PATH_SEP ']'
174# define FILE_SEP '.'
175# else
176# define BIN_READ(dummy) "r"
177# define BIN_WRITE(dummy) "w"
178# define BIN_CREAT(dummy) O_CREAT
179# define BIN_ASSIGN(fp, dummy) fp
180# define PATH_SEP '/'
181# endif
182#endif
183
184/* open has only to arguments on the Mac */
185#if __MWERKS__
186# define OPEN(name, mode, umask) open(name, mode)
187#else
188# define OPEN(name, mode, umask) open(name, mode, umask)
189#endif
190
191#ifdef AMIGA
192# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
193#else
194# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
195#endif
196
197#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200198# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199# define __P(a) a
200# else
201# define __P(a) ()
202# endif
203#endif
204
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
206#define COLS 256 /* change here, if you ever need more columns */
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100207
208/*
209 * LLEN is the maximum length of a line; other than the visible characters
210 * we need to consider also the escape color sequence prologue/epilogue ,
Lennard Hofmann67797192024-05-10 14:17:26 +0200211 * (11 bytes for each character).
Goffredo Baroncelli00221482024-02-10 13:31:06 +0100212 */
Lennard Hofmann67797192024-05-10 14:17:26 +0200213#define LLEN \
214 (39 /* addr: ⌈log10(ULONG_MAX)⌉ if "-d" flag given. We assume ULONG_MAX = 2**128 */ \
215 + 2 /* ": " */ \
216 + 13 * COLS /* hex dump with colors */ \
217 + (COLS - 1) /* whitespace between groups if "-g1" option given and "-c" maxed out */ \
218 + 2 /* whitespace */ \
219 + 12 * COLS /* ASCII dump with colors */ \
220 + 2) /* "\n\0" */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221
222char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
223
224/* the different hextypes known by this program: */
Andre Chang15022722024-09-15 20:03:05 +0200225#define HEX_NORMAL 0x00 /* no flags set */
226#define HEX_POSTSCRIPT 0x01
227#define HEX_CINCLUDE 0x02
228#define HEX_BITS 0x04 /* not hex a dump, but bits: 01111001 */
229#define HEX_LITTLEENDIAN 0x08
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230
Keith Thompson184f71c2024-01-04 21:19:04 +0100231#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((unsigned char)(c)) : (c))
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200232
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200233#define COLOR_PROLOGUE \
234l[c++] = '\033'; \
235l[c++] = '['; \
236l[c++] = '1'; \
237l[c++] = ';'; \
238l[c++] = '3';
239
240#define COLOR_EPILOGUE \
241l[c++] = '\033'; \
242l[c++] = '['; \
243l[c++] = '0'; \
244l[c++] = 'm';
245#define COLOR_RED '1'
246#define COLOR_GREEN '2'
247#define COLOR_YELLOW '3'
248#define COLOR_BLUE '4'
249#define COLOR_WHITE '7'
250
Bram Moolenaare0659a62011-04-01 19:14:40 +0200251static char *pname;
252
253 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100254exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255{
256 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
257 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
258 fprintf(stderr, "Options:\n");
259 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Andre Chang15022722024-09-15 20:03:05 +0200260 fprintf(stderr, " -b binary digit dump (incompatible with -ps). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200261 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000262 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
263 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100264 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100265 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000266 fprintf(stderr, " -h print this summary.\n");
267 fprintf(stderr, " -i output in C include file style.\n");
268 fprintf(stderr, " -l len stop after <len> octets.\n");
David Gow83e11802022-06-29 20:24:49 +0100269 fprintf(stderr, " -n name set the variable name used in C include output (-i).\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100270 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000271 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
272 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
273 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200274 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000275 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
276#ifdef TRY_SEEK
277 "[+][-]", "(or +: rel.) ");
278#else
279 "", "");
280#endif
281 fprintf(stderr, " -u use upper case hex letters.\n");
K.Takataf6fc2552023-09-01 18:41:04 +0200282 fprintf(stderr, " -R when colorize the output; <when> can be 'always', 'auto' or 'never'. Default: 'auto'.\n"),
Bram Moolenaar071d4272004-06-13 20:20:40 +0000283 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
284 exit(1);
285}
286
Bram Moolenaare0659a62011-04-01 19:14:40 +0200287 static void
DungSagaa2ffb432021-10-22 15:55:31 +0100288perror_exit(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200289{
290 fprintf(stderr, "%s: ", pname);
291 perror(NULL);
292 exit(ret);
293}
294
DungSagaa2ffb432021-10-22 15:55:31 +0100295 static void
296error_exit(int ret, char *msg)
297{
298 fprintf(stderr, "%s: %s\n", pname, msg);
299 exit(ret);
300}
301
DungSagad1d8a592021-11-26 13:59:27 +0000302 static int
303getc_or_die(FILE *fpi)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000304{
DungSagad1d8a592021-11-26 13:59:27 +0000305 int c = getc(fpi);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000306 if (c == EOF && ferror(fpi))
307 perror_exit(2);
DungSagad1d8a592021-11-26 13:59:27 +0000308 return c;
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000309}
310
311 static void
Bram Moolenaar71b36202021-11-25 13:26:19 +0000312putc_or_die(int c, FILE *fpo)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000313{
314 if (putc(c, fpo) == EOF)
315 perror_exit(3);
316}
317
318 static void
319fputs_or_die(char *s, FILE *fpo)
320{
321 if (fputs(s, fpo) == EOF)
322 perror_exit(3);
323}
324
DungSaga7e5503c2021-12-01 11:24:52 +0000325/* Use a macro to allow for different arguments. */
326#define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000327
328 static void
329fclose_or_die(FILE *fpi, FILE *fpo)
330{
331 if (fclose(fpo) != 0)
332 perror_exit(3);
333 if (fclose(fpi) != 0)
334 perror_exit(2);
335}
336
Bram Moolenaar071d4272004-06-13 20:20:40 +0000337/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000338 * If "c" is a hex digit, return the value.
339 * Otherwise return -1.
340 */
341 static int
342parse_hex_digit(int c)
343{
344 return (c >= '0' && c <= '9') ? c - '0'
345 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
346 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
347 : -1;
348}
349
350/*
tristhaus85f45212023-10-06 19:51:13 +0200351 * If "c" is a bin digit, return the value.
352 * Otherwise return -1.
353 */
354 static int
355parse_bin_digit(int c)
356{
357 return (c >= '0' && c <= '1') ? c - '0'
358 : -1;
359}
360
361/*
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000362 * Ignore text on "fpi" until end-of-line or end-of-file.
363 * Return the '\n' or EOF character.
364 * When an error is encountered exit with an error message.
365 */
366 static int
367skip_to_eol(FILE *fpi, int c)
368{
369 while (c != '\n' && c != EOF)
DungSagad1d8a592021-11-26 13:59:27 +0000370 c = getc_or_die(fpi);
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000371 return c;
372}
373
374/*
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 * Max. cols binary characters are decoded from the input stream per line.
376 * Two adjacent garbage characters after evaluated data delimit valid data.
377 * Everything up to the next newline is discarded.
378 *
379 * The name is historic and came from 'undo type opt h'.
380 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200381 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100382huntype(
383 FILE *fpi,
384 FILE *fpo,
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100385 int cols,
386 int hextype,
387 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388{
Christian Brabandt7879bc52023-10-08 20:36:44 +0200389 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 +0000390 long have_off = 0, want_off = 0;
391
392 rewind(fpi);
393
394 while ((c = getc(fpi)) != EOF)
395 {
396 if (c == '\r') /* Doze style input file? */
397 continue;
398
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100399 /* Allow multiple spaces. This doesn't work when there is normal text
400 * after the hex codes in the last line that looks like hex, thus only
401 * use it for PostScript format. */
402 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000403 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000404
tristhaus85f45212023-10-06 19:51:13 +0200405 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
406 {
407 n3 = n2;
408 n2 = n1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409
tristhaus85f45212023-10-06 19:51:13 +0200410 n1 = parse_hex_digit(c);
411 if (n1 == -1 && ign_garb)
412 continue;
413 }
414 else /* HEX_BITS */
415 {
416 n1 = parse_hex_digit(c);
417 if (n1 == -1 && ign_garb)
418 continue;
419
420 bt = parse_bin_digit(c);
421 if (bt != -1)
422 {
423 b = ((b << 1) | bt);
424 ++bcnt;
425 }
426 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427
428 ign_garb = 0;
429
tristhaus85f45212023-10-06 19:51:13 +0200430 if ((hextype != HEX_POSTSCRIPT) && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 {
tristhaus85f45212023-10-06 19:51:13 +0200432 if (hextype == HEX_NORMAL)
433 {
434 if (n1 < 0)
435 {
436 p = 0;
437 continue;
438 }
439 want_off = (want_off << 4) | n1;
440 }
441 else /* HEX_BITS */
442 {
OldWorldOrdr1c140302023-10-25 20:57:30 +0200443 if (n1 < 0)
444 {
445 p = 0;
tristhaus85f45212023-10-06 19:51:13 +0200446 bcnt = 0;
OldWorldOrdr1c140302023-10-25 20:57:30 +0200447 continue;
448 }
449 want_off = (want_off << 4) | n1;
tristhaus85f45212023-10-06 19:51:13 +0200450 }
451 continue;
452 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000453
454 if (base_off + want_off != have_off)
455 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200456 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100457 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000459 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460 have_off = base_off + want_off;
461#endif
462 if (base_off + want_off < have_off)
DungSaga7e5503c2021-12-01 11:24:52 +0000463 error_exit(5, "Sorry, cannot seek backwards.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000465 putc_or_die(0, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 }
467
tristhaus85f45212023-10-06 19:51:13 +0200468 if (hextype == HEX_NORMAL || hextype == HEX_POSTSCRIPT)
469 {
470 if (n2 >= 0 && n1 >= 0)
471 {
472 putc_or_die((n2 << 4) | n1, fpo);
473 have_off++;
474 want_off++;
475 n1 = -1;
476 if (!hextype && (++p >= cols))
477 /* skip the rest of the line as garbage */
478 c = skip_to_eol(fpi, c);
479 }
480 else if (n1 < 0 && n2 < 0 && n3 < 0)
481 /* already stumbled into garbage, skip line, wait and see */
482 c = skip_to_eol(fpi, c);
483 }
484 else /* HEX_BITS */
485 {
486 if (bcnt == 8)
487 {
488 putc_or_die(b, fpo);
489 have_off++;
490 want_off++;
491 b = 0;
492 bcnt = 0;
493 if (++p >= cols)
494 /* skip the rest of the line as garbage */
495 c = skip_to_eol(fpi, c);
496 }
497 }
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000498
DungSaga47810462021-10-22 12:55:42 +0100499 if (c == '\n')
500 {
tristhaus85f45212023-10-06 19:51:13 +0200501 if (hextype == HEX_NORMAL || hextype == HEX_BITS)
DungSaga47810462021-10-22 12:55:42 +0100502 want_off = 0;
503 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 ign_garb = 1;
505 }
506 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200507 if (fflush(fpo) != 0)
DungSagaa2ffb432021-10-22 15:55:31 +0100508 perror_exit(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509#ifdef TRY_SEEK
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000510 fseek(fpo, 0L, SEEK_END);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511#endif
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000512 fclose_or_die(fpi, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 return 0;
514}
515
516/*
517 * Print line l. If nz is false, xxdline regards the line a line of
518 * zeroes. If there are three or more consecutive lines of zeroes,
519 * they are replaced by a single '*' character.
520 *
521 * If the output ends with more than two lines of zeroes, you
522 * should call xxdline again with l being the last line and nz
523 * negative. This ensures that the last line is shown even when
524 * it is all zeroes.
525 *
526 * If nz is always positive, lines are never suppressed.
527 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200528 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100529xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530{
531 static char z[LLEN+1];
532 static int zero_seen = 0;
533
534 if (!nz && zero_seen == 1)
535 strcpy(z, l);
536
537 if (nz || !zero_seen++)
538 {
539 if (nz)
540 {
541 if (nz < 0)
542 zero_seen--;
543 if (zero_seen == 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000544 fputs_or_die(z, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 if (zero_seen > 2)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000546 fputs_or_die("*\n", fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000547 }
548 if (nz >= 0 || zero_seen > 0)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000549 fputs_or_die(l, fp);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 if (nz)
551 zero_seen = 0;
552 }
553}
554
555/* This is an EBCDIC to ASCII conversion table */
556/* from a proposed BTL standard April 16, 1979 */
557static unsigned char etoa64[] =
558{
559 0040,0240,0241,0242,0243,0244,0245,0246,
560 0247,0250,0325,0056,0074,0050,0053,0174,
561 0046,0251,0252,0253,0254,0255,0256,0257,
562 0260,0261,0041,0044,0052,0051,0073,0176,
563 0055,0057,0262,0263,0264,0265,0266,0267,
564 0270,0271,0313,0054,0045,0137,0076,0077,
565 0272,0273,0274,0275,0276,0277,0300,0301,
566 0302,0140,0072,0043,0100,0047,0075,0042,
567 0303,0141,0142,0143,0144,0145,0146,0147,
568 0150,0151,0304,0305,0306,0307,0310,0311,
569 0312,0152,0153,0154,0155,0156,0157,0160,
570 0161,0162,0136,0314,0315,0316,0317,0320,
571 0321,0345,0163,0164,0165,0166,0167,0170,
572 0171,0172,0322,0323,0324,0133,0326,0327,
573 0330,0331,0332,0333,0334,0335,0336,0337,
574 0340,0341,0342,0343,0344,0135,0346,0347,
575 0173,0101,0102,0103,0104,0105,0106,0107,
576 0110,0111,0350,0351,0352,0353,0354,0355,
577 0175,0112,0113,0114,0115,0116,0117,0120,
578 0121,0122,0356,0357,0360,0361,0362,0363,
579 0134,0237,0123,0124,0125,0126,0127,0130,
580 0131,0132,0364,0365,0366,0367,0370,0371,
581 0060,0061,0062,0063,0064,0065,0066,0067,
582 0070,0071,0372,0373,0374,0375,0376,0377
583};
584
K.Takataf6fc2552023-09-01 18:41:04 +0200585 static void
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200586begin_coloring_char (char *l, int *c, int e, int ebcdic)
587{
588 if (ebcdic)
589 {
590 if ((e >= 75 && e <= 80) || (e >= 90 && e <= 97) ||
591 (e >= 107 && e <= 111) || (e >= 121 && e <= 127) ||
592 (e >= 129 && e <= 137) || (e >= 145 && e <= 154) ||
593 (e >= 162 && e <= 169) || (e >= 192 && e <= 201) ||
594 (e >= 208 && e <= 217) || (e >= 226 && e <= 233) ||
595 (e >= 240 && e <= 249) || (e == 189) || (e == 64) ||
596 (e == 173) || (e == 224) )
597 l[(*c)++] = COLOR_GREEN;
598
599 else if (e == 37 || e == 13 || e == 5)
600 l[(*c)++] = COLOR_YELLOW;
601 else if (e == 0)
602 l[(*c)++] = COLOR_WHITE;
603 else if (e == 255)
604 l[(*c)++] = COLOR_BLUE;
605 else
606 l[(*c)++] = COLOR_RED;
607 }
608 else /* ASCII */
609 {
Igor Todorovski48a75f32024-01-09 21:05:48 +0000610 #if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200611 if (e >= 64)
612 l[(*c)++] = COLOR_GREEN;
613 #else
614 if (e > 31 && e < 127)
615 l[(*c)++] = COLOR_GREEN;
616 #endif
617
618 else if (e == 9 || e == 10 || e == 13)
619 l[(*c)++] = COLOR_YELLOW;
620 else if (e == 0)
621 l[(*c)++] = COLOR_WHITE;
622 else if (e == 255)
623 l[(*c)++] = COLOR_BLUE;
624 else
625 l[(*c)++] = COLOR_RED;
626 }
627 l[(*c)++] = 'm';
628}
629
K.Takataf6fc2552023-09-01 18:41:04 +0200630 static int
631enable_color(void)
632{
633#ifdef WIN32
634 DWORD mode;
635 HANDLE out;
636
637 if (!isatty(1))
638 return 0;
639
640 out = GetStdHandle(STD_OUTPUT_HANDLE);
641 GetConsoleMode(out, &mode);
642 mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
643 return (int)SetConsoleMode(out, mode);
644#elif defined(UNIX)
645 return isatty(STDOUT_FILENO);
646#else
647 return 0;
648#endif
649}
650
Bram Moolenaare0659a62011-04-01 19:14:40 +0200651 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100652main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653{
654 FILE *fp, *fpo;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200655 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0, i, x;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000656 int cols = 0, colsgiven = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200657 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658 int ebcdic = 0;
659 int octspergrp = -1; /* number of octets grouped in output */
660 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100661 long length = -1, n = 0, seekoff = 0;
662 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200663 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200664 char *pp;
David Gow83e11802022-06-29 20:24:49 +0100665 char *varname = NULL;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100666 int addrlen = 9;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200667 int color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200668 char *no_color;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200669
K.Takataf6fc2552023-09-01 18:41:04 +0200670 no_color = getenv("NO_COLOR");
671 if (no_color == NULL || no_color[0] == '\0')
672 color = enable_color();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000673
674#ifdef AMIGA
675 /* This program doesn't work when started from the Workbench */
676 if (argc == 0)
677 exit(1);
678#endif
679
680 pname = argv[0];
681 for (pp = pname; *pp; )
682 if (*pp++ == PATH_SEP)
683 pname = pp;
684#ifdef FILE_SEP
685 for (pp = pname; *pp; pp++)
686 if (*pp == FILE_SEP)
687 {
688 *pp = '\0';
689 break;
690 }
691#endif
692
693 while (argc >= 2)
694 {
695 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
696 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
Andre Chang15022722024-09-15 20:03:05 +0200697 else if (!STRNCMP(pp, "-b", 2)) hextype |= HEX_BITS;
698 else if (!STRNCMP(pp, "-e", 2)) hextype |= HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
Andre Chang15022722024-09-15 20:03:05 +0200700 else if (!STRNCMP(pp, "-p", 2)) hextype |= HEX_POSTSCRIPT;
701 else if (!STRNCMP(pp, "-i", 2)) hextype |= HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200702 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200703 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 else if (!STRNCMP(pp, "-r", 2)) revert++;
705 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
706 else if (!STRNCMP(pp, "-v", 2))
707 {
708 fprintf(stderr, "%s%s\n", version, osver);
709 exit(0);
710 }
711 else if (!STRNCMP(pp, "-c", 2))
712 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100713 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200714 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100715 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000716 {
717 colsgiven = 1;
718 cols = (int)strtol(pp + 2, NULL, 0);
719 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000720 else
721 {
722 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200723 exit_with_usage();
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000724 colsgiven = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 cols = (int)strtol(argv[2], NULL, 0);
726 argv++;
727 argc--;
728 }
729 }
730 else if (!STRNCMP(pp, "-g", 2))
731 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100732 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 octspergrp = (int)strtol(pp + 2, NULL, 0);
734 else
735 {
736 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200737 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738 octspergrp = (int)strtol(argv[2], NULL, 0);
739 argv++;
740 argc--;
741 }
742 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100743 else if (!STRNCMP(pp, "-o", 2))
744 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100745 int reloffset = 0;
746 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100747 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100748 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100749 else
750 {
751 if (!argv[2])
752 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100753
754 if (argv[2][0] == '+')
755 reloffset++;
756 if (argv[2][reloffset] == '-')
757 negoffset++;
758
759 if (negoffset)
760 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
761 else
762 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
763
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100764 argv++;
765 argc--;
766 }
767 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 else if (!STRNCMP(pp, "-s", 2))
769 {
770 relseek = 0;
771 negseek = 0;
772 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
773 {
774#ifdef TRY_SEEK
775 if (pp[2] == '+')
776 relseek++;
777 if (pp[2+relseek] == '-')
778 negseek++;
779#endif
780 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
781 }
782 else
783 {
784 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200785 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786#ifdef TRY_SEEK
787 if (argv[2][0] == '+')
788 relseek++;
789 if (argv[2][relseek] == '-')
790 negseek++;
791#endif
792 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
793 argv++;
794 argc--;
795 }
796 }
797 else if (!STRNCMP(pp, "-l", 2))
798 {
799 if (pp[2] && STRNCMP("en", pp + 2, 2))
800 length = strtol(pp + 2, (char **)NULL, 0);
801 else
802 {
803 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200804 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 length = strtol(argv[2], (char **)NULL, 0);
806 argv++;
807 argc--;
808 }
809 }
David Gow83e11802022-06-29 20:24:49 +0100810 else if (!STRNCMP(pp, "-n", 2))
811 {
812 if (pp[2] && STRNCMP("ame", pp + 2, 3))
813 varname = pp + 2;
814 else
815 {
816 if (!argv[2])
817 exit_with_usage();
818 varname = argv[2];
819 argv++;
820 argc--;
821 }
822 }
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200823 else if (!STRNCMP(pp, "-R", 2))
824 {
K.Takataf6fc2552023-09-01 18:41:04 +0200825 char *pw = pp + 2;
826 if (!pw[0])
827 {
828 pw = argv[2];
829 argv++;
830 argc--;
831 }
832 if (!pw)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200833 exit_with_usage();
K.Takataf6fc2552023-09-01 18:41:04 +0200834 if (!STRNCMP(pw, "always", 6))
835 {
836 (void)enable_color();
837 color = 1;
838 }
839 else if (!STRNCMP(pw, "never", 5))
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200840 color = 0;
K.Takataf6fc2552023-09-01 18:41:04 +0200841 else if (!STRNCMP(pw, "auto", 4))
K.Takata233f9562023-09-04 07:46:59 +0200842 color = enable_color();
K.Takataf6fc2552023-09-01 18:41:04 +0200843 else
844 exit_with_usage();
Aapo Rantalainene2528ae2023-08-31 17:58:13 +0200845 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 else if (!strcmp(pp, "--")) /* end of options */
847 {
848 argv++;
849 argc--;
850 break;
851 }
852 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200853 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 else
855 break; /* not an option */
856
857 argv++; /* advance to next argument */
858 argc--;
859 }
860
Andre Chang15022722024-09-15 20:03:05 +0200861 if (hextype != (HEX_CINCLUDE | HEX_BITS))
862 {
863 /* Allow at most one bit to be set in hextype */
864 if (hextype & (hextype - 1))
865 error_exit(1, "only one of -b, -e, -u, -p, -i can be used");
866 }
867
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000868 if (!colsgiven || (!cols && hextype != HEX_POSTSCRIPT))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 switch (hextype)
870 {
871 case HEX_POSTSCRIPT: cols = 30; break;
872 case HEX_CINCLUDE: cols = 12; break;
Andre Chang15022722024-09-15 20:03:05 +0200873 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874 case HEX_BITS: cols = 6; break;
875 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100876 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 default: cols = 16; break;
878 }
879
880 if (octspergrp < 0)
881 switch (hextype)
882 {
Andre Chang15022722024-09-15 20:03:05 +0200883 case HEX_CINCLUDE | HEX_BITS:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 case HEX_BITS: octspergrp = 1; break;
885 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100886 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 case HEX_POSTSCRIPT:
888 case HEX_CINCLUDE:
889 default: octspergrp = 0; break;
890 }
891
Erik Auerswaldc0a1d372022-01-14 11:58:48 +0000892 if ((hextype == HEX_POSTSCRIPT && cols < 0) ||
893 (hextype != HEX_POSTSCRIPT && cols < 1) ||
894 ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000895 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000896 {
897 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
898 exit(1);
899 }
900
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100901 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000902 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100903 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
DungSagaa2ffb432021-10-22 15:55:31 +0100904 error_exit(1, "number of octets per group must be a power of 2 with -e.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905
906 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200907 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000908
909 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
910 BIN_ASSIGN(fp = stdin, !revert);
911 else
912 {
913 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
914 {
915 fprintf(stderr,"%s: ", pname);
916 perror(argv[1]);
917 return 2;
918 }
919 }
920
921 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
922 BIN_ASSIGN(fpo = stdout, revert);
923 else
924 {
925 int fd;
926 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
927
928 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
929 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
930 {
931 fprintf(stderr, "%s: ", pname);
932 perror(argv[2]);
933 return 3;
934 }
935 rewind(fpo);
936 }
Igor Todorovski48a75f32024-01-09 21:05:48 +0000937#ifdef __MVS__
938 // Disable auto-conversion on input file descriptors
939 __disableautocvt(fileno(fp));
940#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000941
942 if (revert)
tristhaus85f45212023-10-06 19:51:13 +0200943 switch (hextype)
944 {
945 case HEX_NORMAL:
946 case HEX_POSTSCRIPT:
947 case HEX_BITS:
948 return huntype(fp, fpo, cols, hextype,
949 negseek ? -seekoff : seekoff);
950 break;
951 default:
952 error_exit(-1, "Sorry, cannot revert this type of hexdump");
953 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000954
955 if (seekoff || negseek || !relseek)
956 {
957#ifdef TRY_SEEK
958 if (relseek)
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000959 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000960 else
Bram Moolenaar786e05b2021-11-14 13:46:05 +0000961 e = fseek(fp, negseek ? -seekoff : seekoff,
962 negseek ? SEEK_END : SEEK_SET);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000963 if (e < 0 && negseek)
DungSaga7e5503c2021-12-01 11:24:52 +0000964 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000965 if (e >= 0)
966 seekoff = ftell(fp);
967 else
968#endif
969 {
970 long s = seekoff;
971
972 while (s--)
DungSaga7e5503c2021-12-01 11:24:52 +0000973 if (getc_or_die(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200974 {
DungSaga7e5503c2021-12-01 11:24:52 +0000975 error_exit(4, "Sorry, cannot seek.");
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200976 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000977 }
978 }
979
Andre Chang15022722024-09-15 20:03:05 +0200980 if (hextype & HEX_CINCLUDE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000981 {
David Gow83e11802022-06-29 20:24:49 +0100982 /* A user-set variable name overrides fp == stdin */
983 if (varname == NULL && fp != stdin)
984 varname = argv[1];
985
986 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000987 {
Keith Thompson184f71c2024-01-04 21:19:04 +0100988 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +0100989 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +0100990 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
Bram Moolenaar8af87bd2021-11-25 11:16:50 +0000991 fputs_or_die("[] = {\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000992 }
993
994 p = 0;
DungSagad1d8a592021-11-26 13:59:27 +0000995 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
Andre Chang15022722024-09-15 20:03:05 +0200996 {
997 if (hextype & HEX_BITS)
998 {
999 if (p == 0)
1000 fputs_or_die(" ", fpo);
1001 else if (p % cols == 0)
1002 fputs_or_die(",\n ", fpo);
1003 else
1004 fputs_or_die(", ", fpo);
1005
1006 FPRINTF_OR_DIE((fpo, "0b"));
1007 for (int j = 7; j >= 0; j--)
1008 putc_or_die((c & (1 << j)) ? '1' : '0', fpo);
1009 p++;
1010 }
1011 else
1012 {
1013 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
DungSaga7e5503c2021-12-01 11:24:52 +00001014 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
Andre Chang15022722024-09-15 20:03:05 +02001015 p++;
1016 }
1017 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001018
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001019 if (p)
1020 fputs_or_die("\n", fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001021
David Gow83e11802022-06-29 20:24:49 +01001022 if (varname != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001023 {
DungSagad1d8a592021-11-26 13:59:27 +00001024 fputs_or_die("};\n", fpo);
Christian Brabandtfa8c9712024-01-25 20:50:49 +01001025 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((unsigned char)varname[0]) ? "__" : ""));
David Gow83e11802022-06-29 20:24:49 +01001026 for (e = 0; (c = varname[e]) != 0; e++)
Keith Thompson184f71c2024-01-04 21:19:04 +01001027 putc_or_die(isalnum((unsigned char)c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
DungSaga7e5503c2021-12-01 11:24:52 +00001028 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
Bram Moolenaar071d4272004-06-13 20:20:40 +00001029 }
1030
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001031 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001032 return 0;
1033 }
1034
1035 if (hextype == HEX_POSTSCRIPT)
1036 {
1037 p = cols;
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 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001040 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
1041 putc_or_die(hexx[e & 0xf], fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001042 n++;
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001043 if (cols > 0 && !--p)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001044 {
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001045 putc_or_die('\n', fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001046 p = cols;
1047 }
1048 }
Erik Auerswaldc0a1d372022-01-14 11:58:48 +00001049 if (cols == 0 || p < cols)
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001050 putc_or_die('\n', fpo);
1051 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001052 return 0;
1053 }
1054
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001055 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001056
Bram Moolenaar4dcdf292015-03-05 17:51:15 +01001057 if (hextype != HEX_BITS)
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001058 {
1059 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
1060 if (color)
1061 grplen += 11 * octspergrp; /* color-code needs 11 extra characters */
1062 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001063 else /* hextype == HEX_BITS */
1064 grplen = 8 * octspergrp + 1;
1065
DungSagad1d8a592021-11-26 13:59:27 +00001066 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001067 {
1068 if (p == 0)
1069 {
DungSaga581f41a2021-11-22 11:57:31 +00001070 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
Bram Moolenaar363d6142020-05-30 20:50:25 +02001071 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaar4390d872023-03-05 20:17:39 +00001072 for (c = addrlen; c < LLEN; l[c++] = ' ')
1073 ;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001074 }
DungSaga48608b42021-11-24 11:18:07 +00001075 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
1076 c = addrlen + 1 + (grplen * x) / octspergrp;
DungSaga581f41a2021-11-22 11:57:31 +00001077 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001078 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001079 if (color)
1080 {
1081 COLOR_PROLOGUE
1082 begin_coloring_char(l,&c,e,ebcdic);
1083 l[c++] = hexx[(e >> 4) & 0xf];
1084 l[c++] = hexx[e & 0xf];
1085 COLOR_EPILOGUE
1086 }
1087 else /*No colors*/
1088 {
1089 l[c] = hexx[(e >> 4) & 0xf];
1090 l[++c] = hexx[e & 0xf];
1091 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001092 }
1093 else /* hextype == HEX_BITS */
1094 {
Bram Moolenaar071d4272004-06-13 20:20:40 +00001095 for (i = 7; i >= 0; i--)
DungSaga48608b42021-11-24 11:18:07 +00001096 l[c++] = (e & (1 << i)) ? '1' : '0';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001097 }
Bram Moolenaar085346f2018-02-24 18:30:55 +01001098 if (e)
1099 nonzero++;
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +00001100 /* When changing this update definition of LLEN above. */
Bram Moolenaar4390d872023-03-05 20:17:39 +00001101 if (hextype == HEX_LITTLEENDIAN)
1102 /* last group will be fully used, round up */
1103 c = grplen * ((cols + octspergrp - 1) / octspergrp);
1104 else
1105 c = (grplen * cols - 1) / octspergrp;
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001106
1107 if (color)
1108 {
1109 if (hextype == HEX_BITS)
1110 c += addrlen + 3 + p*12;
1111 else
1112 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p*12;
1113
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001114 COLOR_PROLOGUE
1115 begin_coloring_char(l,&c,e,ebcdic);
Igor Todorovski48a75f32024-01-09 21:05:48 +00001116#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001117 if (e >= 64)
1118 l[c++] = e;
1119 else
1120 l[c++] = '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001121#else
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001122 if (ebcdic)
1123 e = (e < 64) ? '.' : etoa64[e-64];
1124 l[c++] = (e > 31 && e < 127) ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +00001125#endif
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001126 COLOR_EPILOGUE
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001127 }
1128 else /*no colors*/
1129 {
1130 if (ebcdic)
1131 e = (e < 64) ? '.' : etoa64[e-64];
1132
Aapo Rantalainenc73fc862024-10-19 15:54:57 +02001133 if (hextype == HEX_LITTLEENDIAN)
1134 c -= 1;
1135
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001136 c += addrlen + 3 + p;
1137 l[c++] =
Igor Todorovski48a75f32024-01-09 21:05:48 +00001138#if defined(__MVS__) && __CHARSET_LIB == 0
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001139 (e >= 64)
1140#else
1141 (e > 31 && e < 127)
1142#endif
1143 ? e : '.';
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001144 }
Aapo Rantalainenc73fc862024-10-19 15:54:57 +02001145 n++;
1146 if (++p == cols)
1147 {
1148 l[c++] = '\n';
1149 l[c] = '\0';
1150 xxdline(fpo, l, autoskip ? nonzero : 1);
1151 nonzero = 0;
1152 p = 0;
1153 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001154 }
1155 if (p)
1156 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001157 l[c++] = '\n';
1158 l[c] = '\0';
1159 if (color)
1160 {
Aapo Rantalainene2528ae2023-08-31 17:58:13 +02001161 x = p;
1162 if (hextype == HEX_LITTLEENDIAN)
1163 {
1164 int fill = octspergrp - (p % octspergrp);
1165 if (fill == octspergrp) fill = 0;
1166
1167 c = addrlen + 1 + (grplen * (x - (octspergrp-fill))) / octspergrp;
1168
1169 for (i = 0; i < fill;i++)
1170 {
1171 COLOR_PROLOGUE
1172 l[c++] = COLOR_RED;
1173 l[c++] = 'm';
1174 l[c++] = ' '; /* empty space */
1175 COLOR_EPILOGUE
1176 x++;
1177 p++;
1178 }
1179 }
1180
1181 if (hextype != HEX_BITS)
1182 {
1183 c = addrlen + 1 + (grplen * x) / octspergrp;
1184 c += cols - p;
1185 c += (cols - p) / octspergrp;
1186
1187 for (i = cols - p; i > 0;i--)
1188 {
1189 COLOR_PROLOGUE
1190 l[c++] = COLOR_RED;
1191 l[c++] = 'm';
1192 l[c++] = ' '; /* empty space */
1193 COLOR_EPILOGUE
1194 }
1195 }
1196 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001197 xxdline(fpo, l, 1);
1198 }
1199 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +00001200 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001201
Bram Moolenaar8af87bd2021-11-25 11:16:50 +00001202 fclose_or_die(fp, fpo);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001203 return 0;
1204}
Bram Moolenaare0659a62011-04-01 19:14:40 +02001205
1206/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */