blob: c24089e4ed2fa5fc1cf3c6cc67f6b2a3b5a90659 [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 Moolenaaraf703582019-01-31 11:00:42 +0100475 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000476
477#ifdef AMIGA
478 /* This program doesn't work when started from the Workbench */
479 if (argc == 0)
480 exit(1);
481#endif
482
483 pname = argv[0];
484 for (pp = pname; *pp; )
485 if (*pp++ == PATH_SEP)
486 pname = pp;
487#ifdef FILE_SEP
488 for (pp = pname; *pp; pp++)
489 if (*pp == FILE_SEP)
490 {
491 *pp = '\0';
492 break;
493 }
494#endif
495
496 while (argc >= 2)
497 {
498 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
499 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
500 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100501 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
503 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
504 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200505 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000506 else if (!STRNCMP(pp, "-r", 2)) revert++;
507 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
508 else if (!STRNCMP(pp, "-v", 2))
509 {
510 fprintf(stderr, "%s%s\n", version, osver);
511 exit(0);
512 }
513 else if (!STRNCMP(pp, "-c", 2))
514 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100515 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200516 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100517 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
518 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 else
520 {
521 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200522 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 cols = (int)strtol(argv[2], NULL, 0);
524 argv++;
525 argc--;
526 }
527 }
528 else if (!STRNCMP(pp, "-g", 2))
529 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100530 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000531 octspergrp = (int)strtol(pp + 2, NULL, 0);
532 else
533 {
534 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200535 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 octspergrp = (int)strtol(argv[2], NULL, 0);
537 argv++;
538 argc--;
539 }
540 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100541 else if (!STRNCMP(pp, "-o", 2))
542 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100543 int reloffset = 0;
544 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100545 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100546 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100547 else
548 {
549 if (!argv[2])
550 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100551
552 if (argv[2][0] == '+')
553 reloffset++;
554 if (argv[2][reloffset] == '-')
555 negoffset++;
556
557 if (negoffset)
558 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
559 else
560 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
561
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100562 argv++;
563 argc--;
564 }
565 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566 else if (!STRNCMP(pp, "-s", 2))
567 {
568 relseek = 0;
569 negseek = 0;
570 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
571 {
572#ifdef TRY_SEEK
573 if (pp[2] == '+')
574 relseek++;
575 if (pp[2+relseek] == '-')
576 negseek++;
577#endif
578 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
579 }
580 else
581 {
582 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200583 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000584#ifdef TRY_SEEK
585 if (argv[2][0] == '+')
586 relseek++;
587 if (argv[2][relseek] == '-')
588 negseek++;
589#endif
590 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
591 argv++;
592 argc--;
593 }
594 }
595 else if (!STRNCMP(pp, "-l", 2))
596 {
597 if (pp[2] && STRNCMP("en", pp + 2, 2))
598 length = strtol(pp + 2, (char **)NULL, 0);
599 else
600 {
601 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200602 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000603 length = strtol(argv[2], (char **)NULL, 0);
604 argv++;
605 argc--;
606 }
607 }
608 else if (!strcmp(pp, "--")) /* end of options */
609 {
610 argv++;
611 argc--;
612 break;
613 }
614 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200615 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 else
617 break; /* not an option */
618
619 argv++; /* advance to next argument */
620 argc--;
621 }
622
623 if (!cols)
624 switch (hextype)
625 {
626 case HEX_POSTSCRIPT: cols = 30; break;
627 case HEX_CINCLUDE: cols = 12; break;
628 case HEX_BITS: cols = 6; break;
629 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100630 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 default: cols = 16; break;
632 }
633
634 if (octspergrp < 0)
635 switch (hextype)
636 {
637 case HEX_BITS: octspergrp = 1; break;
638 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100639 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000640 case HEX_POSTSCRIPT:
641 case HEX_CINCLUDE:
642 default: octspergrp = 0; break;
643 }
644
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100645 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000646 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 {
648 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
649 exit(1);
650 }
651
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100652 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000653 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100654 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
655 {
656 fprintf(stderr,
657 "%s: number of octets per group must be a power of 2 with -e.\n",
658 pname);
659 exit(1);
660 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
662 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200663 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000664
665 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
666 BIN_ASSIGN(fp = stdin, !revert);
667 else
668 {
669 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
670 {
671 fprintf(stderr,"%s: ", pname);
672 perror(argv[1]);
673 return 2;
674 }
675 }
676
677 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
678 BIN_ASSIGN(fpo = stdout, revert);
679 else
680 {
681 int fd;
682 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
683
684 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
685 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
686 {
687 fprintf(stderr, "%s: ", pname);
688 perror(argv[2]);
689 return 3;
690 }
691 rewind(fpo);
692 }
693
694 if (revert)
695 {
696 if (hextype && (hextype != HEX_POSTSCRIPT))
697 {
698 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
699 return -1;
700 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200701 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000702 negseek ? -seekoff : seekoff);
703 }
704
705 if (seekoff || negseek || !relseek)
706 {
707#ifdef TRY_SEEK
708 if (relseek)
709 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
710 else
711 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
712 if (e < 0 && negseek)
713 {
714 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
715 return 4;
716 }
717 if (e >= 0)
718 seekoff = ftell(fp);
719 else
720#endif
721 {
722 long s = seekoff;
723
724 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200725 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200726 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200727 if (ferror(fp))
728 {
729 die(2);
730 }
731 else
732 {
733 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
734 return 4;
735 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200736 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 }
738 }
739
740 if (hextype == HEX_CINCLUDE)
741 {
742 if (fp != stdin)
743 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
745 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200747 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200748 die(3);
749 if (fputs("[] = {\n", fpo) == EOF)
750 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751 }
752
753 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200754 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
756 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200757 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200758 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200759 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 p++;
761 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200762 if (c == EOF && ferror(fp))
763 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100765 if (p && fputs("\n", fpo) == EOF)
766 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200767 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100768 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769
770 if (fp != stdin)
771 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200772 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
773 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200775 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200776 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200777 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200778 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 }
780
Bram Moolenaare0659a62011-04-01 19:14:40 +0200781 if (fclose(fp))
782 die(2);
783 if (fclose(fpo))
784 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 return 0;
786 }
787
788 if (hextype == HEX_POSTSCRIPT)
789 {
790 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200791 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
793 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200794 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
795 || putc(hexx[e & 0xf], fpo) == EOF)
796 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797 n++;
798 if (!--p)
799 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200800 if (putc('\n', fpo) == EOF)
801 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 p = cols;
803 }
804 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200805 if (e == EOF && ferror(fp))
806 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200808 if (putc('\n', fpo) == EOF)
809 die(3);
810 if (fclose(fp))
811 die(2);
812 if (fclose(fpo))
813 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 return 0;
815 }
816
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100817 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000818
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100819 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000820 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
821 else /* hextype == HEX_BITS */
822 grplen = 8 * octspergrp + 1;
823
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 : */