blob: 8cd760b15383fd81beae434d175b721f09d4bab1 [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
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100237exit_with_usage(void)
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
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100267die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200268{
269 fprintf(stderr, "%s: ", pname);
270 perror(NULL);
271 exit(ret);
272}
273
Bram Moolenaar071d4272004-06-13 20:20:40 +0000274/*
275 * Max. cols binary characters are decoded from the input stream per line.
276 * Two adjacent garbage characters after evaluated data delimit valid data.
277 * Everything up to the next newline is discarded.
278 *
279 * The name is historic and came from 'undo type opt h'.
280 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200281 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100282huntype(
283 FILE *fpi,
284 FILE *fpo,
285 FILE *fperr,
286 int cols,
287 int hextype,
288 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000289{
290 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
291 long have_off = 0, want_off = 0;
292
293 rewind(fpi);
294
295 while ((c = getc(fpi)) != EOF)
296 {
297 if (c == '\r') /* Doze style input file? */
298 continue;
299
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100300 /* Allow multiple spaces. This doesn't work when there is normal text
301 * after the hex codes in the last line that looks like hex, thus only
302 * use it for PostScript format. */
303 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000304 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000305
Bram Moolenaar071d4272004-06-13 20:20:40 +0000306 n3 = n2;
307 n2 = n1;
308
309 if (c >= '0' && c <= '9')
310 n1 = c - '0';
311 else if (c >= 'a' && c <= 'f')
312 n1 = c - 'a' + 10;
313 else if (c >= 'A' && c <= 'F')
314 n1 = c - 'A' + 10;
315 else
316 {
317 n1 = -1;
318 if (ign_garb)
319 continue;
320 }
321
322 ign_garb = 0;
323
324 if (p >= cols)
325 {
326 if (!hextype)
327 {
328 if (n1 < 0)
329 {
330 p = 0;
331 continue;
332 }
333 want_off = (want_off << 4) | n1;
334 continue;
335 }
336 else
337 p = 0;
338 }
339
340 if (base_off + want_off != have_off)
341 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200342 if (fflush(fpo) != 0)
343 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344#ifdef TRY_SEEK
345 c = fseek(fpo, base_off + want_off - have_off, 1);
346 if (c >= 0)
347 have_off = base_off + want_off;
348#endif
349 if (base_off + want_off < have_off)
350 {
351 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
352 return 5;
353 }
354 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200355 if (putc(0, fpo) == EOF)
356 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000357 }
358
359 if (n2 >= 0 && n1 >= 0)
360 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200361 if (putc((n2 << 4) | n1, fpo) == EOF)
362 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000363 have_off++;
364 want_off++;
365 n1 = -1;
366 if ((++p >= cols) && !hextype)
367 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000368 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000369 want_off = 0;
370 while ((c = getc(fpi)) != '\n' && c != EOF)
371 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200372 if (c == EOF && ferror(fpi))
373 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000374 ign_garb = 1;
375 }
376 }
377 else if (n1 < 0 && n2 < 0 && n3 < 0)
378 {
379 /* already stumbled into garbage, skip line, wait and see */
380 if (!hextype)
381 want_off = 0;
382 while ((c = getc(fpi)) != '\n' && c != EOF)
383 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200384 if (c == EOF && ferror(fpi))
385 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000386 ign_garb = 1;
387 }
388 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200389 if (fflush(fpo) != 0)
390 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000391#ifdef TRY_SEEK
392 fseek(fpo, 0L, 2);
393#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200394 if (fclose(fpo) != 0)
395 die(3);
396 if (fclose(fpi) != 0)
397 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000398 return 0;
399}
400
401/*
402 * Print line l. If nz is false, xxdline regards the line a line of
403 * zeroes. If there are three or more consecutive lines of zeroes,
404 * they are replaced by a single '*' character.
405 *
406 * If the output ends with more than two lines of zeroes, you
407 * should call xxdline again with l being the last line and nz
408 * negative. This ensures that the last line is shown even when
409 * it is all zeroes.
410 *
411 * If nz is always positive, lines are never suppressed.
412 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200413 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100414xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000415{
416 static char z[LLEN+1];
417 static int zero_seen = 0;
418
419 if (!nz && zero_seen == 1)
420 strcpy(z, l);
421
422 if (nz || !zero_seen++)
423 {
424 if (nz)
425 {
426 if (nz < 0)
427 zero_seen--;
428 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200429 if (fputs(z, fp) == EOF)
430 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200432 if (fputs("*\n", fp) == EOF)
433 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000434 }
435 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200436 if (fputs(l, fp) == EOF)
437 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000438 if (nz)
439 zero_seen = 0;
440 }
441}
442
443/* This is an EBCDIC to ASCII conversion table */
444/* from a proposed BTL standard April 16, 1979 */
445static unsigned char etoa64[] =
446{
447 0040,0240,0241,0242,0243,0244,0245,0246,
448 0247,0250,0325,0056,0074,0050,0053,0174,
449 0046,0251,0252,0253,0254,0255,0256,0257,
450 0260,0261,0041,0044,0052,0051,0073,0176,
451 0055,0057,0262,0263,0264,0265,0266,0267,
452 0270,0271,0313,0054,0045,0137,0076,0077,
453 0272,0273,0274,0275,0276,0277,0300,0301,
454 0302,0140,0072,0043,0100,0047,0075,0042,
455 0303,0141,0142,0143,0144,0145,0146,0147,
456 0150,0151,0304,0305,0306,0307,0310,0311,
457 0312,0152,0153,0154,0155,0156,0157,0160,
458 0161,0162,0136,0314,0315,0316,0317,0320,
459 0321,0345,0163,0164,0165,0166,0167,0170,
460 0171,0172,0322,0323,0324,0133,0326,0327,
461 0330,0331,0332,0333,0334,0335,0336,0337,
462 0340,0341,0342,0343,0344,0135,0346,0347,
463 0173,0101,0102,0103,0104,0105,0106,0107,
464 0110,0111,0350,0351,0352,0353,0354,0355,
465 0175,0112,0113,0114,0115,0116,0117,0120,
466 0121,0122,0356,0357,0360,0361,0362,0363,
467 0134,0237,0123,0124,0125,0126,0127,0130,
468 0131,0132,0364,0365,0366,0367,0370,0371,
469 0060,0061,0062,0063,0064,0065,0066,0067,
470 0070,0071,0372,0373,0374,0375,0376,0377
471};
472
Bram Moolenaare0659a62011-04-01 19:14:40 +0200473 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100474main(int argc, 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 : */