/*
* Run thru the command-line args looking for filenames, and generate a
* hexdump of each file.  If there are no filenames, we will produce  a
* hexdump of stdin.
*
* We have a few interesting options.
*
* -a
*   ASCII.  The hex portion is omitted.  Also, ascii control chars are
*   shown in one of the standard manners, \r or ^B for example.
*
* -b<n>
*   Buffer  size of <n>.  The default is 64, which barely fits into 80
*   columns with the default settings.
*
* -w<n>
*   Word size of <n> bytes. A blank column will appear after this many
*   bytes in the output. The default is 8. 0 means no inserted blanks.
*
* -1
*   One-line hexdump, as in much IBM software; the hardest to read.
*
* -2 or -h
*   Horizontal dump. The hex data is shown on one line; the ascii data
*   is  above  it, with spaces inserted to produce alignment.  This is
*   the best format for cutting and pasting the hex values.
*
* -3 or -v
*   Vertical dump (the default). Each 64 bytes takes 3 lines:  one for
*   the  ascii data; one for the high-order hex digit, and one for the
*   low-order hex digit.  This format is the most compact and easy  to
*   read of the three.
*
* By John Chambers <jc@trillian.mit.edu>
*
*/
#include "V.h"
#include "sys_fcntl.h"

#define BUF 64
int  bs = BUF;
char *b;
char *filename = 0;
int  files = 0;
Flag ascfl = 0;	/* ASCII or HEX dump? */

main(ac,av)
	char**av;
{	int   a;
	int   c0, c1;
	int   fd;

	ac = Vinit(ac,av);
	hex_base = 1;

	for (a=1; a<ac; a++) {
		V4 "arg%3d=\"%s\"",a,av[a] D;
		c0 = av[a][0];
		if (c0 == '-' || c0 == '+') {
			switch (c1 = av[a][1]) {
				case 'a':
				case 'A':
					ascfl = 1;
					V2 "ASCII dump." D;
					break;
				case 'b':
				case 'B':	/* Buffer size for hex dumps */
					if (sscanf(av[a]+2,"%d",&bs) < 1)
						bs = 50;
					V2 "bs=%d.",bs D;
					Ifree(b);
					if (!(b = (CP)MallocM(bs,"buffer")))
						Fail;
					V3 "Buf: %08X bs=%d.",b,bs D;
					continue;
				case 'd':
				case 'D':
					Vopt(av[a]+2);
					continue;
				case '1':
				case '2': case 'h': case 'H':
				case '3': case 'v': case 'V':
					hex_fmt = c1;
					V2 "Format: %c",hex_fmt D;
					break;
				case 'w':
				case 'W':	/* Word size for hex dumps */
					if (sscanf(av[a]+2,"%d",&hex_word) < 1)
						hex_word = 8;
					V2 "hex_word=%d.",hex_word D;
					continue;
				default:
					V1 "Unknown option \"%s\" ignored.",av[a] D;
			}
			continue;
		}
		V3 "File \"%s\"",av[a] D;
		V3 "Format: %c",hex_fmt D;
		if ((fd = Open(av[a],O_RDONLY,0)) > 0) {
			V3 "File %d=`%s'",fd,av[a] D;
			hd(fd,av[a]);
			Close(fd);
		} else {
			V1 "Can't read \"%s\" [Err %d=%s]",av[a],Erreason D;
		}
		++files;
	}
	if (files <= 0) {
		V3 "No files, dump stdin:" D;
		hd(0,0);
	}
fail:
	Exit(0);
}
hd(fd,file)
	char *file;
{	long m=0, n;

	if (!b) {
		if (!(b = (CP)MallocM(bs,"buffer")))
			Fail;
		V3 "Buf: %08X bs=%d.",b,bs D;
	}
	if (file) {
		n = strlen(file);
		Write(1,file,n);
		Write(1,":\n",2);
	}
	while ((n = Read(fd,b,bs)) > 0) {
		if (ascfl)
		     Ascfpna(1,b,n,m);
		else Hexfpna(1,b,n,m);
		m += n;
	}
fail:
	return m;
}
