/* Compile with HiTech C for CP/M-80 v3.09 */

/* c -c b:putsys.c */
/* c putsys.obj bdos.obj */

/* corrected problem with TOUPPER in convert drive number */

#include <cpm.h>
#include <stddef.h>
#include <ctype.h>
#include <stat.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h> 
#include "B:BDOS.H"


FILE * infile;

struct stat FileStat;

int optVerbose=1;
int optLogin=1;
int optDebug=0;
int optInvalid=0;

char * tMAGIC="MAGIC";
char * tBOOT="BOOT";
char * tDCM="DCM";
char * tBIOS="BIOS";
char * tCCP="CCP";
char * tBDOS="BDOS";
char * tCPM="CPM";
char * tLDR="LDR";
char * tSYS="SYS";
char * tALL="ALL";

char * ptrInvoked;
char * ptrType;
char * ptrIF;

char * ptrNOT;

short iType=0;
short iStart=0;
short iEnd=0;
short iCount=0;

unsigned char * Buffer;
unsigned char data[(128*72)+256];

short CPMversion;

char bios(int BiosFunct, int BC, int DE);

char abios(int pBiosFunct, int pBC, int pDE)
{
struct DirectBios BiosPB;
if (CPMversion==3)
	{
	BiosPB.Func=pBiosFunct; 
	BiosPB.A=0;
	BiosPB.BC=pBC;
	BiosPB.DE=pDE;
	BiosPB.HL=0;

	return(bdos(50,&BiosPB));
	}

if (CPMversion==2)
	return(bios(pBiosFunct, pBC, pDE));

return(0);
}

char abiosa(int pBiosFunct, char pA)
{
struct DirectBios BiosPB;
if (CPMversion==3)
	{
	BiosPB.Func=pBiosFunct; 
	BiosPB.A=pA;
	BiosPB.BC=0;
	BiosPB.DE=0;
	BiosPB.HL=0;

	return(bdos(50,&BiosPB));
	}

return(0);
}
void Exit(int code, char * message1, char * message2)
{
	if (message1 !=0) fprintf (stderr,"\n   %s\n", message1);
	if (message2 !=0) fprintf (stderr,"\n   %s\n", message2);
	if ( code ==1 ) 
		{
		fprintf (stderr,"\n Usage: PutSys TYPE=<Type> [[IF=]<FileName>] [<opts>]\n");
		fprintf (stderr,"   Type  Sectors\n");
		fprintf (stderr,"   %-6s  5    (1)\n",tMAGIC);
		fprintf (stderr,"   %-6s  6    (1)\n",tBOOT);
		fprintf (stderr,"   %-6s  9-16 (8)\n",tDCM);
		fprintf (stderr,"   %-6s 17-28 (12)\n",tBIOS);
		fprintf (stderr,"   %-6s 29-44 (16)\n",tCCP);
		fprintf (stderr,"   %-6s 45-72 (28)\n",tBDOS);
		fprintf (stderr,"   %-6s 29-72 (44)\n",tCPM);
		fprintf (stderr,"   %-6s 17-72 (56)\n",tLDR);
		fprintf (stderr,"   %-6s  6-72 (67)\n",tSYS);
		fprintf (stderr,"   %-6s  1-72 (72)\n",tALL);
		fprintf (stderr,"\n  Help  /H or /?\n");
		fprintf (stderr,"  Login (SelDsk) /[+|-]L\n");
		fprintf (stderr,"  Verbose  /[+|-]V\n");
		};
	exit (code);
}

int GetSlashOptions(char * ptrStr)
{
	int j=0; int offOpt=0;
	if (ptrStr[0] != '/' )return (0);
	for (j = 1; j < strlen(ptrStr) ; j++ )
	{
	switch (ptrStr[j])
		{
		case '/' : break;
		case '+' : offOpt=0;  break;
		case '-' : offOpt=1;  break;
		case 'L' :
				if (offOpt==1)
					{optLogin = 0;  offOpt=0;}
				else
					{optLogin = 1;};
				break;
		case 'V' :
				if (offOpt==1)
					{optVerbose = 0;  offOpt=0;}
				else
					{optVerbose = 1;};
				break;
		case 'G' :
				if (offOpt==1)
					{optDebug = 0;  offOpt=0;}
				else
					{optDebug = 1;};
				break;
		case '?' :
		case 'H' :
		 	Exit (1,0,0);
		default: fprintf (stderr," Invalid Option %c \n" ,(char)ptrStr[j]);
			optInvalid=1;
		}
	}
	return(1);
}

int GetNamedStringOptions(char *ptrStr)
{
	if (strncmp("IF=",ptrStr,3)==0 ) 
	{
		ptrIF=ptrStr+3;
		return(1);
	}
	if (strncmp("TYPE=",ptrStr,5)==0 ) 
	{
		ptrType=ptrStr+5;
		return(1);
	}
	
 return(0);
}

void GetOptions(int argc, char * argv[], char * env[])
{
int i ; 
char * ptrStr ;
ptrInvoked=argv[0];
for (i = 0; i < argc ; i++)
 {
  ptrStr = argv[i];
  if ( strlen(ptrStr) != 0 )
  {
  	if ( GetSlashOptions(ptrStr) );
  	else if (GetNamedStringOptions(ptrStr));
  	else ptrIF=ptrStr;
  }
 }
}

void PrintCmdLine(int argc, char * argv[], char * env[])
{
 int i;
 printf("argc is %d \n" , argc);
 for (i = 0 ; i < argc ; i++) fprintf(stderr," Argument %d is %s \n",i,argv[i]);
 fprintf(stderr,"Type is %s \n" , ptrType);
 fprintf(stderr,"Filename is %s \n" , ptrIF);
 fprintf(stderr,"optDebug is %d \n" , optDebug);
 fprintf(stderr,"optLogin is %d \n" , optLogin);
 fprintf(stderr,"optVerbose is %d \n" , optVerbose);
}

unsigned char * InitBuffer(char pValue)
{
short i;
	for (i=0; i<(72*128+256); i++)
	{
	data[i]=pValue;
	}

	i=((short)data % 256);
	if (i !=0 ) 
		return( (unsigned char*)data + (256-i) );
	else
		return( (unsigned char*)data );
}

short SetParameters ()
{
	if (strcmp (tMAGIC,ptrType)==0){ iStart=5;  iEnd=5 ; iCount=1;}
	if (strcmp (tBOOT,ptrType)==0) { iStart=6;  iEnd=6 ; iCount=1;}
	if (strcmp (tDCM,ptrType)==0)  { iStart=9;  iEnd=16; iCount=8;}
	if (strcmp (tBIOS,ptrType)==0) { iStart=17; iEnd=28; iCount=12;}
	if (strcmp (tCCP,ptrType)==0)  { iStart=29; iEnd=44; iCount=16;}
	if (strcmp (tBDOS,ptrType)==0) { iStart=45; iEnd=72; iCount=28;}
	if (strcmp (tCPM,ptrType)==0)  { iStart=29; iEnd=72; iCount=44;}
	if (strcmp (tLDR,ptrType)==0)  { iStart=17; iEnd=72; iCount=56;}
	if (strcmp (tSYS,ptrType)==0)  { iStart=6;  iEnd=72; iCount=67;}
	if (strcmp (tALL,ptrType)==0)  { iStart=1;  iEnd=72; iCount=72;}
	return(iCount);
}

int ConverDriveLetterToNumber(int pKey)
{
int tKey;
tKey=pKey;
  if ( ( tKey >= 'A') && (tKey < 'Q')) 
	return( tKey - 'A');
  else if ( (tKey >='a') && (tKey < 'q'))
	return( tKey - 'a');
  else
	return(-1);
}

short GetDriveNumber ( char * pMessage )
{
int key=0;
short tDiskDrive;
	do
	{
	  do
	  {
		fprintf(stderr,"\n Input %s Disk Drive Letter (A-P) - ",pMessage);

		key = getch();
		putch(key);
		switch (key)
		{
			case 3:     /* cntrl-c */
			case 4 :    /* cntrl-d */
			case 26:  Exit(0,0,0);  break;   /* cntrl-z */
			default : tDiskDrive=ConverDriveLetterToNumber(key);
		}
	  } while (tDiskDrive ==-1);

	  fprintf(stderr,"\n Press Return when %s drive %c ready (Cntrl-C to abort) - ",pMessage,(char)key);

	  key = getch();
	  putch(key);
	  switch (key)
	  {
		case 3:     /* cntrl-c */
		case 4 :    /* cntrl-d */
		case 26:  Exit(0,0,0);  break;   /* cntrl-z */
	  }
	}while ( (key != 13) && (key != 10) );
return(tDiskDrive);
}


int main(int argc, char * argv[], char * env[])
{
long BytesRead=0;
long BytesWrote=0;
long RecordsRead=0;
long RecordsWrote=0;
long BytesInFile=0;
long RecordsInFile=0;

char RetA=0;
short DiskDrive=1;
short Sector=0; 
short Track=0;
short DMA=0;
short LogIn=0;

CPMversion=GetCPMVERS();

if (CPMversion == 0x00) CPMversion=1;
else if ((CPMversion >= 0x20) && (CPMversion <0x30)) CPMversion=2;
else if ((CPMversion >= 0x30) && (CPMversion <0x40)) CPMversion=3;
else CPMversion=0;

if ((CPMversion!=2) && (CPMversion!=3)) Exit(1,"Requires CPM 2.x or 3.x",0);

	GetOptions(argc,argv,env);

	if (optVerbose) fprintf(stderr,"\nPut System Tracks for PCxxxx  Version 1.2 for CP/M-80\n");
	if (optDebug) PrintCmdLine (argc,argv,env);
	if (optInvalid == 1) Exit(1,0,0);

	if (ptrType !=0)
	{
		if (SetParameters()==0)
		{ 
			fprintf(stderr,"\nInvalid Type=%s\n",ptrType);
			Exit(1,0,0);
		}
	}
	else
	{
		Exit(1,"No Type Specified!",0);
	}

	if(optVerbose) fprintf(stderr,"\n Type=%s Start=%d, End=%d, Count=%d\n",ptrType,iStart,iEnd,iCount);

	if (ptrIF != 0 )
	{
		if ( (infile = fopen( ptrIF, "rb" ))==NULL )
		{ 
			fprintf(stderr,"\nCan not open %s\n",ptrIF);
			Exit(1,0,0);
		}
	}

	Buffer=InitBuffer(0xe5);

	if(optVerbose) 
	{
		fprintf(stderr,"\n Buffer at 0x%04lX\n",Buffer);
		if (optLogin) ptrNOT=" "; else ptrNOT=" NOT ";
		fprintf(stderr,"\n Disk will%sbe Logged In during BIOS SelDSK\n",ptrNOT);
	}

	if (ptrIF!=0)
	{
		/* Read from File */

		stat(ptrIF, &FileStat);

		BytesInFile=FileStat.st_size;
		RecordsInFile=BytesInFile/128;

		if (optVerbose)
		{
		fprintf(stderr,"\n %ld - 0o%lo - 0x%lX records in file\n",RecordsInFile,RecordsInFile,RecordsInFile);
		fprintf(stderr," %ld - 0o%lo - 0x%lX bytes in file\n",BytesInFile,BytesInFile,BytesInFile);
		fprintf(stderr,"\n Reading file %s as %s\n",ptrIF,ptrType);
		}

		RecordsRead=fread(Buffer,128,iCount,infile); 

		fclose(infile);
	}
	else
	{
		/* get source disk drive */

		DiskDrive=GetDriveNumber("Source");

		/* Read system from system track 0 */

		if(optVerbose) fprintf(stderr,"\n\n Reading System Track as %s\n",ptrType);

		DMA=(short)Buffer;

		/*seldsk 09*/
		if (optLogin == 0){LogIn=1;} else {LogIn=0;}
		RetA=abios(9, DiskDrive, LogIn); /* 0=A: 1=B:  login de  */

		/*settrk 10*/
		RetA=abios(10, Track, 0); /*track 0 and de=0*/

		for (Sector = iStart ; Sector <= iEnd ; Sector++)
		{
			/*setsec 11*/
			RetA=abios(11, Sector, 0);

			/*setdma 12*/
			RetA=abios(12, DMA, 0);

			/*setbank 28*/
			RetA=abiosa(28, 1);

			/*readsec 13*/
			RetA=abios(13, 0, 0);
			DMA+=128;
			if (RetA==0) RecordsRead+=1;
		}
	}

	BytesRead=RecordsRead*128;

	if(optVerbose)
	{
		fprintf(stderr,"\n %ld - 0o%lo - 0x%lX records read\n",RecordsRead ,RecordsRead, RecordsRead);
		fprintf(stderr," %ld - 0o%lo - 0x%lX bytes read\n",BytesRead ,BytesRead, BytesRead);
	}

/* get disk destination drive */

DiskDrive=GetDriveNumber("Destination");

/* write system to system Track 0 */

	DMA=(short)Buffer;

	/*seldsk 09*/
	if (optLogin == 0){LogIn=1;} else {LogIn=0;}
	RetA=abios(9, DiskDrive, LogIn); /* 0=A: 1=B:  login de  */

	/*settrk 10*/
	RetA=abios(10, Track, 0); /*track 0 and de=0*/

	for (Sector = iStart ; Sector <= iEnd ; Sector++)
	{
		/*setsec 11*/
		RetA=abios(11, Sector, 0);

		/*setdma 12*/
		RetA=abios(12, DMA, 0);

		/*setbank 28*/
		RetA=abiosa(28, 1);

		/*writesec 14*/
		if (optDebug==0)
			RetA=abios(14, 0, 0);
		else
			RetA=abios(13, 0, 0);
		DMA+=128;
		if (RetA==0) RecordsWrote+=1;
	}

	BytesWrote=RecordsWrote*128;

	if(optVerbose)
	{
	fprintf(stderr,"\n\n %ld - 0o%lo - 0x%lX records writen\n",RecordsWrote ,RecordsWrote, RecordsWrote);
	fprintf(stderr," %ld - 0o%lo - 0x%lX bytes writen\n",BytesWrote ,BytesWrote, BytesWrote);
	}
	return (0);
}

