/*
 *  Jhd - Japanese Hexdecimal Dump
 *
 *    Written by Masato Minda
 *               minmin@strauss.uec.junet
 *
 *    Created Sep. 11, 1986  Version 1.0
 *            Sep. 14, 1988  Version 2.0
 *    modified
 *      Jan. 20, 1989  Ver. 2.1
 *        little bug fix in octal-word.
 *      Feb. 23, 1989  Ver. 2.2
 *        correct offset, file is stdin.
 */
static char rcsid[] =
	"@(#)$Id: jhd.c,v 2.3 1992/06/02 23:35:50 minmin Exp $";
/*
 *  definition of System type
 */
#define  UNIX    1        /*  in UNIX  */
#define  OS9     0        /*  in OS9 68000 */
#define  LSI     0        /*  in LSI-C  */

#define  EUC     1        /*  if set, kanji code is EUC (Shift-JIS default)  */

#include  <stdio.h>
#include  <ctype.h>

#define  BSIZE      16384       /*  input buffer size */

#define  T_ASCII        0       /*  ascii terminal  */
#define  T_KANA         1       /*  kana terminal  */
#define  T_KANJI        2       /*  kanji terminal  */

#define  HEXDMP         0       /*  dump in hexdecimal  */
#define  CHRDMP         1       /*  dump in charactor  */
#define  OCTDMP         2       /*  dump in octal word  */
#define  OCTBYT         3       /*  dump in octal byte  */
#define  OCTREV         4       /*  dump in octal reverse  */

#define  KSHIFT      0x8e       /*  JAE kana shift in  */

#if  OS9
#	define  EXSTAT   0
#	define  isatty(n)  (_gs_size(n) == -1)
#else
#	define  EXSTAT   1
#endif

#if   LSI
	unsigned char    Ibuf[BSIZE];
#endif

unsigned char    Buf[BSIZE];             /*  input buffer  */
unsigned char    Tbuf[64];
unsigned char   *Lbuf = NULL;            /*  last 16 byte  */

char   *Prgnam = "jhd";
long    Offset;                 /*  dump offset  */
long    Addr;                   /*  current address  */
int     Bsize = BSIZE;
int     Admode = 0;             /*  address display mode  */
FILE   *Fp;                     /*  file pointer  */
int     Ttype;                  /*  terminal type  */
int     Skip = 0;               /*  skip next data  (kanji2 printed)  */
int     Dwidth = 16;            /*  dump width in byte  */
int     Putast;                 /*  '*' display flag  */
int     Mode = HEXDMP;          /*  dump mode  */
int     Vflag = 0;              /*  visual option  */

#if  LSI
	extern unsigned char    _osmajor;    /*  MS-DOS version number  */
#endif

#if  EUC

int     Kskip = 0;

#ifdef  iskanji
#	undef  iskanji
#endif
#ifdef  iskanji2
#	undef  iskanji2
#endif
#ifdef iskana
#	undef  iskana
#endif
#ifdef iskana2
#	undef  iskana2
#endif

iskanji(c)
register int    c;
{
	c &= 0xff;
	return (c >= 0xa1 && c <= 0xfe);
}

#define  iskana(c)	(c == KSHIFT)

iskana2(c)
register int     c;
{
	c &= 0xff;
	return (c >= 0xa1 && c <= 0xdf);
}

#else  /*  EUC  */

/*
 *   for kanji kana mode
 */
#ifndef  iskanji
int    iskanji(c)
register int    c;
{
	c &= 0xff;
	return (c >= 0x81 && c <= 0x9f || c >= 0xe0 && c <= 0xfc);
}
#endif

#ifndef  iskanji2
int    iskanji2(c)
register int    c;
{
	c &= 0xff;
	return (c >= 0x40 && c <= 0x7e || c >= 0x80 && c <= 0xfc);
}
#endif

#ifndef  iskana
int    iskana(c)
register int    c;
{
	c &= 0xff;
	return (c >= 0xa1 && c <= 0xdf);
}
#endif

#endif  /*  EUC  */

/*
 *  set_ttype - check terminal type
 */
set_ttype ()
{
#if  UNIX || OS9
	char   *getenv ();
	char   *p;

	if ((p = getenv ("TTYPE")) == NULL) {
		Ttype = T_ASCII;
	} else if (!strcmp(p, "mskanji") || !strcmp(p, "jiskanji")) {
		Ttype = T_KANJI;
#if  EUC == 0
	} else if (!strcmp(p, "kana")) {
		Ttype = T_KANA;
#endif
	} else {
		Ttype = T_ASCII;
	}
#endif  /*  UNIX || OS9  */
#if  LSI
	Ttype = T_KANJI;
#endif
}

/*
 *  Kindex returns a pointer to the first occurrence of character
 *  c in string s, or zero if c does not occur in  the string.
 *  checks at shift-JIS code.
 */
char   *kindex(s, c)
register char   *s;
register int     c;
{
	while (*s) {
		if (*s == c) {
			return s;
		}
		if (iskanji(*s)) {
			++s;
		}
		++s;
	}
	return NULL;
}

putspc (n)
register int     n;
{
	while (n--) {
		putchar (' ');
	}
}

putoct (n, w)
register long   n;
int    w;
{
	register int     c;

	if (w > 1) {
		putoct (n >> 3, w - 1);
	}
	c = n & 0x7;
	putchar (c + '0');
}

puthex (n, w)
register long   n;
int    w;
{
	register int     c;

	if (w > 1) {
		puthex (n >> 4, w - 1);
	}
	c = n & 0xf;
	c += c <= 9 ? '0': '7';
	putchar (c);
}

/*
 *  chksame - check n byte same data
 */
int    chksame(new, old, n)
register unsigned char   *new;
register unsigned char   *old;
register int     n;
{
	if (old == NULL) {
		return 0;
	}
	while (n--) {
		if (*new++ != *old++) {
			return 0;
		}
	}
	return 1;
}

#if  EUC

/*
 *  dmpkanji - dump in kanji with JAE-Kanji
 */
dmpkanji (base, size)
register unsigned char   *base;
register int     size;
{
	register int    c;

	putchar (' ');
	while (size--) {
		c = *base++;
		if (Skip || Kskip) {
			Kskip = Skip = 0;
			putchar (' ');
		} else if (size == 0 && iskanji(c)) {
			Skip = c;
		} else if (size == 0 && iskana(c)) {
			Kskip = c;
		} else if (iskanji(c) && iskanji(*base)) {
			putchar (c);
			putchar (*base);
			--size;
			++base;
		} else if (iskana(c) && iskana2(c)) {
			putchar (c);
			putchar (*base);
			--size;
			++base;
		} else if (isprint(c)) {
			putchar (c);
		} else {
			putchar ('.');
		}
	}
}

dmpkana (base, size)
unsigned char   *base;
int     size;
{
	/*  not called in EUC  */
}

#else  /*  EUC  */

/*
 *  dmpkanji - dump in kanji with Shift-JIS
 */
dmpkanji (base, size)
register unsigned char   *base;
register int     size;
{
	register int    c;

	putchar (' ');
	while (size--) {
		c = *base++;
		if (Skip) {
			Skip = 0;
			putchar (' ');
		} else if (size == 0 && iskanji(c)) {
			Skip = c;
		} else if (iskanji(c) && iskanji2(*base)) {
			putchar (c);
			putchar (*base);
			--size;
			++base;
		} else if (iskana(c) || isprint(c)) {
			putchar (c);
		} else {
			putchar ('.');
		}
	}
}

/*
 *  dmpkana - dump in hankaku katakana
 */
dmpkana (base, size)
register unsigned char   *base;
register int     size;
{
	register int     c;

	putchar (' ');
	while (size--) {
		c = *base++;
		if (isprint(c) || iskana(c)) {
			putchar (c);
		} else {
			putchar ('.');
		}
	}
}

#endif  /*  EUC  */

/*
 *  dmpascii - dump in ascii charactor
 */
dmpascii (base, size)
register unsigned char   *base;
register int     size;
{
	register int     c;

	putchar (' ');
	while (size--) {
		c = *base++;
		if (isprint(c)) {
			putchar (c);
		} else {
			putchar ('.');
		}
	}
}

/*
 *  octdmp0 - dump octal in word
 */
octdmp0 (base, size)
register unsigned char   *base;
register int     size;
{
	while (size > 0) {
		putchar (' ');
		putoct ((long)((unsigned)(base[0] << 8) + (unsigned)base[1]), 6);
		base += 2;
		size -= 2;
	}
}

/*
 *  octdmp1 - dump octal in byte
 */
octdmp1 (base, size, adr)
register unsigned char   *base;
register int     size;
register int     adr;
{
	while (size--) {
		putchar (' ');
		putoct ((long)((unsigned)*base++), 3);
		if (++adr == 8) {
			putchar (' ');
		}
	}
}

/*
 *  octdmp2 - dump octal in reverse word
 */
octdmp2 (base, size)
register unsigned char   *base;
register int     size;
{
	while (size > 0) {
		putchar (' ');
		putoct ((long)((unsigned)(base[1] << 8) + (unsigned)base[0]), 6);
		base += 2;
		size -= 2;
	}
}

/*
 * hdmp - dump hexdecimal
 */
hexdmp (base, size, adr)
register unsigned char   *base;
register int     size;
register int     adr;
{
	while (size--) {
		putchar (' ');
		puthex ((long)((unsigned)*base++), 2);
		if (++adr == 8) {
			putchar (' ');
		}
	}
}

dmpmode (buf, size, adv)
register unsigned char   *buf;
register int     size;
register int     adv;
{
	Putast = 0;
#if  EUC
	if (Kskip) {
		if (iskana2(*buf)) {
			putchar (Kskip);
			putchar (*buf);
			putchar ('\n');
		} else {
			putchar ('.');
			putchar ('\n');
			Kskip = 0;
		}
	}
	if (Skip) {
		if (iskanji(*buf)) {
			putchar (Skip);
			putchar (*buf);
			putchar ('\n');
		} else {
			putchar ('.');
			putchar ('\n');
			Skip = 0;
		}
	}
#else  /*  EUC  */
	if (Skip) {
		if (iskanji2(*buf)) {
			putchar (Skip);
			putchar (*buf);
			putchar ('\n');
		} else {
			putchar ('.');
			putchar ('\n');
			Skip = 0;
		}
	}
#endif  /*  EUC  */
	if (Admode) {
		putoct (Addr, 11);
	} else {
		puthex (Addr, 8);
	}
	putchar (' ');
	buf += adv;
	switch (Mode) {

	case 0:  /*  hex dump with ascii */
		putspc (adv * 3 + (adv >= 8? 1: 0));
		hexdmp (buf, size, adv);
		putspc ((Dwidth - (size + adv)) * 3 + ((size + adv) < 8? 2: 1) + adv);
		dmpascii (buf, size);
		break;

	case 1:  /*  hex dump with kana */
		putspc (adv * 3 + (adv >= 8? 1: 0));
		hexdmp (buf, size, adv);
		putspc ((Dwidth - (size + adv)) * 3 + ((size + adv) < 8? 2: 1) + adv);
		dmpkana (buf, size);
		break;
	
	case 2:  /*  hex dump with kanji  */
		putspc (adv * 3 + (adv >= 8? 1: 0));
		hexdmp (buf, size, adv);
		putspc ((Dwidth - (size + adv)) * 3 + ((size + adv) < 8? 2: 1) + adv);
		dmpkanji (buf, size);
		break;

	case 3:  /*  char dump in ascii  */
		putspc (adv);
		dmpascii (buf, size);
		break;

	case 4:  /*  char dump in kana  */
		putspc (adv);
		dmpkana (buf, size);
		break;

	case 5:  /*  char dump in kanji  */
		putspc (adv);
		dmpkanji (buf, size);
		break;

	case 6:  /*  octal dump in word  */
	case 7:
	case 8:
		putspc ((adv / 2) * 7);
		octdmp0 (buf, size);
		break;

	case 9:  /*  octal dump in byte  */
	case 10:
	case 11:
		putspc (adv * 4 + (adv >= 8? 1: 0));
		octdmp1 (buf, size, adv);
		break;

	case 12: /*  octal dump in reverse word  */
	case 13:
	case 14:
		putspc (adv * 7);
		octdmp2 (buf, size);
		break;
	}
}

dmpall (buf, size)
register unsigned char   *buf;
register int     size;
{
	register int     ss;

	ss = Offset - Addr;
	if (size < Dwidth) {
		dmpmode (buf, size - ss, ss);
#if  EUC
		if (Kskip || Skip) {
			putchar ('.');
			Skip = Kskip = 0;
		}
#else
		if (Skip) {
			putchar ('.');
			Skip = 0;
		}
#endif
		putchar ('\n');
		Addr += size;
		return;
	}
	if (Addr != Offset) {
		dmpmode (buf, Dwidth - ss, ss);
#if  EUC 
		if (!Skip && !Kskip) {
			putchar ('\n');
		}
#else
		if (!Skip) {
			putchar ('\n');
		}
#endif
		Addr += Dwidth;
		buf += Dwidth;
		size -= Dwidth;
	}
	while (size >= Dwidth) {
		if (!Vflag && chksame(buf, Lbuf, Dwidth)) {
			if (!Putast) {
#if  EUC
				if (Skip || Kskip) {
					putchar ('.');
					putchar ('\n');
					Skip = Kskip = 0;
				}
#else
				if (Skip) {
					putchar ('.');
					putchar ('\n');
					Skip = 0;
				}
#endif
				putchar ('*');
				putchar ('\n');
				Putast = 1;
			}
		} else {
			dmpmode (buf, Dwidth, 0);
#if  EUC
			if (!Skip && !Kskip) {
				putchar ('\n');
			}
#else
			if (!Skip) {
				putchar ('\n');
			}
#endif
		}
		Lbuf = buf;
		Addr += Dwidth;
		buf += Dwidth;
		size -= Dwidth;
	}
	if (size != 0) {
		dmpmode (buf, size, 0);
#if  EUC
		if (Skip || Kskip) {
			putchar ('.');
			Skip = Kskip = 0;
		}
#else
		if (Skip) {
			putchar ('.');
			Skip = 0;
		}
#endif
		Addr += size;
		putchar ('\n');
	}
	Offset = Addr;
}

setlast (ptr)
register unsigned char   *ptr;
{
	register int    n;
	register unsigned char  *bp;

	n = Dwidth;
	Lbuf = bp = Tbuf;
	while (n--) {
		*bp++ = *ptr++;
	}
}

/*
 *  dump file
 */
dmpmain ()
{
	register int     size;

	Mode = Mode * 3 + Ttype;
	Addr = (Offset & ~(Dwidth - 1));
	while ((size = fread(Buf, 1, BSIZE, Fp)) != 0) {
		dmpall (Buf, size);
		setlast (Buf + size - Dwidth);
	}
	if (Putast) {
		--Addr;
		if (Admode) {
			putoct (Addr, 11);
		} else {
			puthex (Addr, 8);
		}
		putchar ('\n');
	}
}

/*
 *  setname return a tail name of path
 */
char   *setname(path)
register char   *path;
{
	register char   *pt;

	while ((pt = kindex(path, '/')) != NULL) {
		path = pt + 1;
	}
#if  LSI
	while ((pt = kindex(path, ':')) != NULL) {
		path = pt + 1;
	}
	while ((pt = kindex(path, '\\')) != NULL) {
		path = pt + 1;
	}
	if (kindex(path, '.') != NULL) {
		*kindex(path, '.') = '\0';
	}
	pt = path;
	while (*pt) {
		/* --- program name to lower case --- */
		if (isupper(*pt)) {
			*pt += ' ';
		}
		++pt;
	}
#endif
	return path;
}

usage ()
{
	fputs ("Usage: ", stderr);
	fputs (Prgnam, stderr);
#if  EUC
	fputs (" [ -abcjorvO ] [ <file> ] [ +[x|o]<offset>[k] ]\n", stderr);
#else
	fputs (" [ -abcjkorvO ] [ <file> ] [ +[x|o]<offset>[k] ]\n", stderr);
#endif
	exit (EXSTAT);
}

toobig ()
{
	fputs (Prgnam, stderr);
	fputs (": Offset too large!\n", stderr);
	exit (EXSTAT);
}

no_open (name)
char   *name;
{
	fputs (Prgnam, stderr);
	fputs (": ", stderr);
	fputs (name, stderr);
	fputs (": can't open.\n", stderr);
	exit (EXSTAT);
}

skipread (fp)
FILE   *fp;
{
	register long   offset;

	if (Offset == 0L) {
		return;
	}
	offset = Offset & ~(Dwidth - 1);
	while (offset > (long)BSIZE) {
		if (fread(Buf, 1, BSIZE, fp) < BSIZE) {
			toobig ();
		}
		offset -= BSIZE;
	}
	if (fread(Buf, 1, (int)offset, fp) < (int)offset) {
		toobig ();
	}
}

skipfile (fp)
FILE   *fp;
{
	if (fseek(fp, Offset & ~(Dwidth - 1), 0) != 0) {
		toobig ();
		/* --- not reached --- */
	}
}

chkofst (p)
register char   *p;
{
	long    atol();
	register unsigned     c;

	if (*p == 'x' || *p == 'X') {
		Offset = 0;
		++p;
		c = (unsigned)*p++;
		while (isxdigit(c)) {
			if (isdigit(c)) {
				Offset = (Offset << 4) + (c - '0');
			} else {
				Offset = (Offset << 4) +
				       ((islower(c)? toupper(c): c) - 'A' + 10);
			}
			c = (unsigned)*p++;
		}
	} else if (*p == 'o' || *p == 'O' || *p == '0') {
		Offset = 0;
		++p;
		while (isdigit(*p)) {
			Offset = ((Offset << 3) & ~7L) + ((*p - '0') & 7);
			++p;
		}
	} else {
		Offset = atol(p);
		while (isdigit(*p)) {
			++p;
		}
	}
	if (Offset && (*p == 'K' || *p == 'k')) {
		Offset <<= 10;
	}
}

main (argc, argv)
int     argc;
char  **argv;
{
#if  UNIX || OS9
	Prgnam = setname(*argv);
#endif
#if  LSI
	if (_osmajor > 2) {
		/* --- MS-DOS version 3.xx or later --- */
		Prgnam = setname(*argv);
	}
#endif
	set_ttype();
	while (--argc && **++argv == '-' && *(*argv + 1) != '\0') {
		while (*++*argv) switch (**argv) {

		case 'b':
			Mode = OCTBYT;
			Dwidth = 16;
			continue;

		case 'c':
			Mode = CHRDMP;
			Dwidth = 64;
			continue;

		case 'o':
			Mode = OCTDMP;
			Dwidth = 16;
			continue;

		case 'r':
			Mode = OCTREV;
			Dwidth = 16;
			continue;

		case 'a':
			Ttype = T_ASCII;
			continue;
#if  EUC == 0
		case 'k':
			Ttype = T_KANA;
			continue;
#endif
		case 'j':
			Ttype = T_KANJI;
			continue;

		case 'v':
			Vflag = 1;
			continue;

		case 'O':
			Admode = 1;
			continue;

		default:
			usage ();
		}
	}
	++argc;
	--argv;
	if (argc > 1 && argv[1][0] == '+') {
		chkofst (argv[1] + 1);
		--argc;
		++argv;
	} else if (argc > 2 && argv[2][0] == '+') {
		chkofst (argv[2] + 1);
	}
	if (argc == 1 && isatty(fileno(stdin))) {
		usage ();
		/* --- not reached --- */
	}
	if (argc == 1 || argc > 1 && **(argv + 1) == '-') {
		Fp = stdin;
#if  LSI
		Fp->mode |= _BINARY;
		setvbuf (Fp, Ibuf, _IOFBF, BSIZE);
#endif
		skipread (stdin);
		dmpmain ();
		exit (0);
	}
	--argc;
#if  OS9
	if ((Fp = fopen(*++argv, "r")) == NULL && (Fp = fopen(*argv, "d")) == NULL)
#endif
#if  LSI 
	if ((Fp = fopen(*++argv, "rb")) == NULL)
#endif
#if  UNIX
	if ((Fp = fopen(*++argv, "r")) == NULL)
#endif
	{
		no_open(*argv);
		/* --- not reached --- */
	}
	if (argc > 1 && argv[1][0] == '+') {
		chkofst (argv[1] + 1);
	}
#if  LSI
	setvbuf (Fp, Ibuf, _IOFBF, BSIZE);
#endif
	if (isatty(fileno(Fp))) {
		skipread (Fp);
	} else {
		skipfile (Fp);
	}
	dmpmain ();
	fclose (Fp);
	exit (0);
}


syntax highlighted by Code2HTML, v. 0.9.1