blob: f89f4d3b03900ea80aef253dcf0ad14c7c5ee1e2 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
38 * 18.07.96 gcc -Wall @ SunOS4 is now slient.
39 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaar071d4272004-06-13 20:20:40 +000055 *
56 * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
57 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020058 * I hereby grant permission to distribute and use xxd
59 * under X11-MIT or GPL-2.0 (at the user's choice).
60 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000061 * Small changes made afterwards by Bram Moolenaar et al.
62 *
63 * Distribute freely and credit me,
64 * make money and share with me,
65 * lose money and don't ask me.
66 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000067
68/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
69#if _MSC_VER >= 1400
70# define _CRT_SECURE_NO_DEPRECATE
71# define _CRT_NONSTDC_NO_DEPRECATE
72#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000073#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
74# define CYGWIN
75#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000076
Bram Moolenaar071d4272004-06-13 20:20:40 +000077#include <stdio.h>
78#ifdef VAXC
79# include <file.h>
80#else
81# include <fcntl.h>
82#endif
Bram Moolenaara06ecab2016-07-16 14:47:36 +020083#if defined(WIN32) || defined(__BORLANDC__) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000084# include <io.h> /* for setmode() */
85#else
86# ifdef UNIX
87# include <unistd.h>
88# endif
89#endif
90#include <stdlib.h>
91#include <string.h> /* for strncmp() */
92#include <ctype.h> /* for isalnum() */
93#if __MWERKS__ && !defined(BEBOX)
94# include <unix.h> /* for fdopen() on MAC */
95#endif
96
97#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
98/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
99# define fileno(f) ((f)->fd)
100FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
101#endif
102
103
104/* This corrects the problem of missing prototypes for certain functions
105 * in some GNU installations (e.g. SunOS 4.1.x).
106 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
107 */
108#if defined(__GNUC__) && defined(__STDC__)
109# ifndef __USE_FIXED_PROTOTYPES__
110# define __USE_FIXED_PROTOTYPES__
111# endif
112#endif
113
114#ifndef __USE_FIXED_PROTOTYPES__
115/*
116 * This is historic and works only if the compiler really has no prototypes:
117 *
118 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
119 * FILE is defined on OS 4.x, not on 5.x (Solaris).
120 * if __SVR4 is defined (some Solaris versions), don't include this.
121 */
122#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
123# define __P(a) a
124/* excerpt from my sun_stdlib.h */
125extern int fprintf __P((FILE *, char *, ...));
126extern int fputs __P((char *, FILE *));
127extern int _flsbuf __P((unsigned char, FILE *));
128extern int _filbuf __P((FILE *));
129extern int fflush __P((FILE *));
130extern int fclose __P((FILE *));
131extern int fseek __P((FILE *, long, int));
132extern int rewind __P((FILE *));
133
134extern void perror __P((char *));
135# endif
136#endif
137
138extern long int strtol();
139extern long int ftell();
140
141char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
142#ifdef WIN32
143char osver[] = " (Win32)";
144#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146#endif
147
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200148#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149# define BIN_READ(yes) ((yes) ? "rb" : "rt")
150# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
151# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
152# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000153# define PATH_SEP '\\'
154#elif defined(CYGWIN)
155# define BIN_READ(yes) ((yes) ? "rb" : "rt")
156# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
157# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
158# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
159# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160#else
161# ifdef VMS
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# define FILE_SEP '.'
168# else
169# define BIN_READ(dummy) "r"
170# define BIN_WRITE(dummy) "w"
171# define BIN_CREAT(dummy) O_CREAT
172# define BIN_ASSIGN(fp, dummy) fp
173# define PATH_SEP '/'
174# endif
175#endif
176
177/* open has only to arguments on the Mac */
178#if __MWERKS__
179# define OPEN(name, mode, umask) open(name, mode)
180#else
181# define OPEN(name, mode, umask) open(name, mode, umask)
182#endif
183
184#ifdef AMIGA
185# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
186#else
187# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
188#endif
189
190#ifndef __P
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200191# if defined(__STDC__) || defined(WIN32) || defined(__BORLANDC__)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192# define __P(a) a
193# else
194# define __P(a) ()
195# endif
196#endif
197
198/* Let's collect some prototypes */
199/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200200static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200201static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200202static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203static void xxdline __P((FILE *, char *, int));
204
205#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
206#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100207#define LLEN (12 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208
209char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
210
211/* the different hextypes known by this program: */
212#define HEX_NORMAL 0
213#define HEX_POSTSCRIPT 1
214#define HEX_CINCLUDE 2
215#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100216#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217
Bram Moolenaare0659a62011-04-01 19:14:40 +0200218static char *pname;
219
220 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100221exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000222{
223 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
224 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
225 fprintf(stderr, "Options:\n");
226 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100227 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000228 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
229 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100230 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
231 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232 fprintf(stderr, " -h print this summary.\n");
233 fprintf(stderr, " -i output in C include file style.\n");
234 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100235 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000236 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
237 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
238 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
239 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
240#ifdef TRY_SEEK
241 "[+][-]", "(or +: rel.) ");
242#else
243 "", "");
244#endif
245 fprintf(stderr, " -u use upper case hex letters.\n");
246 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
247 exit(1);
248}
249
Bram Moolenaare0659a62011-04-01 19:14:40 +0200250 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100251die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200252{
253 fprintf(stderr, "%s: ", pname);
254 perror(NULL);
255 exit(ret);
256}
257
Bram Moolenaar071d4272004-06-13 20:20:40 +0000258/*
259 * Max. cols binary characters are decoded from the input stream per line.
260 * Two adjacent garbage characters after evaluated data delimit valid data.
261 * Everything up to the next newline is discarded.
262 *
263 * The name is historic and came from 'undo type opt h'.
264 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200265 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100266huntype(
267 FILE *fpi,
268 FILE *fpo,
269 FILE *fperr,
270 int cols,
271 int hextype,
272 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000273{
274 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
275 long have_off = 0, want_off = 0;
276
277 rewind(fpi);
278
279 while ((c = getc(fpi)) != EOF)
280 {
281 if (c == '\r') /* Doze style input file? */
282 continue;
283
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100284 /* Allow multiple spaces. This doesn't work when there is normal text
285 * after the hex codes in the last line that looks like hex, thus only
286 * use it for PostScript format. */
287 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000288 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000289
Bram Moolenaar071d4272004-06-13 20:20:40 +0000290 n3 = n2;
291 n2 = n1;
292
293 if (c >= '0' && c <= '9')
294 n1 = c - '0';
295 else if (c >= 'a' && c <= 'f')
296 n1 = c - 'a' + 10;
297 else if (c >= 'A' && c <= 'F')
298 n1 = c - 'A' + 10;
299 else
300 {
301 n1 = -1;
302 if (ign_garb)
303 continue;
304 }
305
306 ign_garb = 0;
307
308 if (p >= cols)
309 {
310 if (!hextype)
311 {
312 if (n1 < 0)
313 {
314 p = 0;
315 continue;
316 }
317 want_off = (want_off << 4) | n1;
318 continue;
319 }
320 else
321 p = 0;
322 }
323
324 if (base_off + want_off != have_off)
325 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200326 if (fflush(fpo) != 0)
327 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000328#ifdef TRY_SEEK
329 c = fseek(fpo, base_off + want_off - have_off, 1);
330 if (c >= 0)
331 have_off = base_off + want_off;
332#endif
333 if (base_off + want_off < have_off)
334 {
335 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
336 return 5;
337 }
338 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200339 if (putc(0, fpo) == EOF)
340 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000341 }
342
343 if (n2 >= 0 && n1 >= 0)
344 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200345 if (putc((n2 << 4) | n1, fpo) == EOF)
346 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 have_off++;
348 want_off++;
349 n1 = -1;
350 if ((++p >= cols) && !hextype)
351 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000352 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 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 }
361 else if (n1 < 0 && n2 < 0 && n3 < 0)
362 {
363 /* already stumbled into garbage, skip line, wait and see */
364 if (!hextype)
365 want_off = 0;
366 while ((c = getc(fpi)) != '\n' && c != EOF)
367 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200368 if (c == EOF && ferror(fpi))
369 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370 ign_garb = 1;
371 }
372 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200373 if (fflush(fpo) != 0)
374 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000375#ifdef TRY_SEEK
376 fseek(fpo, 0L, 2);
377#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200378 if (fclose(fpo) != 0)
379 die(3);
380 if (fclose(fpi) != 0)
381 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382 return 0;
383}
384
385/*
386 * Print line l. If nz is false, xxdline regards the line a line of
387 * zeroes. If there are three or more consecutive lines of zeroes,
388 * they are replaced by a single '*' character.
389 *
390 * If the output ends with more than two lines of zeroes, you
391 * should call xxdline again with l being the last line and nz
392 * negative. This ensures that the last line is shown even when
393 * it is all zeroes.
394 *
395 * If nz is always positive, lines are never suppressed.
396 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200397 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100398xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000399{
400 static char z[LLEN+1];
401 static int zero_seen = 0;
402
403 if (!nz && zero_seen == 1)
404 strcpy(z, l);
405
406 if (nz || !zero_seen++)
407 {
408 if (nz)
409 {
410 if (nz < 0)
411 zero_seen--;
412 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200413 if (fputs(z, fp) == EOF)
414 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200416 if (fputs("*\n", fp) == EOF)
417 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 }
419 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200420 if (fputs(l, fp) == EOF)
421 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000422 if (nz)
423 zero_seen = 0;
424 }
425}
426
427/* This is an EBCDIC to ASCII conversion table */
428/* from a proposed BTL standard April 16, 1979 */
429static unsigned char etoa64[] =
430{
431 0040,0240,0241,0242,0243,0244,0245,0246,
432 0247,0250,0325,0056,0074,0050,0053,0174,
433 0046,0251,0252,0253,0254,0255,0256,0257,
434 0260,0261,0041,0044,0052,0051,0073,0176,
435 0055,0057,0262,0263,0264,0265,0266,0267,
436 0270,0271,0313,0054,0045,0137,0076,0077,
437 0272,0273,0274,0275,0276,0277,0300,0301,
438 0302,0140,0072,0043,0100,0047,0075,0042,
439 0303,0141,0142,0143,0144,0145,0146,0147,
440 0150,0151,0304,0305,0306,0307,0310,0311,
441 0312,0152,0153,0154,0155,0156,0157,0160,
442 0161,0162,0136,0314,0315,0316,0317,0320,
443 0321,0345,0163,0164,0165,0166,0167,0170,
444 0171,0172,0322,0323,0324,0133,0326,0327,
445 0330,0331,0332,0333,0334,0335,0336,0337,
446 0340,0341,0342,0343,0344,0135,0346,0347,
447 0173,0101,0102,0103,0104,0105,0106,0107,
448 0110,0111,0350,0351,0352,0353,0354,0355,
449 0175,0112,0113,0114,0115,0116,0117,0120,
450 0121,0122,0356,0357,0360,0361,0362,0363,
451 0134,0237,0123,0124,0125,0126,0127,0130,
452 0131,0132,0364,0365,0366,0367,0370,0371,
453 0060,0061,0062,0063,0064,0065,0066,0067,
454 0070,0071,0372,0373,0374,0375,0376,0377
455};
456
Bram Moolenaare0659a62011-04-01 19:14:40 +0200457 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100458main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000459{
460 FILE *fp, *fpo;
461 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
462 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
463 int ebcdic = 0;
464 int octspergrp = -1; /* number of octets grouped in output */
465 int grplen; /* total chars per octet group */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100466 long length = -1, n = 0, seekoff = 0, displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200467 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200468 char *pp;
Bram 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;
498 else if (!STRNCMP(pp, "-r", 2)) revert++;
499 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
500 else if (!STRNCMP(pp, "-v", 2))
501 {
502 fprintf(stderr, "%s%s\n", version, osver);
503 exit(0);
504 }
505 else if (!STRNCMP(pp, "-c", 2))
506 {
507 if (pp[2] && STRNCMP("ols", pp + 2, 3))
508 cols = (int)strtol(pp + 2, NULL, 0);
509 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 {
520 if (pp[2] && STRNCMP("group", pp + 2, 5))
521 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 {
533 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
534 displayoff = (int)strtol(pp + 2, NULL, 0);
535 else
536 {
537 if (!argv[2])
538 exit_with_usage();
539 displayoff = (int)strtol(argv[2], NULL, 0);
540 argv++;
541 argc--;
542 }
543 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000544 else if (!STRNCMP(pp, "-s", 2))
545 {
546 relseek = 0;
547 negseek = 0;
548 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
549 {
550#ifdef TRY_SEEK
551 if (pp[2] == '+')
552 relseek++;
553 if (pp[2+relseek] == '-')
554 negseek++;
555#endif
556 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
557 }
558 else
559 {
560 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200561 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000562#ifdef TRY_SEEK
563 if (argv[2][0] == '+')
564 relseek++;
565 if (argv[2][relseek] == '-')
566 negseek++;
567#endif
568 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
569 argv++;
570 argc--;
571 }
572 }
573 else if (!STRNCMP(pp, "-l", 2))
574 {
575 if (pp[2] && STRNCMP("en", pp + 2, 2))
576 length = strtol(pp + 2, (char **)NULL, 0);
577 else
578 {
579 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200580 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000581 length = strtol(argv[2], (char **)NULL, 0);
582 argv++;
583 argc--;
584 }
585 }
586 else if (!strcmp(pp, "--")) /* end of options */
587 {
588 argv++;
589 argc--;
590 break;
591 }
592 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200593 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000594 else
595 break; /* not an option */
596
597 argv++; /* advance to next argument */
598 argc--;
599 }
600
601 if (!cols)
602 switch (hextype)
603 {
604 case HEX_POSTSCRIPT: cols = 30; break;
605 case HEX_CINCLUDE: cols = 12; break;
606 case HEX_BITS: cols = 6; break;
607 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100608 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000609 default: cols = 16; break;
610 }
611
612 if (octspergrp < 0)
613 switch (hextype)
614 {
615 case HEX_BITS: octspergrp = 1; break;
616 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100617 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000618 case HEX_POSTSCRIPT:
619 case HEX_CINCLUDE:
620 default: octspergrp = 0; break;
621 }
622
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100623 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000624 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 {
626 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
627 exit(1);
628 }
629
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100630 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100632 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
633 {
634 fprintf(stderr,
635 "%s: number of octets per group must be a power of 2 with -e.\n",
636 pname);
637 exit(1);
638 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000639
640 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200641 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000642
643 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
644 BIN_ASSIGN(fp = stdin, !revert);
645 else
646 {
647 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
648 {
649 fprintf(stderr,"%s: ", pname);
650 perror(argv[1]);
651 return 2;
652 }
653 }
654
655 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
656 BIN_ASSIGN(fpo = stdout, revert);
657 else
658 {
659 int fd;
660 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
661
662 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
663 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
664 {
665 fprintf(stderr, "%s: ", pname);
666 perror(argv[2]);
667 return 3;
668 }
669 rewind(fpo);
670 }
671
672 if (revert)
673 {
674 if (hextype && (hextype != HEX_POSTSCRIPT))
675 {
676 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
677 return -1;
678 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200679 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000680 negseek ? -seekoff : seekoff);
681 }
682
683 if (seekoff || negseek || !relseek)
684 {
685#ifdef TRY_SEEK
686 if (relseek)
687 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
688 else
689 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
690 if (e < 0 && negseek)
691 {
692 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
693 return 4;
694 }
695 if (e >= 0)
696 seekoff = ftell(fp);
697 else
698#endif
699 {
700 long s = seekoff;
701
702 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200703 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200704 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200705 if (ferror(fp))
706 {
707 die(2);
708 }
709 else
710 {
711 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
712 return 4;
713 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200714 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715 }
716 }
717
718 if (hextype == HEX_CINCLUDE)
719 {
720 if (fp != stdin)
721 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200722 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
723 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200725 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
726 die(3);
727 if (fputs("[] = {\n", fpo) == EOF)
728 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000729 }
730
731 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200732 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
734 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200735 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200736 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200737 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000738 p++;
739 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200740 if (c == EOF && ferror(fp))
741 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100743 if (p && fputs("\n", fpo) == EOF)
744 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200745 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100746 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000747
748 if (fp != stdin)
749 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200750 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
751 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200753 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
754 die(3);
755 if (fprintf(fpo, "_len = %d;\n", p) < 0)
756 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 }
758
Bram Moolenaare0659a62011-04-01 19:14:40 +0200759 if (fclose(fp))
760 die(2);
761 if (fclose(fpo))
762 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 return 0;
764 }
765
766 if (hextype == HEX_POSTSCRIPT)
767 {
768 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200769 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
771 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200772 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
773 || putc(hexx[e & 0xf], fpo) == EOF)
774 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000775 n++;
776 if (!--p)
777 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200778 if (putc('\n', fpo) == EOF)
779 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000780 p = cols;
781 }
782 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200783 if (e == EOF && ferror(fp))
784 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000785 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200786 if (putc('\n', fpo) == EOF)
787 die(3);
788 if (fclose(fp))
789 die(2);
790 if (fclose(fpo))
791 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 return 0;
793 }
794
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100795 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100797 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
799 else /* hextype == HEX_BITS */
800 grplen = 8 * octspergrp + 1;
801
Bram Moolenaare0659a62011-04-01 19:14:40 +0200802 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000803 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
804 {
805 if (p == 0)
806 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100807 sprintf(l, "%08lx:",
808 ((unsigned long)(n + seekoff + displayoff)) & 0xffffffff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 for (c = 9; c < LLEN; l[c++] = ' ');
810 }
811 if (hextype == HEX_NORMAL)
812 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100813 l[c = (10 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
814 l[++c] = hexx[ e & 0xf];
815 }
816 else if (hextype == HEX_LITTLEENDIAN)
817 {
818 int x = p ^ (octspergrp-1);
819 l[c = (10 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
820 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000821 }
822 else /* hextype == HEX_BITS */
823 {
824 int i;
825
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100826 c = (10 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 for (i = 7; i >= 0; i--)
828 l[++c] = (e & (1 << i)) ? '1' : '0';
829 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100830 if (e)
831 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000832 if (ebcdic)
833 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000834 /* When changing this update definition of LLEN above. */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100835 l[12 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836#ifdef __MVS__
837 (e >= 64)
838#else
839 (e > 31 && e < 127)
840#endif
841 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842 n++;
843 if (++p == cols)
844 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100845 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 xxdline(fpo, l, autoskip ? nonzero : 1);
847 nonzero = 0;
848 p = 0;
849 }
850 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200851 if (e == EOF && ferror(fp))
852 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853 if (p)
854 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100855 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 xxdline(fpo, l, 1);
857 }
858 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000859 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860
Bram Moolenaare0659a62011-04-01 19:14:40 +0200861 if (fclose(fp))
862 die(2);
863 if (fclose(fpo))
864 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 return 0;
866}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200867
868/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */