blob: 4e352034edb71409f5f188fff829f703b7a9df4d [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
Bram Moolenaar4b96df52020-01-26 22:00:26 +010038 * 18.07.96 gcc -Wall @ SunOS4 is now silent.
Bram Moolenaar071d4272004-06-13 20:20:40 +000039 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaard8c56a02019-01-30 23:02:25 +010055 * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
Bram Moolenaar363d6142020-05-30 20:50:25 +020056 * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen
Bram Moolenaar071d4272004-06-13 20:20:40 +000057 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020058 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000059 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020060 * I hereby grant permission to distribute and use xxd
61 * under X11-MIT or GPL-2.0 (at the user's choice).
62 *
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +020063 * Contributions by Bram Moolenaar et al.
Bram Moolenaar071d4272004-06-13 20:20:40 +000064 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000065
66/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
67#if _MSC_VER >= 1400
68# define _CRT_SECURE_NO_DEPRECATE
69# define _CRT_NONSTDC_NO_DEPRECATE
70#endif
Bram Moolenaar6ef8f9e2019-03-02 07:15:28 +010071#if !defined(CYGWIN) && defined(__CYGWIN__)
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000072# define CYGWIN
73#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000074
Bram Moolenaar071d4272004-06-13 20:20:40 +000075#include <stdio.h>
76#ifdef VAXC
77# include <file.h>
78#else
79# include <fcntl.h>
80#endif
Bram Moolenaareae1b912019-05-09 15:12:55 +020081#if defined(WIN32) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000082# include <io.h> /* for setmode() */
83#else
84# ifdef UNIX
85# include <unistd.h>
86# endif
87#endif
88#include <stdlib.h>
89#include <string.h> /* for strncmp() */
90#include <ctype.h> /* for isalnum() */
Bram Moolenaard8c56a02019-01-30 23:02:25 +010091#include <limits.h>
Bram Moolenaar071d4272004-06-13 20:20:40 +000092#if __MWERKS__ && !defined(BEBOX)
93# include <unix.h> /* for fdopen() on MAC */
94#endif
95
Bram Moolenaar071d4272004-06-13 20:20:40 +000096
97/* This corrects the problem of missing prototypes for certain functions
98 * in some GNU installations (e.g. SunOS 4.1.x).
99 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
100 */
101#if defined(__GNUC__) && defined(__STDC__)
102# ifndef __USE_FIXED_PROTOTYPES__
103# define __USE_FIXED_PROTOTYPES__
104# endif
105#endif
106
107#ifndef __USE_FIXED_PROTOTYPES__
108/*
109 * This is historic and works only if the compiler really has no prototypes:
110 *
111 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
112 * FILE is defined on OS 4.x, not on 5.x (Solaris).
113 * if __SVR4 is defined (some Solaris versions), don't include this.
114 */
115#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
116# define __P(a) a
117/* excerpt from my sun_stdlib.h */
118extern int fprintf __P((FILE *, char *, ...));
119extern int fputs __P((char *, FILE *));
120extern int _flsbuf __P((unsigned char, FILE *));
121extern int _filbuf __P((FILE *));
122extern int fflush __P((FILE *));
123extern int fclose __P((FILE *));
124extern int fseek __P((FILE *, long, int));
125extern int rewind __P((FILE *));
126
127extern void perror __P((char *));
128# endif
129#endif
130
131extern long int strtol();
132extern long int ftell();
133
=?UTF-8?q?J=C3=BCrgen=20Weigert?=80b2ba32021-06-29 20:36:25 +0200134char version[] = "xxd 2020-02-04 by Juergen Weigert et al.";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000135#ifdef WIN32
136char osver[] = " (Win32)";
137#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000138char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000139#endif
140
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200141#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000142# define BIN_READ(yes) ((yes) ? "rb" : "rt")
143# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
144# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
145# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000146# define PATH_SEP '\\'
147#elif defined(CYGWIN)
148# define BIN_READ(yes) ((yes) ? "rb" : "rt")
149# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
150# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
151# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
152# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000153#else
154# ifdef VMS
155# define BIN_READ(dummy) "r"
156# define BIN_WRITE(dummy) "w"
157# define BIN_CREAT(dummy) O_CREAT
158# define BIN_ASSIGN(fp, dummy) fp
159# define PATH_SEP ']'
160# define FILE_SEP '.'
161# else
162# define BIN_READ(dummy) "r"
163# define BIN_WRITE(dummy) "w"
164# define BIN_CREAT(dummy) O_CREAT
165# define BIN_ASSIGN(fp, dummy) fp
166# define PATH_SEP '/'
167# endif
168#endif
169
170/* open has only to arguments on the Mac */
171#if __MWERKS__
172# define OPEN(name, mode, umask) open(name, mode)
173#else
174# define OPEN(name, mode, umask) open(name, mode, umask)
175#endif
176
177#ifdef AMIGA
178# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
179#else
180# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
181#endif
182
183#ifndef __P
Bram Moolenaareae1b912019-05-09 15:12:55 +0200184# if defined(__STDC__) || defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000185# define __P(a) a
186# else
187# define __P(a) ()
188# endif
189#endif
190
191/* Let's collect some prototypes */
192/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200193static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200194static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200195static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196static void xxdline __P((FILE *, char *, int));
197
198#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
199#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100200#define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000201
202char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
203
204/* the different hextypes known by this program: */
205#define HEX_NORMAL 0
206#define HEX_POSTSCRIPT 1
207#define HEX_CINCLUDE 2
208#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100209#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000210
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200211#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
212
Bram Moolenaare0659a62011-04-01 19:14:40 +0200213static char *pname;
214
215 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100216exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217{
218 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
219 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
220 fprintf(stderr, "Options:\n");
221 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100222 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200223 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
225 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100226 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
Atsushi SUGAWARA34a36482021-10-17 16:09:08 +0100227 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 fprintf(stderr, " -h print this summary.\n");
229 fprintf(stderr, " -i output in C include file style.\n");
230 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100231 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
233 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
234 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
Bram Moolenaar363d6142020-05-30 20:50:25 +0200235 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
237#ifdef TRY_SEEK
238 "[+][-]", "(or +: rel.) ");
239#else
240 "", "");
241#endif
242 fprintf(stderr, " -u use upper case hex letters.\n");
243 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
244 exit(1);
245}
246
Bram Moolenaare0659a62011-04-01 19:14:40 +0200247 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100248die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200249{
250 fprintf(stderr, "%s: ", pname);
251 perror(NULL);
252 exit(ret);
253}
254
Bram Moolenaar071d4272004-06-13 20:20:40 +0000255/*
256 * Max. cols binary characters are decoded from the input stream per line.
257 * Two adjacent garbage characters after evaluated data delimit valid data.
258 * Everything up to the next newline is discarded.
259 *
260 * The name is historic and came from 'undo type opt h'.
261 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200262 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100263huntype(
264 FILE *fpi,
265 FILE *fpo,
266 FILE *fperr,
267 int cols,
268 int hextype,
269 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000270{
271 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
272 long have_off = 0, want_off = 0;
273
274 rewind(fpi);
275
276 while ((c = getc(fpi)) != EOF)
277 {
278 if (c == '\r') /* Doze style input file? */
279 continue;
280
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100281 /* Allow multiple spaces. This doesn't work when there is normal text
282 * after the hex codes in the last line that looks like hex, thus only
283 * use it for PostScript format. */
284 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000285 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000286
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287 n3 = n2;
288 n2 = n1;
289
290 if (c >= '0' && c <= '9')
291 n1 = c - '0';
292 else if (c >= 'a' && c <= 'f')
293 n1 = c - 'a' + 10;
294 else if (c >= 'A' && c <= 'F')
295 n1 = c - 'A' + 10;
296 else
297 {
298 n1 = -1;
299 if (ign_garb)
300 continue;
301 }
302
303 ign_garb = 0;
304
305 if (p >= cols)
306 {
307 if (!hextype)
308 {
309 if (n1 < 0)
310 {
311 p = 0;
312 continue;
313 }
314 want_off = (want_off << 4) | n1;
315 continue;
316 }
317 else
318 p = 0;
319 }
320
321 if (base_off + want_off != have_off)
322 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200323 if (fflush(fpo) != 0)
324 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000325#ifdef TRY_SEEK
326 c = fseek(fpo, base_off + want_off - have_off, 1);
327 if (c >= 0)
328 have_off = base_off + want_off;
329#endif
330 if (base_off + want_off < have_off)
331 {
332 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
333 return 5;
334 }
335 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200336 if (putc(0, fpo) == EOF)
337 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000338 }
339
340 if (n2 >= 0 && n1 >= 0)
341 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200342 if (putc((n2 << 4) | n1, fpo) == EOF)
343 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 have_off++;
345 want_off++;
346 n1 = -1;
347 if ((++p >= cols) && !hextype)
348 {
DungSagac89c91c2021-10-16 19:07:46 +0100349 /* skip the rest of the line as garbage */
350 n2 = -1;
351 n3 = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 }
353 }
DungSagac89c91c2021-10-16 19:07:46 +0100354 if (n1 < 0 && n2 < 0 && n3 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 {
356 /* already stumbled into garbage, skip line, wait and see */
357 if (!hextype)
358 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 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200366 if (fflush(fpo) != 0)
367 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000368#ifdef TRY_SEEK
369 fseek(fpo, 0L, 2);
370#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200371 if (fclose(fpo) != 0)
372 die(3);
373 if (fclose(fpi) != 0)
374 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375 return 0;
376}
377
378/*
379 * Print line l. If nz is false, xxdline regards the line a line of
380 * zeroes. If there are three or more consecutive lines of zeroes,
381 * they are replaced by a single '*' character.
382 *
383 * If the output ends with more than two lines of zeroes, you
384 * should call xxdline again with l being the last line and nz
385 * negative. This ensures that the last line is shown even when
386 * it is all zeroes.
387 *
388 * If nz is always positive, lines are never suppressed.
389 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200390 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100391xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000392{
393 static char z[LLEN+1];
394 static int zero_seen = 0;
395
396 if (!nz && zero_seen == 1)
397 strcpy(z, l);
398
399 if (nz || !zero_seen++)
400 {
401 if (nz)
402 {
403 if (nz < 0)
404 zero_seen--;
405 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200406 if (fputs(z, fp) == EOF)
407 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200409 if (fputs("*\n", fp) == EOF)
410 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000411 }
412 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200413 if (fputs(l, fp) == EOF)
414 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 if (nz)
416 zero_seen = 0;
417 }
418}
419
420/* This is an EBCDIC to ASCII conversion table */
421/* from a proposed BTL standard April 16, 1979 */
422static unsigned char etoa64[] =
423{
424 0040,0240,0241,0242,0243,0244,0245,0246,
425 0247,0250,0325,0056,0074,0050,0053,0174,
426 0046,0251,0252,0253,0254,0255,0256,0257,
427 0260,0261,0041,0044,0052,0051,0073,0176,
428 0055,0057,0262,0263,0264,0265,0266,0267,
429 0270,0271,0313,0054,0045,0137,0076,0077,
430 0272,0273,0274,0275,0276,0277,0300,0301,
431 0302,0140,0072,0043,0100,0047,0075,0042,
432 0303,0141,0142,0143,0144,0145,0146,0147,
433 0150,0151,0304,0305,0306,0307,0310,0311,
434 0312,0152,0153,0154,0155,0156,0157,0160,
435 0161,0162,0136,0314,0315,0316,0317,0320,
436 0321,0345,0163,0164,0165,0166,0167,0170,
437 0171,0172,0322,0323,0324,0133,0326,0327,
438 0330,0331,0332,0333,0334,0335,0336,0337,
439 0340,0341,0342,0343,0344,0135,0346,0347,
440 0173,0101,0102,0103,0104,0105,0106,0107,
441 0110,0111,0350,0351,0352,0353,0354,0355,
442 0175,0112,0113,0114,0115,0116,0117,0120,
443 0121,0122,0356,0357,0360,0361,0362,0363,
444 0134,0237,0123,0124,0125,0126,0127,0130,
445 0131,0132,0364,0365,0366,0367,0370,0371,
446 0060,0061,0062,0063,0064,0065,0066,0067,
447 0070,0071,0372,0373,0374,0375,0376,0377
448};
449
Bram Moolenaare0659a62011-04-01 19:14:40 +0200450 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100451main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452{
453 FILE *fp, *fpo;
454 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200455 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
456 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000457 int ebcdic = 0;
458 int octspergrp = -1; /* number of octets grouped in output */
459 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100460 long length = -1, n = 0, seekoff = 0;
461 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200462 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200463 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100464 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000465
466#ifdef AMIGA
467 /* This program doesn't work when started from the Workbench */
468 if (argc == 0)
469 exit(1);
470#endif
471
472 pname = argv[0];
473 for (pp = pname; *pp; )
474 if (*pp++ == PATH_SEP)
475 pname = pp;
476#ifdef FILE_SEP
477 for (pp = pname; *pp; pp++)
478 if (*pp == FILE_SEP)
479 {
480 *pp = '\0';
481 break;
482 }
483#endif
484
485 while (argc >= 2)
486 {
487 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
488 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
489 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100490 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
492 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
493 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200494 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200495 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000496 else if (!STRNCMP(pp, "-r", 2)) revert++;
497 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
498 else if (!STRNCMP(pp, "-v", 2))
499 {
500 fprintf(stderr, "%s%s\n", version, osver);
501 exit(0);
502 }
503 else if (!STRNCMP(pp, "-c", 2))
504 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100505 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200506 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100507 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
508 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000509 else
510 {
511 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200512 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000513 cols = (int)strtol(argv[2], NULL, 0);
514 argv++;
515 argc--;
516 }
517 }
518 else if (!STRNCMP(pp, "-g", 2))
519 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100520 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 octspergrp = (int)strtol(pp + 2, NULL, 0);
522 else
523 {
524 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200525 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000526 octspergrp = (int)strtol(argv[2], NULL, 0);
527 argv++;
528 argc--;
529 }
530 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100531 else if (!STRNCMP(pp, "-o", 2))
532 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100533 int reloffset = 0;
534 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100535 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100536 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100537 else
538 {
539 if (!argv[2])
540 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100541
542 if (argv[2][0] == '+')
543 reloffset++;
544 if (argv[2][reloffset] == '-')
545 negoffset++;
546
547 if (negoffset)
548 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
549 else
550 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
551
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100552 argv++;
553 argc--;
554 }
555 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000556 else if (!STRNCMP(pp, "-s", 2))
557 {
558 relseek = 0;
559 negseek = 0;
560 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
561 {
562#ifdef TRY_SEEK
563 if (pp[2] == '+')
564 relseek++;
565 if (pp[2+relseek] == '-')
566 negseek++;
567#endif
568 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
569 }
570 else
571 {
572 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200573 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000574#ifdef TRY_SEEK
575 if (argv[2][0] == '+')
576 relseek++;
577 if (argv[2][relseek] == '-')
578 negseek++;
579#endif
580 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
581 argv++;
582 argc--;
583 }
584 }
585 else if (!STRNCMP(pp, "-l", 2))
586 {
587 if (pp[2] && STRNCMP("en", pp + 2, 2))
588 length = strtol(pp + 2, (char **)NULL, 0);
589 else
590 {
591 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200592 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000593 length = strtol(argv[2], (char **)NULL, 0);
594 argv++;
595 argc--;
596 }
597 }
598 else if (!strcmp(pp, "--")) /* end of options */
599 {
600 argv++;
601 argc--;
602 break;
603 }
604 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200605 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000606 else
607 break; /* not an option */
608
609 argv++; /* advance to next argument */
610 argc--;
611 }
612
613 if (!cols)
614 switch (hextype)
615 {
616 case HEX_POSTSCRIPT: cols = 30; break;
617 case HEX_CINCLUDE: cols = 12; break;
618 case HEX_BITS: cols = 6; break;
619 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100620 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 default: cols = 16; break;
622 }
623
624 if (octspergrp < 0)
625 switch (hextype)
626 {
627 case HEX_BITS: octspergrp = 1; break;
628 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100629 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630 case HEX_POSTSCRIPT:
631 case HEX_CINCLUDE:
632 default: octspergrp = 0; break;
633 }
634
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100635 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000636 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 {
638 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
639 exit(1);
640 }
641
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100642 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100644 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
645 {
646 fprintf(stderr,
647 "%s: number of octets per group must be a power of 2 with -e.\n",
648 pname);
649 exit(1);
650 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000651
652 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200653 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000654
655 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
656 BIN_ASSIGN(fp = stdin, !revert);
657 else
658 {
659 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
660 {
661 fprintf(stderr,"%s: ", pname);
662 perror(argv[1]);
663 return 2;
664 }
665 }
666
667 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
668 BIN_ASSIGN(fpo = stdout, revert);
669 else
670 {
671 int fd;
672 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
673
674 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
675 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
676 {
677 fprintf(stderr, "%s: ", pname);
678 perror(argv[2]);
679 return 3;
680 }
681 rewind(fpo);
682 }
683
684 if (revert)
685 {
686 if (hextype && (hextype != HEX_POSTSCRIPT))
687 {
688 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
689 return -1;
690 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200691 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000692 negseek ? -seekoff : seekoff);
693 }
694
695 if (seekoff || negseek || !relseek)
696 {
697#ifdef TRY_SEEK
698 if (relseek)
699 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
700 else
701 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
702 if (e < 0 && negseek)
703 {
704 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
705 return 4;
706 }
707 if (e >= 0)
708 seekoff = ftell(fp);
709 else
710#endif
711 {
712 long s = seekoff;
713
714 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200715 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200716 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200717 if (ferror(fp))
718 {
719 die(2);
720 }
721 else
722 {
723 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
724 return 4;
725 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200726 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 }
728 }
729
730 if (hextype == HEX_CINCLUDE)
731 {
732 if (fp != stdin)
733 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200734 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
735 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200737 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 die(3);
739 if (fputs("[] = {\n", fpo) == EOF)
740 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 }
742
743 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
746 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200747 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200748 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200749 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000750 p++;
751 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200752 if (c == EOF && ferror(fp))
753 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100755 if (p && fputs("\n", fpo) == EOF)
756 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200757 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100758 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759
760 if (fp != stdin)
761 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200762 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
763 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200765 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200766 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200767 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200768 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 }
770
Bram Moolenaare0659a62011-04-01 19:14:40 +0200771 if (fclose(fp))
772 die(2);
773 if (fclose(fpo))
774 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 return 0;
776 }
777
778 if (hextype == HEX_POSTSCRIPT)
779 {
780 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200781 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
783 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200784 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
785 || putc(hexx[e & 0xf], fpo) == EOF)
786 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 n++;
788 if (!--p)
789 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200790 if (putc('\n', fpo) == EOF)
791 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 p = cols;
793 }
794 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200795 if (e == EOF && ferror(fp))
796 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000797 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200798 if (putc('\n', fpo) == EOF)
799 die(3);
800 if (fclose(fp))
801 die(2);
802 if (fclose(fpo))
803 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 return 0;
805 }
806
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100807 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100809 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
811 else /* hextype == HEX_BITS */
812 grplen = 8 * octspergrp + 1;
813
Bram Moolenaare0659a62011-04-01 19:14:40 +0200814 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
816 {
817 if (p == 0)
818 {
Bram Moolenaar363d6142020-05-30 20:50:25 +0200819 if (decimal_offset)
820 addrlen = sprintf(l, "%08ld:",
821 ((unsigned long)(n + seekoff + displayoff)));
822 else
823 addrlen = sprintf(l, "%08lx:",
824 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100825 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 : */