#include <dpmi.h>
#include <go32.h>
#include <stdio.h>

char *version="Writedsk 2.0";
unsigned char track[6400];
int chrntab[40];
int ptr;
int drive;
int adr;
int biosparams=0x522;
_go32_dpmi_registers r;

search_id()
{
	for(;ptr<6400;ptr++)
		if ( *(unsigned *)(track+ptr)==0
		&& *(unsigned *)(track+ptr+4)==0xFEA1A1A1) {
			ptr+=8;
			return *(unsigned *)(track+ptr);
		}
	return 0;
}

find_data()
{
	for(;ptr<6400;ptr++)
		if ( *(unsigned *)(track+ptr)==0xFBA1A1A1) {
			ptr+=4;
			return;
		}
}

int write_sector(char *buf,int chrn,int track,int head)
{
	int try, size= ((char *)&chrn)[3];
	dosmemput(buf,128<<size,adr);
	dosmemput(&size,1,biosparams+3);
	for(try=0;try<3;try++) {
		r.x.ax=0x0301; r.h.ch=track;
		r.h.cl=((char *)&chrn)[2];
		r.h.dh=head; r.h.dl=drive;
		r.x.es=adr>>4; r.x.bx=adr&0xF;
		_go32_dpmi_simulate_int(0x13,&r);
		if (r.h.ah==0) return 0;
		r.x.ax=0;
		_go32_dpmi_simulate_int(0x13,&r);
	}
	return -1;
}

format_track(char *chrnlist,int cyl,int head,int sectors)
{
return 0; /****** doesn't work with DD disks in HD drive ...
	int try;
	dosmemput(chrnlist,sectors*4,adr);
	for (try=0;try<3;try++) {
		r.x.bx=adr&0xF; r.x.es=adr>>4;
		r.h.ch=cyl; r.h.cl=1; r.h.dh=head; r.h.dl=drive;
		r.h.ah=5; r.h.al=sectors;
		_go32_dpmi_simulate_int(0x13,&r);
		if (r.h.ah==0) return 0;
		r.x.ax=0;
		_go32_dpmi_simulate_int(0x13,&r);
	}
	return -1;
******/
}

write_track(int cyl,int head)
{
	int sectors=0, errors, i, try;
	ptr=0;
	while((chrntab[sectors]=search_id())!=0) {
		find_data();
		ptr+= 128 << ((char *)(chrntab+sectors))[3];
		sectors++;
	}
	for(try=0;try<3;try++) {
		if (format_track((char *)chrntab,cyl,head,sectors)!=0) 
			continue;
		ptr=0; errors=0;
		for(i=0;i<sectors;i++) {
			search_id(); find_data();
			if (write_sector(track+ptr,chrntab[i],cyl,head)!=0) {
				errors++;
				break;
			}
		}
		if (errors==0) { putchar("."); fflush(stdout); return 0; }
	}
	i=2;
	dosmemput(&i,1,biosparams+3);
	printf("\nWrite error\n");
	exit(1);
}

unsigned char params[11];
read_drive_params()
{
int i;
	adr=_go32_info_block.linear_address_of_transfer_buffer & 0xFFFFF;
	r.h.ah=8; r.h.dl=drive;
	_go32_dpmi_simulate_int(0x13,&r);
/*
	biosparams=(r.x.es<<4)+r.x.di;
	dosmemget(biosparams,11,params);
	for(i=0;i<11;i++) printf("%x ",params[i]);
	printf("\n");
*/
	r.h.ah=0x18; r.h.ch=79; r.h.cl=9; r.h.dl=drive;
	_go32_dpmi_simulate_int(0x13,&r);
}

main(int argc,char *argv[])
{
	FILE *fd;
	int t,h,tracks,sides,geometry,n=2;
	char diskid[8], *signature="MFM_DISK";

	printf("%s\n",version);
	if (argc!=3) {
		printf("Usage: writedsk <disk-image> <floppy-drive:>\n");
		exit(1);
	}
	fd=fopen(argv[1],"rb");
	if (fd==NULL) {
		printf("Unable to open %s for reading\n",argv[1]);
		exit(1);
	}
	fread(diskid,8,1,fd);
	if (strncmp(diskid,signature,8)!=0) {
		printf("%s is not a disk image\n",argv[1]);
		exit(1);
	}
	if (strcmp(argv[2],"a:")==0 || strcmp(argv[2],"A:")==0)
		drive=0;
	else if (strcmp(argv[2],"b:")==0 || strcmp(argv[2],"B:")==0)
		drive=1;
	else {
		printf("Invalid floppy drive specification (%s)\n",argv[2]);
		exit(1);
	}
	fread(&sides,1,4,fd); fread(&tracks,1,4,fd); fread(&geometry,1,4,fd);
	fread(&track,256-20,1,fd);
	printf("Warning: this operation will erase all data on floppy !\n");
	printf("Press Return to continue, or Ctrl-C to quit\n");
	scanf("%s",track);
	read_drive_params();
	for (h=0;h<sides;h++) {
		for (t=0;t<tracks;t++) {
			fread(&track,6400,1,fd);
			write_track(t,h);
		}
		printf("\n");
	}
	dosmemput(&n,1,biosparams+3);
}
