home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / xxd / xxd.c < prev   
Encoding:
C/C++ Source or Header  |  2003-05-24  |  20.2 KB  |  768 lines

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