blob: 749df435d2f6a323d5e94f2875d4abf9f6a7a0e5 [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
DungSaga375c35a2021-10-18 13:16:03 +0100305 if (!hextype && (p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 {
DungSaga375c35a2021-10-18 13:16:03 +0100307 if (n1 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000308 {
DungSaga375c35a2021-10-18 13:16:03 +0100309 p = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000310 continue;
311 }
DungSaga375c35a2021-10-18 13:16:03 +0100312 want_off = (want_off << 4) | n1;
313 continue;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000314 }
315
316 if (base_off + want_off != have_off)
317 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200318 if (fflush(fpo) != 0)
319 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000320#ifdef TRY_SEEK
321 c = fseek(fpo, base_off + want_off - have_off, 1);
322 if (c >= 0)
323 have_off = base_off + want_off;
324#endif
325 if (base_off + want_off < have_off)
326 {
327 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
328 return 5;
329 }
330 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200331 if (putc(0, fpo) == EOF)
332 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000333 }
334
335 if (n2 >= 0 && n1 >= 0)
336 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200337 if (putc((n2 << 4) | n1, fpo) == EOF)
338 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000339 have_off++;
340 want_off++;
341 n1 = -1;
DungSaga375c35a2021-10-18 13:16:03 +0100342 if (!hextype && (++p >= cols))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343 {
DungSagac89c91c2021-10-16 19:07:46 +0100344 /* skip the rest of the line as garbage */
345 n2 = -1;
346 n3 = -1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 }
348 }
DungSagac89c91c2021-10-16 19:07:46 +0100349 if (n1 < 0 && n2 < 0 && n3 < 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 {
351 /* already stumbled into garbage, skip line, wait and see */
352 if (!hextype)
353 want_off = 0;
354 while ((c = getc(fpi)) != '\n' && c != EOF)
355 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200356 if (c == EOF && ferror(fpi))
357 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 ign_garb = 1;
359 }
360 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200361 if (fflush(fpo) != 0)
362 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363#ifdef TRY_SEEK
364 fseek(fpo, 0L, 2);
365#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200366 if (fclose(fpo) != 0)
367 die(3);
368 if (fclose(fpi) != 0)
369 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 return 0;
371}
372
373/*
374 * Print line l. If nz is false, xxdline regards the line a line of
375 * zeroes. If there are three or more consecutive lines of zeroes,
376 * they are replaced by a single '*' character.
377 *
378 * If the output ends with more than two lines of zeroes, you
379 * should call xxdline again with l being the last line and nz
380 * negative. This ensures that the last line is shown even when
381 * it is all zeroes.
382 *
383 * If nz is always positive, lines are never suppressed.
384 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200385 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100386xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000387{
388 static char z[LLEN+1];
389 static int zero_seen = 0;
390
391 if (!nz && zero_seen == 1)
392 strcpy(z, l);
393
394 if (nz || !zero_seen++)
395 {
396 if (nz)
397 {
398 if (nz < 0)
399 zero_seen--;
400 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200401 if (fputs(z, fp) == EOF)
402 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000403 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200404 if (fputs("*\n", fp) == EOF)
405 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000406 }
407 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200408 if (fputs(l, fp) == EOF)
409 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000410 if (nz)
411 zero_seen = 0;
412 }
413}
414
415/* This is an EBCDIC to ASCII conversion table */
416/* from a proposed BTL standard April 16, 1979 */
417static unsigned char etoa64[] =
418{
419 0040,0240,0241,0242,0243,0244,0245,0246,
420 0247,0250,0325,0056,0074,0050,0053,0174,
421 0046,0251,0252,0253,0254,0255,0256,0257,
422 0260,0261,0041,0044,0052,0051,0073,0176,
423 0055,0057,0262,0263,0264,0265,0266,0267,
424 0270,0271,0313,0054,0045,0137,0076,0077,
425 0272,0273,0274,0275,0276,0277,0300,0301,
426 0302,0140,0072,0043,0100,0047,0075,0042,
427 0303,0141,0142,0143,0144,0145,0146,0147,
428 0150,0151,0304,0305,0306,0307,0310,0311,
429 0312,0152,0153,0154,0155,0156,0157,0160,
430 0161,0162,0136,0314,0315,0316,0317,0320,
431 0321,0345,0163,0164,0165,0166,0167,0170,
432 0171,0172,0322,0323,0324,0133,0326,0327,
433 0330,0331,0332,0333,0334,0335,0336,0337,
434 0340,0341,0342,0343,0344,0135,0346,0347,
435 0173,0101,0102,0103,0104,0105,0106,0107,
436 0110,0111,0350,0351,0352,0353,0354,0355,
437 0175,0112,0113,0114,0115,0116,0117,0120,
438 0121,0122,0356,0357,0360,0361,0362,0363,
439 0134,0237,0123,0124,0125,0126,0127,0130,
440 0131,0132,0364,0365,0366,0367,0370,0371,
441 0060,0061,0062,0063,0064,0065,0066,0067,
442 0070,0071,0372,0373,0374,0375,0376,0377
443};
444
Bram Moolenaare0659a62011-04-01 19:14:40 +0200445 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100446main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000447{
448 FILE *fp, *fpo;
449 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200450 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
451 int capitalize = 0, decimal_offset = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000452 int ebcdic = 0;
453 int octspergrp = -1; /* number of octets grouped in output */
454 int grplen; /* total chars per octet group */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100455 long length = -1, n = 0, seekoff = 0;
456 unsigned long displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200457 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200458 char *pp;
Bram Moolenaaraf703582019-01-31 11:00:42 +0100459 int addrlen = 9;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000460
461#ifdef AMIGA
462 /* This program doesn't work when started from the Workbench */
463 if (argc == 0)
464 exit(1);
465#endif
466
467 pname = argv[0];
468 for (pp = pname; *pp; )
469 if (*pp++ == PATH_SEP)
470 pname = pp;
471#ifdef FILE_SEP
472 for (pp = pname; *pp; pp++)
473 if (*pp == FILE_SEP)
474 {
475 *pp = '\0';
476 break;
477 }
478#endif
479
480 while (argc >= 2)
481 {
482 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
483 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
484 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100485 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000486 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
487 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
488 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200489 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar363d6142020-05-30 20:50:25 +0200490 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000491 else if (!STRNCMP(pp, "-r", 2)) revert++;
492 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
493 else if (!STRNCMP(pp, "-v", 2))
494 {
495 fprintf(stderr, "%s%s\n", version, osver);
496 exit(0);
497 }
498 else if (!STRNCMP(pp, "-c", 2))
499 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100500 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200501 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100502 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
503 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000504 else
505 {
506 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200507 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000508 cols = (int)strtol(argv[2], NULL, 0);
509 argv++;
510 argc--;
511 }
512 }
513 else if (!STRNCMP(pp, "-g", 2))
514 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100515 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000516 octspergrp = (int)strtol(pp + 2, NULL, 0);
517 else
518 {
519 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200520 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000521 octspergrp = (int)strtol(argv[2], NULL, 0);
522 argv++;
523 argc--;
524 }
525 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100526 else if (!STRNCMP(pp, "-o", 2))
527 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100528 int reloffset = 0;
529 int negoffset = 0;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100530 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100531 displayoff = strtoul(pp + 2, NULL, 0);
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100532 else
533 {
534 if (!argv[2])
535 exit_with_usage();
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100536
537 if (argv[2][0] == '+')
538 reloffset++;
539 if (argv[2][reloffset] == '-')
540 negoffset++;
541
542 if (negoffset)
543 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
544 else
545 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
546
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100547 argv++;
548 argc--;
549 }
550 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000551 else if (!STRNCMP(pp, "-s", 2))
552 {
553 relseek = 0;
554 negseek = 0;
555 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
556 {
557#ifdef TRY_SEEK
558 if (pp[2] == '+')
559 relseek++;
560 if (pp[2+relseek] == '-')
561 negseek++;
562#endif
563 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
564 }
565 else
566 {
567 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200568 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000569#ifdef TRY_SEEK
570 if (argv[2][0] == '+')
571 relseek++;
572 if (argv[2][relseek] == '-')
573 negseek++;
574#endif
575 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
576 argv++;
577 argc--;
578 }
579 }
580 else if (!STRNCMP(pp, "-l", 2))
581 {
582 if (pp[2] && STRNCMP("en", pp + 2, 2))
583 length = strtol(pp + 2, (char **)NULL, 0);
584 else
585 {
586 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200587 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000588 length = strtol(argv[2], (char **)NULL, 0);
589 argv++;
590 argc--;
591 }
592 }
593 else if (!strcmp(pp, "--")) /* end of options */
594 {
595 argv++;
596 argc--;
597 break;
598 }
599 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200600 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000601 else
602 break; /* not an option */
603
604 argv++; /* advance to next argument */
605 argc--;
606 }
607
608 if (!cols)
609 switch (hextype)
610 {
611 case HEX_POSTSCRIPT: cols = 30; break;
612 case HEX_CINCLUDE: cols = 12; break;
613 case HEX_BITS: cols = 6; break;
614 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100615 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000616 default: cols = 16; break;
617 }
618
619 if (octspergrp < 0)
620 switch (hextype)
621 {
622 case HEX_BITS: octspergrp = 1; break;
623 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100624 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 case HEX_POSTSCRIPT:
626 case HEX_CINCLUDE:
627 default: octspergrp = 0; break;
628 }
629
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100630 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000631 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000632 {
633 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
634 exit(1);
635 }
636
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100637 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000638 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100639 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
640 {
641 fprintf(stderr,
642 "%s: number of octets per group must be a power of 2 with -e.\n",
643 pname);
644 exit(1);
645 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646
647 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200648 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000649
650 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
651 BIN_ASSIGN(fp = stdin, !revert);
652 else
653 {
654 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
655 {
656 fprintf(stderr,"%s: ", pname);
657 perror(argv[1]);
658 return 2;
659 }
660 }
661
662 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
663 BIN_ASSIGN(fpo = stdout, revert);
664 else
665 {
666 int fd;
667 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
668
669 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
670 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
671 {
672 fprintf(stderr, "%s: ", pname);
673 perror(argv[2]);
674 return 3;
675 }
676 rewind(fpo);
677 }
678
679 if (revert)
680 {
681 if (hextype && (hextype != HEX_POSTSCRIPT))
682 {
683 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
684 return -1;
685 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200686 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000687 negseek ? -seekoff : seekoff);
688 }
689
690 if (seekoff || negseek || !relseek)
691 {
692#ifdef TRY_SEEK
693 if (relseek)
694 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
695 else
696 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
697 if (e < 0 && negseek)
698 {
699 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
700 return 4;
701 }
702 if (e >= 0)
703 seekoff = ftell(fp);
704 else
705#endif
706 {
707 long s = seekoff;
708
709 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200710 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200711 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200712 if (ferror(fp))
713 {
714 die(2);
715 }
716 else
717 {
718 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
719 return 4;
720 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200721 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722 }
723 }
724
725 if (hextype == HEX_CINCLUDE)
726 {
727 if (fp != stdin)
728 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200729 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
730 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200732 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200733 die(3);
734 if (fputs("[] = {\n", fpo) == EOF)
735 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736 }
737
738 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200739 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
741 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200742 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200743 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 p++;
746 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200747 if (c == EOF && ferror(fp))
748 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100750 if (p && fputs("\n", fpo) == EOF)
751 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200752 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100753 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754
755 if (fp != stdin)
756 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200757 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
758 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200760 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200761 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200762 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200763 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 }
765
Bram Moolenaare0659a62011-04-01 19:14:40 +0200766 if (fclose(fp))
767 die(2);
768 if (fclose(fpo))
769 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770 return 0;
771 }
772
773 if (hextype == HEX_POSTSCRIPT)
774 {
775 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200776 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
778 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200779 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
780 || putc(hexx[e & 0xf], fpo) == EOF)
781 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 n++;
783 if (!--p)
784 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200785 if (putc('\n', fpo) == EOF)
786 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000787 p = cols;
788 }
789 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200790 if (e == EOF && ferror(fp))
791 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200793 if (putc('\n', fpo) == EOF)
794 die(3);
795 if (fclose(fp))
796 die(2);
797 if (fclose(fpo))
798 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 return 0;
800 }
801
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100802 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100804 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000805 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
806 else /* hextype == HEX_BITS */
807 grplen = 8 * octspergrp + 1;
808
Bram Moolenaare0659a62011-04-01 19:14:40 +0200809 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000810 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
811 {
812 if (p == 0)
813 {
Bram Moolenaar363d6142020-05-30 20:50:25 +0200814 if (decimal_offset)
815 addrlen = sprintf(l, "%08ld:",
816 ((unsigned long)(n + seekoff + displayoff)));
817 else
818 addrlen = sprintf(l, "%08lx:",
819 ((unsigned long)(n + seekoff + displayoff)));
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100820 for (c = addrlen; c < LLEN; l[c++] = ' ');
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 }
822 if (hextype == HEX_NORMAL)
823 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100824 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100825 l[++c] = hexx[ e & 0xf];
826 }
827 else if (hextype == HEX_LITTLEENDIAN)
828 {
829 int x = p ^ (octspergrp-1);
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100830 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100831 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 }
833 else /* hextype == HEX_BITS */
834 {
835 int i;
836
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100837 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 for (i = 7; i >= 0; i--)
839 l[++c] = (e & (1 << i)) ? '1' : '0';
840 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100841 if (e)
842 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 if (ebcdic)
844 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000845 /* When changing this update definition of LLEN above. */
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100846 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847#ifdef __MVS__
848 (e >= 64)
849#else
850 (e > 31 && e < 127)
851#endif
852 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 n++;
854 if (++p == cols)
855 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100856 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857 xxdline(fpo, l, autoskip ? nonzero : 1);
858 nonzero = 0;
859 p = 0;
860 }
861 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200862 if (e == EOF && ferror(fp))
863 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864 if (p)
865 {
Bram Moolenaard8c56a02019-01-30 23:02:25 +0100866 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000867 xxdline(fpo, l, 1);
868 }
869 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000870 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871
Bram Moolenaare0659a62011-04-01 19:14:40 +0200872 if (fclose(fp))
873 die(2);
874 if (fclose(fpo))
875 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876 return 0;
877}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200878
879/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */