1 /* 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
8 * consecutive lines of zeroes, as unix od does.
9 * -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 silent.
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
43 * (azc10@yahoo.com)
44 * 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
51 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
52 * 2011 March Better error handling by Florian Zumbiehl.
53 * 2011 April Formatting by Bram Moolenaar
54 * 08.06.2013 Little-endian hexdump (-e) and offset (-o) by Vadim Vygonets.
55 * 11.01.2019 Add full 64/32 bit range to -o and output by Christer Jensen.
56 * 04.02.2020 Add -d for decimal offsets by Aapo Rantalainen
57 *
58 * (c) 1990-1998 by Juergen Weigert (jnweiger@gmail.com)
59 *
60 * I hereby grant permission to distribute and use xxd
61 * under X11-MIT or GPL-2.0 (at the user's choice).
62 *
63 * Contributions by Bram Moolenaar et al.
64 */
65
66 /* Visual Studio 2005 has 'deprecated' many of the standard CRT functions */
67 #if _MSC_VER >= 1400
68 # define _CRT_SECURE_NO_DEPRECATE
69 # define _CRT_NONSTDC_NO_DEPRECATE
70 #endif
71 #if !defined(CYGWIN) && defined(__CYGWIN__)
72 # define CYGWIN
73 #endif
74
75 #include <stdio.h>
76 #ifdef VAXC
77 # include <file.h>
78 #else
79 # include <fcntl.h>
80 #endif
81 #if defined(WIN32) || defined(CYGWIN)
82 # include <io.h> /* for setmode() */
83 #else
84 # ifdef UNIX
85 # include <unistd.h>
86 # endif
87 #endif
88 #include <stdlib.h>
89 #include <string.h> /* for strncmp() */
90 #include <ctype.h> /* for isalnum() */
91 #include <limits.h>
92 #if __MWERKS__ && !defined(BEBOX)
93 # include <unix.h> /* for fdopen() on MAC */
94 #endif
95
96
97 /* This corrects the problem of missing prototypes for certain functions
98 * in some GNU installations (e.g. SunOS 4.1.x).
99 * Darren Hiebert <darren@hmi.com> (sparc-sun-sunos4.1.3_U1/2.7.2.2)
100 */
101 #if defined(__GNUC__) && defined(__STDC__)
102 # ifndef __USE_FIXED_PROTOTYPES__
103 # define __USE_FIXED_PROTOTYPES__
104 # endif
105 #endif
106
107 #ifndef __USE_FIXED_PROTOTYPES__
108 /*
109 * This is historic and works only if the compiler really has no prototypes:
110 *
111 * Include prototypes for Sun OS 4.x, when using an ANSI compiler.
112 * FILE is defined on OS 4.x, not on 5.x (Solaris).
113 * if __SVR4 is defined (some Solaris versions), don't include this.
114 */
115 #if defined(sun) && defined(FILE) && !defined(__SVR4) && defined(__STDC__)
116 # define __P(a) a
117 /* excerpt from my sun_stdlib.h */
118 extern int fprintf __P((FILE *, char *, ...));
119 extern int fputs __P((char *, FILE *));
120 extern int _flsbuf __P((unsigned char, FILE *));
121 extern int _filbuf __P((FILE *));
122 extern int fflush __P((FILE *));
123 extern int fclose __P((FILE *));
124 extern int fseek __P((FILE *, long, int));
125 extern int rewind __P((FILE *));
126
127 extern void perror __P((char *));
128 # endif
129 #endif
130
131 extern long int strtol();
132 extern long int ftell();
133
134 char version[] = "xxd 2021-10-22 by Juergen Weigert et al.";
135 #ifdef WIN32
136 char osver[] = " (Win32)";
137 #else
138 char osver[] = "";
139 #endif
140
141 #if defined(WIN32)
142 # define BIN_READ(yes) ((yes) ? "rb" : "rt")
143 # define BIN_WRITE(yes) ((yes) ? "wb" : "wt")
144 # define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
145 # define BIN_ASSIGN(fp, yes) setmode(fileno(fp), (yes) ? O_BINARY : O_TEXT)
146 # define PATH_SEP '\\'
147 #elif defined(CYGWIN)
148 # define BIN_READ(yes) ((yes) ? "rb" : "rt")
149 # define BIN_WRITE(yes) ((yes) ? "wb" : "w")
150 # define BIN_CREAT(yes) ((yes) ? (O_CREAT|O_BINARY) : O_CREAT)
151 # define BIN_ASSIGN(fp, yes) ((yes) ? (void) setmode(fileno(fp), O_BINARY) : (void) (fp))
152 # define PATH_SEP '/'
153 #else
154 # ifdef VMS
155 # define BIN_READ(dummy) "r"
156 # define BIN_WRITE(dummy) "w"
157 # define BIN_CREAT(dummy) O_CREAT
158 # define BIN_ASSIGN(fp, dummy) fp
159 # define PATH_SEP ']'
160 # define FILE_SEP '.'
161 # else
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 # endif
168 #endif
169
170 /* open has only to arguments on the Mac */
171 #if __MWERKS__
172 # define OPEN(name, mode, umask) open(name, mode)
173 #else
174 # define OPEN(name, mode, umask) open(name, mode, umask)
175 #endif
176
177 #ifdef AMIGA
178 # define STRNCMP(s1, s2, l) strncmp(s1, s2, (size_t)l)
179 #else
180 # define STRNCMP(s1, s2, l) strncmp(s1, s2, l)
181 #endif
182
183 #ifndef __P
184 # if defined(__STDC__) || defined(WIN32)
185 # define __P(a) a
186 # else
187 # define __P(a) ()
188 # endif
189 #endif
190
191 #define TRY_SEEK /* attempt to use lseek, or skip forward by reading */
192 #define COLS 256 /* change here, if you ever need more columns */
193 #define LLEN ((2*(int)sizeof(unsigned long)) + 4 + (9*COLS-1) + COLS + 2)
194
195 char hexxa[] = "0123456789abcdef0123456789ABCDEF", *hexx = hexxa;
196
197 /* the different hextypes known by this program: */
198 #define HEX_NORMAL 0
199 #define HEX_POSTSCRIPT 1
200 #define HEX_CINCLUDE 2
201 #define HEX_BITS 3 /* not hex a dump, but bits: 01111001 */
202 #define HEX_LITTLEENDIAN 4
203
204 #define CONDITIONAL_CAPITALIZE(c) (capitalize ? toupper((int)c) : c)
205
206 static char *pname;
207
208 static void
exit_with_usage(void)209 exit_with_usage(void)
210 {
211 fprintf(stderr, "Usage:\n %s [options] [infile [outfile]]\n", pname);
212 fprintf(stderr, " or\n %s -r [-s [-]offset] [-c cols] [-ps] [infile [outfile]]\n", pname);
213 fprintf(stderr, "Options:\n");
214 fprintf(stderr, " -a toggle autoskip: A single '*' replaces nul-lines. Default off.\n");
215 fprintf(stderr, " -b binary digit dump (incompatible with -ps,-i,-r). Default hex.\n");
216 fprintf(stderr, " -C capitalize variable names in C include file style (-i).\n");
217 fprintf(stderr, " -c cols format <cols> octets per line. Default 16 (-i: 12, -ps: 30).\n");
218 fprintf(stderr, " -E show characters in EBCDIC. Default ASCII.\n");
219 fprintf(stderr, " -e little-endian dump (incompatible with -ps,-i,-r).\n");
220 fprintf(stderr, " -g bytes number of octets per group in normal output. Default 2 (-e: 4).\n");
221 fprintf(stderr, " -h print this summary.\n");
222 fprintf(stderr, " -i output in C include file style.\n");
223 fprintf(stderr, " -l len stop after <len> octets.\n");
224 fprintf(stderr, " -o off add <off> to the displayed file position.\n");
225 fprintf(stderr, " -ps output in postscript plain hexdump style.\n");
226 fprintf(stderr, " -r reverse operation: convert (or patch) hexdump into binary.\n");
227 fprintf(stderr, " -r -s off revert with <off> added to file positions found in hexdump.\n");
228 fprintf(stderr, " -d show offset in decimal instead of hex.\n");
229 fprintf(stderr, " -s %sseek start at <seek> bytes abs. %sinfile offset.\n",
230 #ifdef TRY_SEEK
231 "[+][-]", "(or +: rel.) ");
232 #else
233 "", "");
234 #endif
235 fprintf(stderr, " -u use upper case hex letters.\n");
236 fprintf(stderr, " -v show version: \"%s%s\".\n", version, osver);
237 exit(1);
238 }
239
240 static void
perror_exit(int ret)241 perror_exit(int ret)
242 {
243 fprintf(stderr, "%s: ", pname);
244 perror(NULL);
245 exit(ret);
246 }
247
248 static void
error_exit(int ret,char * msg)249 error_exit(int ret, char *msg)
250 {
251 fprintf(stderr, "%s: %s\n", pname, msg);
252 exit(ret);
253 }
254
255 static int
getc_or_die(FILE * fpi)256 getc_or_die(FILE *fpi)
257 {
258 int c = getc(fpi);
259 if (c == EOF && ferror(fpi))
260 perror_exit(2);
261 return c;
262 }
263
264 static void
putc_or_die(int c,FILE * fpo)265 putc_or_die(int c, FILE *fpo)
266 {
267 if (putc(c, fpo) == EOF)
268 perror_exit(3);
269 }
270
271 static void
fputs_or_die(char * s,FILE * fpo)272 fputs_or_die(char *s, FILE *fpo)
273 {
274 if (fputs(s, fpo) == EOF)
275 perror_exit(3);
276 }
277
278 /* Use a macro to allow for different arguments. */
279 #define FPRINTF_OR_DIE(args) if (fprintf args < 0) perror_exit(3)
280
281 static void
fclose_or_die(FILE * fpi,FILE * fpo)282 fclose_or_die(FILE *fpi, FILE *fpo)
283 {
284 if (fclose(fpo) != 0)
285 perror_exit(3);
286 if (fclose(fpi) != 0)
287 perror_exit(2);
288 }
289
290 /*
291 * If "c" is a hex digit, return the value.
292 * Otherwise return -1.
293 */
294 static int
parse_hex_digit(int c)295 parse_hex_digit(int c)
296 {
297 return (c >= '0' && c <= '9') ? c - '0'
298 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
299 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
300 : -1;
301 }
302
303 /*
304 * Ignore text on "fpi" until end-of-line or end-of-file.
305 * Return the '\n' or EOF character.
306 * When an error is encountered exit with an error message.
307 */
308 static int
skip_to_eol(FILE * fpi,int c)309 skip_to_eol(FILE *fpi, int c)
310 {
311 while (c != '\n' && c != EOF)
312 c = getc_or_die(fpi);
313 return c;
314 }
315
316 /*
317 * Max. cols binary characters are decoded from the input stream per line.
318 * Two adjacent garbage characters after evaluated data delimit valid data.
319 * Everything up to the next newline is discarded.
320 *
321 * The name is historic and came from 'undo type opt h'.
322 */
323 static int
huntype(FILE * fpi,FILE * fpo,int cols,int hextype,long base_off)324 huntype(
325 FILE *fpi,
326 FILE *fpo,
327 int cols,
328 int hextype,
329 long base_off)
330 {
331 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
332 long have_off = 0, want_off = 0;
333
334 rewind(fpi);
335
336 while ((c = getc(fpi)) != EOF)
337 {
338 if (c == '\r') /* Doze style input file? */
339 continue;
340
341 /* Allow multiple spaces. This doesn't work when there is normal text
342 * after the hex codes in the last line that looks like hex, thus only
343 * use it for PostScript format. */
344 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
345 continue;
346
347 n3 = n2;
348 n2 = n1;
349
350 n1 = parse_hex_digit(c);
351 if (n1 == -1 && ign_garb)
352 continue;
353
354 ign_garb = 0;
355
356 if (!hextype && (p >= cols))
357 {
358 if (n1 < 0)
359 {
360 p = 0;
361 continue;
362 }
363 want_off = (want_off << 4) | n1;
364 continue;
365 }
366
367 if (base_off + want_off != have_off)
368 {
369 if (fflush(fpo) != 0)
370 perror_exit(3);
371 #ifdef TRY_SEEK
372 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
373 have_off = base_off + want_off;
374 #endif
375 if (base_off + want_off < have_off)
376 error_exit(5, "Sorry, cannot seek backwards.");
377 for (; have_off < base_off + want_off; have_off++)
378 putc_or_die(0, fpo);
379 }
380
381 if (n2 >= 0 && n1 >= 0)
382 {
383 putc_or_die((n2 << 4) | n1, fpo);
384 have_off++;
385 want_off++;
386 n1 = -1;
387 if (!hextype && (++p >= cols))
388 /* skip the rest of the line as garbage */
389 c = skip_to_eol(fpi, c);
390 }
391 else if (n1 < 0 && n2 < 0 && n3 < 0)
392 /* already stumbled into garbage, skip line, wait and see */
393 c = skip_to_eol(fpi, c);
394
395 if (c == '\n')
396 {
397 if (!hextype)
398 want_off = 0;
399 p = cols;
400 ign_garb = 1;
401 }
402 }
403 if (fflush(fpo) != 0)
404 perror_exit(3);
405 #ifdef TRY_SEEK
406 fseek(fpo, 0L, SEEK_END);
407 #endif
408 fclose_or_die(fpi, fpo);
409 return 0;
410 }
411
412 /*
413 * Print line l. If nz is false, xxdline regards the line a line of
414 * zeroes. If there are three or more consecutive lines of zeroes,
415 * they are replaced by a single '*' character.
416 *
417 * If the output ends with more than two lines of zeroes, you
418 * should call xxdline again with l being the last line and nz
419 * negative. This ensures that the last line is shown even when
420 * it is all zeroes.
421 *
422 * If nz is always positive, lines are never suppressed.
423 */
424 static void
xxdline(FILE * fp,char * l,int nz)425 xxdline(FILE *fp, char *l, int nz)
426 {
427 static char z[LLEN+1];
428 static int zero_seen = 0;
429
430 if (!nz && zero_seen == 1)
431 strcpy(z, l);
432
433 if (nz || !zero_seen++)
434 {
435 if (nz)
436 {
437 if (nz < 0)
438 zero_seen--;
439 if (zero_seen == 2)
440 fputs_or_die(z, fp);
441 if (zero_seen > 2)
442 fputs_or_die("*\n", fp);
443 }
444 if (nz >= 0 || zero_seen > 0)
445 fputs_or_die(l, fp);
446 if (nz)
447 zero_seen = 0;
448 }
449 }
450
451 /* This is an EBCDIC to ASCII conversion table */
452 /* from a proposed BTL standard April 16, 1979 */
453 static unsigned char etoa64[] =
454 {
455 0040,0240,0241,0242,0243,0244,0245,0246,
456 0247,0250,0325,0056,0074,0050,0053,0174,
457 0046,0251,0252,0253,0254,0255,0256,0257,
458 0260,0261,0041,0044,0052,0051,0073,0176,
459 0055,0057,0262,0263,0264,0265,0266,0267,
460 0270,0271,0313,0054,0045,0137,0076,0077,
461 0272,0273,0274,0275,0276,0277,0300,0301,
462 0302,0140,0072,0043,0100,0047,0075,0042,
463 0303,0141,0142,0143,0144,0145,0146,0147,
464 0150,0151,0304,0305,0306,0307,0310,0311,
465 0312,0152,0153,0154,0155,0156,0157,0160,
466 0161,0162,0136,0314,0315,0316,0317,0320,
467 0321,0345,0163,0164,0165,0166,0167,0170,
468 0171,0172,0322,0323,0324,0133,0326,0327,
469 0330,0331,0332,0333,0334,0335,0336,0337,
470 0340,0341,0342,0343,0344,0135,0346,0347,
471 0173,0101,0102,0103,0104,0105,0106,0107,
472 0110,0111,0350,0351,0352,0353,0354,0355,
473 0175,0112,0113,0114,0115,0116,0117,0120,
474 0121,0122,0356,0357,0360,0361,0362,0363,
475 0134,0237,0123,0124,0125,0126,0127,0130,
476 0131,0132,0364,0365,0366,0367,0370,0371,
477 0060,0061,0062,0063,0064,0065,0066,0067,
478 0070,0071,0372,0373,0374,0375,0376,0377
479 };
480
481 int
main(int argc,char * argv[])482 main(int argc, char *argv[])
483 {
484 FILE *fp, *fpo;
485 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
486 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
487 int capitalize = 0, decimal_offset = 0;
488 int ebcdic = 0;
489 int octspergrp = -1; /* number of octets grouped in output */
490 int grplen; /* total chars per octet group */
491 long length = -1, n = 0, seekoff = 0;
492 unsigned long displayoff = 0;
493 static char l[LLEN+1]; /* static because it may be too big for stack */
494 char *pp;
495 int addrlen = 9;
496
497 #ifdef AMIGA
498 /* This program doesn't work when started from the Workbench */
499 if (argc == 0)
500 exit(1);
501 #endif
502
503 pname = argv[0];
504 for (pp = pname; *pp; )
505 if (*pp++ == PATH_SEP)
506 pname = pp;
507 #ifdef FILE_SEP
508 for (pp = pname; *pp; pp++)
509 if (*pp == FILE_SEP)
510 {
511 *pp = '\0';
512 break;
513 }
514 #endif
515
516 while (argc >= 2)
517 {
518 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
519 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
520 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
521 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
522 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
523 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
524 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
525 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
526 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
527 else if (!STRNCMP(pp, "-r", 2)) revert++;
528 else if (!STRNCMP(pp, "-E", 2)) ebcdic++;
529 else if (!STRNCMP(pp, "-v", 2))
530 {
531 fprintf(stderr, "%s%s\n", version, osver);
532 exit(0);
533 }
534 else if (!STRNCMP(pp, "-c", 2))
535 {
536 if (pp[2] && !STRNCMP("apitalize", pp + 2, 9))
537 capitalize = 1;
538 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
539 cols = (int)strtol(pp + 2, NULL, 0);
540 else
541 {
542 if (!argv[2])
543 exit_with_usage();
544 cols = (int)strtol(argv[2], NULL, 0);
545 argv++;
546 argc--;
547 }
548 }
549 else if (!STRNCMP(pp, "-g", 2))
550 {
551 if (pp[2] && STRNCMP("roup", pp + 2, 4))
552 octspergrp = (int)strtol(pp + 2, NULL, 0);
553 else
554 {
555 if (!argv[2])
556 exit_with_usage();
557 octspergrp = (int)strtol(argv[2], NULL, 0);
558 argv++;
559 argc--;
560 }
561 }
562 else if (!STRNCMP(pp, "-o", 2))
563 {
564 int reloffset = 0;
565 int negoffset = 0;
566 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
567 displayoff = strtoul(pp + 2, NULL, 0);
568 else
569 {
570 if (!argv[2])
571 exit_with_usage();
572
573 if (argv[2][0] == '+')
574 reloffset++;
575 if (argv[2][reloffset] == '-')
576 negoffset++;
577
578 if (negoffset)
579 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
580 else
581 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
582
583 argv++;
584 argc--;
585 }
586 }
587 else if (!STRNCMP(pp, "-s", 2))
588 {
589 relseek = 0;
590 negseek = 0;
591 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
592 {
593 #ifdef TRY_SEEK
594 if (pp[2] == '+')
595 relseek++;
596 if (pp[2+relseek] == '-')
597 negseek++;
598 #endif
599 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
600 }
601 else
602 {
603 if (!argv[2])
604 exit_with_usage();
605 #ifdef TRY_SEEK
606 if (argv[2][0] == '+')
607 relseek++;
608 if (argv[2][relseek] == '-')
609 negseek++;
610 #endif
611 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
612 argv++;
613 argc--;
614 }
615 }
616 else if (!STRNCMP(pp, "-l", 2))
617 {
618 if (pp[2] && STRNCMP("en", pp + 2, 2))
619 length = strtol(pp + 2, (char **)NULL, 0);
620 else
621 {
622 if (!argv[2])
623 exit_with_usage();
624 length = strtol(argv[2], (char **)NULL, 0);
625 argv++;
626 argc--;
627 }
628 }
629 else if (!strcmp(pp, "--")) /* end of options */
630 {
631 argv++;
632 argc--;
633 break;
634 }
635 else if (pp[0] == '-' && pp[1]) /* unknown option */
636 exit_with_usage();
637 else
638 break; /* not an option */
639
640 argv++; /* advance to next argument */
641 argc--;
642 }
643
644 if (!cols)
645 switch (hextype)
646 {
647 case HEX_POSTSCRIPT: cols = 30; break;
648 case HEX_CINCLUDE: cols = 12; break;
649 case HEX_BITS: cols = 6; break;
650 case HEX_NORMAL:
651 case HEX_LITTLEENDIAN:
652 default: cols = 16; break;
653 }
654
655 if (octspergrp < 0)
656 switch (hextype)
657 {
658 case HEX_BITS: octspergrp = 1; break;
659 case HEX_NORMAL: octspergrp = 2; break;
660 case HEX_LITTLEENDIAN: octspergrp = 4; break;
661 case HEX_POSTSCRIPT:
662 case HEX_CINCLUDE:
663 default: octspergrp = 0; break;
664 }
665
666 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
667 && (cols > COLS)))
668 {
669 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
670 exit(1);
671 }
672
673 if (octspergrp < 1 || octspergrp > cols)
674 octspergrp = cols;
675 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
676 error_exit(1, "number of octets per group must be a power of 2 with -e.");
677
678 if (argc > 3)
679 exit_with_usage();
680
681 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
682 BIN_ASSIGN(fp = stdin, !revert);
683 else
684 {
685 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
686 {
687 fprintf(stderr,"%s: ", pname);
688 perror(argv[1]);
689 return 2;
690 }
691 }
692
693 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
694 BIN_ASSIGN(fpo = stdout, revert);
695 else
696 {
697 int fd;
698 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
699
700 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
701 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
702 {
703 fprintf(stderr, "%s: ", pname);
704 perror(argv[2]);
705 return 3;
706 }
707 rewind(fpo);
708 }
709
710 if (revert)
711 {
712 if (hextype && (hextype != HEX_POSTSCRIPT))
713 error_exit(-1, "Sorry, cannot revert this type of hexdump");
714 return huntype(fp, fpo, cols, hextype,
715 negseek ? -seekoff : seekoff);
716 }
717
718 if (seekoff || negseek || !relseek)
719 {
720 #ifdef TRY_SEEK
721 if (relseek)
722 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
723 else
724 e = fseek(fp, negseek ? -seekoff : seekoff,
725 negseek ? SEEK_END : SEEK_SET);
726 if (e < 0 && negseek)
727 error_exit(4, "Sorry, cannot seek.");
728 if (e >= 0)
729 seekoff = ftell(fp);
730 else
731 #endif
732 {
733 long s = seekoff;
734
735 while (s--)
736 if (getc_or_die(fp) == EOF)
737 {
738 error_exit(4, "Sorry, cannot seek.");
739 }
740 }
741 }
742
743 if (hextype == HEX_CINCLUDE)
744 {
745 if (fp != stdin)
746 {
747 FPRINTF_OR_DIE((fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : ""));
748 for (e = 0; (c = argv[1][e]) != 0; e++)
749 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
750 fputs_or_die("[] = {\n", fpo);
751 }
752
753 p = 0;
754 c = 0;
755 while ((length < 0 || p < length) && (c = getc_or_die(fp)) != EOF)
756 {
757 FPRINTF_OR_DIE((fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
758 (p % cols) ? ", " : (!p ? " " : ",\n "), c));
759 p++;
760 }
761
762 if (p)
763 fputs_or_die("\n", fpo);
764
765 if (fp != stdin)
766 {
767 fputs_or_die("};\n", fpo);
768 FPRINTF_OR_DIE((fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : ""));
769 for (e = 0; (c = argv[1][e]) != 0; e++)
770 putc_or_die(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo);
771 FPRINTF_OR_DIE((fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p));
772 }
773
774 fclose_or_die(fp, fpo);
775 return 0;
776 }
777
778 if (hextype == HEX_POSTSCRIPT)
779 {
780 p = cols;
781 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
782 {
783 putc_or_die(hexx[(e >> 4) & 0xf], fpo);
784 putc_or_die(hexx[e & 0xf], fpo);
785 n++;
786 if (!--p)
787 {
788 putc_or_die('\n', fpo);
789 p = cols;
790 }
791 }
792 if (p < cols)
793 putc_or_die('\n', fpo);
794 fclose_or_die(fp, fpo);
795 return 0;
796 }
797
798 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
799
800 if (hextype != HEX_BITS)
801 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
802 else /* hextype == HEX_BITS */
803 grplen = 8 * octspergrp + 1;
804
805 while ((length < 0 || n < length) && (e = getc_or_die(fp)) != EOF)
806 {
807 int x;
808
809 if (p == 0)
810 {
811 addrlen = sprintf(l, decimal_offset ? "%08ld:" : "%08lx:",
812 ((unsigned long)(n + seekoff + displayoff)));
813 for (c = addrlen; c < LLEN; l[c++] = ' ');
814 }
815 x = hextype == HEX_LITTLEENDIAN ? p ^ (octspergrp-1) : p;
816 c = addrlen + 1 + (grplen * x) / octspergrp;
817 if (hextype == HEX_NORMAL || hextype == HEX_LITTLEENDIAN)
818 {
819 l[c] = hexx[(e >> 4) & 0xf];
820 l[++c] = hexx[e & 0xf];
821 }
822 else /* hextype == HEX_BITS */
823 {
824 int i;
825 for (i = 7; i >= 0; i--)
826 l[c++] = (e & (1 << i)) ? '1' : '0';
827 }
828 if (e)
829 nonzero++;
830 if (ebcdic)
831 e = (e < 64) ? '.' : etoa64[e-64];
832 /* When changing this update definition of LLEN above. */
833 c = addrlen + 3 + (grplen * cols - 1)/octspergrp + p;
834 l[c++] =
835 #ifdef __MVS__
836 (e >= 64)
837 #else
838 (e > 31 && e < 127)
839 #endif
840 ? e : '.';
841 n++;
842 if (++p == cols)
843 {
844 l[c] = '\n';
845 l[++c] = '\0';
846 xxdline(fpo, l, autoskip ? nonzero : 1);
847 nonzero = 0;
848 p = 0;
849 }
850 }
851 if (p)
852 {
853 l[c] = '\n';
854 l[++c] = '\0';
855 xxdline(fpo, l, 1);
856 }
857 else if (autoskip)
858 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
859
860 fclose_or_die(fp, fpo);
861 return 0;
862 }
863
864 /* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */
865