blob: 20f06ab7c5c9fdb6b75de552c1a3ddcaea1f7d81 [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 *
58 * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
59 *
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 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000063 * Small changes made afterwards by Bram Moolenaar et al.
64 *
65 * Distribute freely and credit me,
66 * make money and share with me,
67 * lose money and don't ask me.
68 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000069
70/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
71#if _MSC_VER >= 1400
72# define _CRT_SECURE_NO_DEPRECATE
73# define _CRT_NONSTDC_NO_DEPRECATE
74#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010075#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000076# define CYGWIN
77#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000078
Bram Moolenaar071d4272004-06-13 20:20:40 +000079#include <stdio.h>
80#ifdef VAXC
81# include <file.h>
82#else
83# include <fcntl.h>
84#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020085#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000086# include <io.h> /* for setmode() */
87#else
88# ifdef UNIX
89# include <unistd.h>
90# endif
91#endif
92#include <stdlib.h>
93#include <string.h> /* for strncmp() */
94#include <ctype.h> /* for isalnum() */
Bram Moolenaard8c56a02019-01-30 23:02:25 +010095#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000096#if __MWERKS__ && !defined(BEBOX)
97# include <unix.h> /* for fdopen() on MAC */
98#endif
99
Bram Moolenaar071d4272004-06-13 20:20:40 +0000100
101/* This corrects the problem of missing prototypes for certain functions
102 * in some GNU installations (e.g. SunOS 4.1.x).
103 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
104 */
105#if defined(__GNUC__) && defined(__STDC__)
106# ifndef __USE_FIXED_PROTOTYPES__
107# define __USE_FIXED_PROTOTYPES__
108# endif
109#endif
110
111#ifndef __USE_FIXED_PROTOTYPES__
112/*
113 * This is historic and works only if the compiler really has no prototypes:
114 *
115 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
116 * FILE is defined on OS 4.x, not on 5.x (Solaris).
117 * if __SVR4 is defined (some Solaris versions), don't include this.
118 */
119#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
120# define __P(a) a
121/* excerpt from my sun_stdlib.h */
122extern int fprintf __P((FILE *, char *, ...));
123extern int fputs __P((char *, FILE *));
124extern int _flsbuf __P((unsigned char, FILE *));
125extern int _filbuf __P((FILE *));
126extern int fflush __P((FILE *));
127extern int fclose __P((FILE *));
128extern int fseek __P((FILE *, long, int));
129extern int rewind __P((FILE *));
130
131extern void perror __P((char *));
132# endif
133#endif
134
135extern long int strtol();
136extern long int ftell();
137
138char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
139#ifdef WIN32
140char osver[] = " (Win32)";
141#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000143#endif
144
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200145#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146# define BIN_READ(yes) ((yes) ? "rb" : "rt")
147# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
148# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
149# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000150# define PATH_SEP '\\'
151#elif defined(CYGWIN)
152# define BIN_READ(yes) ((yes) ? "rb" : "rt")
153# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
154# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
155# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
156# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000157#else
158# ifdef VMS
159# define BIN_READ(dummy) "r"
160# define BIN_WRITE(dummy) "w"
161# define BIN_CREAT(dummy) O_CREAT
162# define BIN_ASSIGN(fp, dummy) fp
163# define PATH_SEP ']'
164# define FILE_SEP '.'
165# else
166# define BIN_READ(dummy) "r"
167# define BIN_WRITE(dummy) "w"
168# define BIN_CREAT(dummy) O_CREAT
169# define BIN_ASSIGN(fp, dummy) fp
170# define PATH_SEP '/'
171# endif
172#endif
173
174/* open has only to arguments on the Mac */
175#if __MWERKS__
176# define OPEN(name, mode, umask) open(name, mode)
177#else
178# define OPEN(name, mode, umask) open(name, mode, umask)
179#endif
180
181#ifdef AMIGA
182# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
183#else
184# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
185#endif
186
187#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200188# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000189# define __P(a) a
190# else
191# define __P(a) ()
192# endif
193#endif
194
195/* Let's collect some prototypes */
196/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200197static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200198static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200199static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000200static void xxdline __P((FILE *, char *, int));
201
202#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
203#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100204#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205
206char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
207
208/* the different hextypes known by this program: */
209#define HEX_NORMAL 0
210#define HEX_POSTSCRIPT 1
211#define HEX_CINCLUDE 2
212#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100213#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200215#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
216
Bram Moolenaare0659a62011-04-01 19:14:40 +0200217static char *pname;
218
219 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100220exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221{
222 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
223 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
224 fprintf(stderr, "Options:\n");
225 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100226 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200227 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
229 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100230 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
231 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 fprintf(stderr, " -h print this summary.\n");
233 fprintf(stderr, " -i output in C include file style.\n");
234 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100235 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
237 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
238 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200239 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
241#ifdef TRY_SEEK
242 "[+][-]", "(or +: rel.) ");
243#else
244 "", "");
245#endif
246 fprintf(stderr, " -u use upper case hex letters.\n");
247 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
248 exit(1);
249}
250
Bram Moolenaare0659a62011-04-01 19:14:40 +0200251 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100252die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200253{
254 fprintf(stderr, "%s: ", pname);
255 perror(NULL);
256 exit(ret);
257}
258
Bram Moolenaar071d4272004-06-13 20:20:40 +0000259/*
260 * Max. cols binary characters are decoded from the input stream per line.
261 * Two adjacent garbage characters after evaluated data delimit valid data.
262 * Everything up to the next newline is discarded.
263 *
264 * The name is historic and came from 'undo type opt h'.
265 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200266 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100267huntype(
268 FILE *fpi,
269 FILE *fpo,
270 FILE *fperr,
271 int cols,
272 int hextype,
273 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274{
275 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
276 long have_off = 0, want_off = 0;
277
278 rewind(fpi);
279
280 while ((c = getc(fpi)) != EOF)
281 {
282 if (c == '\r') /* Doze style input file? */
283 continue;
284
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100285 /* Allow multiple spaces. This doesn't work when there is normal text
286 * after the hex codes in the last line that looks like hex, thus only
287 * use it for PostScript format. */
288 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000289 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000290
Bram Moolenaar071d4272004-06-13 20:20:40 +0000291 n3 = n2;
292 n2 = n1;
293
294 if (c >= '0' && c <= '9')
295 n1 = c - '0';
296 else if (c >= 'a' && c <= 'f')
297 n1 = c - 'a' + 10;
298 else if (c >= 'A' && c <= 'F')
299 n1 = c - 'A' + 10;
300 else
301 {
302 n1 = -1;
303 if (ign_garb)
304 continue;
305 }
306
307 ign_garb = 0;
308
309 if (p >= cols)
310 {
311 if (!hextype)
312 {
313 if (n1 < 0)
314 {
315 p = 0;
316 continue;
317 }
318 want_off = (want_off << 4) | n1;
319 continue;
320 }
321 else
322 p = 0;
323 }
324
325 if (base_off + want_off != have_off)
326 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200327 if (fflush(fpo) != 0)
328 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000329#ifdef TRY_SEEK
330 c = fseek(fpo, base_off + want_off - have_off, 1);
331 if (c >= 0)
332 have_off = base_off + want_off;
333#endif
334 if (base_off + want_off < have_off)
335 {
336 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
337 return 5;
338 }
339 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200340 if (putc(0, fpo) == EOF)
341 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342 }
343
344 if (n2 >= 0 && n1 >= 0)
345 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200346 if (putc((n2 << 4) | n1, fpo) == EOF)
347 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 have_off++;
349 want_off++;
350 n1 = -1;
351 if ((++p >= cols) && !hextype)
352 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000353 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 want_off = 0;
355 while ((c = getc(fpi)) != '\n' && c != EOF)
356 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200357 if (c == EOF && ferror(fpi))
358 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 ign_garb = 1;
360 }
361 }
362 else if (n1 < 0 && n2 < 0 && n3 < 0)
363 {
364 /* already stumbled into garbage, skip line, wait and see */
365 if (!hextype)
366 want_off = 0;
367 while ((c = getc(fpi)) != '\n' && c != EOF)
368 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200369 if (c == EOF && ferror(fpi))
370 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000371 ign_garb = 1;
372 }
373 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200374 if (fflush(fpo) != 0)
375 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376#ifdef TRY_SEEK
377 fseek(fpo, 0L, 2);
378#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200379 if (fclose(fpo) != 0)
380 die(3);
381 if (fclose(fpi) != 0)
382 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000383 return 0;
384}
385
386/*
387 * Print line l. If nz is false, xxdline regards the line a line of
388 * zeroes. If there are three or more consecutive lines of zeroes,
389 * they are replaced by a single '*' character.
390 *
391 * If the output ends with more than two lines of zeroes, you
392 * should call xxdline again with l being the last line and nz
393 * negative. This ensures that the last line is shown even when
394 * it is all zeroes.
395 *
396 * If nz is always positive, lines are never suppressed.
397 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200398 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100399xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000400{
401 static char z[LLEN+1];
402 static int zero_seen = 0;
403
404 if (!nz && zero_seen == 1)
405 strcpy(z, l);
406
407 if (nz || !zero_seen++)
408 {
409 if (nz)
410 {
411 if (nz < 0)
412 zero_seen--;
413 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200414 if (fputs(z, fp) == EOF)
415 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200417 if (fputs("*\n", fp) == EOF)
418 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419 }
420 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200421 if (fputs(l, fp) == EOF)
422 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 if (nz)
424 zero_seen = 0;
425 }
426}
427
428/* This is an EBCDIC to ASCII conversion table */
429/* from a proposed BTL standard April 16, 1979 */
430static unsigned char etoa64[] =
431{
432 0040,0240,0241,0242,0243,0244,0245,0246,
433 0247,0250,0325,0056,0074,0050,0053,0174,
434 0046,0251,0252,0253,0254,0255,0256,0257,
435 0260,0261,0041,0044,0052,0051,0073,0176,
436 0055,0057,0262,0263,0264,0265,0266,0267,
437 0270,0271,0313,0054,0045,0137,0076,0077,
438 0272,0273,0274,0275,0276,0277,0300,0301,
439 0302,0140,0072,0043,0100,0047,0075,0042,
440 0303,0141,0142,0143,0144,0145,0146,0147,
441 0150,0151,0304,0305,0306,0307,0310,0311,
442 0312,0152,0153,0154,0155,0156,0157,0160,
443 0161,0162,0136,0314,0315,0316,0317,0320,
444 0321,0345,0163,0164,0165,0166,0167,0170,
445 0171,0172,0322,0323,0324,0133,0326,0327,
446 0330,0331,0332,0333,0334,0335,0336,0337,
447 0340,0341,0342,0343,0344,0135,0346,0347,
448 0173,0101,0102,0103,0104,0105,0106,0107,
449 0110,0111,0350,0351,0352,0353,0354,0355,
450 0175,0112,0113,0114,0115,0116,0117,0120,
451 0121,0122,0356,0357,0360,0361,0362,0363,
452 0134,0237,0123,0124,0125,0126,0127,0130,
453 0131,0132,0364,0365,0366,0367,0370,0371,
454 0060,0061,0062,0063,0064,0065,0066,0067,
455 0070,0071,0372,0373,0374,0375,0376,0377
456};
457
Bram Moolenaare0659a62011-04-01 19:14:40 +0200458 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100459main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460{
461 FILE *fp, *fpo;
462 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200463 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
464 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465 int ebcdic = 0;
466 int octspergrp = -1; /* number of octets grouped in output */
467 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100468 long length = -1, n = 0, seekoff = 0;
469 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200470 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200471 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100472 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000473
474#ifdef AMIGA
475 /* This program doesn't work when started from the Workbench */
476 if (argc == 0)
477 exit(1);
478#endif
479
480 pname = argv[0];
481 for (pp = pname; *pp; )
482 if (*pp++ == PATH_SEP)
483 pname = pp;
484#ifdef FILE_SEP
485 for (pp = pname; *pp; pp++)
486 if (*pp == FILE_SEP)
487 {
488 *pp = '\0';
489 break;
490 }
491#endif
492
493 while (argc >= 2)
494 {
495 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
496 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
497 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100498 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
500 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
501 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200502 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200503 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 else if (!STRNCMP(pp, "-r", 2)) revert++;
505 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
506 else if (!STRNCMP(pp, "-v", 2))
507 {
508 fprintf(stderr, "%s%s\n", version, osver);
509 exit(0);
510 }
511 else if (!STRNCMP(pp, "-c", 2))
512 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100513 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200514 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100515 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
516 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 else
518 {
519 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200520 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 cols = (int)strtol(argv[2], NULL, 0);
522 argv++;
523 argc--;
524 }
525 }
526 else if (!STRNCMP(pp, "-g", 2))
527 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100528 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 octspergrp = (int)strtol(pp + 2, NULL, 0);
530 else
531 {
532 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200533 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000534 octspergrp = (int)strtol(argv[2], NULL, 0);
535 argv++;
536 argc--;
537 }
538 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100539 else if (!STRNCMP(pp, "-o", 2))
540 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100541 int reloffset = 0;
542 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100543 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100544 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100545 else
546 {
547 if (!argv[2])
548 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100549
550 if (argv[2][0] == '+')
551 reloffset++;
552 if (argv[2][reloffset] == '-')
553 negoffset++;
554
555 if (negoffset)
556 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
557 else
558 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
559
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100560 argv++;
561 argc--;
562 }
563 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000564 else if (!STRNCMP(pp, "-s", 2))
565 {
566 relseek = 0;
567 negseek = 0;
568 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
569 {
570#ifdef TRY_SEEK
571 if (pp[2] == '+')
572 relseek++;
573 if (pp[2+relseek] == '-')
574 negseek++;
575#endif
576 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
577 }
578 else
579 {
580 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200581 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000582#ifdef TRY_SEEK
583 if (argv[2][0] == '+')
584 relseek++;
585 if (argv[2][relseek] == '-')
586 negseek++;
587#endif
588 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
589 argv++;
590 argc--;
591 }
592 }
593 else if (!STRNCMP(pp, "-l", 2))
594 {
595 if (pp[2] && STRNCMP("en", pp + 2, 2))
596 length = strtol(pp + 2, (char **)NULL, 0);
597 else
598 {
599 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200600 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 length = strtol(argv[2], (char **)NULL, 0);
602 argv++;
603 argc--;
604 }
605 }
606 else if (!strcmp(pp, "--")) /* end of options */
607 {
608 argv++;
609 argc--;
610 break;
611 }
612 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200613 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000614 else
615 break; /* not an option */
616
617 argv++; /* advance to next argument */
618 argc--;
619 }
620
621 if (!cols)
622 switch (hextype)
623 {
624 case HEX_POSTSCRIPT: cols = 30; break;
625 case HEX_CINCLUDE: cols = 12; break;
626 case HEX_BITS: cols = 6; break;
627 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100628 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 default: cols = 16; break;
630 }
631
632 if (octspergrp < 0)
633 switch (hextype)
634 {
635 case HEX_BITS: octspergrp = 1; break;
636 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100637 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 case HEX_POSTSCRIPT:
639 case HEX_CINCLUDE:
640 default: octspergrp = 0; break;
641 }
642
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100643 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000644 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645 {
646 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
647 exit(1);
648 }
649
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100650 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100652 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
653 {
654 fprintf(stderr,
655 "%s: number of octets per group must be a power of 2 with -e.\n",
656 pname);
657 exit(1);
658 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000659
660 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200661 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000662
663 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
664 BIN_ASSIGN(fp = stdin, !revert);
665 else
666 {
667 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
668 {
669 fprintf(stderr,"%s: ", pname);
670 perror(argv[1]);
671 return 2;
672 }
673 }
674
675 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
676 BIN_ASSIGN(fpo = stdout, revert);
677 else
678 {
679 int fd;
680 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
681
682 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
683 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
684 {
685 fprintf(stderr, "%s: ", pname);
686 perror(argv[2]);
687 return 3;
688 }
689 rewind(fpo);
690 }
691
692 if (revert)
693 {
694 if (hextype && (hextype != HEX_POSTSCRIPT))
695 {
696 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
697 return -1;
698 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200699 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000700 negseek ? -seekoff : seekoff);
701 }
702
703 if (seekoff || negseek || !relseek)
704 {
705#ifdef TRY_SEEK
706 if (relseek)
707 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
708 else
709 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
710 if (e < 0 && negseek)
711 {
712 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
713 return 4;
714 }
715 if (e >= 0)
716 seekoff = ftell(fp);
717 else
718#endif
719 {
720 long s = seekoff;
721
722 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200723 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200724 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200725 if (ferror(fp))
726 {
727 die(2);
728 }
729 else
730 {
731 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
732 return 4;
733 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200734 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 }
736 }
737
738 if (hextype == HEX_CINCLUDE)
739 {
740 if (fp != stdin)
741 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200742 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
743 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200745 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200746 die(3);
747 if (fputs("[] = {\n", fpo) == EOF)
748 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 }
750
751 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200752 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
754 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200755 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200756 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200757 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 p++;
759 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200760 if (c == EOF && ferror(fp))
761 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000762
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100763 if (p && fputs("\n", fpo) == EOF)
764 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200765 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100766 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767
768 if (fp != stdin)
769 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200770 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
771 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000772 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200773 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200774 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200775 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200776 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 }
778
Bram Moolenaare0659a62011-04-01 19:14:40 +0200779 if (fclose(fp))
780 die(2);
781 if (fclose(fpo))
782 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000783 return 0;
784 }
785
786 if (hextype == HEX_POSTSCRIPT)
787 {
788 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200789 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000790 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
791 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200792 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
793 || putc(hexx[e & 0xf], fpo) == EOF)
794 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000795 n++;
796 if (!--p)
797 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200798 if (putc('\n', fpo) == EOF)
799 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800 p = cols;
801 }
802 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200803 if (e == EOF && ferror(fp))
804 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200806 if (putc('\n', fpo) == EOF)
807 die(3);
808 if (fclose(fp))
809 die(2);
810 if (fclose(fpo))
811 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812 return 0;
813 }
814
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100815 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000816
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100817 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
819 else /* hextype == HEX_BITS */
820 grplen = 8 * octspergrp + 1;
821
Bram Moolenaare0659a62011-04-01 19:14:40 +0200822 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000823 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
824 {
825 if (p == 0)
826 {
Bram Moolenaar363d6142020-05-30 20:50:25 +0200827 if (decimal_offset)
828 addrlen = sprintf(l, "%08ld:",
829 ((unsigned long)(n + seekoff + displayoff)));
830 else
831 addrlen = sprintf(l, "%08lx:",
832 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100833 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000834 }
835 if (hextype == HEX_NORMAL)
836 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100837 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100838 l[++c] = hexx[ e & 0xf];
839 }
840 else if (hextype == HEX_LITTLEENDIAN)
841 {
842 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100843 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100844 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000845 }
846 else /* hextype == HEX_BITS */
847 {
848 int i;
849
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100850 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000851 for (i = 7; i >= 0; i--)
852 l[++c] = (e & (1 << i)) ? '1' : '0';
853 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100854 if (e)
855 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 if (ebcdic)
857 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000858 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100859 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860#ifdef __MVS__
861 (e >= 64)
862#else
863 (e > 31 && e < 127)
864#endif
865 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866 n++;
867 if (++p == cols)
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, autoskip ? nonzero : 1);
871 nonzero = 0;
872 p = 0;
873 }
874 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200875 if (e == EOF && ferror(fp))
876 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000877 if (p)
878 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100879 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880 xxdline(fpo, l, 1);
881 }
882 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000883 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884
Bram Moolenaare0659a62011-04-01 19:14:40 +0200885 if (fclose(fp))
886 die(2);
887 if (fclose(fpo))
888 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000889 return 0;
890}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200891
892/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */