#include <bios.h>
#include <dos.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef struct {
	int lsn;
	char size;
} cluster;

typedef union {
	struct {
		char flags;
		char name[8];
		char ext[3];
		cluster pointer[4];
		char slink;
	} h;
	struct {
		char flags;
		cluster pointer[7];
		int notused;
		char slink;
	} c;
} dirent;

char *errstr[]={ "General disk error", "Read error", "Invalid drive",
			   "Not a DRAGONDOS disk", "Invalid entry access" };
int err=0;

/*	note: dragon drives are numbered 1-4, so the initial working drive value
	of 0 indicates no valid drive */

int wdrv=0, wtrck=-1, whead=-1, notracks, nosecs, dread=0;
/*	enough buffer for one track (18 sectors) and directory track */
char tbuf[4608], dbuf[4608];

/*	get sector from track buffer or read new track - NULL on error */
char *getabs(int track, int sector) {
	int retry=2;

	if(wdrv<1) {
		err=2;
		return NULL;
	}
	if(dread && (track<0 || track>=notracks || sector<1 || sector>nosecs)) {
		err=1;
		return NULL;
	}
	if(track==20 && sector<19) {
		if(!dread) {
			do {
				if(!retry--) {
					err=1;
					return NULL;
				}
			} while(biosdisk(2, wdrv-1, 0, 20, 1, 18, dbuf));
			dread=1;
		}
		return &dbuf[--sector<<8];
	}
	if(track!=wtrck || whead!=(sector-1)/18) {
		do {
			if(!retry--) {
				wtrck=-1;
				err=1;
				return NULL;
			}
		} while(biosdisk(2, wdrv-1, (sector-1)/18, track, 1, 18, tbuf));
		wtrck=track;
		whead=(sector-1)/18;
	}
	return &tbuf[--sector<<8];
}

/*	get sector from lsn - otherwise same as getabs */
char *getsec(int lsn) {
	return getabs(lsn/nosecs, (lsn%nosecs)+1);
}

/*	set current working drive.  reads track 20 and gets number of tracks and
	sectors per track from sector 1 */
int setwdrv(int drive) {
	char *buf;

	/* error if drive out of range */
	if(drive<1 || drive>4) {
		err=2;
		return -1;
	}
	/* disk reset */
	biosdisk(0, drive-1, 0, 0, 0, 0, NULL);
	wdrv=drive;
	if((buf=getabs(20, 1))==NULL)
		return -1;
	notracks=buf[252];
	nosecs=buf[253];
	/*	check for dragondos disk */
	if((notracks+buf[254]+1)&0xff+(nosecs+buf[255]+1)&0xff) {
		err=3;
		return -1;
	}
	return 0;
}

/*	return little-endian copy of big-endian integer (for lsns) */
int bigend(int num) {
	return (num&0xff00)>>8|(num&0xff)<<8;
}

/*	return directory entry */
dirent *getent(int entry) {
	dirent *ebuf;

	if(entry<0 || entry>159) {
		err=4;
		return NULL;
	}
	ebuf=(dirent *)getabs(20, (entry/10)+3);
	return &ebuf[entry%10];
}

int main(void) {
	char fname[13];
	char far *dparm=MK_FP(0, 0x78);
	dirent *ent;
	int i;

	dparm=MK_FP(dparm[3]<<8|dparm[2], dparm[1]<<8|dparm[0]);
	dparm[3]=1;

	if(setwdrv(2))
		goto errexit;

	if((ent=getent(0))==NULL)
		goto errexit;
	for(i=0; i<160 && !(ent->h.flags&0x20); i++) {
		if((ent=getent(i))==NULL)
			goto errexit;
		if(!(ent->h.flags&0x81)) {
			strncpy(fname, ent->h.name, 8);
			fname[8]=0x00;
			strcat(fname,".");
			strncat(fname, ent->h.ext, 3);
			fname[12]=0x00;
			puts(fname);
		}
	}
	goto normex;
errexit:
	puts(errstr[err]);
	dparm[3]=2;
	exit(1);
normex:
	dparm[3]=2;
	return 0;
}
