blob: d7a556a31d872a1cedcfaba56ea3b9e3214d519c [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* xxd: my hexdump facility. jw
2 *
3 * 2.10.90 changed to word output
4 * 3.03.93 new indent style, dumb bug inserted and fixed.
5 * -c option, mls
6 * 26.04.94 better option parser, -ps, -l, -s added.
7 * 1.07.94 -r badly needs - as input file. Per default autoskip over
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -a shows them too.
10 * -i dump as c-style #include "file.h"
11 * 1.11.95 if "xxd -i" knows the filename, an 'unsigned char filename_bits[]'
12 * array is written in correct c-syntax.
13 * -s improved, now defaults to absolute seek, relative requires a '+'.
14 * -r improved, now -r -s -0x... is supported.
15 * change/suppress leading '\0' bytes.
16 * -l n improved: stops exactly after n bytes.
17 * -r improved, better handling of partial lines with trailing garbage.
18 * -r improved, now -r -p works again!
19 * -r improved, less flushing, much faster now! (that was silly)
20 * 3.04.96 Per repeated request of a single person: autoskip defaults to off.
21 * 15.05.96 -v added. They want to know the version.
22 * -a fixed, to show last line inf file ends in all zeros.
23 * -u added: Print upper case hex-letters, as preferred by unix bc.
24 * -h added to usage message. Usage message extended.
25 * Now using outfile if specified even in normal mode, aehem.
26 * No longer mixing of ints and longs. May help doze people.
27 * Added binify ioctl for same reason. (Enough Doze stress for 1996!)
28 * 16.05.96 -p improved, removed occasional superfluous linefeed.
29 * 20.05.96 -l 0 fixed. tried to read anyway.
30 * 21.05.96 -i fixed. now honours -u, and prepends __ to numeric filenames.
31 * compile -DWIN32 for NT or W95. George V. Reilly, * -v improved :-)
32 * support --gnuish-longhorn-options
33 * 25.05.96 MAC support added: CodeWarrior already uses ``outline'' in Types.h
34 * which is included by MacHeaders (Axel Kielhorn). Renamed to
35 * xxdline().
36 * 7.06.96 -i printed 'int' instead of 'char'. *blush*
37 * added Bram's OS2 ifdefs...
38 * 18.07.96 gcc -Wall @ SunOS4 is now slient.
39 * Added osver for MSDOS/DJGPP/WIN32.
40 * 29.08.96 Added size_t to strncmp() for Amiga.
41 * 24.03.97 Windows NT support (Phil Hanna). Clean exit for Amiga WB (Bram)
42 * 02.04.97 Added -E option, to have EBCDIC translation instead of ASCII
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 22.05.97 added -g (group octets) option (jcook@namerica.kla.com).
45 * 23.09.98 nasty -p -r misfeature fixed: slightly wrong output, when -c was
46 * missing or wrong.
47 * 26.09.98 Fixed: 'xxd -i infile outfile' did not truncate outfile.
48 * 27.10.98 Fixed: -g option parser required blank.
49 * option -b added: 01000101 binary output in normal format.
50 * 16.05.00 Added VAXC changes by Stephen P. Wall
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaare0659a62011-04-01 19:14:40 +020052 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
Bram Moolenaar4dcdf292015-03-05 17:51:15 +010054 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
Bram Moolenaar071d4272004-06-13 20:20:40 +000055 *
56 * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
57 *
Bram Moolenaar43fe3292015-08-04 17:29:07 +020058 * I hereby grant permission to distribute and use xxd
59 * under X11-MIT or GPL-2.0 (at the user's choice).
60 *
Bram Moolenaar071d4272004-06-13 20:20:40 +000061 * Small changes made afterwards by Bram Moolenaar et al.
62 *
63 * Distribute freely and credit me,
64 * make money and share with me,
65 * lose money and don't ask me.
66 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000067
68/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
69#if _MSC_VER >= 1400
70# define _CRT_SECURE_NO_DEPRECATE
71# define _CRT_NONSTDC_NO_DEPRECATE
72#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000073#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
74# define CYGWIN
75#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000076
Bram Moolenaar071d4272004-06-13 20:20:40 +000077#include <stdio.h>
78#ifdef VAXC
79# include <file.h>
80#else
81# include <fcntl.h>
82#endif
Bram Moolenaara06ecab2016-07-16 14:47:36 +020083#if defined(WIN32) || defined(__BORLANDC__) || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000084# include <io.h> /* for setmode() */
85#else
86# ifdef UNIX
87# include <unistd.h>
88# endif
89#endif
90#include <stdlib.h>
91#include <string.h> /* for strncmp() */
92#include <ctype.h> /* for isalnum() */
93#if __MWERKS__ && !defined(BEBOX)
94# include <unix.h> /* for fdopen() on MAC */
95#endif
96
97#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
98/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
99# define fileno(f) ((f)->fd)
100FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
101#endif
102
103
104/* This corrects the problem of missing prototypes for certain functions
105 * in some GNU installations (e.g. SunOS 4.1.x).
106 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
107 */
108#if defined(__GNUC__) && defined(__STDC__)
109# ifndef __USE_FIXED_PROTOTYPES__
110# define __USE_FIXED_PROTOTYPES__
111# endif
112#endif
113
114#ifndef __USE_FIXED_PROTOTYPES__
115/*
116 * This is historic and works only if the compiler really has no prototypes:
117 *
118 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
119 * FILE is defined on OS 4.x, not on 5.x (Solaris).
120 * if __SVR4 is defined (some Solaris versions), don't include this.
121 */
122#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
123# define __P(a) a
124/* excerpt from my sun_stdlib.h */
125extern int fprintf __P((FILE *, char *, ...));
126extern int fputs __P((char *, FILE *));
127extern int _flsbuf __P((unsigned char, FILE *));
128extern int _filbuf __P((FILE *));
129extern int fflush __P((FILE *));
130extern int fclose __P((FILE *));
131extern int fseek __P((FILE *, long, int));
132extern int rewind __P((FILE *));
133
134extern void perror __P((char *));
135# endif
136#endif
137
138extern long int strtol();
139extern long int ftell();
140
141char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
142#ifdef WIN32
143char osver[] = " (Win32)";
144#else
Bram Moolenaar071d4272004-06-13 20:20:40 +0000145char osver[] = "";
Bram Moolenaar071d4272004-06-13 20:20:40 +0000146#endif
147
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200148#if defined(WIN32)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000149# define BIN_READ(yes) ((yes) ? "rb" : "rt")
150# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
151# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
152# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000153# define PATH_SEP '\\'
154#elif defined(CYGWIN)
155# define BIN_READ(yes) ((yes) ? "rb" : "rt")
156# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
157# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
158# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
159# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160#else
161# ifdef VMS
162# define BIN_READ(dummy) "r"
163# define BIN_WRITE(dummy) "w"
164# define BIN_CREAT(dummy) O_CREAT
165# define BIN_ASSIGN(fp, dummy) fp
166# define PATH_SEP ']'
167# define FILE_SEP '.'
168# else
169# define BIN_READ(dummy) "r"
170# define BIN_WRITE(dummy) "w"
171# define BIN_CREAT(dummy) O_CREAT
172# define BIN_ASSIGN(fp, dummy) fp
173# define PATH_SEP '/'
174# endif
175#endif
176
177/* open has only to arguments on the Mac */
178#if __MWERKS__
179# define OPEN(name, mode, umask) open(name, mode)
180#else
181# define OPEN(name, mode, umask) open(name, mode, umask)
182#endif
183
184#ifdef AMIGA
185# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
186#else
187# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
188#endif
189
190#ifndef __P
Bram Moolenaara06ecab2016-07-16 14:47:36 +0200191# if defined(__STDC__) || defined(WIN32) || defined(__BORLANDC__)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000192# define __P(a) a
193# else
194# define __P(a) ()
195# endif
196#endif
197
198/* Let's collect some prototypes */
199/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200200static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200201static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200202static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000203static void xxdline __P((FILE *, char *, int));
204
205#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
206#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100207#define LLEN (12 + (9*COLS-1) + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000208
209char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
210
211/* the different hextypes known by this program: */
212#define HEX_NORMAL 0
213#define HEX_POSTSCRIPT 1
214#define HEX_CINCLUDE 2
215#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100216#define HEX_LITTLEENDIAN 4
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200218#define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
219
Bram Moolenaare0659a62011-04-01 19:14:40 +0200220static char *pname;
221
222 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100223exit_with_usage(void)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000224{
225 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
226 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
227 fprintf(stderr, "Options:\n");
228 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100229 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200230 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000231 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
232 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100233 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
234 fprintf(stderr, " -g number of octets per group in normal output. Default 2 (-e: 4).\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000235 fprintf(stderr, " -h print this summary.\n");
236 fprintf(stderr, " -i output in C include file style.\n");
237 fprintf(stderr, " -l len stop after <len> octets.\n");
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100238 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
240 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
241 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
242 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
243#ifdef TRY_SEEK
244 "[+][-]", "(or +: rel.) ");
245#else
246 "", "");
247#endif
248 fprintf(stderr, " -u use upper case hex letters.\n");
249 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
250 exit(1);
251}
252
Bram Moolenaare0659a62011-04-01 19:14:40 +0200253 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100254die(int ret)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200255{
256 fprintf(stderr, "%s: ", pname);
257 perror(NULL);
258 exit(ret);
259}
260
Bram Moolenaar071d4272004-06-13 20:20:40 +0000261/*
262 * Max. cols binary characters are decoded from the input stream per line.
263 * Two adjacent garbage characters after evaluated data delimit valid data.
264 * Everything up to the next newline is discarded.
265 *
266 * The name is historic and came from 'undo type opt h'.
267 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200268 static int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100269huntype(
270 FILE *fpi,
271 FILE *fpo,
272 FILE *fperr,
273 int cols,
274 int hextype,
275 long base_off)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000276{
277 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
278 long have_off = 0, want_off = 0;
279
280 rewind(fpi);
281
282 while ((c = getc(fpi)) != EOF)
283 {
284 if (c == '\r') /* Doze style input file? */
285 continue;
286
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100287 /* Allow multiple spaces. This doesn't work when there is normal text
288 * after the hex codes in the last line that looks like hex, thus only
289 * use it for PostScript format. */
290 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000291 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000292
Bram Moolenaar071d4272004-06-13 20:20:40 +0000293 n3 = n2;
294 n2 = n1;
295
296 if (c >= '0' && c <= '9')
297 n1 = c - '0';
298 else if (c >= 'a' && c <= 'f')
299 n1 = c - 'a' + 10;
300 else if (c >= 'A' && c <= 'F')
301 n1 = c - 'A' + 10;
302 else
303 {
304 n1 = -1;
305 if (ign_garb)
306 continue;
307 }
308
309 ign_garb = 0;
310
311 if (p >= cols)
312 {
313 if (!hextype)
314 {
315 if (n1 < 0)
316 {
317 p = 0;
318 continue;
319 }
320 want_off = (want_off << 4) | n1;
321 continue;
322 }
323 else
324 p = 0;
325 }
326
327 if (base_off + want_off != have_off)
328 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200329 if (fflush(fpo) != 0)
330 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000331#ifdef TRY_SEEK
332 c = fseek(fpo, base_off + want_off - have_off, 1);
333 if (c >= 0)
334 have_off = base_off + want_off;
335#endif
336 if (base_off + want_off < have_off)
337 {
338 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
339 return 5;
340 }
341 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200342 if (putc(0, fpo) == EOF)
343 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000344 }
345
346 if (n2 >= 0 && n1 >= 0)
347 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200348 if (putc((n2 << 4) | n1, fpo) == EOF)
349 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000350 have_off++;
351 want_off++;
352 n1 = -1;
353 if ((++p >= cols) && !hextype)
354 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000355 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000356 want_off = 0;
357 while ((c = getc(fpi)) != '\n' && c != EOF)
358 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200359 if (c == EOF && ferror(fpi))
360 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000361 ign_garb = 1;
362 }
363 }
364 else if (n1 < 0 && n2 < 0 && n3 < 0)
365 {
366 /* already stumbled into garbage, skip line, wait and see */
367 if (!hextype)
368 want_off = 0;
369 while ((c = getc(fpi)) != '\n' && c != EOF)
370 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200371 if (c == EOF && ferror(fpi))
372 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000373 ign_garb = 1;
374 }
375 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200376 if (fflush(fpo) != 0)
377 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000378#ifdef TRY_SEEK
379 fseek(fpo, 0L, 2);
380#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200381 if (fclose(fpo) != 0)
382 die(3);
383 if (fclose(fpi) != 0)
384 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000385 return 0;
386}
387
388/*
389 * Print line l. If nz is false, xxdline regards the line a line of
390 * zeroes. If there are three or more consecutive lines of zeroes,
391 * they are replaced by a single '*' character.
392 *
393 * If the output ends with more than two lines of zeroes, you
394 * should call xxdline again with l being the last line and nz
395 * negative. This ensures that the last line is shown even when
396 * it is all zeroes.
397 *
398 * If nz is always positive, lines are never suppressed.
399 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200400 static void
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100401xxdline(FILE *fp, char *l, int nz)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000402{
403 static char z[LLEN+1];
404 static int zero_seen = 0;
405
406 if (!nz && zero_seen == 1)
407 strcpy(z, l);
408
409 if (nz || !zero_seen++)
410 {
411 if (nz)
412 {
413 if (nz < 0)
414 zero_seen--;
415 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200416 if (fputs(z, fp) == EOF)
417 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000418 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200419 if (fputs("*\n", fp) == EOF)
420 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000421 }
422 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200423 if (fputs(l, fp) == EOF)
424 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425 if (nz)
426 zero_seen = 0;
427 }
428}
429
430/* This is an EBCDIC to ASCII conversion table */
431/* from a proposed BTL standard April 16, 1979 */
432static unsigned char etoa64[] =
433{
434 0040,0240,0241,0242,0243,0244,0245,0246,
435 0247,0250,0325,0056,0074,0050,0053,0174,
436 0046,0251,0252,0253,0254,0255,0256,0257,
437 0260,0261,0041,0044,0052,0051,0073,0176,
438 0055,0057,0262,0263,0264,0265,0266,0267,
439 0270,0271,0313,0054,0045,0137,0076,0077,
440 0272,0273,0274,0275,0276,0277,0300,0301,
441 0302,0140,0072,0043,0100,0047,0075,0042,
442 0303,0141,0142,0143,0144,0145,0146,0147,
443 0150,0151,0304,0305,0306,0307,0310,0311,
444 0312,0152,0153,0154,0155,0156,0157,0160,
445 0161,0162,0136,0314,0315,0316,0317,0320,
446 0321,0345,0163,0164,0165,0166,0167,0170,
447 0171,0172,0322,0323,0324,0133,0326,0327,
448 0330,0331,0332,0333,0334,0335,0336,0337,
449 0340,0341,0342,0343,0344,0135,0346,0347,
450 0173,0101,0102,0103,0104,0105,0106,0107,
451 0110,0111,0350,0351,0352,0353,0354,0355,
452 0175,0112,0113,0114,0115,0116,0117,0120,
453 0121,0122,0356,0357,0360,0361,0362,0363,
454 0134,0237,0123,0124,0125,0126,0127,0130,
455 0131,0132,0364,0365,0366,0367,0370,0371,
456 0060,0061,0062,0063,0064,0065,0066,0067,
457 0070,0071,0372,0373,0374,0375,0376,0377
458};
459
Bram Moolenaare0659a62011-04-01 19:14:40 +0200460 int
Bram Moolenaarb638a7b2016-01-30 21:29:58 +0100461main(int argc, char *argv[])
Bram Moolenaar071d4272004-06-13 20:20:40 +0000462{
463 FILE *fp, *fpo;
464 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200465 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL, capitalize = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000466 int ebcdic = 0;
467 int octspergrp = -1; /* number of octets grouped in output */
468 int grplen; /* total chars per octet group */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100469 long length = -1, n = 0, seekoff = 0, displayoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200470 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200471 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000472
473#ifdef AMIGA
474 /* This program doesn't work when started from the Workbench */
475 if (argc == 0)
476 exit(1);
477#endif
478
479 pname = argv[0];
480 for (pp = pname; *pp; )
481 if (*pp++ == PATH_SEP)
482 pname = pp;
483#ifdef FILE_SEP
484 for (pp = pname; *pp; pp++)
485 if (*pp == FILE_SEP)
486 {
487 *pp = '\0';
488 break;
489 }
490#endif
491
492 while (argc >= 2)
493 {
494 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
495 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
496 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100497 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000498 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
499 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
500 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200501 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000502 else if (!STRNCMP(pp, "-r", 2)) revert++;
503 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
504 else if (!STRNCMP(pp, "-v", 2))
505 {
506 fprintf(stderr, "%s%s\n", version, osver);
507 exit(0);
508 }
509 else if (!STRNCMP(pp, "-c", 2))
510 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100511 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
Bram Moolenaar79cf7c02018-04-03 14:21:16 +0200512 capitalize = 1;
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100513 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
514 cols = (int)strtol(pp + 2, NULL, 0);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000515 else
516 {
517 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200518 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519 cols = (int)strtol(argv[2], NULL, 0);
520 argv++;
521 argc--;
522 }
523 }
524 else if (!STRNCMP(pp, "-g", 2))
525 {
Bram Moolenaar970f5d32019-01-25 21:52:17 +0100526 if (pp[2] && STRNCMP("roup", pp + 2, 4))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000527 octspergrp = (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 octspergrp = (int)strtol(argv[2], NULL, 0);
533 argv++;
534 argc--;
535 }
536 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100537 else if (!STRNCMP(pp, "-o", 2))
538 {
539 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
540 displayoff = (int)strtol(pp + 2, NULL, 0);
541 else
542 {
543 if (!argv[2])
544 exit_with_usage();
545 displayoff = (int)strtol(argv[2], NULL, 0);
546 argv++;
547 argc--;
548 }
549 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000550 else if (!STRNCMP(pp, "-s", 2))
551 {
552 relseek = 0;
553 negseek = 0;
554 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
555 {
556#ifdef TRY_SEEK
557 if (pp[2] == '+')
558 relseek++;
559 if (pp[2+relseek] == '-')
560 negseek++;
561#endif
562 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
563 }
564 else
565 {
566 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200567 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000568#ifdef TRY_SEEK
569 if (argv[2][0] == '+')
570 relseek++;
571 if (argv[2][relseek] == '-')
572 negseek++;
573#endif
574 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
575 argv++;
576 argc--;
577 }
578 }
579 else if (!STRNCMP(pp, "-l", 2))
580 {
581 if (pp[2] && STRNCMP("en", pp + 2, 2))
582 length = strtol(pp + 2, (char **)NULL, 0);
583 else
584 {
585 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200586 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000587 length = strtol(argv[2], (char **)NULL, 0);
588 argv++;
589 argc--;
590 }
591 }
592 else if (!strcmp(pp, "--")) /* end of options */
593 {
594 argv++;
595 argc--;
596 break;
597 }
598 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200599 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000600 else
601 break; /* not an option */
602
603 argv++; /* advance to next argument */
604 argc--;
605 }
606
607 if (!cols)
608 switch (hextype)
609 {
610 case HEX_POSTSCRIPT: cols = 30; break;
611 case HEX_CINCLUDE: cols = 12; break;
612 case HEX_BITS: cols = 6; break;
613 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100614 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000615 default: cols = 16; break;
616 }
617
618 if (octspergrp < 0)
619 switch (hextype)
620 {
621 case HEX_BITS: octspergrp = 1; break;
622 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100623 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000624 case HEX_POSTSCRIPT:
625 case HEX_CINCLUDE:
626 default: octspergrp = 0; break;
627 }
628
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100629 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000630 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631 {
632 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
633 exit(1);
634 }
635
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100636 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000637 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100638 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
639 {
640 fprintf(stderr,
641 "%s: number of octets per group must be a power of 2 with -e.\n",
642 pname);
643 exit(1);
644 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000645
646 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200647 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000648
649 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
650 BIN_ASSIGN(fp = stdin, !revert);
651 else
652 {
653 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
654 {
655 fprintf(stderr,"%s: ", pname);
656 perror(argv[1]);
657 return 2;
658 }
659 }
660
661 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
662 BIN_ASSIGN(fpo = stdout, revert);
663 else
664 {
665 int fd;
666 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
667
668 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
669 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
670 {
671 fprintf(stderr, "%s: ", pname);
672 perror(argv[2]);
673 return 3;
674 }
675 rewind(fpo);
676 }
677
678 if (revert)
679 {
680 if (hextype && (hextype != HEX_POSTSCRIPT))
681 {
682 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
683 return -1;
684 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200685 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000686 negseek ? -seekoff : seekoff);
687 }
688
689 if (seekoff || negseek || !relseek)
690 {
691#ifdef TRY_SEEK
692 if (relseek)
693 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
694 else
695 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
696 if (e < 0 && negseek)
697 {
698 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
699 return 4;
700 }
701 if (e >= 0)
702 seekoff = ftell(fp);
703 else
704#endif
705 {
706 long s = seekoff;
707
708 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200709 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200710 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200711 if (ferror(fp))
712 {
713 die(2);
714 }
715 else
716 {
717 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
718 return 4;
719 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200720 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000721 }
722 }
723
724 if (hextype == HEX_CINCLUDE)
725 {
726 if (fp != stdin)
727 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200728 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
729 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000730 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200731 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200732 die(3);
733 if (fputs("[] = {\n", fpo) == EOF)
734 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000735 }
736
737 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000739 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
740 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200741 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200742 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200743 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000744 p++;
745 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200746 if (c == EOF && ferror(fp))
747 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100749 if (p && fputs("\n", fpo) == EOF)
750 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200751 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100752 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000753
754 if (fp != stdin)
755 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200756 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
757 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000758 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200759 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200760 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200761 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200762 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000763 }
764
Bram Moolenaare0659a62011-04-01 19:14:40 +0200765 if (fclose(fp))
766 die(2);
767 if (fclose(fpo))
768 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 return 0;
770 }
771
772 if (hextype == HEX_POSTSCRIPT)
773 {
774 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200775 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000776 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
777 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200778 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
779 || putc(hexx[e & 0xf], fpo) == EOF)
780 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 n++;
782 if (!--p)
783 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200784 if (putc('\n', fpo) == EOF)
785 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000786 p = cols;
787 }
788 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200789 if (e == EOF && ferror(fp))
790 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000791 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200792 if (putc('\n', fpo) == EOF)
793 die(3);
794 if (fclose(fp))
795 die(2);
796 if (fclose(fpo))
797 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000798 return 0;
799 }
800
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100801 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100803 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000804 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
805 else /* hextype == HEX_BITS */
806 grplen = 8 * octspergrp + 1;
807
Bram Moolenaare0659a62011-04-01 19:14:40 +0200808 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000809 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
810 {
811 if (p == 0)
812 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100813 sprintf(l, "%08lx:",
814 ((unsigned long)(n + seekoff + displayoff)) & 0xffffffff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 for (c = 9; c < LLEN; l[c++] = ' ');
816 }
817 if (hextype == HEX_NORMAL)
818 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100819 l[c = (10 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
820 l[++c] = hexx[ e & 0xf];
821 }
822 else if (hextype == HEX_LITTLEENDIAN)
823 {
824 int x = p ^ (octspergrp-1);
825 l[c = (10 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
826 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000827 }
828 else /* hextype == HEX_BITS */
829 {
830 int i;
831
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100832 c = (10 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000833 for (i = 7; i >= 0; i--)
834 l[++c] = (e & (1 << i)) ? '1' : '0';
835 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100836 if (e)
837 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838 if (ebcdic)
839 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000840 /* When changing this update definition of LLEN above. */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100841 l[12 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842#ifdef __MVS__
843 (e >= 64)
844#else
845 (e > 31 && e < 127)
846#endif
847 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000848 n++;
849 if (++p == cols)
850 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100851 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000852 xxdline(fpo, l, autoskip ? nonzero : 1);
853 nonzero = 0;
854 p = 0;
855 }
856 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200857 if (e == EOF && ferror(fp))
858 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000859 if (p)
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, 1);
863 }
864 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000865 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000866
Bram Moolenaare0659a62011-04-01 19:14:40 +0200867 if (fclose(fp))
868 die(2);
869 if (fclose(fpo))
870 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000871 return 0;
872}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200873
874/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */