
#include "stdio.h"

#define	CPMDMA	0x80
#define	BYTES	0x4000
#define	MAXTRY	max_sectors*6

char databuf[BYTES];
char *secbuf;
char fstr[16];
int disk;
int track;
int sector;
int disk_size;
int max_sectors;
int max_tracks;
int max_disks;
int min_track;
int xlate;
int xlt;
int buffull;
int bufptr;
int bytecnt;

main(argc,argv)
int argc;
char *argv[];
{
char c;
int i,n;
int temps,tempt;

	buffull=FALSE;
	bufptr=bytecnt=0;
	secbuf=CPMDMA;
	max_disks=4;
	disk=curdsk();
	if (logdisk(disk)==ERROR) {
		printf(" disk error");
		exit();
	}
	if (argc>1)
		params();
	else
		commands();
	diskio();
	dumpsec();
	setmem(databuf,BYTES,0x1a);

	while (1) {
		printf("\n(%04x)*",bytecnt);
		switch (tolower(getchar())) {
			case 'n':
				bump(1);
				diskio();
				dumpsec();
				break;
			case 'b':
				bump(-1);
				diskio();
					dumpsec();
				break;
			case ' ':
			case '\n':
				dumpsec();
				break;
			case '-':
				if (scanf("%d",&n)!=0) {
					bump(-n);
					diskio();
					dumpsec();
				}
				break;
			case '+':
				if (scanf("%d",&n)!=0) {
					bump(n);
					diskio();
					dumpsec();
				}
				break;
			case 't':
				if (scanf("%d",&n)!=0) {
					track=n;
					if (track>max_tracks)
						track=max_tracks;
					if (track<min_track)
						track=min_track;
					diskio();
					dumpsec();
				}
				break;
			case 's':
				if (scanf("%d",&n)!=0) {
					sector=n;
					if (sector>max_sectors)
						sector=max_sectors;
					if (sector<1)
						sector=1;
					diskio();
					dumpsec();
				}
				break;
			case 'r':
				i=1000;
				c='5';
				while (1) {
					for (n=0;n<i;n++) {
						if (kbhit()) {
							c=getchar();
							if (c>'0' && c<='9')
								i=(c-'0')*250;
							else
								c=0;;
						}
					}
					if (c==0)
						break;
					bump(1);
					diskio();
					dumpsec();
				}
				break;
			case 'g':
				if (buffull) {
					printf(" buffer full");
						break;
				}
				if (scanf("%d",&n)==0)
					break;
				tempt=track;
				temps=sector;
				for (i=0;i<n;i++) {
					append();
					bump(1);
					diskio();
				}
				track=tempt;
				sector=temps;
				diskio();
				break;
			case 'a':
				if (buffull) {
					printf(" buffer full");
						break;
				}
				append();
				break;
			case 'u':
				if (bytecnt==0) {
					printf(" buffer empty");
					break;
				}
				bytecnt-=SECSIZ;
				setmem(&databuf[bytecnt],SECSIZ,0x1a);
				buffull=FALSE;
				break;
			case 'e':
				if (bytecnt==0) {
					printf(" buffer empty");
					break;
				}
				bytecnt=0;
				buffull=FALSE;
				setmem(databuf,BYTES,0x1a);
				break;
			case 'd':
				if (bytecnt==0)
					printf(" buffer empty");
				else
					dump();
				break;
			case 'p':
				if (bytecnt==0) {
					printf(" buffer empty");
					break;
				}
				putfile();
				diskio();
				break;
			case 'f':
				gets(fstr);
				if (fstr[0]!=0) {
					find(fstr);
					dumpsec();
				}
				break;
			case 'l':
				n=tolower(getchar())-'a';
				if (n<0 || n>max_disks)
					break;
				if (logdisk(n)==ERROR)
					printf(" no disk %c",n+'A');
				else
					disk=n;
				break;
			case '?':
				commands();
				break;
			case 'q':
				exit();
				break;
			default:
				break;
		}
	}

}
commands()
{
	printf("\n Commands:\n");
	printf("\t 'la' log disk a\t 'a' append sector\n");
	printf("\t 'tn' set track n\t 'u' unappend sector\n");
	printf("\t 'sn' set sector n\t 'e' empty buffer\n");
	printf("\t  'n' next sector\t 'd' display buffer\n");
	printf("\t  'b' back sector\t 'p' put to file\n");
	printf("\t '+n' move +n sectors\t 'r' range\n");
	printf("\t '-n' move -n sectors\t'fs' find string s\n");
	printf("\t 'gn' get n sectors\t '?' help\n");
}
/* Log in a disk.  Looks at the Disk Parameter Header/Block
to see whether or not there is logical to physical sector 
translation and gets the numbers for max-sectors and max-track.  */

logdisk(disk)
int disk;
{
int *dph;
char *dpb;
int spt,dsm,off,bls;
char bsh;

	dph=seldsk(disk);		/* get header addr */
	if (dph==0)			/* if 0, no disk-drive */
		return ERROR;
	xlt=dph[0];			/* translation addr */
	if (xlt==0)			/* do we? */
		xlate=FALSE;
	else
		xlate=TRUE;
	dpb=dph[5];			/* block addr */
	spt=dpb[0];
	bsh=dpb[2];
	dsm=dpb[5];
	off=dpb[13];
	bls=1024*power(2,(bsh-3));
	disk_size=(dsm+1)*power(2,(bsh-3));
	max_tracks=(((dsm+1)*(bls/128))/spt)+off;
	max_sectors=spt;
	min_track=off;
	track=min_track;		/* tracks run 0-n */
	sector=1;			/* sectors 1-n */
	return TRUE;
}

diskio()
{
int i;

	settrk(track);
	if (xlate)
		setsec(sectran(sector-1,xlt));
	else
		setsec(sector-1);
	if (i=lread())
		printf(" read error");
}
bump(amt)
int amt;
{
	sector+=amt;
	if (sector>max_sectors) {
		sector-=max_sectors;
		if (++track>max_tracks)
			track=min_track;
	}
	else if (sector<1) {
		sector+=max_sectors;
		if (--track<min_track)
			track=max_tracks;
	}
}
dump()
{
int n,b,l;

	scanf("%x",&bufptr);
	for (l=0;l<16;l++) {
		n=bufptr;
		if (l==8)
			putchar('\n');
		putchar('\n');
		outhex(bufptr);
		for (b=0;b<16;b++)
			phex(databuf[bufptr++]);
		for (b=0;b<16;b++)
			pasc(databuf[n++]);
	}
	putchar('\n');
}

dumpsec()
{
int l,i,j,t;

	i=t=0;
	printf("\n\ttrack %d, sector %d",track,sector);
	for (l=0;l<8;l++) {
		putchar('\n');
		outhex(i);
		for (j=0;j<16;j++)
			phex(secbuf[i++]);
		for (j=0;j<16;j++)
			pasc(secbuf[t++]);
	}
	putchar('\n');
}
outhex(i)
int i;
{
	pbyte(i>>8);
	pbyte(i);
	printf(": ");
}
phex(c)
char c;
{
	pbyte(c);
	putchar(' ');
}
pbyte(c)
char c;
{
char h;

	h=(c>>4)&0x0f;
	putchar((h>9) ? h+'a'-10 : h+'0');
	h=c&0x0f;
	putchar((h>9) ? h+'a'-10 : h+'0');
}
pasc(c)
char c;
{
	if ((c&0x7f)<' ')
		c='.';
	putchar(c);
}
power(x,n)
int x,n;
{
int p;

	for (p=1;n>0;--n)
		p=p*x;
	return(p);
}
putfile()
{
	char filename[16];
	char iobuf[BUFSIZ];
	int i;
	gets(filename);
	if (!strlen(filename))
		return;
	if (fcreat(filename,iobuf)==ERROR) {
		printf(" cant create %s",filename);
		return;
	}
	for (i=0;i<(bytecnt+SECSIZ);i++)
		putc(databuf[i],iobuf);
	fflush(iobuf);
	fclose(iobuf);
}
params()
{
	printf("\n\tcurrent disk: %c\n",disk+'A');
	printf("\tdisk size: %dK\n",disk_size);
	printf("\tnumber sectors: %d\n",max_sectors);
	printf("\tnumber tracks: %d\n",max_tracks);
	printf("\treserved tracks: %d\n",min_track);
	if (!xlate)
		printf("\tno sector translation\n");
}
find(s)
char *s;
{
int i,j;

	j=0;
	do {
		bump(1);
		diskio();
		if (j++==MAXTRY) {
			printf(" %s not found, continue? ",s);
			if (tolower(getchar())=='n')
				return;
			j=0;
		}
		if (kbhit())
			return;
	}
	while (i=index(secbuf,s)== -1);
	printf("%d",i);
}
index(s,t)
char s[],t[];
{
	int i,j,k;
	for (i=0;s[i]!=0;i++) {
		for (j=i,k=0;t[k]!=0 && s[j]==t[k];j++,k++)
			;
		if (t[k]==0)
			return i;
	}
	return -1;
}
append()
{
int i;
	for (i=0;i<SECSIZ;i++) {
		databuf[bytecnt++]=secbuf[i];
		if (bytecnt==BYTES) {
			printf(" buffer full");
			buffull=TRUE;
			return;
		}
	}
}
                                                            
