blob: bbd9c08a375dabfd277dadb76110ca73310bae5e [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 {
511 if (pp[2] && STRNCMP("ols", pp + 2, 3))
512 cols = (int)strtol(pp + 2, NULL, 0);
513 else
514 {
515 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200516 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000517 cols = (int)strtol(argv[2], NULL, 0);
518 argv++;
519 argc--;
520 }
521 }
522 else if (!STRNCMP(pp, "-g", 2))
523 {
524 if (pp[2] && STRNCMP("group", pp + 2, 5))
525 octspergrp = (int)strtol(pp + 2, NULL, 0);
526 else
527 {
528 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200529 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000530 octspergrp = (int)strtol(argv[2], NULL, 0);
531 argv++;
532 argc--;
533 }
534 }
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100535 else if (!STRNCMP(pp, "-o", 2))
536 {
537 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
538 displayoff = (int)strtol(pp + 2, NULL, 0);
539 else
540 {
541 if (!argv[2])
542 exit_with_usage();
543 displayoff = (int)strtol(argv[2], NULL, 0);
544 argv++;
545 argc--;
546 }
547 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000548 else if (!STRNCMP(pp, "-s", 2))
549 {
550 relseek = 0;
551 negseek = 0;
552 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
553 {
554#ifdef TRY_SEEK
555 if (pp[2] == '+')
556 relseek++;
557 if (pp[2+relseek] == '-')
558 negseek++;
559#endif
560 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
561 }
562 else
563 {
564 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200565 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000566#ifdef TRY_SEEK
567 if (argv[2][0] == '+')
568 relseek++;
569 if (argv[2][relseek] == '-')
570 negseek++;
571#endif
572 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
573 argv++;
574 argc--;
575 }
576 }
577 else if (!STRNCMP(pp, "-l", 2))
578 {
579 if (pp[2] && STRNCMP("en", pp + 2, 2))
580 length = strtol(pp + 2, (char **)NULL, 0);
581 else
582 {
583 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200584 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000585 length = strtol(argv[2], (char **)NULL, 0);
586 argv++;
587 argc--;
588 }
589 }
590 else if (!strcmp(pp, "--")) /* end of options */
591 {
592 argv++;
593 argc--;
594 break;
595 }
596 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200597 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000598 else
599 break; /* not an option */
600
601 argv++; /* advance to next argument */
602 argc--;
603 }
604
605 if (!cols)
606 switch (hextype)
607 {
608 case HEX_POSTSCRIPT: cols = 30; break;
609 case HEX_CINCLUDE: cols = 12; break;
610 case HEX_BITS: cols = 6; break;
611 case HEX_NORMAL:
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100612 case HEX_LITTLEENDIAN:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000613 default: cols = 16; break;
614 }
615
616 if (octspergrp < 0)
617 switch (hextype)
618 {
619 case HEX_BITS: octspergrp = 1; break;
620 case HEX_NORMAL: octspergrp = 2; break;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100621 case HEX_LITTLEENDIAN: octspergrp = 4; break;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000622 case HEX_POSTSCRIPT:
623 case HEX_CINCLUDE:
624 default: octspergrp = 0; break;
625 }
626
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100627 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000628 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000629 {
630 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
631 exit(1);
632 }
633
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100634 if (octspergrp < 1 || octspergrp > cols)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000635 octspergrp = cols;
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100636 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
637 {
638 fprintf(stderr,
639 "%s: number of octets per group must be a power of 2 with -e.\n",
640 pname);
641 exit(1);
642 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000643
644 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200645 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000646
647 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
648 BIN_ASSIGN(fp = stdin, !revert);
649 else
650 {
651 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
652 {
653 fprintf(stderr,"%s: ", pname);
654 perror(argv[1]);
655 return 2;
656 }
657 }
658
659 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
660 BIN_ASSIGN(fpo = stdout, revert);
661 else
662 {
663 int fd;
664 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
665
666 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
667 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
668 {
669 fprintf(stderr, "%s: ", pname);
670 perror(argv[2]);
671 return 3;
672 }
673 rewind(fpo);
674 }
675
676 if (revert)
677 {
678 if (hextype && (hextype != HEX_POSTSCRIPT))
679 {
680 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
681 return -1;
682 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200683 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000684 negseek ? -seekoff : seekoff);
685 }
686
687 if (seekoff || negseek || !relseek)
688 {
689#ifdef TRY_SEEK
690 if (relseek)
691 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
692 else
693 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
694 if (e < 0 && negseek)
695 {
696 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
697 return 4;
698 }
699 if (e >= 0)
700 seekoff = ftell(fp);
701 else
702#endif
703 {
704 long s = seekoff;
705
706 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200707 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200708 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200709 if (ferror(fp))
710 {
711 die(2);
712 }
713 else
714 {
715 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
716 return 4;
717 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200718 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 }
720 }
721
722 if (hextype == HEX_CINCLUDE)
723 {
724 if (fp != stdin)
725 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200726 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
727 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200729 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200730 die(3);
731 if (fputs("[] = {\n", fpo) == EOF)
732 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000733 }
734
735 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200736 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
738 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200739 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200740 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200741 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 p++;
743 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 if (c == EOF && ferror(fp))
745 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100747 if (p && fputs("\n", fpo) == EOF)
748 die(3);
Bram Moolenaarfe70acb2013-06-21 18:31:23 +0200749 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100750 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000751
752 if (fp != stdin)
753 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200754 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
755 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200757 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200758 die(3);
Bram Moolenaar8b31a6f2018-04-03 12:17:25 +0200759 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200760 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000761 }
762
Bram Moolenaare0659a62011-04-01 19:14:40 +0200763 if (fclose(fp))
764 die(2);
765 if (fclose(fpo))
766 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000767 return 0;
768 }
769
770 if (hextype == HEX_POSTSCRIPT)
771 {
772 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200773 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
775 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200776 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
777 || putc(hexx[e & 0xf], fpo) == EOF)
778 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000779 n++;
780 if (!--p)
781 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200782 if (putc('\n', fpo) == EOF)
783 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000784 p = cols;
785 }
786 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200787 if (e == EOF && ferror(fp))
788 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000789 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200790 if (putc('\n', fpo) == EOF)
791 die(3);
792 if (fclose(fp))
793 die(2);
794 if (fclose(fpo))
795 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000796 return 0;
797 }
798
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100799 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000800
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100801 if (hextype != HEX_BITS)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000802 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
803 else /* hextype == HEX_BITS */
804 grplen = 8 * octspergrp + 1;
805
Bram Moolenaare0659a62011-04-01 19:14:40 +0200806 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000807 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
808 {
809 if (p == 0)
810 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100811 sprintf(l, "%08lx:",
812 ((unsigned long)(n + seekoff + displayoff)) & 0xffffffff);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000813 for (c = 9; c < LLEN; l[c++] = ' ');
814 }
815 if (hextype == HEX_NORMAL)
816 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100817 l[c = (10 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
818 l[++c] = hexx[ e & 0xf];
819 }
820 else if (hextype == HEX_LITTLEENDIAN)
821 {
822 int x = p ^ (octspergrp-1);
823 l[c = (10 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
824 l[++c] = hexx[ e & 0xf];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000825 }
826 else /* hextype == HEX_BITS */
827 {
828 int i;
829
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100830 c = (10 + (grplen * p) / octspergrp) - 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 for (i = 7; i >= 0; i--)
832 l[++c] = (e & (1 << i)) ? '1' : '0';
833 }
Bram Moolenaar085346f2018-02-24 18:30:55 +0100834 if (e)
835 nonzero++;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000836 if (ebcdic)
837 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000838 /* When changing this update definition of LLEN above. */
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100839 l[12 + (grplen * cols - 1)/octspergrp + p] =
Bram Moolenaar071d4272004-06-13 20:20:40 +0000840#ifdef __MVS__
841 (e >= 64)
842#else
843 (e > 31 && e < 127)
844#endif
845 ? e : '.';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000846 n++;
847 if (++p == cols)
848 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100849 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000850 xxdline(fpo, l, autoskip ? nonzero : 1);
851 nonzero = 0;
852 p = 0;
853 }
854 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200855 if (e == EOF && ferror(fp))
856 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000857 if (p)
858 {
Bram Moolenaar4dcdf292015-03-05 17:51:15 +0100859 l[c = (12 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
Bram Moolenaar071d4272004-06-13 20:20:40 +0000860 xxdline(fpo, l, 1);
861 }
862 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000863 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000864
Bram Moolenaare0659a62011-04-01 19:14:40 +0200865 if (fclose(fp))
866 die(2);
867 if (fclose(fpo))
868 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 return 0;
870}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200871
872/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */