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