/*--- EDIT # 0039	22 Nov 1981    0:26:24	VD0:[6,1]OD.C;53  */
/*--- PREVIOUS EDIT	22 Nov 1981    0:17:58	VD0:[6,1]OD.C;52  */
/* MODIFIED BY RAY VAN TASSLE 20 Nov 1981, so it would work on block-mode
	dumps. This required a fix in FOPEN & GETC.
*/
#
/*
 *
 *
 * The  information  in  this  document  is  subject  to  change
 * without  notice  and  should not be construed as a commitment
 * by Digital Equipment Corporation or by DECUS.
 * 
 * Neither Digital Equipment Corporation, DECUS, nor the authors
 * assume any responsibility for the use or reliability of  this
 * document or the described software.
 * 
 * 	Copyright (C) 1980, DECUS
 * 
 * 
 * General permission to copy or modify, but not for profit,  is
 * hereby  granted,  provided that the above copyright notice is
 * included and reference made to  the  fact  that  reproduction
 * privileges were granted by DECUS.
 *
 */

#
/*
 * od [-5abrwx] [-f bn] [-l bn] file
 *
 *		od		File dumper
 *
 * This programme is a  replacement for DMP.  It does most things that are
 * done by DMP, and does them in a more reasonable way; in particular, you
 * can dump in more than one format at once.
 *
 * Its options are:
 *		-a		Dump ASCII characters
 *		-b		Dump octal bytes
 *		-f #		Set first block, default is 0
 *		-l #		Set last block, default is EOF
 *		-r		Dump by record
 *		-w		Dump octal words
 *		-x		Dump hexadecimal bytes
 *		-5		Dump radix 50 words.
 *
 * If no dump selection options are present, od defaults to -w.
 *
 * od only runs on the RSX library.
 *
 */
#include <stdio.h>

#define	HUGE	32000
#define BSIZ	512

int	aflag;
int	bflag;
int	fflag;
int	rflag;
int	wflag;
int	xflag;
int	max_size;
char	*fn;
char	*buf = NULL;
FILE	*fp;

int	fbn	= 0;
int	lbn	= HUGE;

main(argc, argv)
char *argv[];
{
	register int i, c;
	register char *p;
	char *bp;

	TIATT();	/* ATTACH THE TERMINAL SO CTRL/O WILL WORK */
	fn = NULL;
	for(i=1; i<argc; ++i) {
		p = argv[i];
		if(*p == '-') {
			++p;
			while(c = *p++)
				switch(c) {

				case '5':
					++fflag;
					break;

				case 'a':
				case 'A':
					++aflag;
					break;

				case 'b':
				case 'B':
					++bflag;
					break;

				case 'r':
				case 'R':
					++rflag;
					break;

				case 'w':
				case 'W':
					++wflag;
					break;

				case 'x':
				case 'X':
					++xflag;
					break;

				case 'f':
				case 'F':
					if(++i >= argc)
						usage();
					fbn = atoi(argv[i]);
					break;

				case 'l':
				case 'L':
					if(++i >= argc)
						usage();
					lbn = atoi(argv[i]);
					break;

				default:
					usage();
				}
		} else if(fn != NULL)
			usage();
		else
			fn = p;
	}
	if(fn == NULL)
		usage();
	if(lbn < fbn)
		usage();
	if(!aflag && !bflag && !fflag && !wflag && !xflag)
		++wflag;
	if((fp=fopen(fn, rflag ? "run" : "rbnu")) == NULL)
		cant(fn);
	max_size = fp->io_rbsz;
 /* For the INDEX file, kludge up the fdb */
	if (fp->io_fdb[33] == 1)
		fp->io_fdb[2] = fp->io_fdb[4] = 0123;
/* MEMDMP (fp, fp+3); */
	if ((buf = malloc(max_size)) == NULL)
		error("Can't allocate record buffer of %d bytes\n",
				max_size);
	bp = "Record";
	/*
	 * Note: the following does not work on the "standard" library.
	 */
	if(!rflag && !frec(fp)) {
		bp = "Block";
		/* max_size = BSIZ			*/
		/* fattr(R_FIX, -1, BSIZ, fp);		*/
		/* if ((buf = malloc(BSIZ)) == NULL)	*/
		/*	error("Can't allocate buf\n");	*/
	}
	dump(bp);
}

/*
 * Do the dump.
 * `bp' is the banner string
 * (either "block" or "record").
 * Block files have been fattr'ed
 * to R_FIX and 512 byte records.
 */
dump(bp)
char *bp;
{
	register int n, rn;
	long		place;
	long		ftell();

	rn = 0;
	while(rn < fbn) {
		fget(buf, max_size, fp);
		if(feof(fp))
			return;
		rn++;
	}
	while(rn <= lbn) {
		place = ftell(fp);
		n = fget(buf, max_size, fp);
		if(feof(fp))
			return;
		buf[n] = NULL;
/* For block-mode, we are off by 1 block number */
		if (!rflag) place -= 512;
		printf("\n%s %d at %ld. %012lo, [%06o %06o] length %d bytes\n\n",
			bp, rn++, place, place, place, n);
		format(buf, n);
	}
}

/*
 * Dump out an `n' byte
 * item according to the flags
 * set by the user.
 */
format(ap, n)
char *ap;
{
	register int  *wp;
	register char *bp;
	register int  i;
	int o, of, nb, c;
	char ab[3], *fmt;

	if(!bflag && !wflag && xflag)
		fmt = "%04x  ";
	else
		fmt = "%06o";
	o = 0;
	while(n) {
		nb = min(16, n);
		of = 1;
		if(wflag) {
			printf(fmt, o);
			of = 0;
			printf(" w");
			wp = ap;
			i = (nb+1)/2;
			while(i--)
				printf("  %06o", *wp++);
			putchar('\n');
		}
		if(aflag) {
			if(of) {
				printf(fmt, o);
				of = 0;
			} else
				printf("      ");
			printf(" a");
			bp = ap;
			i = nb;
			while(i--) {
				c = *bp++ & 0377;
				if(c<' ' || c>'~')
					printf(" %03o", c);
				else
					printf("   %c", c);
			}
			putchar('\n');
		}
		if(bflag) {
			if(of) {
				printf(fmt, o);
				of = 0;
			} else
				printf("      ");
			printf(" b");
			bp = ap;
			i = nb;
			while(i--)
				printf(" %03o", *bp++ & 0377);
			putchar('\n');
		}
		if(fflag) {
			if(of) {
				printf(fmt, o);
				of = 0;
			} else
				printf("      ");
			printf(" 5");
			wp = ap;
			i = (nb+1)/2;
			while(i--) {
				r50toa(ab, wp++, 1);
				printf("     %.3s", ab);
			}
			putchar('\n');
		}
		if(xflag) {
			if(of)
				printf(fmt, o);
			else
				printf("      ");
			printf(" x");
			bp = ap;
			i = nb;
			while(i--)
				printf("  %02x", *bp++ & 0377);
			putchar('\n');
		}
		o  += 16;
		ap += 16;
		n  -= nb;
	}
}

/*
 * Compute the minimum of
 * two numbers.
 * Should be in the library.
 */
min(a, b)
{
	if(a < b)
		return(a);
	return(b);
}

/*
 * Cannot open diagnostic.
 * Just exit.
 */
cant(p)
char *p;
{
	fprintf(stderr, "%s: cannot open\n", p);
	exit(1);
}

/*
 * Usage diagnostic.
 * Just exit.
 */
usage()
{
	fprintf(stderr, "Usage: dump [-5abrwx] [-f bn] [-l bn] file\n");
	exit(1);
}
