blob: c558426ad754b20878c6252b3b39a144ab1e8315 [file] [log] [blame]
Bram Moolenaar071d4272004-06-13 20:20:40 +00001/* 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
Bram Moolenaar82038d72007-05-10 17:15:45 +00008 * consecutive lines of zeroes, as unix od does.
Bram Moolenaar071d4272004-06-13 20:20:40 +00009 * -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
Bram Moolenaar4317d9b2005-03-18 20:25:31 +000043 * (azc10@yahoo.com)
Bram Moolenaar071d4272004-06-13 20:20:40 +000044 * 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
Bram Moolenaar82038d72007-05-10 17:15:45 +000051 * 16.05.00 Improved MMS file and merge for VMS by Zoltan Arpadffy
Bram Moolenaar071d4272004-06-13 20:20:40 +000052 *
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 */
Bram Moolenaar362e1a32006-03-06 23:29:24 +000061
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
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000067#if !defined(CYGWIN) && (defined(CYGWIN32) || defined(__CYGWIN__) || defined(__CYGWIN32__))
68# define CYGWIN
69#endif
Bram Moolenaar362e1a32006-03-06 23:29:24 +000070
Bram Moolenaar071d4272004-06-13 20:20:40 +000071#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
Bram Moolenaardc40a2b2009-06-16 16:29:10 +000083#if defined(MSDOS) || defined(WIN32) || defined(OS2) || defined(__BORLANDC__) \
84 || defined(CYGWIN)
Bram Moolenaar071d4272004-06-13 20:20:40 +000085# 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
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000157#if defined(MSDOS) || defined(WIN32) || defined(OS2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000158# 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)
Bram Moolenaar12033fb2005-12-16 21:49:31 +0000162# 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 '/'
Bram Moolenaar071d4272004-06-13 20:20:40 +0000169#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 */
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000216#define LLEN (11 + (9*COLS-1)/1 + COLS + 2)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000217
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 -p,-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
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000279#if 0 /* this doesn't work when there is normal text after the hex codes in
280 the last line that looks like hex */
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000281 if (c == ' ' || c == '\n' || c == '\t') /* allow multiple spaces */
Bram Moolenaarc9b4b052006-04-30 18:54:39 +0000282 continue;
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000283#endif
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000284
Bram Moolenaar071d4272004-06-13 20:20:40 +0000285 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 {
Bram Moolenaar899dddf2006-03-26 21:06:50 +0000344 /* skip rest of line as garbage */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000345 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("group", pp + 2, 5))
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
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000594 if (cols < 1 || ((hextype == HEX_NORMAL || hextype == HEX_BITS)
595 && (cols > COLS)))
Bram Moolenaar071d4272004-06-13 20:20:40 +0000596 {
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];
Bram Moolenaare9c3bcd2007-12-03 20:32:43 +0000755 /* When changing this update definition of LLEN above. */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000756 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)
Bram Moolenaar82038d72007-05-10 17:15:45 +0000780 xxdline(fpo, l, -1); /* last chance to flush out suppressed lines */
Bram Moolenaar071d4272004-06-13 20:20:40 +0000781
782 fclose(fp);
783 fclose(fpo);
784 return 0;
785}