/*----------------------------------------------------------------------*\
 | Hexadecimal file dump with a few useful options						|
 |																		|
 | Usage: hexdump [-n] [-h | -a] filename								|
 |		-n	Include byte offset on each line							|
 |		-h	Hexadecimal output only										|
 |		-a	ASCII output only											|
 |		-o	Offset into file to start dumping							|
 |		-l	Number of bytes to dump										|
\*----------------------------------------------------------------------*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

main (int argc, char *argv[]) {
	int i,j,c,n;
	FILE *in;
	char string[17];
	char nfmt[8];
	char input_file[128];
	int addr = 0;
	int ascii = 1;
	int hex = 1;
	struct stat fileinfo;
	int offset,length;

	*input_file = 0;
	offset = 0;
	length = 0;

	for (i=1; i < argc; i++)
		if (memcmp (argv[i],"-h",2) == 0) ascii = 0;
		else
			if (memcmp (argv[i],"-a",2) == 0) hex = 0;
			else
				if (memcmp (argv[i],"-n",2) == 0) addr = 1;
				else
					if (memcmp (argv[i],"-o",2) == 0) {
						i++;
						j = atoi (argv[i]);
						if (j > 0) offset = j;
						}
					else
						if (memcmp (argv[i],"-l",2) == 0) {
							i++;
							j = atoi (argv[i]);
							if (j > 0) length = j;
							}
						else
							strcpy (input_file,argv[i]);

	if (*input_file) {
		if (addr)
			if (!stat (input_file,&fileinfo)) {
				c = 0x10000000;
				for (j=8; j > 0; j--) {
					if (fileinfo.st_size >= c) break;
					else c /= 16;
					}
				sprintf (nfmt,"%%%dX: ",j);
				}
			else {
				printf ("Error: cannot get file stat block\n");
				exit (1);
				}
		if (!(in = fopen (input_file,"r"))) {
			printf ("Error: could not open file %s\n",input_file);
			exit (1);
			}
		i = 0;
		n = 0;
		if (offset) {
			fseek (in,offset,SEEK_SET);
			n = ftell (in);
			}
		if (addr) printf (nfmt,n);
		while ((c = fgetc (in)) != EOF) {
			if (hex) printf ("%02X ",(unsigned char) c);
			string[i++] = (isprint(c) ? c : '.');
			string[i] = 0;
			if ((i % 16) == 0) {
				if (ascii) printf ("\t%s\n",string);
				else printf ("\n");
				i = 0;
				string[i] = 0;
				if (addr) printf (nfmt,n);
				}
			n++;
			if (length)
				if (n - offset >= length) break;
			}
		if (ascii) {
			i %= 16;
			if (i == 0) i = 16;
			for (j=0; j < 16-i; j++) printf ("   ");
			printf ("\t%s\n",string);
			}
		}
	else
		printf ("Usage: %s [-n] [-a | -h] [-o offset] [-l length] filename\n",argv[0]);
	}

/*----------------------------------------------------------------------*\
\*----------------------------------------------------------------------*/

