#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <time.h>
#include <dos.h>

extern long time();
extern char *optarg;

/* Atari disk functions */

#define SECTORS_PER_TRACK 18
#define SECT 720

static unsigned char bootblock1[128] = {
	0x00,0x03,0x00,0xe0,0x07,0x4c,0x80,0x30,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x08,0x09,0x0a,0x0b,0x0c,
	0x45,0x72,0x72,0x6f,0x72,0x3a,0x20,0x4e,
	0x6f,0x20,0x44,0x4f,0x53,0x9b,0xad,0x28,
	0x30,0x8d,0x0a,0x03,0xad,0x29,0x30,0x8d,
	0x0b,0x03,0xa9,0x00,0xa2,0x2f,0x20,0xf1,
	0x30,0xad,0x00,0x2f,0x8d,0x28,0x30,0xad,
	0x01,0x2f,0x8d,0x29,0x30,0xa0,0x04,0x84,
	0x91,0xa4,0x91,0xcc,0x1f,0x30,0xf0,0xd6,
	0xb9,0x00,0x2f,0x8d,0x0a,0x03,0xb9,0x01,
	0x2f,0x8d,0x0b,0x03,0xc8,0xc8,0x84,0x91,
	0x60,0x6c,0xe2,0x02,0x11,0x12,0x01,0x02};

static unsigned char bootblock2[128] = {
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

static unsigned char bootblock3[128] = {
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};

char dosfb_buf[11];
char tmpfb_buf[11];

static unsigned char sector[4*256];
static unsigned char *sectp = sector;
static char updated = 0;

static int sectbase = SECT;
static unsigned char head = 0;
static int driveno = 0;

static unsigned int main_sect_map;
static unsigned int total_sectors;
static unsigned int free_sectors;
static unsigned char num_bit_maps;
static unsigned int first_bit_map;
static unsigned int data_sect_1st;
static unsigned int dir_sect_1st;
static unsigned char vol_name[9];
int tracks = 40;
static unsigned char sect_size_flag;
static unsigned char sd_rev;
static unsigned char default_drive;
static unsigned char vol_seq_num;
static unsigned char vol_ran_num;
static unsigned int boot_sect_map;

int track_offset = -40;
int sector_offset = -1;

static char debug=0, debug1=0, pflag=0;

int abort_mode = 0;

struct dir_entry
{
	unsigned char fstatus;
#define PROTECTED 0x01
#define IN_USE    0x08
#define DELETED   0x10
#define SUBDIR    0x20
	unsigned short int fsector_map;
	unsigned char flen[3];
	unsigned char fname[8];
	unsigned char fext[3];
	unsigned char fcr_date[3];
	unsigned char fcr_time[3];
};

struct sector_map
{
	unsigned short int snext;
	unsigned short int sprev;
	unsigned short int sects[126];
};

unsigned char fmt_seq[26] = {7,2,15,10,5,18,13,8,3,16,11,6,1,14,9,4,17,12,255,0,0,0,0,0};

static char temp[80];

void press_return()
{
	if (pflag)
	{
		printf("Press return...");
		gets(temp);
	}
}

void update_time(dirp)
struct dir_entry *dirp;
{
	struct tm *tm_p;
	long time_val;

	time(&time_val);
	tm_p = localtime(&time_val);

	dirp->fcr_date[0] = tm_p->tm_mday;
	dirp->fcr_date[1] = tm_p->tm_mon;
	dirp->fcr_date[2] = tm_p->tm_year;
	dirp->fcr_time[0] = tm_p->tm_hour;
	dirp->fcr_time[1] = tm_p->tm_min;
	dirp->fcr_time[2] = tm_p->tm_sec;
}

void dump_sect(flag)
int flag;
{
	int i,j;
	char buf[17];

	buf[16] = 0;

	if (flag > 0) {
		j = flag;
	} else {
		if (sectbase < 3) {
			j = 128;
		} else {
			j = 256;
		}
	}
	for (i=0; i<j; i++) {
		if (i%16 == 0) printf("%2x %2x  ",flag > 0 ? 0 : sectbase,i);
		printf("%02x ",sectp[i]);
		if (sectp[i] < ' ' || sectp[i] > 0x7f) {
			buf[i%16] = '.';
		} else {
			buf[i%16] = sectp[i];
		}
		if (i%16 == 15) printf("%16s\n",buf);
	}
}

int read_sect(s)
int s;
{
	int i;
	int st;

	if (sectbase == s) return 1;

	if (updated) {
		if (sectbase < 4) {
			savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
		}
		for (i=0; i<3 && (st=awrite(sectbase+(SECT*head),driveno,sectp) != 0); i++)
		{
			printf("Write sector %d failed status %x\n",sectbase,st);
			if (sectbase < 4) {
				savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
			} else {
				savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
			}
		}
		if (sectbase < 4) {
			savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
		}
		updated = 0;
		if (i >= 3) {
			abort_mode = 1;
			printf("Write aborted\n");
		}
	}
	sectbase = s;
	if (sectbase < 4) {
		savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
	}
	for (i=0; i<3 && (st=aread(sectbase+(SECT*head),driveno,sectp) != 0); i++)
	{
		printf("Read sector %d failed status %x\n",sectbase,st);
		if (sectbase < 4) {
			savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
		} else {
			savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
		}
	}
	if (sectbase < 4) {
		savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
	}
	if (i >= 3) {
		abort_mode = 1;
		printf("Read aborted\n");
	}
	return (i<3);
}

void write_sect(s)
{
	if (s == sectbase) {
		updated = 1;
	} else {
		printf("Write sect=%d sectbase=%d\n",s,sectbase);
	}
}

void read_boot_sectors()
{
	int i;

	if (read_sect(1))
	{
		main_sect_map = sectp[9]+sectp[10]*256;
		total_sectors = sectp[11]+sectp[12]*256;
		free_sectors = sectp[13]+sectp[14]*256;
		num_bit_maps = sectp[15];
		first_bit_map = sectp[16]+sectp[17]*256;
		data_sect_1st = sectp[18]+sectp[19]*256;
		dir_sect_1st = sectp[20]+sectp[21]*256;
		for (i=0; i<8; i++) {
			vol_name[i] = sectp[22+i];
		}
		vol_name[8] = 0;
		tracks = sectp[30];
		sect_size_flag = sectp[31];
		sd_rev = sectp[32];
		default_drive = sectp[34];
		vol_seq_num = sectp[38];
		vol_ran_num = sectp[39];
		boot_sect_map = sectp[40]+sectp[41]*256;
	}
	else
	{
		printf("Boot sectors not read\n");
		if (debug) {
			dump_sect(0);
			press_return();
		}
		main_sect_map = 5;
		first_bit_map = 4;
	}

	if (debug) {
		printf("main_sect_map=%d\n",main_sect_map);
		printf("total_sectors=%d\n",total_sectors);
		printf("free_sectors=%d\n",free_sectors);
		printf("num_bit_maps=%d\n",num_bit_maps);
		printf("first_bit_map=%d\n",first_bit_map);
		printf("data_sect_1st=%d\n",data_sect_1st);
		printf("dir_sect_1st=%d\n",dir_sect_1st);
		printf("vol_name=%s\n",vol_name);
		printf("tracks=%d\n",tracks);
		printf("sect_size_flag=%d\n",sect_size_flag);
		printf("sd_rev=%d\n",sd_rev);
		printf("default_drive=%d\n",default_drive);
		printf("vol_seq_num=%d\n",vol_seq_num);
		printf("vol_ran_num=%d\n",vol_ran_num);
		printf("boot_sect_map=%d\n",boot_sect_map);
		press_return();
	}
}

void open_disk()
{
	unsigned char *dmainit();
	int i;

	sectp = dmainit(sector);
	if (sectp != sector) printf("Buffer moved from %x to %x\n",sector,sectp);

	savefb(1,SECTORS_PER_TRACK,dosfb_buf);
	if (debug) {
		printf("DOS media descr ");
		for (i=0; i<10; i++) {
			printf("%d ",dosfb_buf[i]);
		}
		printf("\n");
	}
}

void close_disk()
{
	int i;
	int st;

	if (updated) {
		if (sectbase < 4) {
			savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
		}
		for (i=0; i<3 && (st=awrite(sectbase+(SECT*head),driveno,sectp) != 0); i++)
		{
			printf("Write sector %d failed status %x\n",sectbase,st);
			if (sectbase < 4) {
				savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
			} else {
				savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
			}
		}
		if (i >= 3) {
			abort_mode = 1;
			printf("Write aborted\n");
		}
		updated = 0;
	}
	restfb(dosfb_buf);
}

void dos_io_begin()
{
	restfb(dosfb_buf);
}

void dos_io_end()
{
	savefb(1,SECTORS_PER_TRACK,dosfb_buf);
}

unsigned short alloc_sector(flag)
int flag;
{
	unsigned short sec;

	if (!read_sect(first_bit_map)) return 0;

	if (flag) {
		sec = data_sect_1st;
	} else {
		sec = dir_sect_1st;
	}

	while (sec < SECT) {
		if (sectp[sec>>3] & (1<<(sec&7))) break;
		sec++;
	}
	sectp[sec>>3] &= ~(1<<(sec&7));
	
	write_sect(first_bit_map);

	if (read_sect(1))
	{
		free_sectors--;
		if (flag) {
			data_sect_1st = sec;
		} else {
			dir_sect_1st = sec;
		}
		sectp[13] = free_sectors & 255;
		sectp[14] = free_sectors >> 8;
		sectp[18] = data_sect_1st & 255;
		sectp[19] = data_sect_1st >> 8;
		sectp[20] = dir_sect_1st & 255;
		sectp[21] = dir_sect_1st >> 8;
		write_sect(1);
	} else {
		return 0;
	}

	if (debug) {
		printf("Sector %d allocated\n",sec);
		press_return();
	}
	return (sec);
}

void free_sector(sec)
unsigned short sec;
{
	if (sec == 0) return;

	if (debug) {
		printf("Free sector %d\n",sec);
		press_return();
	}

	if (sec > total_sectors) return;

	read_sect(first_bit_map);

	sectp[sec>>3] |= 1<<(sec&7);
	
	write_sect(first_bit_map);
}

int release_sectors(map)
unsigned short map;
{
	static struct sector_map smap;
	unsigned int s;

	if (debug) {
		printf("Read map sector %d to release sectors\n",map);
		press_return();
	}

	if (!read_sect(map)) return(0);
	memcpy(&smap,sectp,256);
	while (1) {
		for (s=0; s<126; s++) {
			free_sector(smap.sects[s]);
		}
		if (smap.snext == 0) break;

		if (debug) {
			printf("Read next map sector %d\n",smap.snext);
			press_return();
		}

		if (!read_sect(smap.snext)) return(0);
		memcpy(&smap,sectp,256);
	};
	return(1);
}

int read_file_chunk(map,len,pos,cnt,addr)
unsigned short map;
unsigned long len,pos,cnt;
unsigned char *addr;
{
	static struct sector_map smap;
	unsigned int s,c,partcnt;

	s = pos>>8;

	if (debug) {
		printf("Read map sector %d to read file chunk\n",map);
		press_return();
	}

	if (!read_sect(map)) return(0);
	memcpy(&smap,sectp,256);

	if (debug) {
		printf("Rel sector %d\n",s);
		press_return();
	}

	while (s>=126) {
		s -= 126;

		if (debug) {
			printf("Read next map sector %d\n",smap.snext);
			press_return();
		}

		if (!read_sect(smap.snext)) return(0);
		memcpy(&smap,sectp,256);
	}
	if ((pos&0xff) != 0) {
		partcnt = (256-(cnt&0xff));
		if (partcnt > cnt) partcnt = cnt;

		if (debug) {
			printf("Read first partial data sector %d partcnt %d\n",smap.sects[s],partcnt);
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		memcpy(addr,&sectp[(pos&0xff)],partcnt);
		addr += partcnt;
		cnt -= partcnt;
	}
	c = cnt>>8;

	if (debug) {
		printf("Sector count %d\n",c);
		press_return();
	}

	while (c>0) {
		if (debug) {
			printf("Read data sector %d\n",smap.sects[s]);
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		memcpy(addr,sectp,256);
		addr += 256;
		s++;
		c--;
		if (s==126) {
			s = 0;
			if (debug) {
				printf("Read next map sector %d\n",smap.snext);
				press_return();
			}

			if (!read_sect(smap.snext)) return(0);
			memcpy(&smap,sectp,256);
		}
	}
	if ((cnt&0xff) != 0) {
		if (debug) {
			printf("Read last partial data sector %d cnt %d\n",smap.sects[s],(int)(cnt&0xff));
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		if (debug) {
			printf("memcpy %x %x %d\n",addr,sectp,(int)(cnt&0xff));
			press_return();
		}
		memcpy(addr,sectp,(int)(cnt&0xff));
	}
	return(1);
}

int expand_map(map,len,inc)
unsigned short map;
unsigned long len, inc;
{
	static struct sector_map smap;
	unsigned int s;

	s = len>>8;
	if (((len+inc)>>8 == s)&&(len>0)) {
		if (debug) {
			printf("Map sector %d not expanded, not crossing sector, len=%ld inc=%ld\n",map,len,inc);
			press_return();
		}
		return 1;
	}

	if (debug) {
		printf("Read map sector %d to expand map\n",map);
		press_return();
	}

	if (!read_sect(map)) return(0);
	memcpy(&smap,sectp,256);

	while (s>=126) {
		s -= 126;

		map = smap.snext;

		if (debug) {
			printf("Read next map sector %d\n",map);
			press_return();
		}

		if (!read_sect(map)) return(0);
		memcpy(&smap,sectp,256);
	}
	if (s < 125) {
		smap.sects[s] = alloc_sector(1);
		if (!read_sect(map)) return(0);
		memcpy(sectp,&smap,256);
		write_sect(map);
		if (debug) {
			printf("Sector entry %d points to sector %d\n",s,smap.sects[s]);
			press_return();
		}
	} else {
		printf("Cannot expand sector map yet\n");
		return(0);
	}
	return(1);
}

int write_file_chunk(map,len,pos,cnt,addr)
unsigned short map;
unsigned long len,pos,cnt;
unsigned char *addr;
{
	static struct sector_map smap;
	unsigned int s,c,partcnt;

	if (debug) {
		printf("Write file chunk map=%d len=%ld, pos=%ld cnt=%ld\n",map,len,pos,cnt);
		press_return();
	}

	if (!expand_map(map,len,pos+cnt)) return(0);

	s = pos>>8;

	if (debug) {
		printf("Read map sector %d to write file chunk\n",map);
		press_return();
	}

	if (!read_sect(map)) return(0);
	memcpy(&smap,sectp,256);

	if (debug) {
		printf("Rel sector %d\n",s);
		press_return();
	}

	while (s>=126) {
		s -= 126;

		if (debug) {
			printf("Read next map sector %d\n",smap.snext);
			press_return();
		}

		if (!read_sect(smap.snext)) return(0);
		memcpy(&smap,sectp,256);
	}
	if ((pos&0xff) != 0) {
		partcnt = (256-(cnt&0xff));
		if (partcnt > cnt) partcnt = cnt;

		if (debug) {
			printf("Read first partial data sector %d partcnt %d\n",smap.sects[s],partcnt);
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		memcpy(&sectp[(pos&0xff)],addr,partcnt);

		if (debug) {
			printf("Write first partial data sector %d partcnt %d\n",smap.sects[s],partcnt);
			press_return();
		}

		write_sect(smap.sects[s]);

		addr += partcnt;
		cnt -= partcnt;
	}
	c = cnt>>8;

	if (debug) {
		printf("Sector count %d\n",c);
		press_return();
	}

	while (c>0) {
		if (debug) {
			printf("Read data sector %d\n",smap.sects[s]);
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		memcpy(addr,sectp,256);
		addr += 256;
		s++;
		c--;
		if (s==126) {
			s = 0;
			if (debug) {
				printf("Read next map sector %d\n",smap.snext);
				press_return();
			}

			if (!read_sect(smap.snext)) return(0);
			memcpy(&smap,sectp,256);
		}
	}
	if ((cnt&0xff) != 0) {
		if (debug) {
			printf("Read last partial data sector %d\n",smap.sects[s]);
			press_return();
		}

		if (!read_sect(smap.sects[s])) return(0);
		memcpy(sectp,addr,(int)(cnt&0xff));

		if (debug) {
			printf("Write last partial data sector %d\n",smap.sects[s]);
			press_return();
		}

		write_sect(smap.sects[s]);
	}
	return(1);
}

static unsigned char buf[129];

void copy_in_file(map,len,xflag,cflag,dos_fname)
unsigned short *map;
unsigned long *len;
int xflag;
int cflag;
char *dos_fname;
{
	FILE *stream;
	unsigned long curlen, newlen;
	int i,j;

	newlen = 0;
	if (*map == 0) {
		if (debug) {
			printf("New map sector will be allocated\n");
			press_return();
		}
		*map = alloc_sector(0);
		curlen = 0;
	} else {
		curlen = *len;
	}

	if (cflag) {
		dos_io_begin();
		if (xflag) {
			stream = fopen(dos_fname,"r");
		} else {
			stream = fopen(dos_fname,"rb");
		}
		dos_io_end();
		if (stream == NULL) {
			perror(dos_fname);
			return;
		}
	} else {
		stream = stdin;
	}
	newlen = 0;
	while(1) {
		if (cflag) {
			dos_io_begin();
		}
		i = fread(buf,1,128,stream);
		if (debug) {
			printf("Read 128 bytes of data\n");
			press_return();
		}
		if (cflag) {
			dos_io_end();
		}
		if (i <= 0) break;
		if (xflag) {
			/* convert end of line characters */
			for (j=0; j<128; j++) {
				if (buf[j] == '\n') buf[j] = 0x9b;
			}
			if (debug) {
				printf("Convert 128 bytes of data\n");
				press_return();
			}
		}
		if (!write_file_chunk(*map,curlen,newlen,(unsigned long)i,buf)) break;
		newlen += i;
		if (curlen < newlen) curlen = newlen;
	}
	if (cflag) {
		dos_io_begin();
		fclose(stream);
		dos_io_end();
	}
	newlen += i;
	if (curlen < newlen) curlen = newlen;
	*len = curlen;
}

void copy_out_file(map,len,xflag,cflag,dos_fname)
unsigned short map;
unsigned long len;
int xflag;
int cflag;
char *dos_fname;
{
	unsigned char buf[129];
	unsigned long index;
	int i;
	FILE *stream;

	if (cflag) {
		dos_io_begin();
		if (xflag) {
			stream = fopen(dos_fname,"w");
		} else {
			stream = fopen(dos_fname,"wb");
		}
		dos_io_end();
		if (stream == NULL) {
			perror(dos_fname);
			return;
		}
	} else {
		stream = stdout;
	}
	index = 0;
	while(index < len) {
		if (!read_file_chunk(map,len,index,128L,buf)) return;
		if (xflag) {
			/* convert end of line characters */
			for (i=0; i<128; i++) {
				if (buf[i] == 0x9b) buf[i] = '\n';
			}
		}
		if (cflag) {
			dos_io_begin();
		}
		if (len-index < 128) {
			fwrite(buf,1,(int)(len-index),stream);
		} else {
			fwrite(buf,1,128,stream);
		}
		if (cflag) {
			dos_io_end();
		}
		index += 128;
	}
	if (cflag) {
		dos_io_begin();
		fclose(stream);
		dos_io_end();
	}
}

void normalize_fn(fn,fnbase,fn_ext)
char *fn, *fnbase, *fn_ext;
{
	char * p;

	strncpy(fnbase,"        ",8);
	strncpy(fn_ext,"   ",3);

	p = fnbase;
	while (*fn != 0) {
		if (*fn == '.') {
			p = fn_ext;
		} else {
			*p = toupper(*fn);
			p++;
		} 
		fn++;
	}
}

void compact_fn(fn,fnbase,fn_ext)
char *fn, *fnbase, *fn_ext;
{
	char *fnp;
	int i,j;

	fnp = fn;
	for (i=0; i<8; i++) {
		if (fnbase[i] == ' ') break;
		*fnp = fnbase[i];
		fnp++;
	}
	*fnp = '.';
	fnp++;
	for (i=0; i<3; i++) {
		if (fn_ext[i] == ' ') break;
		*fnp = fn_ext[i];
		fnp++;
	}
	*fnp = 0;
	strupr(fn);
}

int fname_eq(fn,fnbase,fn_ext)
char *fn, *fnbase, *fn_ext;
{
	char fbuf[13], *fnp;
	int i,j;

	fnp = fbuf;
	for (i=0; i<8; i++) {
		if (fnbase[i] == ' ') break;
		*fnp = fnbase[i];
		fnp++;
	}
	*fnp = '.';
	fnp++;
	for (i=0; i<3; i++) {
		if (fn_ext[i] == ' ') break;
		*fnp = fn_ext[i];
		fnp++;
	}
	*fnp = 0;
	strupr(fn);
	strupr(fbuf);
	return(strcmp(fn,fbuf) == 0);
}

#define NEW_FIRST_BITMAP SECTORS_PER_TRACK+1
#define NEW_MAIN_DIR_MAP SECTORS_PER_TRACK+2
#define NEW_MAIN_DIR     SECTORS_PER_TRACK+3
#define NEW_FREE_START   SECTORS_PER_TRACK+4

void new_main_dir()
{
	struct sector_map *smp;
	struct dir_entry *dirp;

	smp = sectp;
	dirp = sectp;

	read_sect(NEW_MAIN_DIR_MAP);

	smp->snext = 0;
	smp->sprev = 0;
	smp->sects[0] = NEW_MAIN_DIR;

	write_sect(NEW_MAIN_DIR_MAP);

	read_sect(NEW_MAIN_DIR);

	dirp->fstatus = IN_USE | SUBDIR;
	dirp->fsector_map = 0;
	dirp->flen[0] = 23;
	dirp->flen[1] = 0;
	dirp->flen[2] = 0;
	strncpy(dirp->fname,"MAIN    ",8);
	strncpy(dirp->fext,"   ",3);

	update_time(dirp);

	write_sect(NEW_MAIN_DIR);
}

void new_boot_sector(volname)
char *volname;
{
	int i;

	main_sect_map = NEW_MAIN_DIR_MAP;
	total_sectors = SECT;
	free_sectors = SECT-NEW_FREE_START;
	num_bit_maps = 1;
	first_bit_map = NEW_FIRST_BITMAP;
	data_sect_1st = NEW_FREE_START;
	dir_sect_1st = NEW_FREE_START;
	strncpy(vol_name,"        ",8);
	i = strlen(volname);
	strncpy(vol_name,volname,i<8?i:8);
	tracks = 40;
	sect_size_flag = 0;
	sd_rev = 32;
	default_drive = 1;
	vol_seq_num = 1;
	vol_ran_num = getpid();
	boot_sect_map = 0;

	read_sect(1);

	for (i=0; i<128; i++) {
		sectp[i] = bootblock1[i];
	}

	sectp[9] = main_sect_map & 255;
	sectp[10] = main_sect_map >> 8;
	sectp[11] = total_sectors & 255;
	sectp[12] = total_sectors >> 8;
	sectp[13] = free_sectors & 255;
	sectp[14] = free_sectors >> 8;
	sectp[15] = num_bit_maps;
	sectp[16] = first_bit_map & 255;
	sectp[17] = first_bit_map >> 8;
	sectp[18] = data_sect_1st & 255;
	sectp[19] = data_sect_1st >> 8;
	sectp[20] = dir_sect_1st & 255;
	sectp[21] = dir_sect_1st >> 8;
	for (i=0; i<8; i++) {
		sectp[22+i] = vol_name[i];
	}
	sectp[30] = tracks;
	sectp[31] = sect_size_flag;
	sectp[32] = sd_rev;
	sectp[33] = 6;
	sectp[34] = default_drive;
	sectp[35] = 255;
	sectp[36] = 255;
	sectp[37] = 0;
	sectp[38] = vol_seq_num;
	sectp[39] = vol_ran_num;
	sectp[40] = boot_sect_map & 255;
	sectp[41] = boot_sect_map >> 8;
	sectp[42] = 0;

	for (i=128; i<256; i++) {
		sectp[i] = 9;
	}

	write_sect(1);

	read_sect(2);

	for (i=0; i<128; i++) {
		sectp[i] = bootblock2[i];
	}

	for (i=128; i<256; i++) {
		sectp[i] = 9;
	}

	write_sect(2);

	read_sect(3);

	for (i=0; i<128; i++) {
		sectp[i] = bootblock3[i];
	}

	for (i=128; i<256; i++) {
		sectp[i] = 9;
	}

	write_sect(3);

	read_sect(first_bit_map);

	for (i=0; i<256; i++) {
		sectp[i] = 0;
	}

	write_sect(first_bit_map);
}

int new_toc( volname)
char *volname;
{
	int i;
	new_main_dir();
	new_boot_sector(volname);
	for (i=data_sect_1st; i<=total_sectors; i++) free_sector(i);

	return 1;
}

static char format_errs[40];

int format()
{
	int t;
	int s;
	int err;
	int i;

	err = 0;
	for (t=0; t<tracks; t++) {
		for (i=0; i<3; i++) {
			printf("\rFormat track %02d head %d",t,head);
			if (t==0) {
				savefb(0,SECTORS_PER_TRACK,tmpfb_buf);
			}
			if (t==1) {
				savefb(1,SECTORS_PER_TRACK,tmpfb_buf);
			}
			if ((s=aformat(t,driveno,sectp,fmt_seq,head)) != 0) {
				if (debug) {
					printf("error status %x\n",s);
					dump_sect(16*5);
					press_return();
				}
				err = 1;
				format_errs[t] = 1;
			} else {
				format_errs[t] = 0;
				break;
			}
		}
	}
	printf("\n");
	if (err) {
		for (t=0; t<tracks; t++) {
			if (format_errs[t]) {
				printf("Track %d not formatted\n",t);
			}
		}
	}
	return !err;
}

void usage()
{
	printf("Usage:\nsdatari -h -b -f -d -x -r filename -w filename -c dos_filename\n");
	printf("  d List disk directory\n");
	printf("  h Use side 2 of disk\n");
	printf("  b Use second drive\n");
	printf("  r Read file contents\n");
	printf("  w Write file contents\n");
	printf("  f Format disk\n");
	printf("  x Convert Atari end-of-lines\n");
	printf("  c Copy file to/from dos_filename instead of stdio\n");
	printf("For example:\n");
	printf("  sdatari -f                         Format side 1\n");
	printf("  sdatari -f -h                      Format side 2\n");
	printf("  sdatari -d                         Directory of side 1\n");
	printf("  sdatari -x -r FOOBAR.M65           Read text file and display to screen\n");
	printf("  sdatari -x -r FOO.DOC -c C:F.DOC   Read text file and copy to DOS file\n");
	printf("  sdatari -x -w BAR.DOC -c C:B.DOC   Write text file from DOS file\n");
	printf("  sdatari -w FOOBAR.EXE -c C:F.EXE   Write binary file from DOS file\n");
	printf("  sdatari -x -w JUNK.DOC             Write text file from keybaord\n");
	printf("  sdatari -h -x -w JUNK.DOC          Write text file (side 2) from keybaord\n");
	printf("\n");
}

catcher(sig)
int sig;
{
	printf("Signal %d caught\n",sig);
	close_disk();
	printf("Diskette mode restored\n");
	exit();
}

void main(argc,argv)
int argc;
char **argv;
{
	struct dir_entry dd;
	int c,i;
	unsigned long l,dl,di,firstfree;
	int print_toc,rflag,wflag,xflag,fflag;
	char *fn;
	int dos_copy;
	char *dos_fname;

	print_toc = 0;
	rflag = 0;
	wflag = 0;
	xflag = 0;
	fflag = 0;
	dos_copy = 0;
	c = 1;
	while (c < argc) {
		if (argv[c][0] == '-' && argv[c][2] == 0) {
			switch(argv[c][1]) {
			case 'f':
				fflag = 1;
				break;
			case 'c':
				dos_copy = 1;
				c++;
				if (c < argc) {
					dos_fname = argv[c];
				} else {
					printf("Missing argument to %s\n",argv[c-1]);
					exit();
				}
				break;
			case 'd':
				print_toc = 1;
				break;
			case 'h':
				head = 1;
				break;
			case 'r':
				rflag = 1;
				wflag = 0;
				c++;
				if (c < argc) {
					fn = argv[c];
				} else {
					printf("Missing argument to %s\n",argv[c-1]);
					exit();
				}
				break;
			case 'w':
				wflag = 1;
				rflag = 0;
				c++;
				if (c < argc) {
					fn = argv[c];
				} else {
					printf("Missing argument to %s\n",argv[c-1]);
					exit();
				}
				break;
			case 'x':
				xflag = 1;
				break;
			case 't':
				debug1 = 1;
				break;
			case 'T':
				debug = 1;
				break;
			case 'b':
				driveno = 1;
				break;
			case 'p':
				pflag = 1;
				break;
			default:
				printf("Invalid argument %s\n",argv[c]);
				usage();
				exit();
			}
		} else {
			printf("Invalid argument %s\n",argv[c]);
			usage();
			exit();
		}
		c++;
	}

	if (debug) {
		printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
		c,i,
		l,dl,di,firstfree,
		print_toc,rflag,wflag,xflag,fflag);
	}

	printf("SpartaDOS disk utility.  v0.1e  By Mark K Vallevand\n");
	open_disk();

	signal(SIGINT,catcher);
	signal(SIGTERM,catcher);

	if (debug) {
		printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
		c,i,
		l,dl,di,firstfree,
		print_toc,rflag,wflag,xflag,fflag);
	}

	if (fflag) {
		if (!format()) {
			printf("Format incomplete\n");
		}
		if (new_toc("DOSVOL00")) {
			printf("TOC written\n");
		} else {
			printf("TOC not written\n");
		}
	}

	if (debug) {
		printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
		c,i,
		l,dl,di,firstfree,
		print_toc,rflag,wflag,xflag,fflag);
	}

	firstfree = 0;
	read_boot_sectors();

	if (debug) {
		printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
		c,i,
		l,dl,di,firstfree,
		print_toc,rflag,wflag,xflag,fflag);
	}

	if (read_file_chunk(main_sect_map,23L,0L,23L,&dd)) {

		if (debug) {
			printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
			c,i,
			l,dl,di,firstfree,
			print_toc,rflag,wflag,xflag,fflag);
		}

		if (print_toc) {
			printf("Volume: %s\n",vol_name);
			printf("Directory: ");
			for (i=0; i<8; i++) putchar(dd.fname[i]);
			putchar('.');
			for (i=0; i<3; i++) putchar(dd.fext[i]);
		}
		l = dd.flen[2];
		l *= 256;
		l += dd.flen[1];
		l *= 256;
		l += dd.flen[0];
		dl = l;
		if (print_toc) {
			printf(" %8ld ",l);
		}
		if (print_toc) {
			printf("(%04d) ",dd.fsector_map);
			printf("%02d-%02d-%02d ",
				dd.fcr_date[0],
				dd.fcr_date[1],
				dd.fcr_date[2]);
			printf("%02d:%02d:%02d\n",
				dd.fcr_time[0],
				dd.fcr_time[1],
				dd.fcr_time[2]);
		}

		if (debug) {
			printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
			c,i,
			l,dl,di,firstfree,
			print_toc,rflag,wflag,xflag,fflag);
		}

		for (di=23L; di<dl; di += 23L) {
			if (!read_file_chunk(main_sect_map,dl,di,23L,&dd)) break;

			if (debug) {
				printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
				c,i,
				l,dl,di,firstfree,
				print_toc,rflag,wflag,xflag,fflag);
			}

			if ((dd.fstatus&IN_USE) != 0) {
				if (print_toc) {
					for (i=0; i<8; i++) putchar(dd.fname[i]);
					putchar('.');
					for (i=0; i<3; i++) putchar(dd.fext[i]);
				}
				if ((dd.fstatus&SUBDIR) != 0) {
					if (print_toc) printf("   DIR    ");
				} else {
					l = dd.flen[2];
					l *= 256;
					l += dd.flen[1];
					l *= 256;
					l += dd.flen[0];
					if (print_toc) printf(" %8ld ",l);
				}
				if (print_toc) {
					printf("(%04d) ",dd.fsector_map);
					printf("%02d-%02d-%02d ",
						dd.fcr_date[0],
						dd.fcr_date[1],
						dd.fcr_date[2]);
					printf("%02d:%02d:%02d\n",
						dd.fcr_time[0],
						dd.fcr_time[1],
						dd.fcr_time[2]);
				}
				if (rflag && *fn=='*') {
					char new_fname[13];

					compact_fn(new_fname,dd.fname,dd.fext);
					printf("Copy %s  [yn] y\b",new_fname);
					gets(temp);
					if (tolower(temp[0]) != 'n') {
						char dft_mode;

						printf("To DOS file ");
						gets(temp);
						if (strlen(temp) != 0) {
							strncpy(new_fname,temp,13);
						}
						dft_mode = xflag?'a':'b';
						printf("Binary or Ascii [ba] %c\b",dft_mode);
						gets(temp);
						if (tolower(temp[0]) != dft_mode) {
							if (dft_mode == 'a') dft_mode = 'b'; else dft_mode = 'a';
						}
						copy_out_file(dd.fsector_map,l,dft_mode,1,new_fname);
					}
					continue;
				}
				if (rflag && fname_eq(fn,dd.fname,dd.fext)) {
					copy_out_file(dd.fsector_map,l,xflag,dos_copy,dos_fname);
					break;
				}
				if (wflag && fname_eq(fn,dd.fname,dd.fext)) {
					/* Reuse existing entry */
					if (debug) {
						printf("Reuse existing directory entry\n");
						press_return();
					}
					if (release_sectors(dd.fsector_map,l)) {
						copy_in_file(&dd.fsector_map,&l,xflag,dos_copy,dos_fname);
						dd.flen[0] = l&255;
						dd.flen[1] = (l>>8)&255;
						dd.flen[2] = (l>>16)&255;
						update_time(&dd);
						if (write_file_chunk(main_sect_map,dl,di,23L,&dd)) {
							wflag = 0;
						}
					}
					break;
				}
			} else {
				firstfree = di;
			}
		}
	}
	if (print_toc) printf("%d free sectors\n",free_sectors);
	if (wflag) {

		if (debug) {
			printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
			c,i,
			l,dl,di,firstfree,
			print_toc,rflag,wflag,xflag,fflag);
		}

		if (firstfree == 0) {
			/* There is not a free directory entry */
			if (debug) {
				printf("Use new directory entry\n");
				press_return();
			}
			if (expand_map(main_sect_map,dl,23L)) {
				firstfree = dl;
				dl += 23L;
				if (debug) {
					printf("Directory entry at %ld, directory size %ld\n",firstfree,dl);
					press_return();
				}
				if (read_file_chunk(main_sect_map,23L,0L,23L,&dd)) {
					dd.flen[0] = dl&255;
					dd.flen[1] = (dl>>8)&255;
					dd.flen[2] = (dl>>16)&255;
					if (write_file_chunk(main_sect_map,23L,0L,23L,&dd)) {
						if (debug) {
							printf("Directory expanded\n");
							press_return();
						}
					}
				}
			}
		} else {
			if (debug) {
				printf("Use free directory entry\n");
				press_return();
			}
		}
		if (firstfree != 0) {
			dd.fsector_map = 0;
			dd.fstatus = IN_USE;
			normalize_fn(fn,dd.fname,dd.fext);
			copy_in_file(&dd.fsector_map,&l,xflag,dos_copy,dos_fname);

			if (debug) {
				printf("line %d:c=%d i=%d l=%ld dl=%ld di=%ld ff=%ld p=%d r=%d w=%d x=%d f=%d\n",__LINE__,
				c,i,
				l,dl,di,firstfree,
				print_toc,rflag,wflag,xflag,fflag);
				press_return();
			}

			dd.flen[0] = l&255;
			dd.flen[1] = (l>>8)&255;
			dd.flen[2] = (l>>16)&255;
			update_time(&dd);
			if (write_file_chunk(main_sect_map,dl,firstfree,23L,&dd)) {
				wflag = 0;
					if (debug) {
						printf("Directory updated\n");
						press_return();
					}
			}
		}
	}
	close_disk();
	if (debug) press_return();
	printf("End\n");
}

