/**********************************
* 40 track - 8 sectors per track
***********************************/

#define TRUE	1
#define FALSE 	0
#define BUFSIZE		1024

#define	BDRESET	   0x00
#define	BDSTATUS    0x01
#define	BDREAD	   0x02
#define	BDWRITE	   0x03
#define	BDVERIFY    0x04
#define	BDFORMAT    0x05

#define	FLOPPY1	   0x00
#define	HEAD0	      0x00
#define 	HEAD1			0X01
#define	ONESECTOR	0x01


/***************************************************************
* ADAM2PC - copy files from Adam disk to PC
****************************************************************
* 1.00	12/1/94	Chris Braymen	Creation	under Borland C 3.1
****************************************************************/


#include	<stdio.h>
#include <stdlib.h>
#include <string.h>
#include	<bios.h>
#include	<ctype.h>
#include	"adamfcb.h"

#define MAX_FCB	8*NUM_FCB_IN_BLOCK   /* maximum # of directory entries */

unsigned char	buffer[BUFSIZE];
struct 	EOS_FCB	myDir[MAX_FCB];
char		inFileName[255];
char		outFileName[255];
char		needName;

char 		version[] = "v1.00";


/*********************
* Prototypes
**********************/
int processArgs(int,char**);
int findFCB(char*,struct EOS_FCB*);
int cmpString(char*,char*);
int readDirectory(void);
int verifyEOS(unsigned char*);
int copyFile(struct EOS_FCB*,FILE*);
int convertName(char*,char*);
int isDosFileChar(char);
int eos2c(char*,char*);

#include	"ReadBlk.c"

int main(argc,argv)
	int	argc;
	char	*argv[];
{
	int		block,i;
	int		result;
	FILE		*outFileP;
	struct  	EOS_FCB	myFCB;
	char		tempFileName[255];

	if(!processArgs(argc,argv))
		exit(0);

	if(!readDirectory())
		exit(0);

	if(!findFCB(inFileName,&myFCB)) {
		printf("File not found\n");
		exit(0);
	}

	do {
		if(needName)
			convertName(myFCB.fileName,outFileName);

		eos2c(myFCB.fileName,tempFileName);
		printf("Copying %11s -> %12s ",tempFileName,outFileName);
		if((outFileP=fopen(outFileName,"wb"))==NULL) {
			printf("[Can't open DOS file]\n");
			exit(0);
		}

		result=copyFile(&myFCB,outFileP);
		fclose(outFileP);
		if(result==FALSE) {
			unlink(outFileName);
			exit(0);
		}

		if(strcmp(inFileName,"*")!=0)	/* single filename */
			break;

	} while(findFCB(inFileName,&myFCB));
	return(0);
}

/*******************************************************
* processArgs - process the command line args
*		sets globals inFileName,outFileName
********************************************************/
int processArgs(argc,argv)
   int	argc;
   char	*argv[];
{
   if(argc<2 || argc>3) {
		printf("ADAM2PC %s - Public Domain from Bonafide Systems\n\n",version);
		puts("Usage: ADAM2PC <source ADAM file or *> [destination PC file]");
      puts("If ADAM source is wildcard (*) then PC file spec may not exist.\n");
      return(FALSE);
   }

	needName=TRUE;
	strcpy(inFileName,argv[1]);
	if(argc>2) {
		strcpy(outFileName,argv[2]);
		needName=FALSE;
		if(strcmp(inFileName,"*")==0) {
			puts("Can't specify DOS filename with ADAM wildcard.");
			return(FALSE);
		}
	}
	return(TRUE);
}


/*****************************************************
* findFCB
*	searches the EOS directory for the filename at
*	inFileName or
*	if inFileName is "*" then returns the next filename
*	in the FCB thats not deleted, or BOOT or VOLUME, or DIRECTORY
*	Places FCB in myFCB.
*	returns TRUE if OK, FALSE if error
*****************************************************/
int findFCB(inFileName,myFCB)
	char		inFileName[];
	struct 	EOS_FCB  *myFCB;
{
	static int lastFCB=3;  			/* start past first 3 system files */

	if(strcmp(inFileName,"*")==0) {	      /* process wildcard */
		while(myDir[lastFCB].status!=HOLE) {
			if(!(myDir[lastFCB].status & DELETED)) {
				*myFCB = myDir[lastFCB];
				lastFCB++;            				/* set up for next time */
				return(TRUE);
			}
			lastFCB++;
		}
		return(FALSE);		      	      /* all done */
	}

	/* single filename */
	while(myDir[lastFCB].status!=HOLE) {
		if(!(myDir[lastFCB].status & DELETED)) {
			if(cmpString(inFileName,myDir[lastFCB].fileName)) {
				*myFCB=myDir[lastFCB];
				return(TRUE);			 /* found it */
			}
		}
		lastFCB++;
	}
	return(FALSE);
}					/* didn't find it */



/****************************************************
* cmpString - compares a "C" zero terminated string
*	      with an ADAM "3" terminated string
*	      returns TRUE if the same, FALSE if different
**********************************************************/
int cmpString(cString,aString)
	char	*cString;
	char	*aString;
{
	while(*cString!=0 && *aString!=3) {
		if(*cString!=*aString) {
			return(FALSE);
		}
		cString++;
		aString++;
	}
	return(TRUE);
}


/*****************************************************
* readDirectory
*	reads the EOS directory in the myDir array of FCB structures
*	returns 0 if OK, BIOSDISK error code if error
*****************************************************/
int readDirectory()
{
	int	i,j,done=FALSE;
	int	fcbCount=0;
	int	dirBlocks,blockCount=1;
	char	*bytePtr;

	if(readBlock(blockCount,buffer)) {	/* read directory block */
		printf("Error reading ADAM directory\n");
		return(FALSE);
	}

	if((dirBlocks=verifyEOS(buffer))==0)	{	/* get directory size */
		puts("Not an EOS directory!");
		return(FALSE);
	}
	if(dirBlocks * NUM_FCB_IN_BLOCK >  MAX_FCB) {
		printf("A %d block directory is too big!\n",dirBlocks);
		return(FALSE);
	}

	while(!done) {
		if(blockCount>dirBlocks) {
			puts("Error: No 'hole' found");
			return(FALSE);
		}
		if(readBlock(blockCount,buffer))	{
			printf("Error reading ADAM directory\n");
			return(FALSE);
		}

		for(i=0;i<NUM_FCB_IN_BLOCK;i++) {
			bytePtr=(char*)&myDir[fcbCount];
			for(j=0;j<FCB_SIZE;j++) {             /* copy FCB to structure */
				*bytePtr = buffer[i*FCB_SIZE+j];
				bytePtr++;
			}
			if (myDir[fcbCount].status==HOLE)
				done=TRUE;
			fcbCount++;
		}
		blockCount++;
	}
	return(TRUE);
}

/****************************************************
* verifyEOS - Verifies that the media is an EOS media
*	      and returns the size of the directory.
*	      0 if Error.
*****************************************************/
int verifyEOS(buffer)
	unsigned char buffer[];
{
   int  Count;

   for (Count=0; Count<4; Count++) {
      if (DirChk[Count] != buffer[Count+13]) { 
			return(0);
		}
	}
	return(buffer[12] & 0x7F); /* mask out bit 7 */
}


/******************************************************
* copyFile - copy the file at myFCB to the IBM file outFile
*            returns TRUE if OK, FALSE if error
*******************************************************/
copyFile(myFCB,outFileP)
	struct 	EOS_FCB	*myFCB;
	FILE		*outFileP;
{
	int	bytesToWrite;

	while(myFCB->blocksUsed) {
		if(readBlock((int)myFCB->startBlock,buffer)) {
			printf("[Error reading block %d]\n",myFCB->startBlock);
			return(FALSE);
		}

		if(myFCB->blocksUsed>1)
			bytesToWrite=1024;			   /* a full block */
		else
			bytesToWrite=myFCB->bytesInLastBlock;      /* Last block's bytes */

		if(bytesToWrite!=fwrite(buffer, 1, bytesToWrite, outFileP)) {
			puts("[Error writing DOS file]");
			return(FALSE);
		}

		myFCB->blocksUsed--;
		myFCB->startBlock++;
	}
	puts("[OK]");
	return(TRUE);
}

/**************************************************************
* convertName - converts an ADAM filename to a DOS filename
**************************************************************/
convertName(in,out)
	char	*in;
	char	*out;
{
	int	i=0;

	while(i<8) {
		if(*in==3) {
		   *out='\0';
		   return(0);
		}
		if(*in=='.') {
		   in++;
		   break;
		}
		if(isDosFileChar(*in)) {
			*out=*in;
			out++;
		}
		in++;
		i++;
	}

	*out='.';
	out++;
	i=0;
	while(i<3) {
		if(*in==3) {
		   *out='\0';
		   return(0);
		}
		if(isDosFileChar(*in)) {
			*out=*in;
			out++;
		}
		in++;
		i++;
	}
	*out='\0';
	return(0);
}

/******************************************************
* isDosFileChar - returns TRUE if char is a valid file char
*		  otherwise FALSE
*******************************************************/
char dosFileChars[]="_^$~!#%&-{}()@'`";

isDosFileChar(c)
	char	c;
{
	char	*p1;

	if(isalnum(c))
	   return(TRUE);

	p1=dosFileChars;
	while(*p1) {
	   if(*p1==c)
			return(TRUE);
	   p1++;
	}
	return(FALSE);
}

/************************
* eos2c
*************************/
eos2c(s1,s2)
	char  *s1;
   char	 *s2;
{
   while(*s1!=3) {
      *s2=*s1;
      s1++;
      s2++;
   }
   *s2='\0';
   return(0);
}
