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