blob: 94cc220bfbbb9cfdf850f917a280fec56118d386 [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");
227 fprintf(stderr, " -g 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 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000349 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 want_off = 0;
351 while ((c = getc(fpi)) != '\n' && c != EOF)
352 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200353 if (c == EOF && ferror(fpi))
354 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 ign_garb = 1;
356 }
357 }
358 else if (n1 < 0 && n2 < 0 && n3 < 0)
359 {
360 /* already stumbled into garbage, skip line, wait and see */
361 if (!hextype)
362 want_off = 0;
363 while ((c = getc(fpi)) != '\n' && c != EOF)
364 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200365 if (c == EOF && ferror(fpi))
366 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367 ign_garb = 1;
368 }
369 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200370 if (fflush(fpo) != 0)
371 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372#ifdef TRY_SEEK
373 fseek(fpo, 0L, 2);
374#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200375 if (fclose(fpo) != 0)
376 die(3);
377 if (fclose(fpi) != 0)
378 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000379 return 0;
380}
381
382/*
383 * Print line l. If nz is false, xxdline regards the line a line of
384 * zeroes. If there are three or more consecutive lines of zeroes,
385 * they are replaced by a single '*' character.
386 *
387 * If the output ends with more than two lines of zeroes, you
388 * should call xxdline again with l being the last line and nz
389 * negative. This ensures that the last line is shown even when
390 * it is all zeroes.
391 *
392 * If nz is always positive, lines are never suppressed.
393 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200394 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100395xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396{
397 static char z[LLEN+1];
398 static int zero_seen = 0;
399
400 if (!nz && zero_seen == 1)
401 strcpy(z, l);
402
403 if (nz || !zero_seen++)
404 {
405 if (nz)
406 {
407 if (nz < 0)
408 zero_seen--;
409 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200410 if (fputs(z, fp) == EOF)
411 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200413 if (fputs("*\n", fp) == EOF)
414 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 }
416 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200417 if (fputs(l, fp) == EOF)
418 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000419 if (nz)
420 zero_seen = 0;
421 }
422}
423
424/* This is an EBCDIC to ASCII conversion table */
425/* from a proposed BTL standard April 16, 1979 */
426static unsigned char etoa64[] =
427{
428 0040,0240,0241,0242,0243,0244,0245,0246,
429 0247,0250,0325,0056,0074,0050,0053,0174,
430 0046,0251,0252,0253,0254,0255,0256,0257,
431 0260,0261,0041,0044,0052,0051,0073,0176,
432 0055,0057,0262,0263,0264,0265,0266,0267,
433 0270,0271,0313,0054,0045,0137,0076,0077,
434 0272,0273,0274,0275,0276,0277,0300,0301,
435 0302,0140,0072,0043,0100,0047,0075,0042,
436 0303,0141,0142,0143,0144,0145,0146,0147,
437 0150,0151,0304,0305,0306,0307,0310,0311,
438 0312,0152,0153,0154,0155,0156,0157,0160,
439 0161,0162,0136,0314,0315,0316,0317,0320,
440 0321,0345,0163,0164,0165,0166,0167,0170,
441 0171,0172,0322,0323,0324,0133,0326,0327,
442 0330,0331,0332,0333,0334,0335,0336,0337,
443 0340,0341,0342,0343,0344,0135,0346,0347,
444 0173,0101,0102,0103,0104,0105,0106,0107,
445 0110,0111,0350,0351,0352,0353,0354,0355,
446 0175,0112,0113,0114,0115,0116,0117,0120,
447 0121,0122,0356,0357,0360,0361,0362,0363,
448 0134,0237,0123,0124,0125,0126,0127,0130,
449 0131,0132,0364,0365,0366,0367,0370,0371,
450 0060,0061,0062,0063,0064,0065,0066,0067,
451 0070,0071,0372,0373,0374,0375,0376,0377
452};
453
Bram Moolenaare0659a62011-04-01 19:14:40 +0200454 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100455main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000456{
457 FILE *fp, *fpo;
458 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200459 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
460 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000461 int ebcdic = 0;
462 int octspergrp = -1; /* number of octets grouped in output */
463 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100464 long length = -1, n = 0, seekoff = 0;
465 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200466 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200467 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100468 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000469
470#ifdef AMIGA
471 /* This program doesn't work when started from the Workbench */
472 if (argc == 0)
473 exit(1);
474#endif
475
476 pname = argv[0];
477 for (pp = pname; *pp; )
478 if (*pp++ == PATH_SEP)
479 pname = pp;
480#ifdef FILE_SEP
481 for (pp = pname; *pp; pp++)
482 if (*pp == FILE_SEP)
483 {
484 *pp = '\0';
485 break;
486 }
487#endif
488
489 while (argc >= 2)
490 {
491 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
492 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
493 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100494 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000495 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
496 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
497 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200498 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200499 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 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 Moolenaar363d6142020-05-30 20:50:25 +0200823 if (decimal_offset)
824 addrlen = sprintf(l, "%08ld:",
825 ((unsigned long)(n + seekoff + displayoff)));
826 else
827 addrlen = sprintf(l, "%08lx:",
828 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100829 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000830 }
831 if (hextype == HEX_NORMAL)
832 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100833 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100834 l[++c] = hexx[ e & 0xf];
835 }
836 else if (hextype == HEX_LITTLEENDIAN)
837 {
838 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100839 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100840 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000841 }
842 else /* hextype == HEX_BITS */
843 {
844 int i;
845
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100846 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 for (i = 7; i >= 0; i--)
848 l[++c] = (e & (1 << i)) ? '1' : '0';
849 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100850 if (e)
851 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 if (ebcdic)
853 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000854 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100855 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856#ifdef __MVS__
857 (e >= 64)
858#else
859 (e > 31 && e < 127)
860#endif
861 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 n++;
863 if (++p == cols)
864 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100865 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866 xxdline(fpo, l, autoskip ? nonzero : 1);
867 nonzero = 0;
868 p = 0;
869 }
870 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200871 if (e == EOF && ferror(fp))
872 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000873 if (p)
874 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100875 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 xxdline(fpo, l, 1);
877 }
878 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000879 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000880
Bram Moolenaare0659a62011-04-01 19:14:40 +0200881 if (fclose(fp))
882 die(2);
883 if (fclose(fpo))
884 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 return 0;
886}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200887
888/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */