blob: b8761fc29c8156e12621140dc55d50f86277b275 [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...
38 * 18.07.96 gcc -Wall @ SunOS4 is now slient.
39 * 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 Moolenaar071d4272004-06-13 20:20:40 +000056 *
57 * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
58 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020059 * I hereby grant permission to distribute and use xxd
60 * under X11-MIT or GPL-2.0 (at the user's choice).
61 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000062 * Small changes made afterwards by Bram Moolenaar et al.
63 *
64 * Distribute freely and credit me,
65 * make money and share with me,
66 * lose money and don't ask me.
67 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000068
69/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
70#if _MSC_VER >= 1400
71# define _CRT_SECURE_NO_DEPRECATE
72# define _CRT_NONSTDC_NO_DEPRECATE
73#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000074#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
75# define CYGWIN
76#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000077
Bram Moolenaar071d4272004-06-13 20:20:40 +000078#include <stdio.h>
79#ifdef VAXC
80# include <file.h>
81#else
82# include <fcntl.h>
83#endif
Bram Moolenaara06ecab2016-07-16 14:47:36 +020084#if defined(WIN32) || defined(__BORLANDC__) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000085# include <io.h> /* for setmode() */
86#else
87# ifdef UNIX
88# include <unistd.h>
89# endif
90#endif
91#include <stdlib.h>
92#include <string.h> /* for strncmp() */
93#include <ctype.h> /* for isalnum() */
Bram Moolenaard8c56a02019-01-30 23:02:25 +010094#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000095#if __MWERKS__ && !defined(BEBOX)
96# include <unix.h> /* for fdopen() on MAC */
97#endif
98
99#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
100/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
101# define fileno(f) ((f)->fd)
102FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
103#endif
104
105
106/* This corrects the problem of missing prototypes for certain functions
107 * in some GNU installations (e.g. SunOS 4.1.x).
108 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
109 */
110#if defined(__GNUC__) && defined(__STDC__)
111# ifndef __USE_FIXED_PROTOTYPES__
112# define __USE_FIXED_PROTOTYPES__
113# endif
114#endif
115
116#ifndef __USE_FIXED_PROTOTYPES__
117/*
118 * This is historic and works only if the compiler really has no prototypes:
119 *
120 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
121 * FILE is defined on OS 4.x, not on 5.x (Solaris).
122 * if __SVR4 is defined (some Solaris versions), don't include this.
123 */
124#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
125# define __P(a) a
126/* excerpt from my sun_stdlib.h */
127extern int fprintf __P((FILE *, char *, ...));
128extern int fputs __P((char *, FILE *));
129extern int _flsbuf __P((unsigned char, FILE *));
130extern int _filbuf __P((FILE *));
131extern int fflush __P((FILE *));
132extern int fclose __P((FILE *));
133extern int fseek __P((FILE *, long, int));
134extern int rewind __P((FILE *));
135
136extern void perror __P((char *));
137# endif
138#endif
139
140extern long int strtol();
141extern long int ftell();
142
143char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
144#ifdef WIN32
145char osver[] = " (Win32)";
146#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000147char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000148#endif
149
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200150#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000151# define BIN_READ(yes) ((yes) ? "rb" : "rt")
152# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
153# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
154# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000155# define PATH_SEP '\\'
156#elif defined(CYGWIN)
157# define BIN_READ(yes) ((yes) ? "rb" : "rt")
158# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
159# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
160# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
161# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000162#else
163# ifdef VMS
164# define BIN_READ(dummy) "r"
165# define BIN_WRITE(dummy) "w"
166# define BIN_CREAT(dummy) O_CREAT
167# define BIN_ASSIGN(fp, dummy) fp
168# define PATH_SEP ']'
169# define FILE_SEP '.'
170# else
171# define BIN_READ(dummy) "r"
172# define BIN_WRITE(dummy) "w"
173# define BIN_CREAT(dummy) O_CREAT
174# define BIN_ASSIGN(fp, dummy) fp
175# define PATH_SEP '/'
176# endif
177#endif
178
179/* open has only to arguments on the Mac */
180#if __MWERKS__
181# define OPEN(name, mode, umask) open(name, mode)
182#else
183# define OPEN(name, mode, umask) open(name, mode, umask)
184#endif
185
186#ifdef AMIGA
187# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
188#else
189# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
190#endif
191
192#ifndef __P
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200193# if defined(__STDC__) || defined(WIN32) || defined(__BORLANDC__)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194# define __P(a) a
195# else
196# define __P(a) ()
197# endif
198#endif
199
200/* Let's collect some prototypes */
201/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200202static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200203static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200204static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000205static void xxdline __P((FILE *, char *, int));
206
207#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
208#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100209#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
211char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
212
213/* the different hextypes known by this program: */
214#define HEX_NORMAL 0
215#define HEX_POSTSCRIPT 1
216#define HEX_CINCLUDE 2
217#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100218#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200220#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
221
Bram Moolenaare0659a62011-04-01 19:14:40 +0200222static char *pname;
223
224 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100225exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000226{
227 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
228 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
229 fprintf(stderr, "Options:\n");
230 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100231 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200232 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
234 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100235 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
236 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000237 fprintf(stderr, " -h print this summary.\n");
238 fprintf(stderr, " -i output in C include file style.\n");
239 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100240 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
242 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
243 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
244 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
245#ifdef TRY_SEEK
246 "[+][-]", "(or +: rel.) ");
247#else
248 "", "");
249#endif
250 fprintf(stderr, " -u use upper case hex letters.\n");
251 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
252 exit(1);
253}
254
Bram Moolenaare0659a62011-04-01 19:14:40 +0200255 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100256die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200257{
258 fprintf(stderr, "%s: ", pname);
259 perror(NULL);
260 exit(ret);
261}
262
Bram Moolenaar071d4272004-06-13 20:20:40 +0000263/*
264 * Max. cols binary characters are decoded from the input stream per line.
265 * Two adjacent garbage characters after evaluated data delimit valid data.
266 * Everything up to the next newline is discarded.
267 *
268 * The name is historic and came from 'undo type opt h'.
269 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200270 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100271huntype(
272 FILE *fpi,
273 FILE *fpo,
274 FILE *fperr,
275 int cols,
276 int hextype,
277 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000278{
279 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
280 long have_off = 0, want_off = 0;
281
282 rewind(fpi);
283
284 while ((c = getc(fpi)) != EOF)
285 {
286 if (c == '\r') /* Doze style input file? */
287 continue;
288
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100289 /* Allow multiple spaces. This doesn't work when there is normal text
290 * after the hex codes in the last line that looks like hex, thus only
291 * use it for PostScript format. */
292 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000293 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000294
Bram Moolenaar071d4272004-06-13 20:20:40 +0000295 n3 = n2;
296 n2 = n1;
297
298 if (c >= '0' && c <= '9')
299 n1 = c - '0';
300 else if (c >= 'a' && c <= 'f')
301 n1 = c - 'a' + 10;
302 else if (c >= 'A' && c <= 'F')
303 n1 = c - 'A' + 10;
304 else
305 {
306 n1 = -1;
307 if (ign_garb)
308 continue;
309 }
310
311 ign_garb = 0;
312
313 if (p >= cols)
314 {
315 if (!hextype)
316 {
317 if (n1 < 0)
318 {
319 p = 0;
320 continue;
321 }
322 want_off = (want_off << 4) | n1;
323 continue;
324 }
325 else
326 p = 0;
327 }
328
329 if (base_off + want_off != have_off)
330 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200331 if (fflush(fpo) != 0)
332 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333#ifdef TRY_SEEK
334 c = fseek(fpo, base_off + want_off - have_off, 1);
335 if (c >= 0)
336 have_off = base_off + want_off;
337#endif
338 if (base_off + want_off < have_off)
339 {
340 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
341 return 5;
342 }
343 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200344 if (putc(0, fpo) == EOF)
345 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 }
347
348 if (n2 >= 0 && n1 >= 0)
349 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200350 if (putc((n2 << 4) | n1, fpo) == EOF)
351 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 have_off++;
353 want_off++;
354 n1 = -1;
355 if ((++p >= cols) && !hextype)
356 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000357 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 want_off = 0;
359 while ((c = getc(fpi)) != '\n' && c != EOF)
360 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200361 if (c == EOF && ferror(fpi))
362 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 ign_garb = 1;
364 }
365 }
366 else if (n1 < 0 && n2 < 0 && n3 < 0)
367 {
368 /* already stumbled into garbage, skip line, wait and see */
369 if (!hextype)
370 want_off = 0;
371 while ((c = getc(fpi)) != '\n' && c != EOF)
372 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200373 if (c == EOF && ferror(fpi))
374 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 ign_garb = 1;
376 }
377 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200378 if (fflush(fpo) != 0)
379 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000380#ifdef TRY_SEEK
381 fseek(fpo, 0L, 2);
382#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200383 if (fclose(fpo) != 0)
384 die(3);
385 if (fclose(fpi) != 0)
386 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387 return 0;
388}
389
390/*
391 * Print line l. If nz is false, xxdline regards the line a line of
392 * zeroes. If there are three or more consecutive lines of zeroes,
393 * they are replaced by a single '*' character.
394 *
395 * If the output ends with more than two lines of zeroes, you
396 * should call xxdline again with l being the last line and nz
397 * negative. This ensures that the last line is shown even when
398 * it is all zeroes.
399 *
400 * If nz is always positive, lines are never suppressed.
401 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200402 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100403xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404{
405 static char z[LLEN+1];
406 static int zero_seen = 0;
407
408 if (!nz && zero_seen == 1)
409 strcpy(z, l);
410
411 if (nz || !zero_seen++)
412 {
413 if (nz)
414 {
415 if (nz < 0)
416 zero_seen--;
417 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200418 if (fputs(z, fp) == EOF)
419 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000420 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200421 if (fputs("*\n", fp) == EOF)
422 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000423 }
424 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200425 if (fputs(l, fp) == EOF)
426 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 if (nz)
428 zero_seen = 0;
429 }
430}
431
432/* This is an EBCDIC to ASCII conversion table */
433/* from a proposed BTL standard April 16, 1979 */
434static unsigned char etoa64[] =
435{
436 0040,0240,0241,0242,0243,0244,0245,0246,
437 0247,0250,0325,0056,0074,0050,0053,0174,
438 0046,0251,0252,0253,0254,0255,0256,0257,
439 0260,0261,0041,0044,0052,0051,0073,0176,
440 0055,0057,0262,0263,0264,0265,0266,0267,
441 0270,0271,0313,0054,0045,0137,0076,0077,
442 0272,0273,0274,0275,0276,0277,0300,0301,
443 0302,0140,0072,0043,0100,0047,0075,0042,
444 0303,0141,0142,0143,0144,0145,0146,0147,
445 0150,0151,0304,0305,0306,0307,0310,0311,
446 0312,0152,0153,0154,0155,0156,0157,0160,
447 0161,0162,0136,0314,0315,0316,0317,0320,
448 0321,0345,0163,0164,0165,0166,0167,0170,
449 0171,0172,0322,0323,0324,0133,0326,0327,
450 0330,0331,0332,0333,0334,0335,0336,0337,
451 0340,0341,0342,0343,0344,0135,0346,0347,
452 0173,0101,0102,0103,0104,0105,0106,0107,
453 0110,0111,0350,0351,0352,0353,0354,0355,
454 0175,0112,0113,0114,0115,0116,0117,0120,
455 0121,0122,0356,0357,0360,0361,0362,0363,
456 0134,0237,0123,0124,0125,0126,0127,0130,
457 0131,0132,0364,0365,0366,0367,0370,0371,
458 0060,0061,0062,0063,0064,0065,0066,0067,
459 0070,0071,0372,0373,0374,0375,0376,0377
460};
461
Bram Moolenaare0659a62011-04-01 19:14:40 +0200462 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100463main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000464{
465 FILE *fp, *fpo;
466 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200467 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL, capitalize = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468 int ebcdic = 0;
469 int octspergrp = -1; /* number of octets grouped in output */
470 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100471 long length = -1, n = 0, seekoff = 0;
472 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200473 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200474 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475
476#ifdef AMIGA
477 /* This program doesn't work when started from the Workbench */
478 if (argc == 0)
479 exit(1);
480#endif
481
482 pname = argv[0];
483 for (pp = pname; *pp; )
484 if (*pp++ == PATH_SEP)
485 pname = pp;
486#ifdef FILE_SEP
487 for (pp = pname; *pp; pp++)
488 if (*pp == FILE_SEP)
489 {
490 *pp = '\0';
491 break;
492 }
493#endif
494
495 while (argc >= 2)
496 {
497 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
498 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
499 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100500 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000501 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
502 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
503 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200504 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000505 else if (!STRNCMP(pp, "-r", 2)) revert++;
506 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
507 else if (!STRNCMP(pp, "-v", 2))
508 {
509 fprintf(stderr, "%s%s\n", version, osver);
510 exit(0);
511 }
512 else if (!STRNCMP(pp, "-c", 2))
513 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100514 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200515 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100516 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
517 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000518 else
519 {
520 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200521 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000522 cols = (int)strtol(argv[2], NULL, 0);
523 argv++;
524 argc--;
525 }
526 }
527 else if (!STRNCMP(pp, "-g", 2))
528 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100529 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 octspergrp = (int)strtol(pp + 2, NULL, 0);
531 else
532 {
533 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200534 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000535 octspergrp = (int)strtol(argv[2], NULL, 0);
536 argv++;
537 argc--;
538 }
539 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100540 else if (!STRNCMP(pp, "-o", 2))
541 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100542 int reloffset = 0;
543 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100544 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100545 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100546 else
547 {
548 if (!argv[2])
549 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100550
551 if (argv[2][0] == '+')
552 reloffset++;
553 if (argv[2][reloffset] == '-')
554 negoffset++;
555
556 if (negoffset)
557 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
558 else
559 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
560
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100561 argv++;
562 argc--;
563 }
564 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000565 else if (!STRNCMP(pp, "-s", 2))
566 {
567 relseek = 0;
568 negseek = 0;
569 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
570 {
571#ifdef TRY_SEEK
572 if (pp[2] == '+')
573 relseek++;
574 if (pp[2+relseek] == '-')
575 negseek++;
576#endif
577 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
578 }
579 else
580 {
581 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200582 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000583#ifdef TRY_SEEK
584 if (argv[2][0] == '+')
585 relseek++;
586 if (argv[2][relseek] == '-')
587 negseek++;
588#endif
589 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
590 argv++;
591 argc--;
592 }
593 }
594 else if (!STRNCMP(pp, "-l", 2))
595 {
596 if (pp[2] && STRNCMP("en", pp + 2, 2))
597 length = strtol(pp + 2, (char **)NULL, 0);
598 else
599 {
600 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200601 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000602 length = strtol(argv[2], (char **)NULL, 0);
603 argv++;
604 argc--;
605 }
606 }
607 else if (!strcmp(pp, "--")) /* end of options */
608 {
609 argv++;
610 argc--;
611 break;
612 }
613 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200614 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 else
616 break; /* not an option */
617
618 argv++; /* advance to next argument */
619 argc--;
620 }
621
622 if (!cols)
623 switch (hextype)
624 {
625 case HEX_POSTSCRIPT: cols = 30; break;
626 case HEX_CINCLUDE: cols = 12; break;
627 case HEX_BITS: cols = 6; break;
628 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100629 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 default: cols = 16; break;
631 }
632
633 if (octspergrp < 0)
634 switch (hextype)
635 {
636 case HEX_BITS: octspergrp = 1; break;
637 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100638 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639 case HEX_POSTSCRIPT:
640 case HEX_CINCLUDE:
641 default: octspergrp = 0; break;
642 }
643
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100644 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000645 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646 {
647 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
648 exit(1);
649 }
650
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100651 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000652 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100653 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
654 {
655 fprintf(stderr,
656 "%s: number of octets per group must be a power of 2 with -e.\n",
657 pname);
658 exit(1);
659 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000660
661 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200662 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000663
664 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
665 BIN_ASSIGN(fp = stdin, !revert);
666 else
667 {
668 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
669 {
670 fprintf(stderr,"%s: ", pname);
671 perror(argv[1]);
672 return 2;
673 }
674 }
675
676 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
677 BIN_ASSIGN(fpo = stdout, revert);
678 else
679 {
680 int fd;
681 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
682
683 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
684 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
685 {
686 fprintf(stderr, "%s: ", pname);
687 perror(argv[2]);
688 return 3;
689 }
690 rewind(fpo);
691 }
692
693 if (revert)
694 {
695 if (hextype && (hextype != HEX_POSTSCRIPT))
696 {
697 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
698 return -1;
699 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200700 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701 negseek ? -seekoff : seekoff);
702 }
703
704 if (seekoff || negseek || !relseek)
705 {
706#ifdef TRY_SEEK
707 if (relseek)
708 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
709 else
710 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
711 if (e < 0 && negseek)
712 {
713 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
714 return 4;
715 }
716 if (e >= 0)
717 seekoff = ftell(fp);
718 else
719#endif
720 {
721 long s = seekoff;
722
723 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200724 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200725 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200726 if (ferror(fp))
727 {
728 die(2);
729 }
730 else
731 {
732 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
733 return 4;
734 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200735 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 }
737 }
738
739 if (hextype == HEX_CINCLUDE)
740 {
741 if (fp != stdin)
742 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200743 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
744 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200746 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200747 die(3);
748 if (fputs("[] = {\n", fpo) == EOF)
749 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 }
751
752 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200753 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
755 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200756 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200757 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200758 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 p++;
760 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200761 if (c == EOF && ferror(fp))
762 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100764 if (p && fputs("\n", fpo) == EOF)
765 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200766 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100767 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768
769 if (fp != stdin)
770 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200771 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
772 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200774 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200775 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200776 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200777 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000778 }
779
Bram Moolenaare0659a62011-04-01 19:14:40 +0200780 if (fclose(fp))
781 die(2);
782 if (fclose(fpo))
783 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 return 0;
785 }
786
787 if (hextype == HEX_POSTSCRIPT)
788 {
789 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200790 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
792 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200793 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
794 || putc(hexx[e & 0xf], fpo) == EOF)
795 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 n++;
797 if (!--p)
798 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200799 if (putc('\n', fpo) == EOF)
800 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 p = cols;
802 }
803 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200804 if (e == EOF && ferror(fp))
805 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000806 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200807 if (putc('\n', fpo) == EOF)
808 die(3);
809 if (fclose(fp))
810 die(2);
811 if (fclose(fpo))
812 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 return 0;
814 }
815
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100816 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100818 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
820 else /* hextype == HEX_BITS */
821 grplen = 8 * octspergrp + 1;
822
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100823 int addrlen = 9;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200824 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
826 {
827 if (p == 0)
828 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100829 addrlen = sprintf(l, "%08lx:",
830 ((unsigned long)(n + seekoff + displayoff)));
831 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 }
833 if (hextype == HEX_NORMAL)
834 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100835 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100836 l[++c] = hexx[ e & 0xf];
837 }
838 else if (hextype == HEX_LITTLEENDIAN)
839 {
840 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100841 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100842 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 }
844 else /* hextype == HEX_BITS */
845 {
846 int i;
847
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100848 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000849 for (i = 7; i >= 0; i--)
850 l[++c] = (e & (1 << i)) ? '1' : '0';
851 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100852 if (e)
853 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000854 if (ebcdic)
855 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000856 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100857 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858#ifdef __MVS__
859 (e >= 64)
860#else
861 (e > 31 && e < 127)
862#endif
863 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864 n++;
865 if (++p == cols)
866 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100867 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000868 xxdline(fpo, l, autoskip ? nonzero : 1);
869 nonzero = 0;
870 p = 0;
871 }
872 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200873 if (e == EOF && ferror(fp))
874 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 if (p)
876 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100877 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000878 xxdline(fpo, l, 1);
879 }
880 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000881 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000882
Bram Moolenaare0659a62011-04-01 19:14:40 +0200883 if (fclose(fp))
884 die(2);
885 if (fclose(fpo))
886 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000887 return 0;
888}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200889
890/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */