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

/* c -c b:initdirn.c */
/* c initdirn.obj parseafn.obj datetime.obj biosx.obj bdos.obj */

#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 <malloc.h> */
#include "B:BDOS.H"
#include "B:PARSEAFN.H"
#include "B:DATETIME.H"

char InByte;
char * ptrInvoked;
char * ptrDirName;
int optLong=0;
int optAll=0;
int optSort=0;
int optFE=0;
int optVerbose=1;
int optBlkSize=0;
int optUorCdts=0;
int optDate=0;
int optDebug=0;

int ACflag=0;
int Uflag=0;

short CPMversion;

short DMsize;
short BLKsize;
short BLKcount;
short BlksDir;
unsigned short DSM;
int aUser[16];

int TotalDelEnts ;
int TotalUsedEnts ;
int TotalDTSEnts ;
int TotalPWSEnts ;
int TotalLBLEnts ;
int TotalFILEnts ;

int TotalDirs=0; 
int TotalBlks=0; 
int TotalFils=0;

long pSecInDir;
int lSecPerPhy;
int pSecSize;
int pSPT;
int trk;
int sct;

short * ptrDPH ;
short * ptrXLT ;
struct DirectBios BiosPB;

/* short bdoshl(int func, int arg); */
/* char bdos(int func, int arg); */

/* char bios(int func, int arg, int arg); */

struct CPMfcbLabel fcbLabel;
struct CPMfcb fcb;
struct CPMxfcb xfcb;
struct CPMsfcb sfcb;

struct CPMfcb  srcFCB;

struct CPMdpb * ptrDPB;

char * tempPTR;

struct DirectBios * bios2(struct DirectBios * pBiosPB);
struct DirectBios * bios3(struct DirectBios * pBiosPB);

struct DirectBios * biosx(struct DirectBios * pBiosPB)
{
if (CPMversion==3)
	return(bios3(pBiosPB));
if (CPMversion==2)
	return(bios2(pBiosPB));
return(NULL);
}

void usage(int pErr)
{
  fprintf(stderr, "Usage: %s [-v|q] <drive>:\n\n", ptrInvoked);
  fprintf(stderr, " This program will write Date/Time Stamps to a disk's directory\n");
  fprintf(stderr, "        The disk MUST be BLANK\n");
  fprintf(stderr, " Use SET to add LABEL and turn ON PROTECTION and DATE/TIME STAMPS\n");
  fprintf(stderr, "  -v Verbose\n");
  fprintf(stderr, "  -h or -? help\n");
  exit(pErr);
}

void GetOptions(int argc, char * argv[], char * env[])
{
int i;
char c1,c0;

  for(i = 1; i < argc; i++)
    {
	c0=argv[i][0];
	c1=argv[i][1];
	if (c0 == '-')
	{
		if(c1 == 'D')optDebug=1;
		else if(c1 == 'V')optVerbose=1;
		else if(c1 == 'Q')optVerbose=0;
		else if((c1 == 'H') || (c1 == '?'))usage(0);
		else	{
			fprintf(stderr, "Unknown option %s\n", argv[i]);
			usage(1);
			}
	}
	else	ptrDirName = argv[i];
   }    /* for */
}
int CountFiles(int pDisk)
{
char aRTN;

int tempDR;

int i;

struct CPMfcb * tempPTR;
struct CPMfcb srcFCB;

TotalDelEnts=0;
TotalUsedEnts=0;
TotalPWSEnts=0;
TotalDTSEnts=0;
TotalLBLEnts=0;
TotalFILEnts=0;

for(i = 0 ; i < 16 ; i++) aUser[i]=0;

InitFCB (&srcFCB,'?');

srcFCB.dr='?'; 

aRTN=FindFirst(&srcFCB);

while (aRTN !=-1)
	{
 	if (aRTN!=-1)
		{ 	tempPTR=(struct CPMfcb *)(0x0080+(aRTN*32));
			tempDR=tempPTR->dr;
			/* fprintf(stderr,"ptr= %x, dr=%d aRTN=%d\n",tempPTR,tempDR,aRTN); */
			/* PrintFCB((struct CPMfcb *)(0x0080+(aRTN*32)),0); */
			if (tempDR==0xe5) TotalDelEnts++;
			if (tempDR==0x20) 
			{
				memcpy( &fcbLabel,tempPTR, 32);
				if ((fcbLabel.dl & 0x40)!=0)ACflag=1;
				if ((fcbLabel.dl & 0x20)!=0)Uflag=1;
				if ((fcbLabel.dl & 0x10)!=0)ACflag=1;
				TotalLBLEnts++;
			}
			if (tempDR==0x21) TotalDTSEnts++;
			if ( (tempDR>=0x10)&&(tempDR<0x20) )TotalPWSEnts++;
			if ( (tempDR>=0x0)&&(tempDR<0x10) ){TotalFILEnts++;aUser[tempDR]++;}
			TotalUsedEnts++;		
		}
 	aRTN=FindNext(&srcFCB);
	}
return (TotalFILEnts + TotalPWSEnts + TotalLBLEnts + TotalDTSEnts);
}

int TallyOnes(uchar pByte,int pBits)
{
int t=0;
if (((pByte & 128)!=0)&& (pBits>0))t++;
if (((pByte & 64)!=0)&& (pBits>1))t++;
if (((pByte & 32)!=0)&& (pBits>2))t++;
if (((pByte & 16)!=0)&& (pBits>3))t++;
if (((pByte & 8)!=0)&& (pBits>4))t++;
if (((pByte & 4)!=0)&& (pBits>5))t++;
if (((pByte & 2)!=0)&& (pBits>6))t++;
if (((pByte & 1)!=0)&& (pBits>7))t++;
return(t);
}

int PrintLabel()
{
int i;
char tStr[20];
	fprintf(stdout,"\nDisk Label = ");
	for (i=0;i<8;i++)fprintf( stdout,"%c",fcbLabel.name[i] & 0x7f );
	fprintf(stdout,".");
	for (i=0;i<3;i++)fprintf( stdout,"%c",fcbLabel.ft[i] & 0x7f );

	fprintf(stdout,"    Password=");
	for (i=7;i>=0;i--)fprintf( stdout,"%c",fcbLabel.pw[i] ^ fcbLabel.pd );

	fprintf(stdout,"\n\n    ");
	dts2str( &fcbLabel.ACdts ,tStr );
	fprintf( stdout," %s ", tStr);
	dts2str( &fcbLabel.Udts ,tStr );
	fprintf( stdout," %s ", tStr);

	if ((fcbLabel.dl & 0x80)!=0)fprintf(stdout," Protected ");
	if ((fcbLabel.dl & 0x10)!=0)fprintf(stdout," Create ");
	if ((fcbLabel.dl & 0x40)!=0)fprintf(stdout," Access ");
	if ((fcbLabel.dl & 0x20)!=0)fprintf(stdout," Update ");
	if ((fcbLabel.dl & 0x01)!=0)fprintf(stdout," Labeled ");

	fprintf(stdout,"\n");

}

int CountBits(uchar * pArray, int pMaxBits)
{
int i,t=0;
for (i=0;i<(pMaxBits/8);i++) {t+=TallyOnes(pArray[i],8);}
	if ( (pMaxBits%8)!=0 )t+=TallyOnes(pArray[i],pMaxBits%8);
	return (t);
}

int main(int argc, char * argv[], char * env[])
{
long Entries;
int cUser,cDisk;
int StartUpDrive;

int TotalAvailEnts;

int i;
int t;

int RTN;

uchar * ptrALV;

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!=3)&&(CPMversion!=2))
	{
	fprintf(stderr,"\n Requires CPM 3.x or CPM 2.x\n");
	exit(1);
	}

ptrInvoked="InitDirN";

StartUpDrive=GetCURDISK();

GetOptions(argc,argv,env);

if (optVerbose==1)fprintf(stdout,"%s Version 1.0 for CPM Plus Version 3\n",ptrInvoked);
/* if (optVerbose==1)fprintf(stdout,"   %s %s\n",ptrInvoked,ptrDirName); */

/* PrintFCB((struct CPMfcb *) 0x5c,1); */

InitFCB(&srcFCB,' ');
/* memcpy(&srcFCB,(void *) 0x5c,12); */
/* PrintFCB(&srcFCB,1); */

if (ptrDirName==0)
	cUser=-1;
else
	cUser=ParseDRU(&srcFCB,ptrDirName);

if (cUser!=-1) {fprintf(stderr,"Bad User/Drive\n");usage(1);}

/* PrintFCB(&srcFCB,1); */

if ( srcFCB.dr != 0 )
 {cDisk=(srcFCB.dr)-1; Seldsk(cDisk);}
else
 {fprintf(stderr,"Must specify Drive\n");usage(1);}
	
	ptrDPB->PSH=0;
	ptrDPB->PHM=0;
	ptrDPB=GetDPB();
	if (ptrDPB->BSH ==3) BLKsize=1024;
	if (ptrDPB->BSH ==4) BLKsize=2048;
	if (ptrDPB->BSH ==5) BLKsize=4096;
	if (ptrDPB->BSH ==6) BLKsize=8192;
	if (ptrDPB->BSH ==7) BLKsize=16384;
	BLKcount=(ptrDPB->DSM)+1;
	if (BLKcount > 256) DMsize=16; else DMsize=8;

	ptrALV=(uchar *)(&(ptrDPB->AL0));
	BlksDir=CountBits(ptrALV,16);

	if (CPMversion==2){pSecSize=128;lSecPerPhy=1;}
	else if (ptrDPB->PSH ==0) {pSecSize=128;lSecPerPhy=1;}
	else if (ptrDPB->PSH ==1) {pSecSize=256;lSecPerPhy=2;}
	else if (ptrDPB->PSH ==2) {pSecSize=512;lSecPerPhy=4;}
	else if (ptrDPB->PSH ==3) {pSecSize=1024;lSecPerPhy=8;}
   /*	if (ptrDPB->PSH >=4){ fprintf(stderr,"\n non-IBM Phyical sector size, not supported\n\n"); exit(1); } */
   	else if (ptrDPB->PSH ==4) {pSecSize=2048;lSecPerPhy=16;} 
   	else if (ptrDPB->PSH ==5) {pSecSize=4096;lSecPerPhy=32;} 

	pSecInDir=((long)BlksDir*(long)BLKsize)/pSecSize;
   /*	pSecInDir=(BLKsize/pSecSize)*BlksDir; */
   /*	lSecInDir=(BLKsize/128)*BlksDir;  */

 	pSPT=(ptrDPB->SPT)/((ptrDPB->PHM)+1);

	fprintf(stderr,"\n SPT=%d, pSecSz=%d, pSPT=%d, Blks=%d, BlkSz=%d, DirBlks=%d, DirEnts=%d, Off=%d\n"
			,ptrDPB->SPT,pSecSize,pSPT,BLKcount, BLKsize,BlksDir,(ptrDPB->DRM)+1,ptrDPB->OFF);

InitFCB (&srcFCB,'?');

srcFCB.dr='?'; 

Entries = CountFiles(cDisk+1);
	
if (Entries !=0)
{
	fprintf(stderr,"\nDisk %c is not blank!\n",cDisk+'A');
	if (TotalLBLEnts>0) PrintLabel();
	fprintf (stdout,"\n (%d Label) (%d File entries) (%d Passwords) (at least %d Time/Date Stamps)\n", 
			TotalLBLEnts, TotalFILEnts, TotalPWSEnts,TotalDTSEnts);

	fprintf(stdout," User Numbers with Files:" );
	for (i=0;i<16;i++) if (aUser[i]!=0)fprintf (stdout, " %d",i);
	fprintf (stdout, "\n");

	exit(1);
}
tempPTR=(char *)calloc(128 ,lSecPerPhy);
bdoshl(CPMSDMA,tempPTR);

/* fprintf(stderr,"\n %04x \n",tempPTR); */

for (i=0 ; i < lSecPerPhy; i++) 
	{
	t=i*128;
	tempPTR[t]=0xe5; 
	tempPTR[t+32]=0xe5; 
	tempPTR[t+64]=0xe5; 
	tempPTR[t+96]=0x21;
	}

BiosPB.Func=9; /* seldsk */
BiosPB.A=0;
BiosPB.BC=cDisk;
BiosPB.DE=1;
BiosPB.HL=0;
biosx(&BiosPB);
ptrDPH=BiosPB.HL;

ptrXLT=*ptrDPH;

/* fprintf (stderr,"\n ptrDPH=%04x, xlt=%04x\n",ptrDPH,ptrXLT); */
   fprintf(stderr,"\nDisk in %c will be Formated for CPM 3 Time and Date Stamps...\n",cDisk+'A');
   fprintf(stderr,"\n Ok to Continue? (Y or N) - ");
   InByte=getche();
   if ( (InByte != 'Y') && (InByte != 'y' ) ) exit(1);


for (i=0 ; i<pSecInDir; i++)
	{
	trk=(i / pSPT) + ptrDPB->OFF;
	BiosPB.Func=16; /* sectran */
	BiosPB.A=0;
	BiosPB.BC=(i%pSPT);
	BiosPB.DE=(short)ptrXLT;
	BiosPB.HL=0;
	biosx(&BiosPB);
	sct=BiosPB.HL;
	/* sct=i % pSPT; */
	/* fprintf (stderr,"\n trk=%d, psct=%d",trk,sct); */

	BiosPB.Func=10; /* setrack */
	BiosPB.A=0;
	BiosPB.BC=trk;
	BiosPB.DE=0;
	BiosPB.HL=0;
	biosx(&BiosPB);

	BiosPB.Func=11; /* setsector */
	BiosPB.A=0;
	BiosPB.BC=sct;
	BiosPB.DE=0;
	BiosPB.HL=0;
	biosx(&BiosPB);

	BiosPB.Func=12; /* setDMA */
	BiosPB.A=0;
	BiosPB.BC=(short)tempPTR;
	BiosPB.DE=0;
	BiosPB.HL=0;
	biosx(&BiosPB);

if (CPMversion==3)
	{
	BiosPB.Func=28; /* setbank */
	BiosPB.A=1;
	BiosPB.BC=0;
	BiosPB.DE=0;
	BiosPB.HL=0;
	biosx(&BiosPB);
	}

	BiosPB.Func=14; /* write */
	BiosPB.A=0;
	BiosPB.BC=1;
	BiosPB.DE=0;
	BiosPB.HL=0;
	biosx(&BiosPB);
	 RTN=BiosPB.A; 
	if (RTN!=0){ fprintf(stderr,"\n Error %d writing track=%d, sector=%d\n", RTN, trk, sct);exit(1);}
	}

if ( srcFCB.dr != 0 )Seldsk(StartUpDrive);

fprintf (stderr,"\n ");
}
