blob: e9dab81fbc2128f986ee284f0b26fcf969b16120 [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
Bram Moolenaar071d4272004-06-13 20:20:40 +000057 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020058 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000059 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020060 * I hereby grant permission to distribute and use xxd
61 * under X11-MIT or GPL-2.0 (at the user's choice).
62 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020063 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000065
66/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
67#if _MSC_VER >= 1400
68# define _CRT_SECURE_NO_DEPRECATE
69# define _CRT_NONSTDC_NO_DEPRECATE
70#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010071#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000072# define CYGWIN
73#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000074
Bram Moolenaar071d4272004-06-13 20:20:40 +000075#include <stdio.h>
76#ifdef VAXC
77# include <file.h>
78#else
79# include <fcntl.h>
80#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020081#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082# include <io.h> /* for setmode() */
83#else
84# ifdef UNIX
85# include <unistd.h>
86# endif
87#endif
88#include <stdlib.h>
89#include <string.h> /* for strncmp() */
90#include <ctype.h> /* for isalnum() */
Bram Moolenaard8c56a02019-01-30 23:02:25 +010091#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000092#if __MWERKS__ && !defined(BEBOX)
93# include <unix.h> /* for fdopen() on MAC */
94#endif
95
Bram Moolenaar071d4272004-06-13 20:20:40 +000096
97/* This corrects the problem of missing prototypes for certain functions
98 * in some GNU installations (e.g. SunOS 4.1.x).
99 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
100 */
101#if defined(__GNUC__) && defined(__STDC__)
102# ifndef __USE_FIXED_PROTOTYPES__
103# define __USE_FIXED_PROTOTYPES__
104# endif
105#endif
106
107#ifndef __USE_FIXED_PROTOTYPES__
108/*
109 * This is historic and works only if the compiler really has no prototypes:
110 *
111 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
112 * FILE is defined on OS 4.x, not on 5.x (Solaris).
113 * if __SVR4 is defined (some Solaris versions), don't include this.
114 */
115#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
116# define __P(a) a
117/* excerpt from my sun_stdlib.h */
118extern int fprintf __P((FILE *, char *, ...));
119extern int fputs __P((char *, FILE *));
120extern int _flsbuf __P((unsigned char, FILE *));
121extern int _filbuf __P((FILE *));
122extern int fflush __P((FILE *));
123extern int fclose __P((FILE *));
124extern int fseek __P((FILE *, long, int));
125extern int rewind __P((FILE *));
126
127extern void perror __P((char *));
128# endif
129#endif
130
131extern long int strtol();
132extern long int ftell();
133
DungSaga47810462021-10-22 12:55:42 +0100134char version[] = "xxd 2021-10-22 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135#ifdef WIN32
136char osver[] = " (Win32)";
137#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139#endif
140
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200141#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142# define BIN_READ(yes) ((yes) ? "rb" : "rt")
143# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
144# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
145# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000146# define PATH_SEP '\\'
147#elif defined(CYGWIN)
148# define BIN_READ(yes) ((yes) ? "rb" : "rt")
149# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
150# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
151# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
152# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153#else
154# ifdef VMS
155# define BIN_READ(dummy) "r"
156# define BIN_WRITE(dummy) "w"
157# define BIN_CREAT(dummy) O_CREAT
158# define BIN_ASSIGN(fp, dummy) fp
159# define PATH_SEP ']'
160# define FILE_SEP '.'
161# else
162# define BIN_READ(dummy) "r"
163# define BIN_WRITE(dummy) "w"
164# define BIN_CREAT(dummy) O_CREAT
165# define BIN_ASSIGN(fp, dummy) fp
166# define PATH_SEP '/'
167# endif
168#endif
169
170/* open has only to arguments on the Mac */
171#if __MWERKS__
172# define OPEN(name, mode, umask) open(name, mode)
173#else
174# define OPEN(name, mode, umask) open(name, mode, umask)
175#endif
176
177#ifdef AMIGA
178# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
179#else
180# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
181#endif
182
183#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200184# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185# define __P(a) a
186# else
187# define __P(a) ()
188# endif
189#endif
190
191/* Let's collect some prototypes */
192/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200193static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200194static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200195static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196static void xxdline __P((FILE *, char *, int));
197
198#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
199#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100200#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201
202char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
203
204/* the different hextypes known by this program: */
205#define HEX_NORMAL 0
206#define HEX_POSTSCRIPT 1
207#define HEX_CINCLUDE 2
208#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100209#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200211#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
212
Bram Moolenaare0659a62011-04-01 19:14:40 +0200213static char *pname;
214
215 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100216exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217{
218 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
219 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
220 fprintf(stderr, "Options:\n");
221 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100222 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200223 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
225 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100226 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100227 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 fprintf(stderr, " -h print this summary.\n");
229 fprintf(stderr, " -i output in C include file style.\n");
230 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100231 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
233 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
234 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200235 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
237#ifdef TRY_SEEK
238 "[+][-]", "(or +: rel.) ");
239#else
240 "", "");
241#endif
242 fprintf(stderr, " -u use upper case hex letters.\n");
243 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
244 exit(1);
245}
246
Bram Moolenaare0659a62011-04-01 19:14:40 +0200247 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100248die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200249{
250 fprintf(stderr, "%s: ", pname);
251 perror(NULL);
252 exit(ret);
253}
254
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255/*
256 * Max. cols binary characters are decoded from the input stream per line.
257 * Two adjacent garbage characters after evaluated data delimit valid data.
258 * Everything up to the next newline is discarded.
259 *
260 * The name is historic and came from 'undo type opt h'.
261 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200262 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100263huntype(
264 FILE *fpi,
265 FILE *fpo,
266 FILE *fperr,
267 int cols,
268 int hextype,
269 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270{
271 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
272 long have_off = 0, want_off = 0;
273
274 rewind(fpi);
275
276 while ((c = getc(fpi)) != EOF)
277 {
278 if (c == '\r') /* Doze style input file? */
279 continue;
280
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100281 /* Allow multiple spaces. This doesn't work when there is normal text
282 * after the hex codes in the last line that looks like hex, thus only
283 * use it for PostScript format. */
284 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000285 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000286
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287 n3 = n2;
288 n2 = n1;
289
290 if (c >= '0' && c <= '9')
291 n1 = c - '0';
292 else if (c >= 'a' && c <= 'f')
293 n1 = c - 'a' + 10;
294 else if (c >= 'A' && c <= 'F')
295 n1 = c - 'A' + 10;
296 else
297 {
298 n1 = -1;
299 if (ign_garb)
300 continue;
301 }
302
303 ign_garb = 0;
304
DungSaga375c35a2021-10-18 13:16:03 +0100305 if (!hextype && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 {
DungSaga375c35a2021-10-18 13:16:03 +0100307 if (n1 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 {
DungSaga375c35a2021-10-18 13:16:03 +0100309 p = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 continue;
311 }
DungSaga375c35a2021-10-18 13:16:03 +0100312 want_off = (want_off << 4) | n1;
313 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314 }
315
316 if (base_off + want_off != have_off)
317 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200318 if (fflush(fpo) != 0)
319 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320#ifdef TRY_SEEK
DungSaga47810462021-10-22 12:55:42 +0100321 if (fseek(fpo, base_off + want_off - have_off, 1) >= 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000322 have_off = base_off + want_off;
323#endif
324 if (base_off + want_off < have_off)
325 {
326 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
327 return 5;
328 }
329 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200330 if (putc(0, fpo) == EOF)
331 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000332 }
333
334 if (n2 >= 0 && n1 >= 0)
335 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200336 if (putc((n2 << 4) | n1, fpo) == EOF)
337 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 have_off++;
339 want_off++;
340 n1 = -1;
DungSaga375c35a2021-10-18 13:16:03 +0100341 if (!hextype && (++p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 {
DungSagac89c91c2021-10-16 19:07:46 +0100343 /* skip the rest of the line as garbage */
344 n2 = -1;
345 n3 = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 }
347 }
DungSagac89c91c2021-10-16 19:07:46 +0100348 if (n1 < 0 && n2 < 0 && n3 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000349 {
350 /* already stumbled into garbage, skip line, wait and see */
DungSaga47810462021-10-22 12:55:42 +0100351 while (c != '\n' && c != EOF)
352 c = getc(fpi);
Bram Moolenaare0659a62011-04-01 19:14:40 +0200353 if (c == EOF && ferror(fpi))
354 die(2);
DungSaga47810462021-10-22 12:55:42 +0100355 }
356 if (c == '\n')
357 {
358 if (!hextype)
359 want_off = 0;
360 p = cols;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 ign_garb = 1;
362 }
363 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200364 if (fflush(fpo) != 0)
365 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000366#ifdef TRY_SEEK
367 fseek(fpo, 0L, 2);
368#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200369 if (fclose(fpo) != 0)
370 die(3);
371 if (fclose(fpi) != 0)
372 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 return 0;
374}
375
376/*
377 * Print line l. If nz is false, xxdline regards the line a line of
378 * zeroes. If there are three or more consecutive lines of zeroes,
379 * they are replaced by a single '*' character.
380 *
381 * If the output ends with more than two lines of zeroes, you
382 * should call xxdline again with l being the last line and nz
383 * negative. This ensures that the last line is shown even when
384 * it is all zeroes.
385 *
386 * If nz is always positive, lines are never suppressed.
387 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200388 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100389xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000390{
391 static char z[LLEN+1];
392 static int zero_seen = 0;
393
394 if (!nz && zero_seen == 1)
395 strcpy(z, l);
396
397 if (nz || !zero_seen++)
398 {
399 if (nz)
400 {
401 if (nz < 0)
402 zero_seen--;
403 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200404 if (fputs(z, fp) == EOF)
405 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200407 if (fputs("*\n", fp) == EOF)
408 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409 }
410 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200411 if (fputs(l, fp) == EOF)
412 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413 if (nz)
414 zero_seen = 0;
415 }
416}
417
418/* This is an EBCDIC to ASCII conversion table */
419/* from a proposed BTL standard April 16, 1979 */
420static unsigned char etoa64[] =
421{
422 0040,0240,0241,0242,0243,0244,0245,0246,
423 0247,0250,0325,0056,0074,0050,0053,0174,
424 0046,0251,0252,0253,0254,0255,0256,0257,
425 0260,0261,0041,0044,0052,0051,0073,0176,
426 0055,0057,0262,0263,0264,0265,0266,0267,
427 0270,0271,0313,0054,0045,0137,0076,0077,
428 0272,0273,0274,0275,0276,0277,0300,0301,
429 0302,0140,0072,0043,0100,0047,0075,0042,
430 0303,0141,0142,0143,0144,0145,0146,0147,
431 0150,0151,0304,0305,0306,0307,0310,0311,
432 0312,0152,0153,0154,0155,0156,0157,0160,
433 0161,0162,0136,0314,0315,0316,0317,0320,
434 0321,0345,0163,0164,0165,0166,0167,0170,
435 0171,0172,0322,0323,0324,0133,0326,0327,
436 0330,0331,0332,0333,0334,0335,0336,0337,
437 0340,0341,0342,0343,0344,0135,0346,0347,
438 0173,0101,0102,0103,0104,0105,0106,0107,
439 0110,0111,0350,0351,0352,0353,0354,0355,
440 0175,0112,0113,0114,0115,0116,0117,0120,
441 0121,0122,0356,0357,0360,0361,0362,0363,
442 0134,0237,0123,0124,0125,0126,0127,0130,
443 0131,0132,0364,0365,0366,0367,0370,0371,
444 0060,0061,0062,0063,0064,0065,0066,0067,
445 0070,0071,0372,0373,0374,0375,0376,0377
446};
447
Bram Moolenaare0659a62011-04-01 19:14:40 +0200448 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100449main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000450{
451 FILE *fp, *fpo;
452 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200453 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
454 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000455 int ebcdic = 0;
456 int octspergrp = -1; /* number of octets grouped in output */
457 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100458 long length = -1, n = 0, seekoff = 0;
459 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200460 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200461 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100462 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000463
464#ifdef AMIGA
465 /* This program doesn't work when started from the Workbench */
466 if (argc == 0)
467 exit(1);
468#endif
469
470 pname = argv[0];
471 for (pp = pname; *pp; )
472 if (*pp++ == PATH_SEP)
473 pname = pp;
474#ifdef FILE_SEP
475 for (pp = pname; *pp; pp++)
476 if (*pp == FILE_SEP)
477 {
478 *pp = '\0';
479 break;
480 }
481#endif
482
483 while (argc >= 2)
484 {
485 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
486 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
487 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100488 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000489 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
490 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
491 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200492 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200493 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000494 else if (!STRNCMP(pp, "-r", 2)) revert++;
495 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
496 else if (!STRNCMP(pp, "-v", 2))
497 {
498 fprintf(stderr, "%s%s\n", version, osver);
499 exit(0);
500 }
501 else if (!STRNCMP(pp, "-c", 2))
502 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100503 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200504 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100505 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
506 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000507 else
508 {
509 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200510 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 cols = (int)strtol(argv[2], NULL, 0);
512 argv++;
513 argc--;
514 }
515 }
516 else if (!STRNCMP(pp, "-g", 2))
517 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100518 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 octspergrp = (int)strtol(pp + 2, NULL, 0);
520 else
521 {
522 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200523 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524 octspergrp = (int)strtol(argv[2], NULL, 0);
525 argv++;
526 argc--;
527 }
528 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100529 else if (!STRNCMP(pp, "-o", 2))
530 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100531 int reloffset = 0;
532 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100533 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100534 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100535 else
536 {
537 if (!argv[2])
538 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100539
540 if (argv[2][0] == '+')
541 reloffset++;
542 if (argv[2][reloffset] == '-')
543 negoffset++;
544
545 if (negoffset)
546 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
547 else
548 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
549
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100550 argv++;
551 argc--;
552 }
553 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000554 else if (!STRNCMP(pp, "-s", 2))
555 {
556 relseek = 0;
557 negseek = 0;
558 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
559 {
560#ifdef TRY_SEEK
561 if (pp[2] == '+')
562 relseek++;
563 if (pp[2+relseek] == '-')
564 negseek++;
565#endif
566 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
567 }
568 else
569 {
570 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200571 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000572#ifdef TRY_SEEK
573 if (argv[2][0] == '+')
574 relseek++;
575 if (argv[2][relseek] == '-')
576 negseek++;
577#endif
578 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
579 argv++;
580 argc--;
581 }
582 }
583 else if (!STRNCMP(pp, "-l", 2))
584 {
585 if (pp[2] && STRNCMP("en", pp + 2, 2))
586 length = strtol(pp + 2, (char **)NULL, 0);
587 else
588 {
589 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200590 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 length = strtol(argv[2], (char **)NULL, 0);
592 argv++;
593 argc--;
594 }
595 }
596 else if (!strcmp(pp, "--")) /* end of options */
597 {
598 argv++;
599 argc--;
600 break;
601 }
602 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200603 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000604 else
605 break; /* not an option */
606
607 argv++; /* advance to next argument */
608 argc--;
609 }
610
611 if (!cols)
612 switch (hextype)
613 {
614 case HEX_POSTSCRIPT: cols = 30; break;
615 case HEX_CINCLUDE: cols = 12; break;
616 case HEX_BITS: cols = 6; break;
617 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100618 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000619 default: cols = 16; break;
620 }
621
622 if (octspergrp < 0)
623 switch (hextype)
624 {
625 case HEX_BITS: octspergrp = 1; break;
626 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100627 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 case HEX_POSTSCRIPT:
629 case HEX_CINCLUDE:
630 default: octspergrp = 0; break;
631 }
632
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100633 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000634 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 {
636 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
637 exit(1);
638 }
639
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100640 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100642 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
643 {
644 fprintf(stderr,
645 "%s: number of octets per group must be a power of 2 with -e.\n",
646 pname);
647 exit(1);
648 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649
650 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200651 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652
653 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
654 BIN_ASSIGN(fp = stdin, !revert);
655 else
656 {
657 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
658 {
659 fprintf(stderr,"%s: ", pname);
660 perror(argv[1]);
661 return 2;
662 }
663 }
664
665 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
666 BIN_ASSIGN(fpo = stdout, revert);
667 else
668 {
669 int fd;
670 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
671
672 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
673 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
674 {
675 fprintf(stderr, "%s: ", pname);
676 perror(argv[2]);
677 return 3;
678 }
679 rewind(fpo);
680 }
681
682 if (revert)
683 {
684 if (hextype && (hextype != HEX_POSTSCRIPT))
685 {
686 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
687 return -1;
688 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200689 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000690 negseek ? -seekoff : seekoff);
691 }
692
693 if (seekoff || negseek || !relseek)
694 {
695#ifdef TRY_SEEK
696 if (relseek)
697 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
698 else
699 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
700 if (e < 0 && negseek)
701 {
702 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
703 return 4;
704 }
705 if (e >= 0)
706 seekoff = ftell(fp);
707 else
708#endif
709 {
710 long s = seekoff;
711
712 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200713 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200714 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200715 if (ferror(fp))
716 {
717 die(2);
718 }
719 else
720 {
721 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
722 return 4;
723 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200724 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000725 }
726 }
727
728 if (hextype == HEX_CINCLUDE)
729 {
730 if (fp != stdin)
731 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200732 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
733 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200735 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200736 die(3);
737 if (fputs("[] = {\n", fpo) == EOF)
738 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 }
740
741 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200742 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
744 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200745 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200746 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200747 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 p++;
749 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200750 if (c == EOF && ferror(fp))
751 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100753 if (p && fputs("\n", fpo) == EOF)
754 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200755 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100756 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757
758 if (fp != stdin)
759 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200760 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
761 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200763 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200764 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200765 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200766 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 }
768
Bram Moolenaare0659a62011-04-01 19:14:40 +0200769 if (fclose(fp))
770 die(2);
771 if (fclose(fpo))
772 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 return 0;
774 }
775
776 if (hextype == HEX_POSTSCRIPT)
777 {
778 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200779 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
781 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200782 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
783 || putc(hexx[e & 0xf], fpo) == EOF)
784 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 n++;
786 if (!--p)
787 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200788 if (putc('\n', fpo) == EOF)
789 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 p = cols;
791 }
792 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200793 if (e == EOF && ferror(fp))
794 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200796 if (putc('\n', fpo) == EOF)
797 die(3);
798 if (fclose(fp))
799 die(2);
800 if (fclose(fpo))
801 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 return 0;
803 }
804
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100805 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100807 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
809 else /* hextype == HEX_BITS */
810 grplen = 8 * octspergrp + 1;
811
Bram Moolenaare0659a62011-04-01 19:14:40 +0200812 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
814 {
815 if (p == 0)
816 {
Bram Moolenaar363d6142020-05-30 20:50:25 +0200817 if (decimal_offset)
818 addrlen = sprintf(l, "%08ld:",
819 ((unsigned long)(n + seekoff + displayoff)));
820 else
821 addrlen = sprintf(l, "%08lx:",
822 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100823 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000824 }
825 if (hextype == HEX_NORMAL)
826 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100827 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100828 l[++c] = hexx[ e & 0xf];
829 }
830 else if (hextype == HEX_LITTLEENDIAN)
831 {
832 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100833 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100834 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 }
836 else /* hextype == HEX_BITS */
837 {
838 int i;
839
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100840 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 for (i = 7; i >= 0; i--)
842 l[++c] = (e & (1 << i)) ? '1' : '0';
843 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100844 if (e)
845 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 if (ebcdic)
847 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000848 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100849 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850#ifdef __MVS__
851 (e >= 64)
852#else
853 (e > 31 && e < 127)
854#endif
855 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 n++;
857 if (++p == cols)
858 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100859 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 xxdline(fpo, l, autoskip ? nonzero : 1);
861 nonzero = 0;
862 p = 0;
863 }
864 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200865 if (e == EOF && ferror(fp))
866 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 if (p)
868 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100869 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000870 xxdline(fpo, l, 1);
871 }
872 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000873 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000874
Bram Moolenaare0659a62011-04-01 19:14:40 +0200875 if (fclose(fp))
876 die(2);
877 if (fclose(fpo))
878 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879 return 0;
880}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200881
882/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */