/*
 * od [-5abmrwx] [-f bn] [-l bn] file
 */
#include <stdio.h>

#define	HUGE	32000
#define BSIZE	512

int	aflag;
int	bflag;
int	fflag;
int	mflag;
int	rflag;
int	wflag;
int	xflag;
char	*fn;
char	buf[BSIZE];
FILE	*fp;

int	fbn	= 0;
int	lbn	= HUGE;

char	*nn[]	= { "c ", "c#", "d ", "d#", "e ", "f ", "f#", "g ",
		    "g#", "a ", "a#", "b ", "??", "??", "??", "??" };
char	*an[]	= { "   ", "  a", "  b", " ab" };

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

	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 'm':
				case 'M':
					++mflag;
					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 && !mflag)
		++wflag;
	if((fp=fopen(fn, "ru")) == NULL)
		cant(fn);
	bp = "Record";
	if(!rflag && !frec(fp)) {
		bp = "Block";
		fattr(R_FIX, -1, BSIZE, fp);
	}
	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;

	rn = 0;
	while(rn < fbn) {
		fget(buf, BSIZE, fp);
		if(feof(fp))
			return;
		rn++;
	}
	while(rn <= lbn) {
		n = fget(buf, BSIZE, fp);
		if(feof(fp))
			return;
		printf("\n%s %d, length %d bytes\n\n", bp, rn++, 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, d;
	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/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/2;
			while(i--) {
				r50toa(ab, wp++, 1);
				printf("     %.3s", ab);
			}
			putchar('\n');
		}
		if(mflag) {
			if(of) {
				printf(fmt, o);
				of = 0;
			} else
				printf("      ");
			printf(" m");
			wp = ap;
			i = nb/2;
			while(i--) {
				d = *wp++;
				printf("%3s", an[(d>>12)&03]);
				printf("%2d %2s", (d>>4)&017, nn[d&017]);
			}
			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: od [-5abmrwx] [-f bn] [-l bn] file\n");
	exit(1);
}
