//////////////////////////////////////////////////////////
// ana2dsk.c
// convert Anadisk disk dumps to Flex emulator .DSK format
// See ana2dsk.txt for more info
//
// Dell W. Setzer
// 31 March 2001
// dsetzer@panix.com
//
// Do whatever you like with this code
// Comments appreciated
///////////////////////////////////////////////////////////

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

#ifndef TRUE
#define TRUE 1
#define FALSE 0
#define BOOL int
#endif

#define SEC_SIZE	(256)				// FLEX sector size
#define MAX_TRACK_LEN (SEC_SIZE * 36)	// max FLEX track (36 sectors)

// Anadisk sector record header
typedef struct adrec_t {
	char acyl;		// actual cylinder
	char asid;		// actual side
	char lcyl;		// logical cylinder (as read)
	char lsid;		// logical side (as read)
	char lsec;		// logical sector (as read)
	char llen;		// logical length (as read)
	short count;	// count of bytes which follow (0 if none)
} ADREC;

// FLEX System Information Record in third sector of track 0
typedef struct sir_t {
	char pad[16];		
	char label[11];			// volume label
	char volno[2];			// volume number
	char firstfree_ts[2];	// track/sector of free list head
	char lastfree_ts[2];	// track/sector of free list tail
	char freecount[2];		// free sector count
	char date[3];			// volume creation date
	unsigned char hitrk;	// highest track number (0-relative)
	unsigned char hisec;	// sectors per track
} SIR;

BOOL skipodd = FALSE;

BOOL getrec(FILE *fp, char *buff)
{
	ADREC rec;

	// read next sector record from AnaDisk dump file
	//  skipping odd tracks if necessary

	for (;;) {
		
		// read the record header
		if (fread(&rec,sizeof(rec),1,fp) != 1) {
			perror("read header");
			break;
		}

		// if we're skipping odd tracks, just seek past
		// the data and press on
		if (skipodd && (rec.acyl & 1)) {
			if (fseek(fp,rec.count,SEEK_CUR)) {
				perror("fseek");
				break;
			}
			continue;
		}

		// sanity check
		if (rec.count != SEC_SIZE) {
			printf("Bad sector len %d, track %d, sec %d\n",
				rec.count,rec.acyl,rec.lsec);
			break;
		}

		// get the sector data
		if (fread(buff,SEC_SIZE,1,fp) != 1) {
			perror("read data");
			break;
		}
		return TRUE;
	}

	return FALSE;
}

int main(int argc, char *argv[])
{
	FILE *in,*out;
	int i,trk,sec;
	char *cp,*buff;
	SIR sir;
	BOOL ds,pad;

	if (argc != 3) {
		printf("Usage: ana2dsk <inputname> <outputname>\n");
		printf("  inputname is Anadisk dump file with sector ID info\n");
		printf("  outputname is Flex DSK file\n\n");
		exit(1);
	}

	if ((in=fopen(argv[1],"rb")) == NULL) {
		perror(argv[1]);
		exit(1);
	}

	if ((out=fopen(argv[2],"wb")) == NULL) {
		perror(argv[2]);
		exit(1);
	}

	// allocate buffer which can hold entire track 0 with padding
	if ((buff=malloc(MAX_TRACK_LEN)) == NULL) {
		perror("malloc");
		exit(1);
	}

	memset(buff,0,MAX_TRACK_LEN);

	// get all of single density track 0 side 0 (always 10 sectors)
	cp = buff;
	for (i=0;i<10;i++,cp+=SEC_SIZE) {
		if (!getrec(in,cp))
			exit(1);
	}

	// get SIR from sector 3 in buff
	cp = &buff[SEC_SIZE*2];
	sir = *(SIR *)cp;

	printf("Label: %.11s, %d tracks, %d sectors: ",
		sir.label,sir.hitrk+1, sir.hisec);

	pad = FALSE;
	ds = FALSE;

	switch (sir.hisec) {
	case 10:
		printf("SS/SD\n");
		break;
	case 18:
		printf("SS/DD\n");
		break;
	case 20:
		printf("DS/SD\n");
		ds = TRUE;
		break;
	case 35:
		printf("DS/DD (trimmed)\n");
		ds = TRUE;
		pad = TRUE;
		break;
	case 36:
		printf("DS/DD\n");
		ds = TRUE;
		break;
	default:
		printf("Unrecognized sector format\n");
		exit(1);
		break;
	}

	if (pad)
		printf("(Inserting dummy sector 18's)\n");

	if (sir.hitrk < 79) {
		skipodd = TRUE;
		printf("(Skipping odd numbered tracks)\n");
	}

	// if double sided, read rest of single density track 0 (10 more sectors)
	if (ds) {
		cp = &buff[10*SEC_SIZE];
		for (i=0;i<10;i++,cp+=256)
			if (!getrec(in,cp))
				exit(1);
	}

	// write out track 0, padding to full track length from SIR
	if (fwrite(buff,(int)sir.hisec*256,1,out) != 1) {
		perror(argv[2]);
		exit(1);
	}

	// loop reading and writing rest of image
	for (trk=1;trk<=sir.hitrk;trk++) {
		for (sec=1;sec<=sir.hisec;sec++) {
			// insert dummy sector 18 if necessary
			if (pad && (sec == 18)) {
				memset(buff,0,256);
			} else {
				if (!getrec(in,buff))
					exit(1);
			}
			if (fwrite(buff,256,1,out) != 1) {
				perror(argv[2]);
				exit(1);
			}
		}
	}

	fclose(in);
	fclose(out);
	free(buff);
	printf("\nDone!\n");

	return 0;
}
