blob: f2192cf0d93298ee2e0b3528642238428901a133 [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 Moolenaar6ef8f9e2019-03-02 07:15:28 +010074#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000075# 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 Moolenaareae1b912019-05-09 15:12:55 +020084#if defined(WIN32) || 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
Bram Moolenaar071d4272004-06-13 20:20:40 +000099
100/* This corrects the problem of missing prototypes for certain functions
101 * in some GNU installations (e.g. SunOS 4.1.x).
102 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
103 */
104#if defined(__GNUC__) && defined(__STDC__)
105# ifndef __USE_FIXED_PROTOTYPES__
106# define __USE_FIXED_PROTOTYPES__
107# endif
108#endif
109
110#ifndef __USE_FIXED_PROTOTYPES__
111/*
112 * This is historic and works only if the compiler really has no prototypes:
113 *
114 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
115 * FILE is defined on OS 4.x, not on 5.x (Solaris).
116 * if __SVR4 is defined (some Solaris versions), don't include this.
117 */
118#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
119# define __P(a) a
120/* excerpt from my sun_stdlib.h */
121extern int fprintf __P((FILE *, char *, ...));
122extern int fputs __P((char *, FILE *));
123extern int _flsbuf __P((unsigned char, FILE *));
124extern int _filbuf __P((FILE *));
125extern int fflush __P((FILE *));
126extern int fclose __P((FILE *));
127extern int fseek __P((FILE *, long, int));
128extern int rewind __P((FILE *));
129
130extern void perror __P((char *));
131# endif
132#endif
133
134extern long int strtol();
135extern long int ftell();
136
137char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
138#ifdef WIN32
139char osver[] = " (Win32)";
140#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000141char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142#endif
143
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200144#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145# define BIN_READ(yes) ((yes) ? "rb" : "rt")
146# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
147# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
148# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000149# define PATH_SEP '\\'
150#elif defined(CYGWIN)
151# define BIN_READ(yes) ((yes) ? "rb" : "rt")
152# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
153# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
154# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
155# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000156#else
157# ifdef VMS
158# define BIN_READ(dummy) "r"
159# define BIN_WRITE(dummy) "w"
160# define BIN_CREAT(dummy) O_CREAT
161# define BIN_ASSIGN(fp, dummy) fp
162# define PATH_SEP ']'
163# define FILE_SEP '.'
164# else
165# define BIN_READ(dummy) "r"
166# define BIN_WRITE(dummy) "w"
167# define BIN_CREAT(dummy) O_CREAT
168# define BIN_ASSIGN(fp, dummy) fp
169# define PATH_SEP '/'
170# endif
171#endif
172
173/* open has only to arguments on the Mac */
174#if __MWERKS__
175# define OPEN(name, mode, umask) open(name, mode)
176#else
177# define OPEN(name, mode, umask) open(name, mode, umask)
178#endif
179
180#ifdef AMIGA
181# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
182#else
183# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
184#endif
185
186#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200187# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000188# define __P(a) a
189# else
190# define __P(a) ()
191# endif
192#endif
193
194/* Let's collect some prototypes */
195/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200196static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200197static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200198static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000199static void xxdline __P((FILE *, char *, int));
200
201#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
202#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100203#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000204
205char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
206
207/* the different hextypes known by this program: */
208#define HEX_NORMAL 0
209#define HEX_POSTSCRIPT 1
210#define HEX_CINCLUDE 2
211#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100212#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000213
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200214#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
215
Bram Moolenaare0659a62011-04-01 19:14:40 +0200216static char *pname;
217
218 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100219exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220{
221 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
222 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
223 fprintf(stderr, "Options:\n");
224 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100225 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200226 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000227 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
228 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100229 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
230 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 fprintf(stderr, " -h print this summary.\n");
232 fprintf(stderr, " -i output in C include file style.\n");
233 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100234 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
236 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
237 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
238 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
239#ifdef TRY_SEEK
240 "[+][-]", "(or +: rel.) ");
241#else
242 "", "");
243#endif
244 fprintf(stderr, " -u use upper case hex letters.\n");
245 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
246 exit(1);
247}
248
Bram Moolenaare0659a62011-04-01 19:14:40 +0200249 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100250die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200251{
252 fprintf(stderr, "%s: ", pname);
253 perror(NULL);
254 exit(ret);
255}
256
Bram Moolenaar071d4272004-06-13 20:20:40 +0000257/*
258 * Max. cols binary characters are decoded from the input stream per line.
259 * Two adjacent garbage characters after evaluated data delimit valid data.
260 * Everything up to the next newline is discarded.
261 *
262 * The name is historic and came from 'undo type opt h'.
263 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200264 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100265huntype(
266 FILE *fpi,
267 FILE *fpo,
268 FILE *fperr,
269 int cols,
270 int hextype,
271 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272{
273 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
274 long have_off = 0, want_off = 0;
275
276 rewind(fpi);
277
278 while ((c = getc(fpi)) != EOF)
279 {
280 if (c == '\r') /* Doze style input file? */
281 continue;
282
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100283 /* Allow multiple spaces. This doesn't work when there is normal text
284 * after the hex codes in the last line that looks like hex, thus only
285 * use it for PostScript format. */
286 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000287 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000288
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289 n3 = n2;
290 n2 = n1;
291
292 if (c >= '0' && c <= '9')
293 n1 = c - '0';
294 else if (c >= 'a' && c <= 'f')
295 n1 = c - 'a' + 10;
296 else if (c >= 'A' && c <= 'F')
297 n1 = c - 'A' + 10;
298 else
299 {
300 n1 = -1;
301 if (ign_garb)
302 continue;
303 }
304
305 ign_garb = 0;
306
307 if (p >= cols)
308 {
309 if (!hextype)
310 {
311 if (n1 < 0)
312 {
313 p = 0;
314 continue;
315 }
316 want_off = (want_off << 4) | n1;
317 continue;
318 }
319 else
320 p = 0;
321 }
322
323 if (base_off + want_off != have_off)
324 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200325 if (fflush(fpo) != 0)
326 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000327#ifdef TRY_SEEK
328 c = fseek(fpo, base_off + want_off - have_off, 1);
329 if (c >= 0)
330 have_off = base_off + want_off;
331#endif
332 if (base_off + want_off < have_off)
333 {
334 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
335 return 5;
336 }
337 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200338 if (putc(0, fpo) == EOF)
339 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000340 }
341
342 if (n2 >= 0 && n1 >= 0)
343 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200344 if (putc((n2 << 4) | n1, fpo) == EOF)
345 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000346 have_off++;
347 want_off++;
348 n1 = -1;
349 if ((++p >= cols) && !hextype)
350 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000351 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 want_off = 0;
353 while ((c = getc(fpi)) != '\n' && c != EOF)
354 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200355 if (c == EOF && ferror(fpi))
356 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 ign_garb = 1;
358 }
359 }
360 else if (n1 < 0 && n2 < 0 && n3 < 0)
361 {
362 /* already stumbled into garbage, skip line, wait and see */
363 if (!hextype)
364 want_off = 0;
365 while ((c = getc(fpi)) != '\n' && c != EOF)
366 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200367 if (c == EOF && ferror(fpi))
368 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 ign_garb = 1;
370 }
371 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200372 if (fflush(fpo) != 0)
373 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374#ifdef TRY_SEEK
375 fseek(fpo, 0L, 2);
376#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200377 if (fclose(fpo) != 0)
378 die(3);
379 if (fclose(fpi) != 0)
380 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381 return 0;
382}
383
384/*
385 * Print line l. If nz is false, xxdline regards the line a line of
386 * zeroes. If there are three or more consecutive lines of zeroes,
387 * they are replaced by a single '*' character.
388 *
389 * If the output ends with more than two lines of zeroes, you
390 * should call xxdline again with l being the last line and nz
391 * negative. This ensures that the last line is shown even when
392 * it is all zeroes.
393 *
394 * If nz is always positive, lines are never suppressed.
395 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200396 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100397xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398{
399 static char z[LLEN+1];
400 static int zero_seen = 0;
401
402 if (!nz && zero_seen == 1)
403 strcpy(z, l);
404
405 if (nz || !zero_seen++)
406 {
407 if (nz)
408 {
409 if (nz < 0)
410 zero_seen--;
411 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200412 if (fputs(z, fp) == EOF)
413 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000414 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200415 if (fputs("*\n", fp) == EOF)
416 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000417 }
418 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200419 if (fputs(l, fp) == EOF)
420 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421 if (nz)
422 zero_seen = 0;
423 }
424}
425
426/* This is an EBCDIC to ASCII conversion table */
427/* from a proposed BTL standard April 16, 1979 */
428static unsigned char etoa64[] =
429{
430 0040,0240,0241,0242,0243,0244,0245,0246,
431 0247,0250,0325,0056,0074,0050,0053,0174,
432 0046,0251,0252,0253,0254,0255,0256,0257,
433 0260,0261,0041,0044,0052,0051,0073,0176,
434 0055,0057,0262,0263,0264,0265,0266,0267,
435 0270,0271,0313,0054,0045,0137,0076,0077,
436 0272,0273,0274,0275,0276,0277,0300,0301,
437 0302,0140,0072,0043,0100,0047,0075,0042,
438 0303,0141,0142,0143,0144,0145,0146,0147,
439 0150,0151,0304,0305,0306,0307,0310,0311,
440 0312,0152,0153,0154,0155,0156,0157,0160,
441 0161,0162,0136,0314,0315,0316,0317,0320,
442 0321,0345,0163,0164,0165,0166,0167,0170,
443 0171,0172,0322,0323,0324,0133,0326,0327,
444 0330,0331,0332,0333,0334,0335,0336,0337,
445 0340,0341,0342,0343,0344,0135,0346,0347,
446 0173,0101,0102,0103,0104,0105,0106,0107,
447 0110,0111,0350,0351,0352,0353,0354,0355,
448 0175,0112,0113,0114,0115,0116,0117,0120,
449 0121,0122,0356,0357,0360,0361,0362,0363,
450 0134,0237,0123,0124,0125,0126,0127,0130,
451 0131,0132,0364,0365,0366,0367,0370,0371,
452 0060,0061,0062,0063,0064,0065,0066,0067,
453 0070,0071,0372,0373,0374,0375,0376,0377
454};
455
Bram Moolenaare0659a62011-04-01 19:14:40 +0200456 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100457main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000458{
459 FILE *fp, *fpo;
460 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200461 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL, capitalize = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462 int ebcdic = 0;
463 int octspergrp = -1; /* number of octets grouped in output */
464 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100465 long length = -1, n = 0, seekoff = 0;
466 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200467 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200468 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100469 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470
471#ifdef AMIGA
472 /* This program doesn't work when started from the Workbench */
473 if (argc == 0)
474 exit(1);
475#endif
476
477 pname = argv[0];
478 for (pp = pname; *pp; )
479 if (*pp++ == PATH_SEP)
480 pname = pp;
481#ifdef FILE_SEP
482 for (pp = pname; *pp; pp++)
483 if (*pp == FILE_SEP)
484 {
485 *pp = '\0';
486 break;
487 }
488#endif
489
490 while (argc >= 2)
491 {
492 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
493 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
494 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100495 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
497 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
498 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200499 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000500 else if (!STRNCMP(pp, "-r", 2)) revert++;
501 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
502 else if (!STRNCMP(pp, "-v", 2))
503 {
504 fprintf(stderr, "%s%s\n", version, osver);
505 exit(0);
506 }
507 else if (!STRNCMP(pp, "-c", 2))
508 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100509 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200510 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100511 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
512 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 else
514 {
515 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200516 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 cols = (int)strtol(argv[2], NULL, 0);
518 argv++;
519 argc--;
520 }
521 }
522 else if (!STRNCMP(pp, "-g", 2))
523 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100524 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000525 octspergrp = (int)strtol(pp + 2, NULL, 0);
526 else
527 {
528 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200529 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 octspergrp = (int)strtol(argv[2], NULL, 0);
531 argv++;
532 argc--;
533 }
534 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100535 else if (!STRNCMP(pp, "-o", 2))
536 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100537 int reloffset = 0;
538 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100539 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100540 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100541 else
542 {
543 if (!argv[2])
544 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100545
546 if (argv[2][0] == '+')
547 reloffset++;
548 if (argv[2][reloffset] == '-')
549 negoffset++;
550
551 if (negoffset)
552 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
553 else
554 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
555
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100556 argv++;
557 argc--;
558 }
559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 else if (!STRNCMP(pp, "-s", 2))
561 {
562 relseek = 0;
563 negseek = 0;
564 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
565 {
566#ifdef TRY_SEEK
567 if (pp[2] == '+')
568 relseek++;
569 if (pp[2+relseek] == '-')
570 negseek++;
571#endif
572 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
573 }
574 else
575 {
576 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200577 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578#ifdef TRY_SEEK
579 if (argv[2][0] == '+')
580 relseek++;
581 if (argv[2][relseek] == '-')
582 negseek++;
583#endif
584 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
585 argv++;
586 argc--;
587 }
588 }
589 else if (!STRNCMP(pp, "-l", 2))
590 {
591 if (pp[2] && STRNCMP("en", pp + 2, 2))
592 length = strtol(pp + 2, (char **)NULL, 0);
593 else
594 {
595 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200596 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 length = strtol(argv[2], (char **)NULL, 0);
598 argv++;
599 argc--;
600 }
601 }
602 else if (!strcmp(pp, "--")) /* end of options */
603 {
604 argv++;
605 argc--;
606 break;
607 }
608 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200609 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 else
611 break; /* not an option */
612
613 argv++; /* advance to next argument */
614 argc--;
615 }
616
617 if (!cols)
618 switch (hextype)
619 {
620 case HEX_POSTSCRIPT: cols = 30; break;
621 case HEX_CINCLUDE: cols = 12; break;
622 case HEX_BITS: cols = 6; break;
623 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100624 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 default: cols = 16; break;
626 }
627
628 if (octspergrp < 0)
629 switch (hextype)
630 {
631 case HEX_BITS: octspergrp = 1; break;
632 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100633 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 case HEX_POSTSCRIPT:
635 case HEX_CINCLUDE:
636 default: octspergrp = 0; break;
637 }
638
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100639 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000640 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 {
642 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
643 exit(1);
644 }
645
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100646 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100648 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
649 {
650 fprintf(stderr,
651 "%s: number of octets per group must be a power of 2 with -e.\n",
652 pname);
653 exit(1);
654 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655
656 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200657 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658
659 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
660 BIN_ASSIGN(fp = stdin, !revert);
661 else
662 {
663 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
664 {
665 fprintf(stderr,"%s: ", pname);
666 perror(argv[1]);
667 return 2;
668 }
669 }
670
671 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
672 BIN_ASSIGN(fpo = stdout, revert);
673 else
674 {
675 int fd;
676 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
677
678 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
679 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
680 {
681 fprintf(stderr, "%s: ", pname);
682 perror(argv[2]);
683 return 3;
684 }
685 rewind(fpo);
686 }
687
688 if (revert)
689 {
690 if (hextype && (hextype != HEX_POSTSCRIPT))
691 {
692 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
693 return -1;
694 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200695 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 negseek ? -seekoff : seekoff);
697 }
698
699 if (seekoff || negseek || !relseek)
700 {
701#ifdef TRY_SEEK
702 if (relseek)
703 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
704 else
705 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
706 if (e < 0 && negseek)
707 {
708 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
709 return 4;
710 }
711 if (e >= 0)
712 seekoff = ftell(fp);
713 else
714#endif
715 {
716 long s = seekoff;
717
718 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200719 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200720 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200721 if (ferror(fp))
722 {
723 die(2);
724 }
725 else
726 {
727 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
728 return 4;
729 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200730 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 }
732 }
733
734 if (hextype == HEX_CINCLUDE)
735 {
736 if (fp != stdin)
737 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
739 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200741 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200742 die(3);
743 if (fputs("[] = {\n", fpo) == EOF)
744 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 }
746
747 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200748 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
750 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200751 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200752 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200753 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 p++;
755 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200756 if (c == EOF && ferror(fp))
757 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100759 if (p && fputs("\n", fpo) == EOF)
760 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200761 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100762 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763
764 if (fp != stdin)
765 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200766 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
767 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200769 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200770 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200771 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200772 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 }
774
Bram Moolenaare0659a62011-04-01 19:14:40 +0200775 if (fclose(fp))
776 die(2);
777 if (fclose(fpo))
778 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 return 0;
780 }
781
782 if (hextype == HEX_POSTSCRIPT)
783 {
784 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200785 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
787 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200788 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
789 || putc(hexx[e & 0xf], fpo) == EOF)
790 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 n++;
792 if (!--p)
793 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200794 if (putc('\n', fpo) == EOF)
795 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 p = cols;
797 }
798 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200799 if (e == EOF && ferror(fp))
800 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200802 if (putc('\n', fpo) == EOF)
803 die(3);
804 if (fclose(fp))
805 die(2);
806 if (fclose(fpo))
807 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 return 0;
809 }
810
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100811 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100813 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
815 else /* hextype == HEX_BITS */
816 grplen = 8 * octspergrp + 1;
817
Bram Moolenaare0659a62011-04-01 19:14:40 +0200818 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
820 {
821 if (p == 0)
822 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100823 addrlen = sprintf(l, "%08lx:",
824 ((unsigned long)(n + seekoff + displayoff)));
825 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000826 }
827 if (hextype == HEX_NORMAL)
828 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100829 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100830 l[++c] = hexx[ e & 0xf];
831 }
832 else if (hextype == HEX_LITTLEENDIAN)
833 {
834 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100835 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100836 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 }
838 else /* hextype == HEX_BITS */
839 {
840 int i;
841
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100842 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 for (i = 7; i >= 0; i--)
844 l[++c] = (e & (1 << i)) ? '1' : '0';
845 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100846 if (e)
847 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 if (ebcdic)
849 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000850 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100851 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852#ifdef __MVS__
853 (e >= 64)
854#else
855 (e > 31 && e < 127)
856#endif
857 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000858 n++;
859 if (++p == cols)
860 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100861 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 xxdline(fpo, l, autoskip ? nonzero : 1);
863 nonzero = 0;
864 p = 0;
865 }
866 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200867 if (e == EOF && ferror(fp))
868 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 if (p)
870 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100871 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 xxdline(fpo, l, 1);
873 }
874 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000875 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876
Bram Moolenaare0659a62011-04-01 19:14:40 +0200877 if (fclose(fp))
878 die(2);
879 if (fclose(fpo))
880 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881 return 0;
882}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200883
884/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */