blob: 209ede43d1ca24b9fd337ab225a45234940b7e7b [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 Moolenaar071d4272004-06-13 20:20:40 +000054 *
55 * (c) 1990-1998 by Juergen Weigert (jnweiger@informatik.uni-erlangen.de)
56 *
57 * Small changes made afterwards by Bram Moolenaar et al.
58 *
59 * Distribute freely and credit me,
60 * make money and share with me,
61 * lose money and don't ask me.
62 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000063
64/* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
65#if _MSC_VER >= 1400
66# define _CRT_SECURE_NO_DEPRECATE
67# define _CRT_NONSTDC_NO_DEPRECATE
68#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000069#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
70# define CYGWIN
71#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000072
Bram Moolenaar071d4272004-06-13 20:20:40 +000073#include <stdio.h>
74#ifdef VAXC
75# include <file.h>
76#else
77# include <fcntl.h>
78#endif
79#ifdef __TSC__
80# define MSDOS
81#endif
82#if !defined(OS2) && defined(__EMX__)
83# define OS2
84#endif
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000085#if defined(MSDOS) || defined(WIN32) || defined(OS2) || defined(__BORLANDC__) \
86 || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000087# include <io.h> /* for setmode() */
88#else
89# ifdef UNIX
90# include <unistd.h>
91# endif
92#endif
93#include <stdlib.h>
94#include <string.h> /* for strncmp() */
95#include <ctype.h> /* for isalnum() */
96#if __MWERKS__ && !defined(BEBOX)
97# include <unix.h> /* for fdopen() on MAC */
98#endif
99
100#if defined(__BORLANDC__) && __BORLANDC__ <= 0x0410 && !defined(fileno)
101/* Missing define and prototype grabbed from the BC 4.0 <stdio.h> */
102# define fileno(f) ((f)->fd)
103FILE _FAR *_Cdecl _FARFUNC fdopen(int __handle, char _FAR *__type);
104#endif
105
106
107/* This corrects the problem of missing prototypes for certain functions
108 * in some GNU installations (e.g. SunOS 4.1.x).
109 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
110 */
111#if defined(__GNUC__) && defined(__STDC__)
112# ifndef __USE_FIXED_PROTOTYPES__
113# define __USE_FIXED_PROTOTYPES__
114# endif
115#endif
116
117#ifndef __USE_FIXED_PROTOTYPES__
118/*
119 * This is historic and works only if the compiler really has no prototypes:
120 *
121 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
122 * FILE is defined on OS 4.x, not on 5.x (Solaris).
123 * if __SVR4 is defined (some Solaris versions), don't include this.
124 */
125#if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
126# define __P(a) a
127/* excerpt from my sun_stdlib.h */
128extern int fprintf __P((FILE *, char *, ...));
129extern int fputs __P((char *, FILE *));
130extern int _flsbuf __P((unsigned char, FILE *));
131extern int _filbuf __P((FILE *));
132extern int fflush __P((FILE *));
133extern int fclose __P((FILE *));
134extern int fseek __P((FILE *, long, int));
135extern int rewind __P((FILE *));
136
137extern void perror __P((char *));
138# endif
139#endif
140
141extern long int strtol();
142extern long int ftell();
143
144char version[] = "xxd V1.10 27oct98 by Juergen Weigert";
145#ifdef WIN32
146char osver[] = " (Win32)";
147#else
148# ifdef DJGPP
149char osver[] = " (dos 32 bit)";
150# else
151# ifdef MSDOS
152char osver[] = " (dos 16 bit)";
153# else
154char osver[] = "";
155# endif
156# endif
157#endif
158
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000159#if defined(MSDOS) || defined(WIN32) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000160# define BIN_READ(yes) ((yes) ? "rb" : "rt")
161# define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
162# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
163# define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000164# define PATH_SEP '\\'
165#elif defined(CYGWIN)
166# define BIN_READ(yes) ((yes) ? "rb" : "rt")
167# define BIN_WRITE(yes) ((yes) ? "wb" : "w")
168# define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
169# define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
170# define PATH_SEP '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000171#else
172# ifdef VMS
173# define BIN_READ(dummy) "r"
174# define BIN_WRITE(dummy) "w"
175# define BIN_CREAT(dummy) O_CREAT
176# define BIN_ASSIGN(fp, dummy) fp
177# define PATH_SEP ']'
178# define FILE_SEP '.'
179# else
180# define BIN_READ(dummy) "r"
181# define BIN_WRITE(dummy) "w"
182# define BIN_CREAT(dummy) O_CREAT
183# define BIN_ASSIGN(fp, dummy) fp
184# define PATH_SEP '/'
185# endif
186#endif
187
188/* open has only to arguments on the Mac */
189#if __MWERKS__
190# define OPEN(name, mode, umask) open(name, mode)
191#else
192# define OPEN(name, mode, umask) open(name, mode, umask)
193#endif
194
195#ifdef AMIGA
196# define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
197#else
198# define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
199#endif
200
201#ifndef __P
202# if defined(__STDC__) || defined(MSDOS) || defined(WIN32) || defined(OS2) \
203 || defined(__BORLANDC__)
204# define __P(a) a
205# else
206# define __P(a) ()
207# endif
208#endif
209
210/* Let's collect some prototypes */
211/* CodeWarrior is really picky about missing prototypes */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200212static void exit_with_usage __P((void));
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200213static void die __P((int));
Bram Moolenaare0659a62011-04-01 19:14:40 +0200214static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000215static void xxdline __P((FILE *, char *, int));
216
217#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
218#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000219#define LLEN (11 + (9*COLS-1)/1 + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000220
221char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
222
223/* the different hextypes known by this program: */
224#define HEX_NORMAL 0
225#define HEX_POSTSCRIPT 1
226#define HEX_CINCLUDE 2
227#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
228
Bram Moolenaare0659a62011-04-01 19:14:40 +0200229static char *pname;
230
231 static void
232exit_with_usage()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000233{
234 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
235 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
236 fprintf(stderr, "Options:\n");
237 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100238 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000239 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
240 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
241 fprintf(stderr, " -g number of octets per group in normal output. Default 2.\n");
242 fprintf(stderr, " -h print this summary.\n");
243 fprintf(stderr, " -i output in C include file style.\n");
244 fprintf(stderr, " -l len stop after <len> octets.\n");
245 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
246 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
247 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
248 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
249#ifdef TRY_SEEK
250 "[+][-]", "(or +: rel.) ");
251#else
252 "", "");
253#endif
254 fprintf(stderr, " -u use upper case hex letters.\n");
255 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
256 exit(1);
257}
258
Bram Moolenaare0659a62011-04-01 19:14:40 +0200259 static void
260die(ret)
261 int ret;
262{
263 fprintf(stderr, "%s: ", pname);
264 perror(NULL);
265 exit(ret);
266}
267
Bram Moolenaar071d4272004-06-13 20:20:40 +0000268/*
269 * Max. cols binary characters are decoded from the input stream per line.
270 * Two adjacent garbage characters after evaluated data delimit valid data.
271 * Everything up to the next newline is discarded.
272 *
273 * The name is historic and came from 'undo type opt h'.
274 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200275 static int
276huntype(fpi, fpo, fperr, cols, hextype, base_off)
277 FILE *fpi, *fpo, *fperr;
278 int cols, hextype;
279 long base_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000280{
281 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
282 long have_off = 0, want_off = 0;
283
284 rewind(fpi);
285
286 while ((c = getc(fpi)) != EOF)
287 {
288 if (c == '\r') /* Doze style input file? */
289 continue;
290
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100291 /* Allow multiple spaces. This doesn't work when there is normal text
292 * after the hex codes in the last line that looks like hex, thus only
293 * use it for PostScript format. */
294 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000295 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000296
Bram Moolenaar071d4272004-06-13 20:20:40 +0000297 n3 = n2;
298 n2 = n1;
299
300 if (c >= '0' && c <= '9')
301 n1 = c - '0';
302 else if (c >= 'a' && c <= 'f')
303 n1 = c - 'a' + 10;
304 else if (c >= 'A' && c <= 'F')
305 n1 = c - 'A' + 10;
306 else
307 {
308 n1 = -1;
309 if (ign_garb)
310 continue;
311 }
312
313 ign_garb = 0;
314
315 if (p >= cols)
316 {
317 if (!hextype)
318 {
319 if (n1 < 0)
320 {
321 p = 0;
322 continue;
323 }
324 want_off = (want_off << 4) | n1;
325 continue;
326 }
327 else
328 p = 0;
329 }
330
331 if (base_off + want_off != have_off)
332 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200333 if (fflush(fpo) != 0)
334 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000335#ifdef TRY_SEEK
336 c = fseek(fpo, base_off + want_off - have_off, 1);
337 if (c >= 0)
338 have_off = base_off + want_off;
339#endif
340 if (base_off + want_off < have_off)
341 {
342 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
343 return 5;
344 }
345 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200346 if (putc(0, fpo) == EOF)
347 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000348 }
349
350 if (n2 >= 0 && n1 >= 0)
351 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200352 if (putc((n2 << 4) | n1, fpo) == EOF)
353 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000354 have_off++;
355 want_off++;
356 n1 = -1;
357 if ((++p >= cols) && !hextype)
358 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000359 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000360 want_off = 0;
361 while ((c = getc(fpi)) != '\n' && c != EOF)
362 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200363 if (c == EOF && ferror(fpi))
364 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000365 ign_garb = 1;
366 }
367 }
368 else if (n1 < 0 && n2 < 0 && n3 < 0)
369 {
370 /* already stumbled into garbage, skip line, wait and see */
371 if (!hextype)
372 want_off = 0;
373 while ((c = getc(fpi)) != '\n' && c != EOF)
374 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200375 if (c == EOF && ferror(fpi))
376 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000377 ign_garb = 1;
378 }
379 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200380 if (fflush(fpo) != 0)
381 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000382#ifdef TRY_SEEK
383 fseek(fpo, 0L, 2);
384#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200385 if (fclose(fpo) != 0)
386 die(3);
387 if (fclose(fpi) != 0)
388 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000389 return 0;
390}
391
392/*
393 * Print line l. If nz is false, xxdline regards the line a line of
394 * zeroes. If there are three or more consecutive lines of zeroes,
395 * they are replaced by a single '*' character.
396 *
397 * If the output ends with more than two lines of zeroes, you
398 * should call xxdline again with l being the last line and nz
399 * negative. This ensures that the last line is shown even when
400 * it is all zeroes.
401 *
402 * If nz is always positive, lines are never suppressed.
403 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200404 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000405xxdline(fp, l, nz)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200406 FILE *fp;
407 char *l;
408 int nz;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000409{
410 static char z[LLEN+1];
411 static int zero_seen = 0;
412
413 if (!nz && zero_seen == 1)
414 strcpy(z, l);
415
416 if (nz || !zero_seen++)
417 {
418 if (nz)
419 {
420 if (nz < 0)
421 zero_seen--;
422 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200423 if (fputs(z, fp) == EOF)
424 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000425 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200426 if (fputs("*\n", fp) == EOF)
427 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000428 }
429 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200430 if (fputs(l, fp) == EOF)
431 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000432 if (nz)
433 zero_seen = 0;
434 }
435}
436
437/* This is an EBCDIC to ASCII conversion table */
438/* from a proposed BTL standard April 16, 1979 */
439static unsigned char etoa64[] =
440{
441 0040,0240,0241,0242,0243,0244,0245,0246,
442 0247,0250,0325,0056,0074,0050,0053,0174,
443 0046,0251,0252,0253,0254,0255,0256,0257,
444 0260,0261,0041,0044,0052,0051,0073,0176,
445 0055,0057,0262,0263,0264,0265,0266,0267,
446 0270,0271,0313,0054,0045,0137,0076,0077,
447 0272,0273,0274,0275,0276,0277,0300,0301,
448 0302,0140,0072,0043,0100,0047,0075,0042,
449 0303,0141,0142,0143,0144,0145,0146,0147,
450 0150,0151,0304,0305,0306,0307,0310,0311,
451 0312,0152,0153,0154,0155,0156,0157,0160,
452 0161,0162,0136,0314,0315,0316,0317,0320,
453 0321,0345,0163,0164,0165,0166,0167,0170,
454 0171,0172,0322,0323,0324,0133,0326,0327,
455 0330,0331,0332,0333,0334,0335,0336,0337,
456 0340,0341,0342,0343,0344,0135,0346,0347,
457 0173,0101,0102,0103,0104,0105,0106,0107,
458 0110,0111,0350,0351,0352,0353,0354,0355,
459 0175,0112,0113,0114,0115,0116,0117,0120,
460 0121,0122,0356,0357,0360,0361,0362,0363,
461 0134,0237,0123,0124,0125,0126,0127,0130,
462 0131,0132,0364,0365,0366,0367,0370,0371,
463 0060,0061,0062,0063,0064,0065,0066,0067,
464 0070,0071,0372,0373,0374,0375,0376,0377
465};
466
Bram Moolenaare0659a62011-04-01 19:14:40 +0200467 int
Bram Moolenaar071d4272004-06-13 20:20:40 +0000468main(argc, argv)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200469 int argc;
470 char *argv[];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000471{
472 FILE *fp, *fpo;
473 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
474 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
475 int ebcdic = 0;
476 int octspergrp = -1; /* number of octets grouped in output */
477 int grplen; /* total chars per octet group */
478 long length = -1, n = 0, seekoff = 0;
Bram Moolenaard9462e32011-04-11 21:35:11 +0200479 static char l[LLEN+1]; /* static because it may be too big for stack */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200480 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000481
482#ifdef AMIGA
483 /* This program doesn't work when started from the Workbench */
484 if (argc == 0)
485 exit(1);
486#endif
487
488 pname = argv[0];
489 for (pp = pname; *pp; )
490 if (*pp++ == PATH_SEP)
491 pname = pp;
492#ifdef FILE_SEP
493 for (pp = pname; *pp; pp++)
494 if (*pp == FILE_SEP)
495 {
496 *pp = '\0';
497 break;
498 }
499#endif
500
501 while (argc >= 2)
502 {
503 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
504 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
505 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
506 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
507 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
508 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
509 else if (!STRNCMP(pp, "-r", 2)) revert++;
510 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
511 else if (!STRNCMP(pp, "-v", 2))
512 {
513 fprintf(stderr, "%s%s\n", version, osver);
514 exit(0);
515 }
516 else if (!STRNCMP(pp, "-c", 2))
517 {
518 if (pp[2] && STRNCMP("ols", pp + 2, 3))
519 cols = (int)strtol(pp + 2, NULL, 0);
520 else
521 {
522 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200523 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000524 cols = (int)strtol(argv[2], NULL, 0);
525 argv++;
526 argc--;
527 }
528 }
529 else if (!STRNCMP(pp, "-g", 2))
530 {
531 if (pp[2] && STRNCMP("group", pp + 2, 5))
532 octspergrp = (int)strtol(pp + 2, NULL, 0);
533 else
534 {
535 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200536 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000537 octspergrp = (int)strtol(argv[2], NULL, 0);
538 argv++;
539 argc--;
540 }
541 }
542 else if (!STRNCMP(pp, "-s", 2))
543 {
544 relseek = 0;
545 negseek = 0;
546 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
547 {
548#ifdef TRY_SEEK
549 if (pp[2] == '+')
550 relseek++;
551 if (pp[2+relseek] == '-')
552 negseek++;
553#endif
554 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
555 }
556 else
557 {
558 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200559 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000560#ifdef TRY_SEEK
561 if (argv[2][0] == '+')
562 relseek++;
563 if (argv[2][relseek] == '-')
564 negseek++;
565#endif
566 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
567 argv++;
568 argc--;
569 }
570 }
571 else if (!STRNCMP(pp, "-l", 2))
572 {
573 if (pp[2] && STRNCMP("en", pp + 2, 2))
574 length = strtol(pp + 2, (char **)NULL, 0);
575 else
576 {
577 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200578 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000579 length = strtol(argv[2], (char **)NULL, 0);
580 argv++;
581 argc--;
582 }
583 }
584 else if (!strcmp(pp, "--")) /* end of options */
585 {
586 argv++;
587 argc--;
588 break;
589 }
590 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200591 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000592 else
593 break; /* not an option */
594
595 argv++; /* advance to next argument */
596 argc--;
597 }
598
599 if (!cols)
600 switch (hextype)
601 {
602 case HEX_POSTSCRIPT: cols = 30; break;
603 case HEX_CINCLUDE: cols = 12; break;
604 case HEX_BITS: cols = 6; break;
605 case HEX_NORMAL:
606 default: cols = 16; break;
607 }
608
609 if (octspergrp < 0)
610 switch (hextype)
611 {
612 case HEX_BITS: octspergrp = 1; break;
613 case HEX_NORMAL: octspergrp = 2; break;
614 case HEX_POSTSCRIPT:
615 case HEX_CINCLUDE:
616 default: octspergrp = 0; break;
617 }
618
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000619 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS)
620 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000621 {
622 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
623 exit(1);
624 }
625
626 if (octspergrp < 1)
627 octspergrp = cols;
628
629 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200630 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000631
632 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
633 BIN_ASSIGN(fp = stdin, !revert);
634 else
635 {
636 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
637 {
638 fprintf(stderr,"%s: ", pname);
639 perror(argv[1]);
640 return 2;
641 }
642 }
643
644 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
645 BIN_ASSIGN(fpo = stdout, revert);
646 else
647 {
648 int fd;
649 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
650
651 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
652 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
653 {
654 fprintf(stderr, "%s: ", pname);
655 perror(argv[2]);
656 return 3;
657 }
658 rewind(fpo);
659 }
660
661 if (revert)
662 {
663 if (hextype && (hextype != HEX_POSTSCRIPT))
664 {
665 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
666 return -1;
667 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200668 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000669 negseek ? -seekoff : seekoff);
670 }
671
672 if (seekoff || negseek || !relseek)
673 {
674#ifdef TRY_SEEK
675 if (relseek)
676 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
677 else
678 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
679 if (e < 0 && negseek)
680 {
681 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
682 return 4;
683 }
684 if (e >= 0)
685 seekoff = ftell(fp);
686 else
687#endif
688 {
689 long s = seekoff;
690
691 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200692 if (getc(fp) == EOF)
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200693 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200694 if (ferror(fp))
695 {
696 die(2);
697 }
698 else
699 {
700 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
701 return 4;
702 }
Bram Moolenaar10d77eb2011-04-02 14:44:55 +0200703 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000704 }
705 }
706
707 if (hextype == HEX_CINCLUDE)
708 {
709 if (fp != stdin)
710 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200711 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
712 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000713 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200714 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
715 die(3);
716 if (fputs("[] = {\n", fpo) == EOF)
717 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000718 }
719
720 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200721 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000722 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
723 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200724 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
725 (p % cols) ? ", " : ",\n "+2*!p, c) < 0)
726 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000727 p++;
728 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200729 if (c == EOF && ferror(fp))
730 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000731
Bram Moolenaar53eb37e2013-02-26 14:14:07 +0100732 if (p && fputs("\n", fpo) == EOF)
733 die(3);
734 if (fputs("};\n" + 3 * (fp == stdin), fpo) == EOF)
735 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000736
737 if (fp != stdin)
738 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200739 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
740 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000741 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200742 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
743 die(3);
744 if (fprintf(fpo, "_len = %d;\n", p) < 0)
745 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000746 }
747
Bram Moolenaare0659a62011-04-01 19:14:40 +0200748 if (fclose(fp))
749 die(2);
750 if (fclose(fpo))
751 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000752 return 0;
753 }
754
755 if (hextype == HEX_POSTSCRIPT)
756 {
757 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200758 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000759 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
760 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200761 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
762 || putc(hexx[e & 0xf], fpo) == EOF)
763 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000764 n++;
765 if (!--p)
766 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200767 if (putc('\n', fpo) == EOF)
768 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000769 p = cols;
770 }
771 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200772 if (e == EOF && ferror(fp))
773 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000774 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200775 if (putc('\n', fpo) == EOF)
776 die(3);
777 if (fclose(fp))
778 die(2);
779 if (fclose(fpo))
780 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781 return 0;
782 }
783
784 /* hextype: HEX_NORMAL or HEX_BITS */
785
786 if (hextype == HEX_NORMAL)
787 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
788 else /* hextype == HEX_BITS */
789 grplen = 8 * octspergrp + 1;
790
Bram Moolenaare0659a62011-04-01 19:14:40 +0200791 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000792 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
793 {
794 if (p == 0)
795 {
796 sprintf(l, "%07lx: ", n + seekoff);
797 for (c = 9; c < LLEN; l[c++] = ' ');
798 }
799 if (hextype == HEX_NORMAL)
800 {
801 l[c = (9 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
802 l[++c] = hexx[ e & 0xf];
803 }
804 else /* hextype == HEX_BITS */
805 {
806 int i;
807
808 c = (9 + (grplen * p) / octspergrp) - 1;
809 for (i = 7; i >= 0; i--)
810 l[++c] = (e & (1 << i)) ? '1' : '0';
811 }
812 if (ebcdic)
813 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000814 /* When changing this update definition of LLEN above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000815 l[11 + (grplen * cols - 1)/octspergrp + p] =
816#ifdef __MVS__
817 (e >= 64)
818#else
819 (e > 31 && e < 127)
820#endif
821 ? e : '.';
822 if (e)
823 nonzero++;
824 n++;
825 if (++p == cols)
826 {
827 l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
828 xxdline(fpo, l, autoskip ? nonzero : 1);
829 nonzero = 0;
830 p = 0;
831 }
832 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200833 if (e == EOF && ferror(fp))
834 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000835 if (p)
836 {
837 l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
838 xxdline(fpo, l, 1);
839 }
840 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000841 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000842
Bram Moolenaare0659a62011-04-01 19:14:40 +0200843 if (fclose(fp))
844 die(2);
845 if (fclose(fpo))
846 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000847 return 0;
848}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200849
850/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */