/*
 * This program formats a 5 1/4 inch floppy disk in drive 0 or drive 1
 * of the Olivetti M20.  The format is ECMA standard for the headers.
 * The data fields are filled with 0xE5, which CP/M thinks is a new
 * IBM disk.  This gives the disk the appearance of having an empty
 * directory as far as CP/M is concerned.
 */

#include "stdio.h"

/* densities */
#define	SINGLE 0
#define DOUBLE 1

#define BADTRACK -1
#define MAXBAD 2

#define NTRACKS 40

/* Space for humongous buffer */
#define TRACKSIZ 10000
char	trakbuf[TRACKSIZ];
int	track,
	sector,
	side,
	density,
	drive;

int	intrlv[16] =   { 9, 1, 10, 2,
			11, 3, 12, 4,
			13, 5, 14, 6,
			15, 7, 16, 8};

extern	long map_adr();
long	physaddr;		/* Segmented address of trakbuf */

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

	physaddr = map_adr((long)trakbuf,0);	/* get seg addr	*/
	while(--argc) {
		p = *++argv;
		if (strcmp(p,"a:") == 0) {
			drive = 0;
			warn(p);
			format(p);
		}
		else if (strcmp(p,"b:") == 0) {
			drive = 1;
			warn(p);
			format(p);
		}
		else printf("Unknown drive: %s\n",p);
	}
}

/* Routine to format a disk in a given drive */
format(p)
char *p;
{
	register int i,j,k;
	int	badtracks;

	badtracks = 0;

/* Start with track 0; this track is special. */
	printf("Formatting track %2d",0);
	track = 0;
	density = SINGLE;
	if ( (j = make_zero()) == BADTRACK) {
		printf("Can't format track zero; bad diskette\n");
		return(-1);
	}

/* Now do the other tracks */
	density = DOUBLE;
	for(track = 1; track<=40; track++) {
		printf("%2d",track);
		if( (j = dotrack(track)) == BADTRACK) badtracks++;
		if (badtracks > MAXBAD) {
			printf("%d bad tracks; too many.\n",badtracks);
			return(-1);
		}
	}
	printf("\nFormatting of disk in drive %s complete.\n\n",p);
	return(badtracks);
}

/* Routine to do one track */
dotrack(track)
{
	register int j;

	if( (j = doside(0,track)) == BADTRACK) return(BADTRACK);
	if( (j = doside(1,track)) == BADTRACK) return(BADTRACK);
	return(track);
}

/* Routine to do one double density side */
doside(side,track)
int side,track;
{	register int j,sector;
	char *p;

	p = trakbuf;
	for(j = 0; j < 32; j++) *p++ = 0x4e;	/* Index Gap: 32 hx 4E's */
	for(sector = 0; sector < 16; sector++) {
		for(j = 0; j < 12; j++) *p++ = '\0';
		for(j = 0; j < 3; j++) *p++ = 0xf5;
		*p++ = 0xfe;
		*p++ = track;
		*p++ = side;
		*p++ = intrlv[sector]; /* use interleave table */
		*p++ = (char)DOUBLE;
		*p++ = 0xf7;	/* Puts two CRC bytes out */
		for(j = 0; j < 22; j++) *p++ = 0x4e;
		for(j = 0; j < 12; j++) *p++ = '\0';
		for(j = 0; j < 3; j++) *p++ = 0xf5;
		*p++ = 0xfb;
/* Magic with the data buffer: fill it with hex E5's, and CP/M will think */
/*  that it has an empty directory!					  */
		for(j = 0; j < 256; j++) *p++ = 0xe5;
		*p++ = 0xf7;	/* More CRC's */
		for(j = 0; j < 50; j++) *p++ = 0x4e;	/* sector gap */
	}
/* Now do the end of track gap: 400 hex 4E's	*/
	for(j = 0; j < 400; j++) *p++ = 0x4e;

/* Finally, use assembler magic to write the track image.	*/
	return(writ_im(drive,track,side,physaddr));
}

/* Routine to make track zero, which is special.  It's single-density
 * on side zero, and double density on side one.  Each of these has a
 * different header encoding standard.
 */

make_zero()
{
	register int j,sector;
	char *p;

	p = trakbuf;
	for( j = 0; j < 16; j++) *p++ = 0xff;	/* Index Gap */
	for(sector = 0; sector < 16; sector++) {
		for(j = 0; j < 6; j++) *p++ = '\0';
		*p++ = 0xfe;
		*p++ = 0;	/* Track # */
		*p++ = 0;	/* Side # */
		*p++ = intrlv[sector];
		*p++ = '\0';
		*p++ = 0xf7;		/* CRC */
		for(j = 0; j < 11; j++) *p++ = 0xff;
		for(j = 0; j < 6; j++) *p++ = '\0';
		*p++ = 0xfb;
		for(j = 0; j < 128; j++) *p++ = 0xe5;	/* Magic data */
		*p++ = 0xf7;		/* CRC */
		for(j = 0; j < 24; j++) *p++ = 0xff;	/* Sector Gap */
	}
	for(j = 0; j < 200; j++) *p++ = 0xff;	/* End-of-track Gap */
	j = writ_im(drive,0,0,physaddr);	/* Write side 0 special */
	if(j == BADTRACK) return(j);
	return(doside(1,0));			/* Write side 1 normal  */
}

warn(p)
char *p;
{
	register int c,cc;

	printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
	printf("Warning:  This will destroy all files on disk %s!\n\n",p);
	printf("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n");
	printf("Do you wish to continue? ");
	c = getchar();
	if(c == '\n') exit(1);
	else while( (cc = getchar()) != '\n') ;
	if(c != 'y' && c != 'Y') exit(1);
	return(0);
}
