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 * ([email protected])
44 * 22.05.97 added -g (group octets) option ([email protected]).
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 ([email protected])
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 <[email protected]> (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 /*
256 * If "c" is a hex digit, return the value.
257 * Otherwise return -1.
258 */
259 static int
parse_hex_digit(int c)260 parse_hex_digit(int c)
261 {
262 return (c >= '0' && c <= '9') ? c - '0'
263 : (c >= 'a' && c <= 'f') ? c - 'a' + 10
264 : (c >= 'A' && c <= 'F') ? c - 'A' + 10
265 : -1;
266 }
267
268 /*
269 * Ignore text on "fpi" until end-of-line or end-of-file.
270 * Return the '\n' or EOF character.
271 * When an error is encountered exit with an error message.
272 */
273 static int
skip_to_eol(FILE * fpi,int c)274 skip_to_eol(FILE *fpi, int c)
275 {
276 while (c != '\n' && c != EOF)
277 c = getc(fpi);
278 if (c == EOF && ferror(fpi))
279 perror_exit(2);
280 return c;
281 }
282
283 /*
284 * Max. cols binary characters are decoded from the input stream per line.
285 * Two adjacent garbage characters after evaluated data delimit valid data.
286 * Everything up to the next newline is discarded.
287 *
288 * The name is historic and came from 'undo type opt h'.
289 */
290 static int
huntype(FILE * fpi,FILE * fpo,int cols,int hextype,long base_off)291 huntype(
292 FILE *fpi,
293 FILE *fpo,
294 int cols,
295 int hextype,
296 long base_off)
297 {
298 int c, ign_garb = 1, n1 = -1, n2 = 0, n3, p = cols;
299 long have_off = 0, want_off = 0;
300
301 rewind(fpi);
302
303 while ((c = getc(fpi)) != EOF)
304 {
305 if (c == '\r') /* Doze style input file? */
306 continue;
307
308 /* Allow multiple spaces. This doesn't work when there is normal text
309 * after the hex codes in the last line that looks like hex, thus only
310 * use it for PostScript format. */
311 if (hextype == HEX_POSTSCRIPT && (c == ' ' || c == '\n' || c == '\t'))
312 continue;
313
314 n3 = n2;
315 n2 = n1;
316
317 n1 = parse_hex_digit(c);
318 if (n1 == -1 && ign_garb)
319 continue;
320
321 ign_garb = 0;
322
323 if (!hextype && (p >= cols))
324 {
325 if (n1 < 0)
326 {
327 p = 0;
328 continue;
329 }
330 want_off = (want_off << 4) | n1;
331 continue;
332 }
333
334 if (base_off + want_off != have_off)
335 {
336 if (fflush(fpo) != 0)
337 perror_exit(3);
338 #ifdef TRY_SEEK
339 if (fseek(fpo, base_off + want_off - have_off, SEEK_CUR) >= 0)
340 have_off = base_off + want_off;
341 #endif
342 if (base_off + want_off < have_off)
343 error_exit(5, "sorry, cannot seek backwards.");
344 for (; have_off < base_off + want_off; have_off++)
345 if (putc(0, fpo) == EOF)
346 perror_exit(3);
347 }
348
349 if (n2 >= 0 && n1 >= 0)
350 {
351 if (putc((n2 << 4) | n1, fpo) == EOF)
352 perror_exit(3);
353 have_off++;
354 want_off++;
355 n1 = -1;
356 if (!hextype && (++p >= cols))
357 /* skip the rest of the line as garbage */
358 c = skip_to_eol(fpi, c);
359 }
360 else if (n1 < 0 && n2 < 0 && n3 < 0)
361 /* already stumbled into garbage, skip line, wait and see */
362 c = skip_to_eol(fpi, c);
363
364 if (c == '\n')
365 {
366 if (!hextype)
367 want_off = 0;
368 p = cols;
369 ign_garb = 1;
370 }
371 }
372 if (fflush(fpo) != 0)
373 perror_exit(3);
374 #ifdef TRY_SEEK
375 fseek(fpo, 0L, SEEK_END);
376 #endif
377 if (fclose(fpo) != 0)
378 perror_exit(3);
379 if (fclose(fpi) != 0)
380 perror_exit(2);
381 return 0;
382 }
383
384 /*
385 * Print line l. If nz is false, xxdline regards the line a line of
386 * zeroes. If there are three or more consecutive lines of zeroes,
387 * they are replaced by a single '*' character.
388 *
389 * If the output ends with more than two lines of zeroes, you
390 * should call xxdline again with l being the last line and nz
391 * negative. This ensures that the last line is shown even when
392 * it is all zeroes.
393 *
394 * If nz is always positive, lines are never suppressed.
395 */
396 static void
xxdline(FILE * fp,char * l,int nz)397 xxdline(FILE *fp, char *l, int nz)
398 {
399 static char z[LLEN+1];
400 static int zero_seen = 0;
401
402 if (!nz && zero_seen == 1)
403 strcpy(z, l);
404
405 if (nz || !zero_seen++)
406 {
407 if (nz)
408 {
409 if (nz < 0)
410 zero_seen--;
411 if (zero_seen == 2)
412 if (fputs(z, fp) == EOF)
413 perror_exit(3);
414 if (zero_seen > 2)
415 if (fputs("*\n", fp) == EOF)
416 perror_exit(3);
417 }
418 if (nz >= 0 || zero_seen > 0)
419 if (fputs(l, fp) == EOF)
420 perror_exit(3);
421 if (nz)
422 zero_seen = 0;
423 }
424 }
425
426 /* This is an EBCDIC to ASCII conversion table */
427 /* from a proposed BTL standard April 16, 1979 */
428 static unsigned char etoa64[] =
429 {
430 0040,0240,0241,0242,0243,0244,0245,0246,
431 0247,0250,0325,0056,0074,0050,0053,0174,
432 0046,0251,0252,0253,0254,0255,0256,0257,
433 0260,0261,0041,0044,0052,0051,0073,0176,
434 0055,0057,0262,0263,0264,0265,0266,0267,
435 0270,0271,0313,0054,0045,0137,0076,0077,
436 0272,0273,0274,0275,0276,0277,0300,0301,
437 0302,0140,0072,0043,0100,0047,0075,0042,
438 0303,0141,0142,0143,0144,0145,0146,0147,
439 0150,0151,0304,0305,0306,0307,0310,0311,
440 0312,0152,0153,0154,0155,0156,0157,0160,
441 0161,0162,0136,0314,0315,0316,0317,0320,
442 0321,0345,0163,0164,0165,0166,0167,0170,
443 0171,0172,0322,0323,0324,0133,0326,0327,
444 0330,0331,0332,0333,0334,0335,0336,0337,
445 0340,0341,0342,0343,0344,0135,0346,0347,
446 0173,0101,0102,0103,0104,0105,0106,0107,
447 0110,0111,0350,0351,0352,0353,0354,0355,
448 0175,0112,0113,0114,0115,0116,0117,0120,
449 0121,0122,0356,0357,0360,0361,0362,0363,
450 0134,0237,0123,0124,0125,0126,0127,0130,
451 0131,0132,0364,0365,0366,0367,0370,0371,
452 0060,0061,0062,0063,0064,0065,0066,0067,
453 0070,0071,0372,0373,0374,0375,0376,0377
454 };
455
456 int
main(int argc,char * argv[])457 main(int argc, char *argv[])
458 {
459 FILE *fp, *fpo;
460 int c, e, p = 0, relseek = 1, negseek = 0, revert = 0;
461 int cols = 0, nonzero = 0, autoskip = 0, hextype = HEX_NORMAL;
462 int capitalize = 0, decimal_offset = 0;
463 int ebcdic = 0;
464 int octspergrp = -1; /* number of octets grouped in output */
465 int grplen; /* total chars per octet group */
466 long length = -1, n = 0, seekoff = 0;
467 unsigned long displayoff = 0;
468 static char l[LLEN+1]; /* static because it may be too big for stack */
469 char *pp;
470 int addrlen = 9;
471
472 #ifdef AMIGA
473 /* This program doesn't work when started from the Workbench */
474 if (argc == 0)
475 exit(1);
476 #endif
477
478 pname = argv[0];
479 for (pp = pname; *pp; )
480 if (*pp++ == PATH_SEP)
481 pname = pp;
482 #ifdef FILE_SEP
483 for (pp = pname; *pp; pp++)
484 if (*pp == FILE_SEP)
485 {
486 *pp = '\0';
487 break;
488 }
489 #endif
490
491 while (argc >= 2)
492 {
493 pp = argv[1] + (!STRNCMP(argv[1], "--", 2) && argv[1][2]);
494 if (!STRNCMP(pp, "-a", 2)) autoskip = 1 - autoskip;
495 else if (!STRNCMP(pp, "-b", 2)) hextype = HEX_BITS;
496 else if (!STRNCMP(pp, "-e", 2)) hextype = HEX_LITTLEENDIAN;
497 else if (!STRNCMP(pp, "-u", 2)) hexx = hexxa + 16;
498 else if (!STRNCMP(pp, "-p", 2)) hextype = HEX_POSTSCRIPT;
499 else if (!STRNCMP(pp, "-i", 2)) hextype = HEX_CINCLUDE;
500 else if (!STRNCMP(pp, "-C", 2)) capitalize = 1;
501 else if (!STRNCMP(pp, "-d", 2)) decimal_offset = 1;
502 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("apitalize", pp + 2, 9))
512 capitalize = 1;
513 else if (pp[2] && STRNCMP("ols", pp + 2, 3))
514 cols = (int)strtol(pp + 2, NULL, 0);
515 else
516 {
517 if (!argv[2])
518 exit_with_usage();
519 cols = (int)strtol(argv[2], NULL, 0);
520 argv++;
521 argc--;
522 }
523 }
524 else if (!STRNCMP(pp, "-g", 2))
525 {
526 if (pp[2] && STRNCMP("roup", pp + 2, 4))
527 octspergrp = (int)strtol(pp + 2, NULL, 0);
528 else
529 {
530 if (!argv[2])
531 exit_with_usage();
532 octspergrp = (int)strtol(argv[2], NULL, 0);
533 argv++;
534 argc--;
535 }
536 }
537 else if (!STRNCMP(pp, "-o", 2))
538 {
539 int reloffset = 0;
540 int negoffset = 0;
541 if (pp[2] && STRNCMP("ffset", pp + 2, 5))
542 displayoff = strtoul(pp + 2, NULL, 0);
543 else
544 {
545 if (!argv[2])
546 exit_with_usage();
547
548 if (argv[2][0] == '+')
549 reloffset++;
550 if (argv[2][reloffset] == '-')
551 negoffset++;
552
553 if (negoffset)
554 displayoff = ULONG_MAX - strtoul(argv[2] + reloffset+negoffset, NULL, 0) + 1;
555 else
556 displayoff = strtoul(argv[2] + reloffset+negoffset, NULL, 0);
557
558 argv++;
559 argc--;
560 }
561 }
562 else if (!STRNCMP(pp, "-s", 2))
563 {
564 relseek = 0;
565 negseek = 0;
566 if (pp[2] && STRNCMP("kip", pp+2, 3) && STRNCMP("eek", pp+2, 3))
567 {
568 #ifdef TRY_SEEK
569 if (pp[2] == '+')
570 relseek++;
571 if (pp[2+relseek] == '-')
572 negseek++;
573 #endif
574 seekoff = strtol(pp + 2+relseek+negseek, (char **)NULL, 0);
575 }
576 else
577 {
578 if (!argv[2])
579 exit_with_usage();
580 #ifdef TRY_SEEK
581 if (argv[2][0] == '+')
582 relseek++;
583 if (argv[2][relseek] == '-')
584 negseek++;
585 #endif
586 seekoff = strtol(argv[2] + relseek+negseek, (char **)NULL, 0);
587 argv++;
588 argc--;
589 }
590 }
591 else if (!STRNCMP(pp, "-l", 2))
592 {
593 if (pp[2] && STRNCMP("en", pp + 2, 2))
594 length = strtol(pp + 2, (char **)NULL, 0);
595 else
596 {
597 if (!argv[2])
598 exit_with_usage();
599 length = strtol(argv[2], (char **)NULL, 0);
600 argv++;
601 argc--;
602 }
603 }
604 else if (!strcmp(pp, "--")) /* end of options */
605 {
606 argv++;
607 argc--;
608 break;
609 }
610 else if (pp[0] == '-' && pp[1]) /* unknown option */
611 exit_with_usage();
612 else
613 break; /* not an option */
614
615 argv++; /* advance to next argument */
616 argc--;
617 }
618
619 if (!cols)
620 switch (hextype)
621 {
622 case HEX_POSTSCRIPT: cols = 30; break;
623 case HEX_CINCLUDE: cols = 12; break;
624 case HEX_BITS: cols = 6; break;
625 case HEX_NORMAL:
626 case HEX_LITTLEENDIAN:
627 default: cols = 16; break;
628 }
629
630 if (octspergrp < 0)
631 switch (hextype)
632 {
633 case HEX_BITS: octspergrp = 1; break;
634 case HEX_NORMAL: octspergrp = 2; break;
635 case HEX_LITTLEENDIAN: octspergrp = 4; break;
636 case HEX_POSTSCRIPT:
637 case HEX_CINCLUDE:
638 default: octspergrp = 0; break;
639 }
640
641 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS || hextype == HEX_LITTLEENDIAN)
642 && (cols > COLS)))
643 {
644 fprintf(stderr, "%s: invalid number of columns (max. %d).\n", pname, COLS);
645 exit(1);
646 }
647
648 if (octspergrp < 1 || octspergrp > cols)
649 octspergrp = cols;
650 else if (hextype == HEX_LITTLEENDIAN && (octspergrp & (octspergrp-1)))
651 error_exit(1, "number of octets per group must be a power of 2 with -e.");
652
653 if (argc > 3)
654 exit_with_usage();
655
656 if (argc == 1 || (argv[1][0] == '-' && !argv[1][1]))
657 BIN_ASSIGN(fp = stdin, !revert);
658 else
659 {
660 if ((fp = fopen(argv[1], BIN_READ(!revert))) == NULL)
661 {
662 fprintf(stderr,"%s: ", pname);
663 perror(argv[1]);
664 return 2;
665 }
666 }
667
668 if (argc < 3 || (argv[2][0] == '-' && !argv[2][1]))
669 BIN_ASSIGN(fpo = stdout, revert);
670 else
671 {
672 int fd;
673 int mode = revert ? O_WRONLY : (O_TRUNC|O_WRONLY);
674
675 if (((fd = OPEN(argv[2], mode | BIN_CREAT(revert), 0666)) < 0) ||
676 (fpo = fdopen(fd, BIN_WRITE(revert))) == NULL)
677 {
678 fprintf(stderr, "%s: ", pname);
679 perror(argv[2]);
680 return 3;
681 }
682 rewind(fpo);
683 }
684
685 if (revert)
686 {
687 if (hextype && (hextype != HEX_POSTSCRIPT))
688 error_exit(-1, "sorry, cannot revert this type of hexdump");
689 return huntype(fp, fpo, cols, hextype,
690 negseek ? -seekoff : seekoff);
691 }
692
693 if (seekoff || negseek || !relseek)
694 {
695 #ifdef TRY_SEEK
696 if (relseek)
697 e = fseek(fp, negseek ? -seekoff : seekoff, SEEK_CUR);
698 else
699 e = fseek(fp, negseek ? -seekoff : seekoff,
700 negseek ? SEEK_END : SEEK_SET);
701 if (e < 0 && negseek)
702 error_exit(4, "sorry cannot seek.");
703 if (e >= 0)
704 seekoff = ftell(fp);
705 else
706 #endif
707 {
708 long s = seekoff;
709
710 while (s--)
711 if (getc(fp) == EOF)
712 {
713 if (ferror(fp))
714 {
715 perror_exit(2);
716 }
717 else
718 {
719 error_exit(4, "sorry cannot seek.");
720 }
721 }
722 }
723 }
724
725 if (hextype == HEX_CINCLUDE)
726 {
727 if (fp != stdin)
728 {
729 if (fprintf(fpo, "unsigned char %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
730 perror_exit(3);
731 for (e = 0; (c = argv[1][e]) != 0; e++)
732 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
733 perror_exit(3);
734 if (fputs("[] = {\n", fpo) == EOF)
735 perror_exit(3);
736 }
737
738 p = 0;
739 c = 0;
740 while ((length < 0 || p < length) && (c = getc(fp)) != EOF)
741 {
742 if (fprintf(fpo, (hexx == hexxa) ? "%s0x%02x" : "%s0X%02X",
743 (p % cols) ? ", " : &",\n "[2*!p], c) < 0)
744 perror_exit(3);
745 p++;
746 }
747 if (c == EOF && ferror(fp))
748 perror_exit(2);
749
750 if (p && fputs("\n", fpo) == EOF)
751 perror_exit(3);
752 if (fputs(&"};\n"[3 * (fp == stdin)], fpo) == EOF)
753 perror_exit(3);
754
755 if (fp != stdin)
756 {
757 if (fprintf(fpo, "unsigned int %s", isdigit((int)argv[1][0]) ? "__" : "") < 0)
758 perror_exit(3);
759 for (e = 0; (c = argv[1][e]) != 0; e++)
760 if (putc(isalnum(c) ? CONDITIONAL_CAPITALIZE(c) : '_', fpo) == EOF)
761 perror_exit(3);
762 if (fprintf(fpo, "_%s = %d;\n", capitalize ? "LEN" : "len", p) < 0)
763 perror_exit(3);
764 }
765
766 if (fclose(fp))
767 perror_exit(2);
768 if (fclose(fpo))
769 perror_exit(3);
770 return 0;
771 }
772
773 if (hextype == HEX_POSTSCRIPT)
774 {
775 p = cols;
776 e = 0;
777 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
778 {
779 if (putc(hexx[(e >> 4) & 0xf], fpo) == EOF
780 || putc(hexx[e & 0xf], fpo) == EOF)
781 perror_exit(3);
782 n++;
783 if (!--p)
784 {
785 if (putc('\n', fpo) == EOF)
786 perror_exit(3);
787 p = cols;
788 }
789 }
790 if (e == EOF && ferror(fp))
791 perror_exit(2);
792 if (p < cols)
793 if (putc('\n', fpo) == EOF)
794 perror_exit(3);
795 if (fclose(fp))
796 perror_exit(2);
797 if (fclose(fpo))
798 perror_exit(3);
799 return 0;
800 }
801
802 /* hextype: HEX_NORMAL or HEX_BITS or HEX_LITTLEENDIAN */
803
804 if (hextype != HEX_BITS)
805 grplen = octspergrp + octspergrp + 1; /* chars per octet group */
806 else /* hextype == HEX_BITS */
807 grplen = 8 * octspergrp + 1;
808
809 e = 0;
810 while ((length < 0 || n < length) && (e = getc(fp)) != EOF)
811 {
812 if (p == 0)
813 {
814 if (decimal_offset)
815 addrlen = sprintf(l, "%08ld:",
816 ((unsigned long)(n + seekoff + displayoff)));
817 else
818 addrlen = sprintf(l, "%08lx:",
819 ((unsigned long)(n + seekoff + displayoff)));
820 for (c = addrlen; c < LLEN; l[c++] = ' ');
821 }
822 if (hextype == HEX_NORMAL)
823 {
824 l[c = (addrlen + 1 + (grplen * p) / octspergrp)] = hexx[(e >> 4) & 0xf];
825 l[++c] = hexx[ e & 0xf];
826 }
827 else if (hextype == HEX_LITTLEENDIAN)
828 {
829 int x = p ^ (octspergrp-1);
830 l[c = (addrlen + 1 + (grplen * x) / octspergrp)] = hexx[(e >> 4) & 0xf];
831 l[++c] = hexx[ e & 0xf];
832 }
833 else /* hextype == HEX_BITS */
834 {
835 int i;
836
837 c = (addrlen + 1 + (grplen * p) / octspergrp) - 1;
838 for (i = 7; i >= 0; i--)
839 l[++c] = (e & (1 << i)) ? '1' : '0';
840 }
841 if (e)
842 nonzero++;
843 if (ebcdic)
844 e = (e < 64) ? '.' : etoa64[e-64];
845 /* When changing this update definition of LLEN above. */
846 l[addrlen + 3 + (grplen * cols - 1)/octspergrp + p] =
847 #ifdef __MVS__
848 (e >= 64)
849 #else
850 (e > 31 && e < 127)
851 #endif
852 ? e : '.';
853 n++;
854 if (++p == cols)
855 {
856 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
857 xxdline(fpo, l, autoskip ? nonzero : 1);
858 nonzero = 0;
859 p = 0;
860 }
861 }
862 if (e == EOF && ferror(fp))
863 perror_exit(2);
864 if (p)
865 {
866 l[c = (addrlen + 3 + (grplen * cols - 1)/octspergrp + p)] = '\n'; l[++c] = '\0';
867 xxdline(fpo, l, 1);
868 }
869 else if (autoskip)
870 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
871
872 if (fclose(fp))
873 perror_exit(2);
874 if (fclose(fpo))
875 perror_exit(3);
876 return 0;
877 }
878
879 /* vi:set ts=8 sw=4 sts=2 cino+={2 cino+=n-2 : */
880