/************************************************************************
* Copy a PC file(s) to an ADAM disk
*************************************************************************
* 1.00                           Creation under Borland C 3.1
* 1.01									Fixes bug that reports deleted files as
*											existing. Also copies files when the full
*											path is given.
* 1.02	12/1/94	Chris Braymen	Closes PC file each iteration avoiding
*											out of memory errors. Fixes writeDirectory
*											bugs with multiple directory blocks
*************************************************************************/

#define TRUE	1
#define FALSE 	0

#define BUFSIZE		1024            /* not less that 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



#include	<stdio.h>
#include	<bios.h>
#include	<ctype.h>
#include <stdlib.h>
#include <string.h>
#include <dir.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	inFileAmb[255];
char	inFullName[255];
char	inPath[255];
struct	ffblk myFFBlk;
char	wildProcess;
char	appendFlag=FALSE;
char	appendChar[2];

char 	version[] = "v1.02";

// Prototypes
int  processArgs(int,char**);
int  readDirectory(void);
int  writeDirectory(void);
int  verifyEOS(unsigned char*);
long filesize(FILE*);
int  copyFile(FILE*);
int  compareName(char*,char*);
int  findEmptyFCB(unsigned int);
int  convertName(char*,char*);


#include	"ReadBlk.c"
#include	"WriteBlk.c"

int main(argc,argv)
	int	argc;
	char	*argv[];
{
	int	block;
	int	result;
        FILE	*inFileP;

	if(!processArgs(argc,argv))
		exit(0);

	if(findfirst(inFileAmb,&myFFBlk,0)) {
		fprintf(stderr,"No files match: %s\n",inFileAmb);
		exit(0);
	}

	do {
		strcpy(inFileName,myFFBlk.ff_name);
		convertName(inFileName,outFileName);
		strcpy(inFullName,inPath);
		strcat(inFullName,inFileName);

		if((inFileP=fopen(inFullName,"rb"))==NULL) {
			printf("Can't find PC file: %s\n",inFullName);
			exit(0);
		}

		if(!readDirectory()) {
			exit(0);
		}
		if(!copyFile(inFileP)) {
			exit(0);
		}

		fclose(inFileP);

	} while(findnext(&myFFBlk) == 0);
	return(0);
}

/*******************************************************
* processArgs - process the command line args
*		sets globals inFileName,outFileName
********************************************************/
processArgs(argc,argv)
   int	argc;
   char	*argv[];
{
   int	i, myArg;
   int	len;

   if(argc<2) {
		printf("PC2ADAM %s - Public Domain from Bonafide Systems\n\n",version);
		puts("Usage: PC2ADAM <amb. src. PC file> [unamb. dest. ADAM file] [-T:typechar]");
      puts("If PC filename is ambiguous, then ADAM filename may not be present.");
      puts("The filetype is a single character that will be appended to the ADAM");
      puts("filename.\n");
      return(FALSE);
   }

   wildProcess=TRUE;
   strcpy(inFileAmb,argv[1]);
   strcpy(inPath,argv[1]);
   len=strlen(inPath);
   while(len!=0 && inPath[len-1] != '\\' && inPath[len-1] != ':')
      len--;
   inPath[len]='\0';

   myArg=2;
   while(myArg < argc) {
		if(*(argv[myArg])=='-') {	/* process flag */
			if((*(argv[myArg]+1)=='T' || *(argv[myArg]+1)=='t') &&
					*(argv[myArg]+2)==':' && *(argv[myArg]+3)!='\0' &&
					*(argv[myArg]+4)=='\0') {
				appendFlag=TRUE;
				appendChar[0]=*(argv[myArg]+3);
				appendChar[1]='\0';
				myArg++;
			}
			else {
				printf("Unrecognized argument: %s\n",argv[myArg]);
				return(FALSE);
			}
		}
		else {
			if(!wildProcess) {   /* have we already got our destination? */
				printf("Unrecognized argument: %s\n",argv[myArg]);
				return(FALSE);
			}

			for(i=0;inFileAmb[i]!='\0';i++) {
				if(inFileAmb[i]=='?' || inFileAmb[i]=='*') {
					puts("Can't specify ADAM filename for ambiguous PC filename!");
					return(FALSE);
				}
			}
			strcpy(outFileName,argv[2]);
			outFileName[11]='\0';
			wildProcess=FALSE;
			myArg++;
		}
   } /* while */

   return(TRUE);
}



/*****************************************************
* readDirectory
*	reads the EOS directory in the myDir array of FCB structures
*	returns 0 if OK, BIOSDISK error code if error
*****************************************************/
readDirectory()
{
   int	result,i,j,done=FALSE;
   int	fcbCount=0;
   int	dirBlocks,blockCount=1;
   char	*bytePtr;

   if(result=readBlock(blockCount,buffer)) {	/* read directory block */
   	printf("Error reading block: %d, errcode=%d\n",blockCount,result);
		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(result=readBlock(blockCount,buffer))	{
			printf("Error reading block: %d, errcode=%d\n",blockCount,result);
			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 */
}


/*****************************************************
* writeDirectory
*	writes the EOS directory in the myDir array of FCB structures
*	returns TRUE if OK, FALSE if error
*****************************************************/
writeDirectory()
{
   int	result,i,j;
   int	fcbCount;
   int	dirBlocks;
   char	*bytePtr,*bufferPtr;
   int	done=FALSE;

	dirBlocks=myDir[0].status & 0x7F;	/* number of directory blocks */
   for(i=0;i<dirBlocks && !done;i++) {
		for(j=0;j<BUFSIZE;j++) 		/* zero out buffer */
			buffer[j]=0;
		bufferPtr=buffer;

		for (fcbCount=i*NUM_FCB_IN_BLOCK;
			  fcbCount<(i+1)*NUM_FCB_IN_BLOCK && !done;
			  fcbCount++) {
			bytePtr=(char*)&myDir[fcbCount];
			for(j=0;j<FCB_SIZE;j++) {
				*bufferPtr=*bytePtr;
				bufferPtr++;
				bytePtr++;
			}
			if(myDir[fcbCount].status==HOLE)
				done=TRUE;
		}

		if((result=writeBlock(i+1,buffer))!=0) {
        	printf("[Error writing directory block %d]\n",i+1);
			return(FALSE);
		}
   }
   return(TRUE);
}


/***************************************************************
* filesize
***************************************************************/
long filesize(FILE *stream)
{
   long curpos, length;

   curpos = ftell(stream);
   fseek(stream, 0L, SEEK_END);
   length = ftell(stream);
   fseek(stream, curpos, SEEK_SET);
   return length;
}



/********************************************************
* copyFile - returns TRUE if OK, FALSE if error
********************************************************/
copyFile(fp)
   FILE *fp;
{
   int	newFCB;
   long	bytesInFile,bytesToRead;
   unsigned int	blockNum,blocksInFile;
   int	result,i;

   printf("Copying %12s -> %11s ",inFileName,outFileName);

   /* Compute number of blocks needed to contain file */
   bytesInFile=filesize(fp);
   if(bytesInFile == -1) {
      puts("[Error getting DOS file size!]");
      return(FALSE);
   }
   blocksInFile=bytesInFile/1024;
   if(blocksInFile*1024 != bytesInFile)
      blocksInFile++;

   if((newFCB=findEmptyFCB(blocksInFile))==0) {
		return(FALSE);                   /* error occured */
   }

   if (myDir[newFCB].status==HOLE) {
      myDir[newFCB+1]=myDir[newFCB];
      myDir[newFCB+1].startBlock += blocksInFile;
      myDir[newFCB+1].blocksAllocated -= blocksInFile;
      myDir[newFCB].blocksAllocated = blocksInFile;
   }

   bytesToRead=bytesInFile;
   for(blockNum=myDir[newFCB].startBlock;
			blockNum<myDir[newFCB].startBlock + blocksInFile; blockNum++) {
		if(bytesToRead<1024) {
			fread(buffer,(int)bytesToRead,1,fp);
				for(i=bytesToRead;i<1024;i++)
					buffer[i]='\0';
		}
		else {
			fread(buffer, 1024, 1, fp);
			bytesToRead-=1024;
		}
		if(ferror(fp)) {
			puts("[Error reading DOS file!]");
			return(FALSE);
		}

		if(result=writeBlock(blockNum,buffer)) {
			printf("[Error writing block: %d]\n",blockNum);
			return(FALSE);
		}
   }

   for(i=0;i<11 & outFileName[i]!='\0';i++)
      myDir[newFCB].fileName[i] = outFileName[i];
   myDir[newFCB].fileName[i] = '\3';              /* mark End-of-String */

   myDir[newFCB].status = USER;                   /* file status */
   myDir[newFCB].blocksUsed = blocksInFile;
   myDir[newFCB].bytesInLastBlock = bytesInFile-((blocksInFile-1)*1024);
   for(i=0;i<2;i++)
      myDir[newFCB].date[i]='\0';
   if(writeDirectory()) {
      puts("[OK]");
      return(TRUE);
   }
   return(FALSE);
}


/*********************************************************************
* compareName - returns TRUE if names are the same, FALSE if not
*		EOS terminated strings
*********************************************************************/
compareName(s1,s2)
	char *s1,*s2;
{
	while(*s1 == *s2) {
	   if(*s1=='\3') {	/* end of string? */
			return(TRUE);
		}
	   s1++;
	   s2++;
	}
	return(FALSE);
}




/*********************************************************************
* findEmptyFCB - locates an FCB for the new file
*		 Returns FALSE (0) if can't find one, otherwise the
*		 FCB number to use for the file.
**********************************************************************/
findEmptyFCB(blocksInFile)
	unsigned int	blocksInFile;
{
	int	i;
	int	dirBlocks;
	char	newName[255];


	/* check for duplicate filename */
	i=0;
	while(outFileName[i]) {
	   newName[i]=outFileName[i];
	   i++;
	}
	newName[i]='\3';

	i=3;
	while(myDir[i].status != HOLE) {
	   if(compareName(newName,myDir[i].fileName)) {
			if(!(myDir[i].status & DELETED)) {
	      	puts("[File already exists!]");
				return(FALSE);
			}
	   }
	   i++;
	}

	/* scan for a deleted file to replace */
	i=3;
	while(myDir[i].status != HOLE) {
	   if(myDir[i].status & DELETED) {
	      if(myDir[i].blocksAllocated >= blocksInFile) {
				return(i);
	      }
	   }
	   i++;
	}

	/* Have to use the directory 'HOLE' but don't use it if there */
	/* is no more room to move the HOLE down */
	dirBlocks=myDir[2].status & 0x7F;	/* number of directory blocks */
	if(i==(dirBlocks*NUM_FCB_IN_BLOCK)-1) {
	   puts("[No FCB's left on ADAM disk!]");
	   return(FALSE);
	}

	if(myDir[i].blocksAllocated < blocksInFile) {
	   puts("[No more room on ADAM disk!]");
	   return(FALSE);
	}
	return(i);
}


/*************************************************************
* convertName - Converts the DOS filename to an ADAM filename
**************************************************************/
convertName(in,out)
   char *in;
   char *out;
{
   char *inP,*outP;

   inP=in;
   outP=out;

   if(!wildProcess) {
		if(appendFlag) {
			if(strlen(out)>10) {
				out[10]=appendChar[0];
				out[11]='\0';
			}
			else {
				strcat(out,appendChar);
			}
		}
		return(0);
   }

   if(appendFlag) {
      if(strlen(in)<11) {
			strcpy(out,in);
			strcat(out,appendChar);
      }
      else {
         while(*inP) {
				if(*inP != '.') {
					*outP=*inP;
					outP++;
				}
				inP++;
			}
			*outP='\0';
         if(strlen(out)<11) {
				strcat(out,appendChar);
			}
			else {
				out[10]=appendChar[0];
				out[11]='\0';
         }
      }
   } /* if appending */

   else {  			/* not appending */
      if(strlen(in)<12) {
         strcpy(out,in);
      }
      else {
         while(*inP) {
				if(*inP != '.') {
					*outP=*inP;
					outP++;
				}
				inP++;
         }
			*outP='\0';
      }
   }
   return(0);
}

