blob: c18ad3160807c59a28f2197ac7c6b117dc2eca1b [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
83#ifdef __TSC__
84# define MSDOS
85#endif
86#if !defined(OS2) && defined(__EMX__)
87# define OS2
88#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000089#if defined(MSDOS) || defined(WIN32) || defined(OS2) || defined(__BORLANDC__) \
90 || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000091# include <io.h> /* for setmode() */
92#else
93# ifdef UNIX
94# include <unistd.h>
95# endif
96#endif
97#include <stdlib.h>
98#include <string.h> /* for strncmp() */
99#include <ctype.h> /* for isalnum() */
100#if __MWERKS__ && !defined(BEBOX)
101# include <unix.h> /* for fdopen() on MAC */
102#endif
103
104#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
105/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
106# define fileno(f) ((f)->fd)
107FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
108#endif
109
110
111/* This corrects the problem of missing prototypes for certain functions
112 * in some GNU installations (e.g. SunOS 4.1.x).
113 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
114 */
115#if defined(__GNUC__) && defined(__STDC__)
116# ifndef __USE_FIXED_PROTOTYPES__
117# define __USE_FIXED_PROTOTYPES__
118# endif
119#endif
120
121#ifndef __USE_FIXED_PROTOTYPES__
122/*
123 * This is historic and works only if the compiler really has no prototypes:
124 *
125 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
126 * FILE is defined on OS 4.x, not on 5.x (Solaris).
127 * if __SVR4 is defined (some Solaris versions), don't include this.
128 */
129#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
130# define __P(a) a
131/* excerpt from my sun_stdlib.h */
132extern int fprintf __P((FILE *, char *, ...));
133extern int fputs __P((char *, FILE *));
134extern int _flsbuf __P((unsigned char, FILE *));
135extern int _filbuf __P((FILE *));
136extern int fflush __P((FILE *));
137extern int fclose __P((FILE *));
138extern int fseek __P((FILE *, long, int));
139extern int rewind __P((FILE *));
140
141extern void perror __P((char *));
142# endif
143#endif
144
145extern long int strtol();
146extern long int ftell();
147
148char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
149#ifdef WIN32
150char osver[] = " (Win32)";
151#else
152# ifdef DJGPP
153char osver[] = " (dos 32 bit)";
154# else
155# ifdef MSDOS
156char osver[] = " (dos 16 bit)";
157# else
158char osver[] = "";
159# endif
160# endif
161#endif
162
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000163#if defined(MSDOS) || defined(WIN32) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000164# define BIN_READ(yes) ((yes) ? "rb" : "rt")
165# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
166# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
167# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000168# define PATH_SEP '\\'
169#elif defined(CYGWIN)
170# define BIN_READ(yes) ((yes) ? "rb" : "rt")
171# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
172# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
173# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
174# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000175#else
176# ifdef VMS
177# define BIN_READ(dummy) "r"
178# define BIN_WRITE(dummy) "w"
179# define BIN_CREAT(dummy) O_CREAT
180# define BIN_ASSIGN(fp, dummy) fp
181# define PATH_SEP ']'
182# define FILE_SEP '.'
183# else
184# define BIN_READ(dummy) "r"
185# define BIN_WRITE(dummy) "w"
186# define BIN_CREAT(dummy) O_CREAT
187# define BIN_ASSIGN(fp, dummy) fp
188# define PATH_SEP '/'
189# endif
190#endif
191
192/* open has only to arguments on the Mac */
193#if __MWERKS__
194# define OPEN(name, mode, umask) open(name, mode)
195#else
196# define OPEN(name, mode, umask) open(name, mode, umask)
197#endif
198
199#ifdef AMIGA
200# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
201#else
202# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
203#endif
204
205#ifndef __P
206# if defined(__STDC__) || defined(MSDOS) || defined(WIN32) || defined(OS2) \
207 || defined(__BORLANDC__)
208# define __P(a) a
209# else
210# define __P(a) ()
211# endif
212#endif
213
214/* Let's collect some prototypes */
215/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200216static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200217static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200218static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219static void xxdline __P((FILE *, char *, int));
220
221#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
222#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100223#define LLEN (12 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224
225char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
226
227/* the different hextypes known by this program: */
228#define HEX_NORMAL 0
229#define HEX_POSTSCRIPT 1
230#define HEX_CINCLUDE 2
231#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100232#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233
Bram Moolenaare0659a62011-04-01 19:14:40 +0200234static char *pname;
235
236 static void
237exit_with_usage()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238{
239 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
240 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
241 fprintf(stderr, "Options:\n");
242 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100243 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000244 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
245 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100246 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
247 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000248 fprintf(stderr, " -h print this summary.\n");
249 fprintf(stderr, " -i output in C include file style.\n");
250 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100251 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000252 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
253 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
254 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
255 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
256#ifdef TRY_SEEK
257 "[+][-]", "(or +: rel.) ");
258#else
259 "", "");
260#endif
261 fprintf(stderr, " -u use upper case hex letters.\n");
262 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
263 exit(1);
264}
265
Bram Moolenaare0659a62011-04-01 19:14:40 +0200266 static void
267die(ret)
268 int ret;
269{
270 fprintf(stderr, "%s: ", pname);
271 perror(NULL);
272 exit(ret);
273}
274
Bram Moolenaar071d4272004-06-13 20:20:40 +0000275/*
276 * Max. cols binary characters are decoded from the input stream per line.
277 * Two adjacent garbage characters after evaluated data delimit valid data.
278 * Everything up to the next newline is discarded.
279 *
280 * The name is historic and came from 'undo type opt h'.
281 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200282 static int
283huntype(fpi, fpo, fperr, cols, hextype, base_off)
284 FILE *fpi, *fpo, *fperr;
285 int cols, hextype;
286 long base_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000287{
288 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
289 long have_off = 0, want_off = 0;
290
291 rewind(fpi);
292
293 while ((c = getc(fpi)) != EOF)
294 {
295 if (c == '\r') /* Doze style input file? */
296 continue;
297
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100298 /* Allow multiple spaces. This doesn't work when there is normal text
299 * after the hex codes in the last line that looks like hex, thus only
300 * use it for PostScript format. */
301 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000302 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000303
Bram Moolenaar071d4272004-06-13 20:20:40 +0000304 n3 = n2;
305 n2 = n1;
306
307 if (c >= '0' && c <= '9')
308 n1 = c - '0';
309 else if (c >= 'a' && c <= 'f')
310 n1 = c - 'a' + 10;
311 else if (c >= 'A' && c <= 'F')
312 n1 = c - 'A' + 10;
313 else
314 {
315 n1 = -1;
316 if (ign_garb)
317 continue;
318 }
319
320 ign_garb = 0;
321
322 if (p >= cols)
323 {
324 if (!hextype)
325 {
326 if (n1 < 0)
327 {
328 p = 0;
329 continue;
330 }
331 want_off = (want_off << 4) | n1;
332 continue;
333 }
334 else
335 p = 0;
336 }
337
338 if (base_off + want_off != have_off)
339 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200340 if (fflush(fpo) != 0)
341 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000342#ifdef TRY_SEEK
343 c = fseek(fpo, base_off + want_off - have_off, 1);
344 if (c >= 0)
345 have_off = base_off + want_off;
346#endif
347 if (base_off + want_off < have_off)
348 {
349 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
350 return 5;
351 }
352 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200353 if (putc(0, fpo) == EOF)
354 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000355 }
356
357 if (n2 >= 0 && n1 >= 0)
358 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200359 if (putc((n2 << 4) | n1, fpo) == EOF)
360 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 have_off++;
362 want_off++;
363 n1 = -1;
364 if ((++p >= cols) && !hextype)
365 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000366 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000367 want_off = 0;
368 while ((c = getc(fpi)) != '\n' && c != EOF)
369 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200370 if (c == EOF && ferror(fpi))
371 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000372 ign_garb = 1;
373 }
374 }
375 else if (n1 < 0 && n2 < 0 && n3 < 0)
376 {
377 /* already stumbled into garbage, skip line, wait and see */
378 if (!hextype)
379 want_off = 0;
380 while ((c = getc(fpi)) != '\n' && c != EOF)
381 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200382 if (c == EOF && ferror(fpi))
383 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384 ign_garb = 1;
385 }
386 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200387 if (fflush(fpo) != 0)
388 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389#ifdef TRY_SEEK
390 fseek(fpo, 0L, 2);
391#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200392 if (fclose(fpo) != 0)
393 die(3);
394 if (fclose(fpi) != 0)
395 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000396 return 0;
397}
398
399/*
400 * Print line l. If nz is false, xxdline regards the line a line of
401 * zeroes. If there are three or more consecutive lines of zeroes,
402 * they are replaced by a single '*' character.
403 *
404 * If the output ends with more than two lines of zeroes, you
405 * should call xxdline again with l being the last line and nz
406 * negative. This ensures that the last line is shown even when
407 * it is all zeroes.
408 *
409 * If nz is always positive, lines are never suppressed.
410 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200411 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000412xxdline(fp, l, nz)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200413 FILE *fp;
414 char *l;
415 int nz;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000416{
417 static char z[LLEN+1];
418 static int zero_seen = 0;
419
420 if (!nz && zero_seen == 1)
421 strcpy(z, l);
422
423 if (nz || !zero_seen++)
424 {
425 if (nz)
426 {
427 if (nz < 0)
428 zero_seen--;
429 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200430 if (fputs(z, fp) == EOF)
431 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200433 if (fputs("*\n", fp) == EOF)
434 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000435 }
436 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200437 if (fputs(l, fp) == EOF)
438 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000439 if (nz)
440 zero_seen = 0;
441 }
442}
443
444/* This is an EBCDIC to ASCII conversion table */
445/* from a proposed BTL standard April 16, 1979 */
446static unsigned char etoa64[] =
447{
448 0040,0240,0241,0242,0243,0244,0245,0246,
449 0247,0250,0325,0056,0074,0050,0053,0174,
450 0046,0251,0252,0253,0254,0255,0256,0257,
451 0260,0261,0041,0044,0052,0051,0073,0176,
452 0055,0057,0262,0263,0264,0265,0266,0267,
453 0270,0271,0313,0054,0045,0137,0076,0077,
454 0272,0273,0274,0275,0276,0277,0300,0301,
455 0302,0140,0072,0043,0100,0047,0075,0042,
456 0303,0141,0142,0143,0144,0145,0146,0147,
457 0150,0151,0304,0305,0306,0307,0310,0311,
458 0312,0152,0153,0154,0155,0156,0157,0160,
459 0161,0162,0136,0314,0315,0316,0317,0320,
460 0321,0345,0163,0164,0165,0166,0167,0170,
461 0171,0172,0322,0323,0324,0133,0326,0327,
462 0330,0331,0332,0333,0334,0335,0336,0337,
463 0340,0341,0342,0343,0344,0135,0346,0347,
464 0173,0101,0102,0103,0104,0105,0106,0107,
465 0110,0111,0350,0351,0352,0353,0354,0355,
466 0175,0112,0113,0114,0115,0116,0117,0120,
467 0121,0122,0356,0357,0360,0361,0362,0363,
468 0134,0237,0123,0124,0125,0126,0127,0130,
469 0131,0132,0364,0365,0366,0367,0370,0371,
470 0060,0061,0062,0063,0064,0065,0066,0067,
471 0070,0071,0372,0373,0374,0375,0376,0377
472};
473
Bram Moolenaare0659a62011-04-01 19:14:40 +0200474 int
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475main(argc, argv)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200476 int argc;
477 char *argv[];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000478{
479 FILE *fp, *fpo;
480 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
481 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
482 int ebcdic = 0;
483 int octspergrp = -1; /* number of octets grouped in output */
484 int grplen; /* total chars per octet group */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100485 long length = -1, n = 0, seekoff = 0, displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200486 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200487 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000488
489#ifdef AMIGA
490 /* This program doesn't work when started from the Workbench */
491 if (argc == 0)
492 exit(1);
493#endif
494
495 pname = argv[0];
496 for (pp = pname; *pp; )
497 if (*pp++ == PATH_SEP)
498 pname = pp;
499#ifdef FILE_SEP
500 for (pp = pname; *pp; pp++)
501 if (*pp == FILE_SEP)
502 {
503 *pp = '\0';
504 break;
505 }
506#endif
507
508 while (argc >= 2)
509 {
510 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
511 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
512 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100513 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000514 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
515 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
516 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
517 else if (!STRNCMP(pp, "-r", 2)) revert++;
518 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
519 else if (!STRNCMP(pp, "-v", 2))
520 {
521 fprintf(stderr, "%s%s\n", version, osver);
522 exit(0);
523 }
524 else if (!STRNCMP(pp, "-c", 2))
525 {
526 if (pp[2] && STRNCMP("ols", pp + 2, 3))
527 cols = (int)strtol(pp + 2, NULL, 0);
528 else
529 {
530 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200531 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000532 cols = (int)strtol(argv[2], NULL, 0);
533 argv++;
534 argc--;
535 }
536 }
537 else if (!STRNCMP(pp, "-g", 2))
538 {
539 if (pp[2] && STRNCMP("group", pp + 2, 5))
540 octspergrp = (int)strtol(pp + 2, NULL, 0);
541 else
542 {
543 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200544 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000545 octspergrp = (int)strtol(argv[2], NULL, 0);
546 argv++;
547 argc--;
548 }
549 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100550 else if (!STRNCMP(pp, "-o", 2))
551 {
552 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
553 displayoff = (int)strtol(pp + 2, NULL, 0);
554 else
555 {
556 if (!argv[2])
557 exit_with_usage();
558 displayoff = (int)strtol(argv[2], NULL, 0);
559 argv++;
560 argc--;
561 }
562 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000563 else if (!STRNCMP(pp, "-s", 2))
564 {
565 relseek = 0;
566 negseek = 0;
567 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
568 {
569#ifdef TRY_SEEK
570 if (pp[2] == '+')
571 relseek++;
572 if (pp[2+relseek] == '-')
573 negseek++;
574#endif
575 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
576 }
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#ifdef TRY_SEEK
582 if (argv[2][0] == '+')
583 relseek++;
584 if (argv[2][relseek] == '-')
585 negseek++;
586#endif
587 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
588 argv++;
589 argc--;
590 }
591 }
592 else if (!STRNCMP(pp, "-l", 2))
593 {
594 if (pp[2] && STRNCMP("en", pp + 2, 2))
595 length = strtol(pp + 2, (char **)NULL, 0);
596 else
597 {
598 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200599 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 length = strtol(argv[2], (char **)NULL, 0);
601 argv++;
602 argc--;
603 }
604 }
605 else if (!strcmp(pp, "--")) /* end of options */
606 {
607 argv++;
608 argc--;
609 break;
610 }
611 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200612 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 else
614 break; /* not an option */
615
616 argv++; /* advance to next argument */
617 argc--;
618 }
619
620 if (!cols)
621 switch (hextype)
622 {
623 case HEX_POSTSCRIPT: cols = 30; break;
624 case HEX_CINCLUDE: cols = 12; break;
625 case HEX_BITS: cols = 6; break;
626 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100627 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000628 default: cols = 16; break;
629 }
630
631 if (octspergrp < 0)
632 switch (hextype)
633 {
634 case HEX_BITS: octspergrp = 1; break;
635 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100636 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 case HEX_POSTSCRIPT:
638 case HEX_CINCLUDE:
639 default: octspergrp = 0; break;
640 }
641
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100642 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000643 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000644 {
645 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
646 exit(1);
647 }
648
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100649 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000650 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100651 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
652 {
653 fprintf(stderr,
654 "%s: number of octets per group must be a power of 2 with -e.\n",
655 pname);
656 exit(1);
657 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658
659 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200660 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000661
662 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
663 BIN_ASSIGN(fp = stdin, !revert);
664 else
665 {
666 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
667 {
668 fprintf(stderr,"%s: ", pname);
669 perror(argv[1]);
670 return 2;
671 }
672 }
673
674 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
675 BIN_ASSIGN(fpo = stdout, revert);
676 else
677 {
678 int fd;
679 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
680
681 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
682 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
683 {
684 fprintf(stderr, "%s: ", pname);
685 perror(argv[2]);
686 return 3;
687 }
688 rewind(fpo);
689 }
690
691 if (revert)
692 {
693 if (hextype && (hextype != HEX_POSTSCRIPT))
694 {
695 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
696 return -1;
697 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200698 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000699 negseek ? -seekoff : seekoff);
700 }
701
702 if (seekoff || negseek || !relseek)
703 {
704#ifdef TRY_SEEK
705 if (relseek)
706 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
707 else
708 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
709 if (e < 0 && negseek)
710 {
711 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
712 return 4;
713 }
714 if (e >= 0)
715 seekoff = ftell(fp);
716 else
717#endif
718 {
719 long s = seekoff;
720
721 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200722 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200723 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200724 if (ferror(fp))
725 {
726 die(2);
727 }
728 else
729 {
730 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
731 return 4;
732 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200733 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000734 }
735 }
736
737 if (hextype == HEX_CINCLUDE)
738 {
739 if (fp != stdin)
740 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200741 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
742 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000743 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
745 die(3);
746 if (fputs("[] = {\n", fpo) == EOF)
747 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 }
749
750 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200751 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
753 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200754 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200755 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200756 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000757 p++;
758 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200759 if (c == EOF && ferror(fp))
760 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100762 if (p && fputs("\n", fpo) == EOF)
763 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200764 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100765 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000766
767 if (fp != stdin)
768 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200769 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
770 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000771 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200772 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
773 die(3);
774 if (fprintf(fpo, "_len = %d;\n", p) < 0)
775 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 }
777
Bram Moolenaare0659a62011-04-01 19:14:40 +0200778 if (fclose(fp))
779 die(2);
780 if (fclose(fpo))
781 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000782 return 0;
783 }
784
785 if (hextype == HEX_POSTSCRIPT)
786 {
787 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200788 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
790 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200791 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
792 || putc(hexx[e & 0xf], fpo) == EOF)
793 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000794 n++;
795 if (!--p)
796 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200797 if (putc('\n', fpo) == EOF)
798 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000799 p = cols;
800 }
801 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200802 if (e == EOF && ferror(fp))
803 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200805 if (putc('\n', fpo) == EOF)
806 die(3);
807 if (fclose(fp))
808 die(2);
809 if (fclose(fpo))
810 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 return 0;
812 }
813
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100814 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100816 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000817 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
818 else /* hextype == HEX_BITS */
819 grplen = 8 * octspergrp + 1;
820
Bram Moolenaare0659a62011-04-01 19:14:40 +0200821 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000822 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
823 {
824 if (p == 0)
825 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100826 sprintf(l, "%08lx:",
827 ((unsigned long)(n + seekoff + displayoff)) & 0xffffffff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000828 for (c = 9; c < LLEN; l[c++] = ' ');
829 }
830 if (hextype == HEX_NORMAL)
831 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100832 l[c = (10 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
833 l[++c] = hexx[ e & 0xf];
834 }
835 else if (hextype == HEX_LITTLEENDIAN)
836 {
837 int x = p ^ (octspergrp-1);
838 l[c = (10 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
839 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000840 }
841 else /* hextype == HEX_BITS */
842 {
843 int i;
844
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100845 c = (10 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 for (i = 7; i >= 0; i--)
847 l[++c] = (e & (1 << i)) ? '1' : '0';
848 }
849 if (ebcdic)
850 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000851 /* When changing this update definition of LLEN above. */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100852 l[12 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000853#ifdef __MVS__
854 (e >= 64)
855#else
856 (e > 31 && e < 127)
857#endif
858 ? e : '.';
859 if (e)
860 nonzero++;
861 n++;
862 if (++p == cols)
863 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100864 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000865 xxdline(fpo, l, autoskip ? nonzero : 1);
866 nonzero = 0;
867 p = 0;
868 }
869 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200870 if (e == EOF && ferror(fp))
871 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 if (p)
873 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100874 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000875 xxdline(fpo, l, 1);
876 }
877 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000878 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000879
Bram Moolenaare0659a62011-04-01 19:14:40 +0200880 if (fclose(fp))
881 die(2);
882 if (fclose(fpo))
883 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000884 return 0;
885}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200886
887/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */