blob: b39f4d43646677f3cc0ac0ca5030a948473620a0 [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));
213static int huntype __P((FILE *, FILE *, FILE *, int, int, long));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000214static void xxdline __P((FILE *, char *, int));
215
216#define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
217#define COLS 256 /* change here, if you ever need more columns */
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000218#define LLEN (11 + (9*COLS-1)/1 + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000219
220char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
221
222/* the different hextypes known by this program: */
223#define HEX_NORMAL 0
224#define HEX_POSTSCRIPT 1
225#define HEX_CINCLUDE 2
226#define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
227
Bram Moolenaare0659a62011-04-01 19:14:40 +0200228static char *pname;
229
230 static void
231exit_with_usage()
Bram Moolenaar071d4272004-06-13 20:20:40 +0000232{
233 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
234 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
235 fprintf(stderr, "Options:\n");
236 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100237 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
Bram Moolenaar071d4272004-06-13 20:20:40 +0000238 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
239 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
240 fprintf(stderr, " -g number of octets per group in normal output. Default 2.\n");
241 fprintf(stderr, " -h print this summary.\n");
242 fprintf(stderr, " -i output in C include file style.\n");
243 fprintf(stderr, " -l len stop after <len> octets.\n");
244 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
245 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
246 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
247 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
248#ifdef TRY_SEEK
249 "[+][-]", "(or +: rel.) ");
250#else
251 "", "");
252#endif
253 fprintf(stderr, " -u use upper case hex letters.\n");
254 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
255 exit(1);
256}
257
Bram Moolenaare0659a62011-04-01 19:14:40 +0200258 static void
259die(ret)
260 int ret;
261{
262 fprintf(stderr, "%s: ", pname);
263 perror(NULL);
264 exit(ret);
265}
266
Bram Moolenaar071d4272004-06-13 20:20:40 +0000267/*
268 * Max. cols binary characters are decoded from the input stream per line.
269 * Two adjacent garbage characters after evaluated data delimit valid data.
270 * Everything up to the next newline is discarded.
271 *
272 * The name is historic and came from 'undo type opt h'.
273 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200274 static int
275huntype(fpi, fpo, fperr, cols, hextype, base_off)
276 FILE *fpi, *fpo, *fperr;
277 int cols, hextype;
278 long base_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000279{
280 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
281 long have_off = 0, want_off = 0;
282
283 rewind(fpi);
284
285 while ((c = getc(fpi)) != EOF)
286 {
287 if (c == '\r') /* Doze style input file? */
288 continue;
289
Bram Moolenaar8a33e742010-02-17 18:28:41 +0100290 /* Allow multiple spaces. This doesn't work when there is normal text
291 * after the hex codes in the last line that looks like hex, thus only
292 * use it for PostScript format. */
293 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000294 continue;
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000295
Bram Moolenaar071d4272004-06-13 20:20:40 +0000296 n3 = n2;
297 n2 = n1;
298
299 if (c >= '0' && c <= '9')
300 n1 = c - '0';
301 else if (c >= 'a' && c <= 'f')
302 n1 = c - 'a' + 10;
303 else if (c >= 'A' && c <= 'F')
304 n1 = c - 'A' + 10;
305 else
306 {
307 n1 = -1;
308 if (ign_garb)
309 continue;
310 }
311
312 ign_garb = 0;
313
314 if (p >= cols)
315 {
316 if (!hextype)
317 {
318 if (n1 < 0)
319 {
320 p = 0;
321 continue;
322 }
323 want_off = (want_off << 4) | n1;
324 continue;
325 }
326 else
327 p = 0;
328 }
329
330 if (base_off + want_off != have_off)
331 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200332 if (fflush(fpo) != 0)
333 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000334#ifdef TRY_SEEK
335 c = fseek(fpo, base_off + want_off - have_off, 1);
336 if (c >= 0)
337 have_off = base_off + want_off;
338#endif
339 if (base_off + want_off < have_off)
340 {
341 fprintf(fperr, "%s: sorry, cannot seek backwards.\n", pname);
342 return 5;
343 }
344 for (; have_off < base_off + want_off; have_off++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200345 if (putc(0, fpo) == EOF)
346 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000347 }
348
349 if (n2 >= 0 && n1 >= 0)
350 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200351 if (putc((n2 << 4) | n1, fpo) == EOF)
352 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000353 have_off++;
354 want_off++;
355 n1 = -1;
356 if ((++p >= cols) && !hextype)
357 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000358 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000359 want_off = 0;
360 while ((c = getc(fpi)) != '\n' && c != EOF)
361 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200362 if (c == EOF && ferror(fpi))
363 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000364 ign_garb = 1;
365 }
366 }
367 else if (n1 < 0 && n2 < 0 && n3 < 0)
368 {
369 /* already stumbled into garbage, skip line, wait and see */
370 if (!hextype)
371 want_off = 0;
372 while ((c = getc(fpi)) != '\n' && c != EOF)
373 ;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200374 if (c == EOF && ferror(fpi))
375 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000376 ign_garb = 1;
377 }
378 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200379 if (fflush(fpo) != 0)
380 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000381#ifdef TRY_SEEK
382 fseek(fpo, 0L, 2);
383#endif
Bram Moolenaare0659a62011-04-01 19:14:40 +0200384 if (fclose(fpo) != 0)
385 die(3);
386 if (fclose(fpi) != 0)
387 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000388 return 0;
389}
390
391/*
392 * Print line l. If nz is false, xxdline regards the line a line of
393 * zeroes. If there are three or more consecutive lines of zeroes,
394 * they are replaced by a single '*' character.
395 *
396 * If the output ends with more than two lines of zeroes, you
397 * should call xxdline again with l being the last line and nz
398 * negative. This ensures that the last line is shown even when
399 * it is all zeroes.
400 *
401 * If nz is always positive, lines are never suppressed.
402 */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200403 static void
Bram Moolenaar071d4272004-06-13 20:20:40 +0000404xxdline(fp, l, nz)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200405 FILE *fp;
406 char *l;
407 int nz;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000408{
409 static char z[LLEN+1];
410 static int zero_seen = 0;
411
412 if (!nz && zero_seen == 1)
413 strcpy(z, l);
414
415 if (nz || !zero_seen++)
416 {
417 if (nz)
418 {
419 if (nz < 0)
420 zero_seen--;
421 if (zero_seen == 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200422 if (fputs(z, fp) == EOF)
423 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000424 if (zero_seen > 2)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200425 if (fputs("*\n", fp) == EOF)
426 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000427 }
428 if (nz >= 0 || zero_seen > 0)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200429 if (fputs(l, fp) == EOF)
430 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000431 if (nz)
432 zero_seen = 0;
433 }
434}
435
436/* This is an EBCDIC to ASCII conversion table */
437/* from a proposed BTL standard April 16, 1979 */
438static unsigned char etoa64[] =
439{
440 0040,0240,0241,0242,0243,0244,0245,0246,
441 0247,0250,0325,0056,0074,0050,0053,0174,
442 0046,0251,0252,0253,0254,0255,0256,0257,
443 0260,0261,0041,0044,0052,0051,0073,0176,
444 0055,0057,0262,0263,0264,0265,0266,0267,
445 0270,0271,0313,0054,0045,0137,0076,0077,
446 0272,0273,0274,0275,0276,0277,0300,0301,
447 0302,0140,0072,0043,0100,0047,0075,0042,
448 0303,0141,0142,0143,0144,0145,0146,0147,
449 0150,0151,0304,0305,0306,0307,0310,0311,
450 0312,0152,0153,0154,0155,0156,0157,0160,
451 0161,0162,0136,0314,0315,0316,0317,0320,
452 0321,0345,0163,0164,0165,0166,0167,0170,
453 0171,0172,0322,0323,0324,0133,0326,0327,
454 0330,0331,0332,0333,0334,0335,0336,0337,
455 0340,0341,0342,0343,0344,0135,0346,0347,
456 0173,0101,0102,0103,0104,0105,0106,0107,
457 0110,0111,0350,0351,0352,0353,0354,0355,
458 0175,0112,0113,0114,0115,0116,0117,0120,
459 0121,0122,0356,0357,0360,0361,0362,0363,
460 0134,0237,0123,0124,0125,0126,0127,0130,
461 0131,0132,0364,0365,0366,0367,0370,0371,
462 0060,0061,0062,0063,0064,0065,0066,0067,
463 0070,0071,0372,0373,0374,0375,0376,0377
464};
465
Bram Moolenaare0659a62011-04-01 19:14:40 +0200466 int
Bram Moolenaar071d4272004-06-13 20:20:40 +0000467main(argc, argv)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200468 int argc;
469 char *argv[];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000470{
471 FILE *fp, *fpo;
472 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
473 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
474 int ebcdic = 0;
475 int octspergrp = -1; /* number of octets grouped in output */
476 int grplen; /* total chars per octet group */
477 long length = -1, n = 0, seekoff = 0;
478 char l[LLEN+1];
Bram Moolenaare0659a62011-04-01 19:14:40 +0200479 char *pp;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000480
481#ifdef AMIGA
482 /* This program doesn't work when started from the Workbench */
483 if (argc == 0)
484 exit(1);
485#endif
486
487 pname = argv[0];
488 for (pp = pname; *pp; )
489 if (*pp++ == PATH_SEP)
490 pname = pp;
491#ifdef FILE_SEP
492 for (pp = pname; *pp; pp++)
493 if (*pp == FILE_SEP)
494 {
495 *pp = '\0';
496 break;
497 }
498#endif
499
500 while (argc >= 2)
501 {
502 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
503 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
504 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
505 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
506 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
507 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
508 else if (!STRNCMP(pp, "-r", 2)) revert++;
509 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
510 else if (!STRNCMP(pp, "-v", 2))
511 {
512 fprintf(stderr, "%s%s\n", version, osver);
513 exit(0);
514 }
515 else if (!STRNCMP(pp, "-c", 2))
516 {
517 if (pp[2] && STRNCMP("ols", pp + 2, 3))
518 cols = (int)strtol(pp + 2, NULL, 0);
519 else
520 {
521 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200522 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000523 cols = (int)strtol(argv[2], NULL, 0);
524 argv++;
525 argc--;
526 }
527 }
528 else if (!STRNCMP(pp, "-g", 2))
529 {
530 if (pp[2] && STRNCMP("group", pp + 2, 5))
531 octspergrp = (int)strtol(pp + 2, NULL, 0);
532 else
533 {
534 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200535 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000536 octspergrp = (int)strtol(argv[2], NULL, 0);
537 argv++;
538 argc--;
539 }
540 }
541 else if (!STRNCMP(pp, "-s", 2))
542 {
543 relseek = 0;
544 negseek = 0;
545 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
546 {
547#ifdef TRY_SEEK
548 if (pp[2] == '+')
549 relseek++;
550 if (pp[2+relseek] == '-')
551 negseek++;
552#endif
553 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
554 }
555 else
556 {
557 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200558 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000559#ifdef TRY_SEEK
560 if (argv[2][0] == '+')
561 relseek++;
562 if (argv[2][relseek] == '-')
563 negseek++;
564#endif
565 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
566 argv++;
567 argc--;
568 }
569 }
570 else if (!STRNCMP(pp, "-l", 2))
571 {
572 if (pp[2] && STRNCMP("en", pp + 2, 2))
573 length = strtol(pp + 2, (char **)NULL, 0);
574 else
575 {
576 if (!argv[2])
Bram Moolenaare0659a62011-04-01 19:14:40 +0200577 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000578 length = strtol(argv[2], (char **)NULL, 0);
579 argv++;
580 argc--;
581 }
582 }
583 else if (!strcmp(pp, "--")) /* end of options */
584 {
585 argv++;
586 argc--;
587 break;
588 }
589 else if (pp[0] == '-' && pp[1]) /* unknown option */
Bram Moolenaare0659a62011-04-01 19:14:40 +0200590 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000591 else
592 break; /* not an option */
593
594 argv++; /* advance to next argument */
595 argc--;
596 }
597
598 if (!cols)
599 switch (hextype)
600 {
601 case HEX_POSTSCRIPT: cols = 30; break;
602 case HEX_CINCLUDE: cols = 12; break;
603 case HEX_BITS: cols = 6; break;
604 case HEX_NORMAL:
605 default: cols = 16; break;
606 }
607
608 if (octspergrp < 0)
609 switch (hextype)
610 {
611 case HEX_BITS: octspergrp = 1; break;
612 case HEX_NORMAL: octspergrp = 2; break;
613 case HEX_POSTSCRIPT:
614 case HEX_CINCLUDE:
615 default: octspergrp = 0; break;
616 }
617
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000618 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS)
619 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000620 {
621 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
622 exit(1);
623 }
624
625 if (octspergrp < 1)
626 octspergrp = cols;
627
628 if (argc > 3)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200629 exit_with_usage();
Bram Moolenaar071d4272004-06-13 20:20:40 +0000630
631 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
632 BIN_ASSIGN(fp = stdin, !revert);
633 else
634 {
635 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
636 {
637 fprintf(stderr,"%s: ", pname);
638 perror(argv[1]);
639 return 2;
640 }
641 }
642
643 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
644 BIN_ASSIGN(fpo = stdout, revert);
645 else
646 {
647 int fd;
648 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
649
650 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
651 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
652 {
653 fprintf(stderr, "%s: ", pname);
654 perror(argv[2]);
655 return 3;
656 }
657 rewind(fpo);
658 }
659
660 if (revert)
661 {
662 if (hextype && (hextype != HEX_POSTSCRIPT))
663 {
664 fprintf(stderr, "%s: sorry, cannot revert this type of hexdump\n", pname);
665 return -1;
666 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200667 return huntype(fp, fpo, stderr, cols, hextype,
Bram Moolenaar071d4272004-06-13 20:20:40 +0000668 negseek ? -seekoff : seekoff);
669 }
670
671 if (seekoff || negseek || !relseek)
672 {
673#ifdef TRY_SEEK
674 if (relseek)
675 e = fseek(fp, negseek ? -seekoff : seekoff, 1);
676 else
677 e = fseek(fp, negseek ? -seekoff : seekoff, negseek ? 2 : 0);
678 if (e < 0 && negseek)
679 {
680 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
681 return 4;
682 }
683 if (e >= 0)
684 seekoff = ftell(fp);
685 else
686#endif
687 {
688 long s = seekoff;
689
690 while (s--)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200691 if (getc(fp) == EOF)
692 if (ferror(fp))
693 {
694 die(2);
695 }
696 else
697 {
698 fprintf(stderr, "%s: sorry cannot seek.\n", pname);
699 return 4;
700 }
Bram Moolenaar071d4272004-06-13 20:20:40 +0000701 }
702 }
703
704 if (hextype == HEX_CINCLUDE)
705 {
706 if (fp != stdin)
707 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200708 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
709 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000710 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200711 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
712 die(3);
713 if (fputs("[] = {\n", fpo) == EOF)
714 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000715 }
716
717 p = 0;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200718 c = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000719 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
720 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200721 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
722 (p % cols) ? ", " : ",\n "+2*!p, c) < 0)
723 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000724 p++;
725 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200726 if (c == EOF && ferror(fp))
727 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000728
729 if (p)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200730 if (fputs("\n};\n" + 3 * (fp == stdin), fpo) == EOF)
731 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000732
733 if (fp != stdin)
734 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200735 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
736 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000737 for (e = 0; (c = argv[1][e]) != 0; e++)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200738 if (putc(isalnum(c) ? c : '_', fpo) == EOF)
739 die(3);
740 if (fprintf(fpo, "_len = %d;\n", p) < 0)
741 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000742 }
743
Bram Moolenaare0659a62011-04-01 19:14:40 +0200744 if (fclose(fp))
745 die(2);
746 if (fclose(fpo))
747 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000748 return 0;
749 }
750
751 if (hextype == HEX_POSTSCRIPT)
752 {
753 p = cols;
Bram Moolenaare0659a62011-04-01 19:14:40 +0200754 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000755 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
756 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200757 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
758 || putc(hexx[e & 0xf], fpo) == EOF)
759 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000760 n++;
761 if (!--p)
762 {
Bram Moolenaare0659a62011-04-01 19:14:40 +0200763 if (putc('\n', fpo) == EOF)
764 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000765 p = cols;
766 }
767 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200768 if (e == EOF && ferror(fp))
769 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000770 if (p < cols)
Bram Moolenaare0659a62011-04-01 19:14:40 +0200771 if (putc('\n', fpo) == EOF)
772 die(3);
773 if (fclose(fp))
774 die(2);
775 if (fclose(fpo))
776 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000777 return 0;
778 }
779
780 /* hextype: HEX_NORMAL or HEX_BITS */
781
782 if (hextype == HEX_NORMAL)
783 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
784 else /* hextype == HEX_BITS */
785 grplen = 8 * octspergrp + 1;
786
Bram Moolenaare0659a62011-04-01 19:14:40 +0200787 e = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000788 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
789 {
790 if (p == 0)
791 {
792 sprintf(l, "%07lx: ", n + seekoff);
793 for (c = 9; c < LLEN; l[c++] = ' ');
794 }
795 if (hextype == HEX_NORMAL)
796 {
797 l[c = (9 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
798 l[++c] = hexx[ e & 0xf];
799 }
800 else /* hextype == HEX_BITS */
801 {
802 int i;
803
804 c = (9 + (grplen * p) / octspergrp) - 1;
805 for (i = 7; i >= 0; i--)
806 l[++c] = (e & (1 << i)) ? '1' : '0';
807 }
808 if (ebcdic)
809 e = (e < 64) ? '.' : etoa64[e-64];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000810 /* When changing this update definition of LLEN above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000811 l[11 + (grplen * cols - 1)/octspergrp + p] =
812#ifdef __MVS__
813 (e >= 64)
814#else
815 (e > 31 && e < 127)
816#endif
817 ? e : '.';
818 if (e)
819 nonzero++;
820 n++;
821 if (++p == cols)
822 {
823 l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
824 xxdline(fpo, l, autoskip ? nonzero : 1);
825 nonzero = 0;
826 p = 0;
827 }
828 }
Bram Moolenaare0659a62011-04-01 19:14:40 +0200829 if (e == EOF && ferror(fp))
830 die(2);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000831 if (p)
832 {
833 l[c = (11 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
834 xxdline(fpo, l, 1);
835 }
836 else if (autoskip)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000837 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000838
Bram Moolenaare0659a62011-04-01 19:14:40 +0200839 if (fclose(fp))
840 die(2);
841 if (fclose(fpo))
842 die(3);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000843 return 0;
844}
Bram Moolenaare0659a62011-04-01 19:14:40 +0200845
846/* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */