blob: 8b09c85d6ef6470b7317e0c92dd72e4fd2af0b68 [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 *
58 * Small changes made afterwards by Bram Moolenaar et al.
59 *
60 * Distribute freely and credit me,
61 * make money and share with me,
62 * lose money and don't ask me.
63 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000064
65/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
66#if _MSC_VER >= 1400
67# define _CRT_SECURE_NO_DEPRECATE
68# define _CRT_NONSTDC_NO_DEPRECATE
69#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000070#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
71# define CYGWIN
72#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000073
Bram Moolenaar071d4272004-06-13 20:20:40 +000074#include <stdio.h>
75#ifdef VAXC
76# include <file.h>
77#else
78# include <fcntl.h>
79#endif
80#ifdef __TSC__
81# define MSDOS
82#endif
83#if !defined(OS2) && defined(__EMX__)
84# define OS2
85#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000086#if defined(MSDOS) || defined(WIN32) || defined(OS2) || defined(__BORLANDC__) \
87 || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000088# include <io.h> /* for setmode() */
89#else
90# ifdef UNIX
91# include <unistd.h>
92# endif
93#endif
94#include <stdlib.h>
95#include <string.h> /* for strncmp() */
96#include <ctype.h> /* for isalnum() */
97#if __MWERKS__ && !defined(BEBOX)
98# include <unix.h> /* for fdopen() on MAC */
99#endif
100
101#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
102/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
103# define fileno(f) ((f)->fd)
104FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
105#endif
106
107
108/* This corrects the problem of missing prototypes for certain functions
109 * in some GNU installations (e.g. SunOS 4.1.x).
110 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
111 */
112#if defined(__GNUC__) && defined(__STDC__)
113# ifndef __USE_FIXED_PROTOTYPES__
114# define __USE_FIXED_PROTOTYPES__
115# endif
116#endif
117
118#ifndef __USE_FIXED_PROTOTYPES__
119/*
120 * This is historic and works only if the compiler really has no prototypes:
121 *
122 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
123 * FILE is defined on OS 4.x, not on 5.x (Solaris).
124 * if __SVR4 is defined (some Solaris versions), don't include this.
125 */
126#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
127# define __P(a) a
128/* excerpt from my sun_stdlib.h */
129extern int fprintf __P((FILE *, char *, ...));
130extern int fputs __P((char *, FILE *));
131extern int _flsbuf __P((unsigned char, FILE *));
132extern int _filbuf __P((FILE *));
133extern int fflush __P((FILE *));
134extern int fclose __P((FILE *));
135extern int fseek __P((FILE *, long, int));
136extern int rewind __P((FILE *));
137
138extern void perror __P((char *));
139# endif
140#endif
141
142extern long int strtol();
143extern long int ftell();
144
145char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
146#ifdef WIN32
147char osver[] = " (Win32)";
148#else
149# ifdef DJGPP
150char osver[] = " (dos 32 bit)";
151# else
152# ifdef MSDOS
153char osver[] = " (dos 16 bit)";
154# else
155char osver[] = "";
156# endif
157# endif
158#endif
159
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000160#if defined(MSDOS) || defined(WIN32) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000161# define BIN_READ(yes) ((yes) ? "rb" : "rt")
162# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
163# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
164# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000165# define PATH_SEP '\\'
166#elif defined(CYGWIN)
167# define BIN_READ(yes) ((yes) ? "rb" : "rt")
168# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
169# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
170# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
171# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000172#else
173# ifdef VMS
174# define BIN_READ(dummy) "r"
175# define BIN_WRITE(dummy) "w"
176# define BIN_CREAT(dummy) O_CREAT
177# define BIN_ASSIGN(fp, dummy) fp
178# define PATH_SEP ']'
179# define FILE_SEP '.'
180# else
181# define BIN_READ(dummy) "r"
182# define BIN_WRITE(dummy) "w"
183# define BIN_CREAT(dummy) O_CREAT
184# define BIN_ASSIGN(fp, dummy) fp
185# define PATH_SEP '/'
186# endif
187#endif
188
189/* open has only to arguments on the Mac */
190#if __MWERKS__
191# define OPEN(name, mode, umask) open(name, mode)
192#else
193# define OPEN(name, mode, umask) open(name, mode, umask)
194#endif
195
196#ifdef AMIGA
197# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
198#else
199# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
200#endif
201
202#ifndef __P
203# if defined(__STDC__) || defined(MSDOS) || defined(WIN32) || defined(OS2) \
204 || defined(__BORLANDC__)
205# define __P(a) a
206# else
207# define __P(a) ()
208# endif
209#endif
210
211/* Let's collect some prototypes */
212/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200213static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200214static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200215static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000216static void xxdline __P((FILE *, char *, int));
217
218#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
219#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100220#define LLEN (12 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000221
222char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
223
224/* the different hextypes known by this program: */
225#define HEX_NORMAL 0
226#define HEX_POSTSCRIPT 1
227#define HEX_CINCLUDE 2
228#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100229#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000230
Bram Moolenaare0659a62011-04-01 19:14:40 +0200231static char *pname;
232
233 static void
234exit_with_usage()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235{
236 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
237 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
238 fprintf(stderr, "Options:\n");
239 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100240 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000241 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
242 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100243 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
244 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000245 fprintf(stderr, " -h print this summary.\n");
246 fprintf(stderr, " -i output in C include file style.\n");
247 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100248 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000249 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
250 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
251 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
252 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
253#ifdef TRY_SEEK
254 "[+][-]", "(or +: rel.) ");
255#else
256 "", "");
257#endif
258 fprintf(stderr, " -u use upper case hex letters.\n");
259 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
260 exit(1);
261}
262
Bram Moolenaare0659a62011-04-01 19:14:40 +0200263 static void
264die(ret)
265 int ret;
266{
267 fprintf(stderr, "%s: ", pname);
268 perror(NULL);
269 exit(ret);
270}
271
Bram Moolenaar071d4272004-06-13 20:20:40 +0000272/*
273 * Max. cols binary characters are decoded from the input stream per line.
274 * Two adjacent garbage characters after evaluated data delimit valid data.
275 * Everything up to the next newline is discarded.
276 *
277 * The name is historic and came from 'undo type opt h'.
278 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200279 static int
280huntype(fpi, fpo, fperr, cols, hextype, base_off)
281 FILE *fpi, *fpo, *fperr;
282 int cols, hextype;
283 long base_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000284{
285 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
286 long have_off = 0, want_off = 0;
287
288 rewind(fpi);
289
290 while ((c = getc(fpi)) != EOF)
291 {
292 if (c == '\r') /* Doze style input file? */
293 continue;
294
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100295 /* Allow multiple spaces. This doesn't work when there is normal text
296 * after the hex codes in the last line that looks like hex, thus only
297 * use it for PostScript format. */
298 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000299 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000300
Bram Moolenaar071d4272004-06-13 20:20:40 +0000301 n3 = n2;
302 n2 = n1;
303
304 if (c >= '0' && c <= '9')
305 n1 = c - '0';
306 else if (c >= 'a' && c <= 'f')
307 n1 = c - 'a' + 10;
308 else if (c >= 'A' && c <= 'F')
309 n1 = c - 'A' + 10;
310 else
311 {
312 n1 = -1;
313 if (ign_garb)
314 continue;
315 }
316
317 ign_garb = 0;
318
319 if (p >= cols)
320 {
321 if (!hextype)
322 {
323 if (n1 < 0)
324 {
325 p = 0;
326 continue;
327 }
328 want_off = (want_off << 4) | n1;
329 continue;
330 }
331 else
332 p = 0;
333 }
334
335 if (base_off + want_off != have_off)
336 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200337 if (fflush(fpo) != 0)
338 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000339#ifdef TRY_SEEK
340 c = fseek(fpo, base_off + want_off - have_off, 1);
341 if (c >= 0)
342 have_off = base_off + want_off;
343#endif
344 if (base_off + want_off < have_off)
345 {
346 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
347 return 5;
348 }
349 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200350 if (putc(0, fpo) == EOF)
351 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000352 }
353
354 if (n2 >= 0 && n1 >= 0)
355 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200356 if (putc((n2 << 4) | n1, fpo) == EOF)
357 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000358 have_off++;
359 want_off++;
360 n1 = -1;
361 if ((++p >= cols) && !hextype)
362 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000363 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 want_off = 0;
365 while ((c = getc(fpi)) != '\n' && c != EOF)
366 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200367 if (c == EOF && ferror(fpi))
368 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 ign_garb = 1;
370 }
371 }
372 else if (n1 < 0 && n2 < 0 && n3 < 0)
373 {
374 /* already stumbled into garbage, skip line, wait and see */
375 if (!hextype)
376 want_off = 0;
377 while ((c = getc(fpi)) != '\n' && c != EOF)
378 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200379 if (c == EOF && ferror(fpi))
380 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381 ign_garb = 1;
382 }
383 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200384 if (fflush(fpo) != 0)
385 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386#ifdef TRY_SEEK
387 fseek(fpo, 0L, 2);
388#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200389 if (fclose(fpo) != 0)
390 die(3);
391 if (fclose(fpi) != 0)
392 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000393 return 0;
394}
395
396/*
397 * Print line l. If nz is false, xxdline regards the line a line of
398 * zeroes. If there are three or more consecutive lines of zeroes,
399 * they are replaced by a single '*' character.
400 *
401 * If the output ends with more than two lines of zeroes, you
402 * should call xxdline again with l being the last line and nz
403 * negative. This ensures that the last line is shown even when
404 * it is all zeroes.
405 *
406 * If nz is always positive, lines are never suppressed.
407 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200408 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409xxdline(fp, l, nz)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200410 FILE *fp;
411 char *l;
412 int nz;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000413{
414 static char z[LLEN+1];
415 static int zero_seen = 0;
416
417 if (!nz && zero_seen == 1)
418 strcpy(z, l);
419
420 if (nz || !zero_seen++)
421 {
422 if (nz)
423 {
424 if (nz < 0)
425 zero_seen--;
426 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200427 if (fputs(z, fp) == EOF)
428 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000429 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200430 if (fputs("*\n", fp) == EOF)
431 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 }
433 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200434 if (fputs(l, fp) == EOF)
435 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000436 if (nz)
437 zero_seen = 0;
438 }
439}
440
441/* This is an EBCDIC to ASCII conversion table */
442/* from a proposed BTL standard April 16, 1979 */
443static unsigned char etoa64[] =
444{
445 0040,0240,0241,0242,0243,0244,0245,0246,
446 0247,0250,0325,0056,0074,0050,0053,0174,
447 0046,0251,0252,0253,0254,0255,0256,0257,
448 0260,0261,0041,0044,0052,0051,0073,0176,
449 0055,0057,0262,0263,0264,0265,0266,0267,
450 0270,0271,0313,0054,0045,0137,0076,0077,
451 0272,0273,0274,0275,0276,0277,0300,0301,
452 0302,0140,0072,0043,0100,0047,0075,0042,
453 0303,0141,0142,0143,0144,0145,0146,0147,
454 0150,0151,0304,0305,0306,0307,0310,0311,
455 0312,0152,0153,0154,0155,0156,0157,0160,
456 0161,0162,0136,0314,0315,0316,0317,0320,
457 0321,0345,0163,0164,0165,0166,0167,0170,
458 0171,0172,0322,0323,0324,0133,0326,0327,
459 0330,0331,0332,0333,0334,0335,0336,0337,
460 0340,0341,0342,0343,0344,0135,0346,0347,
461 0173,0101,0102,0103,0104,0105,0106,0107,
462 0110,0111,0350,0351,0352,0353,0354,0355,
463 0175,0112,0113,0114,0115,0116,0117,0120,
464 0121,0122,0356,0357,0360,0361,0362,0363,
465 0134,0237,0123,0124,0125,0126,0127,0130,
466 0131,0132,0364,0365,0366,0367,0370,0371,
467 0060,0061,0062,0063,0064,0065,0066,0067,
468 0070,0071,0372,0373,0374,0375,0376,0377
469};
470
Bram Moolenaare0659a62011-04-01 19:14:40 +0200471 int
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472main(argc, argv)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200473 int argc;
474 char *argv[];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000475{
476 FILE *fp, *fpo;
477 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
478 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
479 int ebcdic = 0;
480 int octspergrp = -1; /* number of octets grouped in output */
481 int grplen; /* total chars per octet group */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100482 long length = -1, n = 0, seekoff = 0, displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200483 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200484 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000485
486#ifdef AMIGA
487 /* This program doesn't work when started from the Workbench */
488 if (argc == 0)
489 exit(1);
490#endif
491
492 pname = argv[0];
493 for (pp = pname; *pp; )
494 if (*pp++ == PATH_SEP)
495 pname = pp;
496#ifdef FILE_SEP
497 for (pp = pname; *pp; pp++)
498 if (*pp == FILE_SEP)
499 {
500 *pp = '\0';
501 break;
502 }
503#endif
504
505 while (argc >= 2)
506 {
507 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
508 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
509 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100510 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000511 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
512 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
513 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
514 else if (!STRNCMP(pp, "-r", 2)) revert++;
515 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
516 else if (!STRNCMP(pp, "-v", 2))
517 {
518 fprintf(stderr, "%s%s\n", version, osver);
519 exit(0);
520 }
521 else if (!STRNCMP(pp, "-c", 2))
522 {
523 if (pp[2] && STRNCMP("ols", pp + 2, 3))
524 cols = (int)strtol(pp + 2, NULL, 0);
525 else
526 {
527 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200528 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000529 cols = (int)strtol(argv[2], NULL, 0);
530 argv++;
531 argc--;
532 }
533 }
534 else if (!STRNCMP(pp, "-g", 2))
535 {
536 if (pp[2] && STRNCMP("group", pp + 2, 5))
537 octspergrp = (int)strtol(pp + 2, NULL, 0);
538 else
539 {
540 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200541 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000542 octspergrp = (int)strtol(argv[2], NULL, 0);
543 argv++;
544 argc--;
545 }
546 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100547 else if (!STRNCMP(pp, "-o", 2))
548 {
549 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
550 displayoff = (int)strtol(pp + 2, NULL, 0);
551 else
552 {
553 if (!argv[2])
554 exit_with_usage();
555 displayoff = (int)strtol(argv[2], NULL, 0);
556 argv++;
557 argc--;
558 }
559 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560 else if (!STRNCMP(pp, "-s", 2))
561 {
562 relseek = 0;
563 negseek = 0;
564 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
565 {
566#ifdef TRY_SEEK
567 if (pp[2] == '+')
568 relseek++;
569 if (pp[2+relseek] == '-')
570 negseek++;
571#endif
572 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
573 }
574 else
575 {
576 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200577 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578#ifdef TRY_SEEK
579 if (argv[2][0] == '+')
580 relseek++;
581 if (argv[2][relseek] == '-')
582 negseek++;
583#endif
584 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
585 argv++;
586 argc--;
587 }
588 }
589 else if (!STRNCMP(pp, "-l", 2))
590 {
591 if (pp[2] && STRNCMP("en", pp + 2, 2))
592 length = strtol(pp + 2, (char **)NULL, 0);
593 else
594 {
595 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200596 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000597 length = strtol(argv[2], (char **)NULL, 0);
598 argv++;
599 argc--;
600 }
601 }
602 else if (!strcmp(pp, "--")) /* end of options */
603 {
604 argv++;
605 argc--;
606 break;
607 }
608 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200609 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000610 else
611 break; /* not an option */
612
613 argv++; /* advance to next argument */
614 argc--;
615 }
616
617 if (!cols)
618 switch (hextype)
619 {
620 case HEX_POSTSCRIPT: cols = 30; break;
621 case HEX_CINCLUDE: cols = 12; break;
622 case HEX_BITS: cols = 6; break;
623 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100624 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000625 default: cols = 16; break;
626 }
627
628 if (octspergrp < 0)
629 switch (hextype)
630 {
631 case HEX_BITS: octspergrp = 1; break;
632 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100633 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000634 case HEX_POSTSCRIPT:
635 case HEX_CINCLUDE:
636 default: octspergrp = 0; break;
637 }
638
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100639 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000640 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000641 {
642 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
643 exit(1);
644 }
645
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100646 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000647 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100648 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
649 {
650 fprintf(stderr,
651 "%s: number of octets per group must be a power of 2 with -e.\n",
652 pname);
653 exit(1);
654 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000655
656 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200657 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000658
659 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
660 BIN_ASSIGN(fp = stdin, !revert);
661 else
662 {
663 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
664 {
665 fprintf(stderr,"%s: ", pname);
666 perror(argv[1]);
667 return 2;
668 }
669 }
670
671 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
672 BIN_ASSIGN(fpo = stdout, revert);
673 else
674 {
675 int fd;
676 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
677
678 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
679 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
680 {
681 fprintf(stderr, "%s: ", pname);
682 perror(argv[2]);
683 return 3;
684 }
685 rewind(fpo);
686 }
687
688 if (revert)
689 {
690 if (hextype && (hextype != HEX_POSTSCRIPT))
691 {
692 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
693 return -1;
694 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200695 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000696 negseek ? -seekoff : seekoff);
697 }
698
699 if (seekoff || negseek || !relseek)
700 {
701#ifdef TRY_SEEK
702 if (relseek)
703 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
704 else
705 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
706 if (e < 0 && negseek)
707 {
708 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
709 return 4;
710 }
711 if (e >= 0)
712 seekoff = ftell(fp);
713 else
714#endif
715 {
716 long s = seekoff;
717
718 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200719 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200720 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200721 if (ferror(fp))
722 {
723 die(2);
724 }
725 else
726 {
727 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
728 return 4;
729 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200730 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731 }
732 }
733
734 if (hextype == HEX_CINCLUDE)
735 {
736 if (fp != stdin)
737 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
739 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200741 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
742 die(3);
743 if (fputs("[] = {\n", fpo) == EOF)
744 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000745 }
746
747 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200748 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000749 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
750 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200751 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200752 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200753 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000754 p++;
755 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200756 if (c == EOF && ferror(fp))
757 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100759 if (p && fputs("\n", fpo) == EOF)
760 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200761 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100762 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763
764 if (fp != stdin)
765 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200766 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
767 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000768 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200769 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
770 die(3);
771 if (fprintf(fpo, "_len = %d;\n", p) < 0)
772 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000773 }
774
Bram Moolenaare0659a62011-04-01 19:14:40 +0200775 if (fclose(fp))
776 die(2);
777 if (fclose(fpo))
778 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 return 0;
780 }
781
782 if (hextype == HEX_POSTSCRIPT)
783 {
784 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200785 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
787 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200788 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
789 || putc(hexx[e & 0xf], fpo) == EOF)
790 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 n++;
792 if (!--p)
793 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200794 if (putc('\n', fpo) == EOF)
795 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 p = cols;
797 }
798 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200799 if (e == EOF && ferror(fp))
800 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000801 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200802 if (putc('\n', fpo) == EOF)
803 die(3);
804 if (fclose(fp))
805 die(2);
806 if (fclose(fpo))
807 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000808 return 0;
809 }
810
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100811 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000812
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100813 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000814 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
815 else /* hextype == HEX_BITS */
816 grplen = 8 * octspergrp + 1;
817
Bram Moolenaare0659a62011-04-01 19:14:40 +0200818 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000819 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
820 {
821 if (p == 0)
822 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100823 sprintf(l, "%08lx:",
824 ((unsigned long)(n + seekoff + displayoff)) & 0xffffffff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 for (c = 9; c < LLEN; l[c++] = ' ');
826 }
827 if (hextype == HEX_NORMAL)
828 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100829 l[c = (10 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
830 l[++c] = hexx[ e & 0xf];
831 }
832 else if (hextype == HEX_LITTLEENDIAN)
833 {
834 int x = p ^ (octspergrp-1);
835 l[c = (10 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
836 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000837 }
838 else /* hextype == HEX_BITS */
839 {
840 int i;
841
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100842 c = (10 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 for (i = 7; i >= 0; i--)
844 l[++c] = (e & (1 << i)) ? '1' : '0';
845 }
846 if (ebcdic)
847 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000848 /* When changing this update definition of LLEN above. */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100849 l[12 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850#ifdef __MVS__
851 (e >= 64)
852#else
853 (e > 31 && e < 127)
854#endif
855 ? e : '.';
856 if (e)
857 nonzero++;
858 n++;
859 if (++p == cols)
860 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100861 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000862 xxdline(fpo, l, autoskip ? nonzero : 1);
863 nonzero = 0;
864 p = 0;
865 }
866 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200867 if (e == EOF && ferror(fp))
868 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 if (p)
870 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100871 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000872 xxdline(fpo, l, 1);
873 }
874 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000875 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000876
Bram Moolenaare0659a62011-04-01 19:14:40 +0200877 if (fclose(fp))
878 die(2);
879 if (fclose(fpo))
880 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000881 return 0;
882}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200883
884/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */