home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Go64!
/
Go64_1999-06_1999_CSW_Side_A.d64
/
1581cp50.zip
/
SRC
/
1581HLVL.C
< prev
next >
Wrap
C/C++ Source or Header
|
1999-05-13
|
36KB
|
1,077 lines
/*
* cOPYRIGHT (c) 1998, 1999 wOLFGANG mOSER
*
* tHIS PROGRAM IS FREE SOFTWARE; YOU CAN REDISTRIBUTE IT AND/OR MODIFY
* IT UNDER THE TERMS OF THE gnu gENERAL pUBLIC lICENSE AS PUBLISHED BY
* THE fREE sOFTWARE fOUNDATION; EITHER VERSION 2, OR (AT YOUR OPTION)
* ANY LATER VERSION.
*
* tHIS PROGRAM IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT without any warranty; WITHOUT EVEN THE IMPLIED WARRANTY OF
* merchantability OR fitness for a particular purpose. sEE THE
* gnu gENERAL pUBLIC lICENSE FOR MORE DETAILS.
*
* yOU SHOULD HAVE RECEIVED A COPY OF THE gnu gENERAL pUBLIC lICENSE
* ALONG WITH THIS PROGRAM (SEE THE FILE copying); IF NOT, WRITE TO THE
* fREE sOFTWARE fOUNDATION, iNC., 675 mASS aVE, cAMBRIDGE, ma 02139, usa.
*/
/*
* cOMMODORE cbm 1581 FLOPPY DISK COPY UTIL FOR pc'S, 1581hlvl.c
*
* wOLFGANG mOSER <WOMO@MINDLESS.COM>
* HTTP://WWW.GM.FH-KOELN.DE/{$7e}WOMO (UP TO dEZEMBER 1999)
*
*
* bASIC INFORMATIONS FROM dAN fANDRICH <DAN@FCH.WIMSEY.BC.CA>.
* hIS README OF THE CBMFS-0.3 DRIVER FOR lINUX EXPLAINED ME, WHAT THE
* DIFFERENCE BETWEEN A dos FORMATTED 800 KB DISK AND A cbm 1581 DISK IS.
* (CHECK: HTTP://VANBC.WIMSEY.COM/{$7e}DANF/SOFTWARE/)
*
*
* bASIC IMPLEMENTATIONS BY cIRIACO gARC{CBM-K}A DE cELIS <CIRI@GUI.UVA.ES>
* hIS UTIL 765dEBUG, vERSION 5.0 IS GREAT FOR LEARNING DMA BASED
* DIRECT FLOPPY DISK CONTROLLER PROGRAMMING.
* (CHECK: FTP://FTP.GUI.UVA.ES/PUB/PC/2M/765D50SR.ZIP)
*
* cHECK OUT FOR HIS FLOPPY DISK UTILS 2m AND 2mgui, THE LAST WORDS
* IN IMPROVING FLOPPY DISK STORAGE CAPACITY.
* HTTP://WWW.GUI.UVA.ES/2M, FTP://FTP.GUI.UVA.ES/PUB/PC/2M
*
*
* fOR ADDITIONAL INFORMATIONS TO fdc PROGRAMMING CHECK:
* HTTP://DEVELOPER.INTEL.COM/DESIGN/PERIPHRL/DATASHTS/290468.HTM
* AND GET THE INTEL 82078 chmos sINGLE-cHIP fLOPPY dISK cONTROLLER
* pdf DOCUMENT:
* HTTP://WWW.INTEL.NL/DESIGN/PERIPHRL/DATASHTS/29047403.PDF
* nATIONAL sEMICONDUCTOR HAS ALSO SOME PAGES ABOUT THEIR pc
* COMPATIBLE CONTROLLERS:
* HTTP://WWW.NATIONAL.COM/PF/dp/dp8473.HTML
* HTTP://WWW.NATIONAL.COM/PF/dp/dp8477b.HTML
*
* aNOTHER GOOD SOURCE FOR FLOPPY DISK CONTROLLER PROGRAMMING INFORMATION
* ARE THE LINUX KERNAL SOURCES, YOU COULD HAVE A LOOK INTO:
* HTTP://WWW.CS.UTEXAS.EDU/USERS/PETERSON/LINUX/INCLUDE/LINUX/FDREG.H
* HTTP://WWW.CS.UTEXAS.EDU/USERS/PETERSON/LINUX/DRIVERS/BLOCK/FLOPPY.C
*/
#INCLUDE "1581HLVL.H"
#INCLUDE <STDIO.H>
#INCLUDE <CONIO.H>
#INCLUDE <ASSERT.H>
/*
80,// cYLINDERS: 80 CYLINDERS PER DISK
2,// hEADS: 2 SIDES (TRACKS) PER CYLINDER
10,// sECTORS: 10 SECTORS PER TRACK (SIDE)
2,// bPs: 512 BYTES PER SECTOR
2,// rATE: 250 KILOBIT PER SECOND
1,// mODULATION: mfm
0Xdf,// sPECIFYcmd
0X0c,// rwgap3: 12
0X23,// fMTgap: 35
0X00// pATTERN: 0
*/
STATIC CONST fdcPARAMETERsET fdPRMsETS[2]={$7b}
{$7b}80,2,10,2,2,1,0Xdf,0X0c,0X23,0X00{$7d},
//{$7b}81,2,10,3,0,1,0Xcf,0X0c,0X64,0Xe5{$7d}// gap AND pATTERN ARE FROM THE cmd fd2000 MANUAL
{$7b}81,2,10,3,0,1,0Xcf,0X0c,0X64,0X00{$7d}// gap AND pATTERN ARE FROM THE cmd fd2000 MANUAL
{$7d};
STATIC CHAR fILENAMErETsTR[261];// OUTPUT PATH AND FILENAME
// WAITS FOR A DISK OR A NEW DISK IN THE SPECIFIED DRIVE
//
// INPUT: DRIVE:THE DRIVE, WHERE A DISK HAS TO BE INSERTED INTO
// NEWdISK: IF NOT 0, A NEW DISK IS REQUIRED (DISK CHANGE)
// OUTPUT: 1 - DISK OR NEW DISK IS IN
// 0 - THE WAIT HAS BEEN ABORTED BY THE USER (<esc> PRESSED)
//
INT WAITfORdISKcHNG(UINT8 DRIVE, INT NEWdISK){$7b}
INT KEY=0X20,O,N;
IF(NEWdISK) PRINTF("pLEASE CHANGE THE DISK ...\N");
ELSE PRINTF("wAITING FOR DISK DRIVE READY STATUS, PLEASE INSERT A DISK ...\N");
O=-1;
DO{$7b}
IF(KEY==0X00) WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
DO{$7b}
N=SENSEdISKsTATUS(DRIVE);
IF(O!=N){$7b}
PRINTF("\RdISK sTATUS: ");
SWITCH(N){$7b}
CASE 0: PRINTF("DISK IS OUT "); BREAK;
CASE 1: PRINTF("(OLD) DISK IS IN"); BREAK;
CASE 2: PRINTF("NEW DISK IS IN ");
{$7d}
{$7d}
SWITCH(N){$7b}
CASE 1:// (OLD) DISK IS IN
IF(NEWdISK) BREAK;// IF NEW DISK INSERT NEEDED, DON'T RETURN
CASE 2:// NEW DISK
PRINTF("\N");
RETURN 1;
{$7d}
O=N;
{$7d}WHILE(!KBHIT());
{$7d}WHILE((KEY=GETCH())!=0X1b);
PRINTF("\N");
RETURN 0;
{$7d}
// PRINTS ALL VALUES FROM A RESULT STRING TO THE CONSOLE
//
// INPUT: POINTER TO THE RESULT STRING STRUCTURE
// OUTPUT: NONE
//
VOID cbmPRINTsTATUS(RESULTsTRING *RESsTR, CONST CHAR *jOB){$7b}
IF(RESsTR==null) RETURN;
IF(RESsTR->d.st1&0X02) jOB="wRITE PROTECT ";
ELSE IF(jOB==null) jOB="";
IF(RESsTR->d.st0&0Xff00){$7b}
IF(RESsTR->d.st0>=-2) PRINTF("fdc DOESN'T ANSWER (%SPUT TIMEOUT).\N",(RESsTR->d.st0)==-1?"IN":"OUT");
ELSE PRINTF("uNKNOWN fdc COMMUNICATION PROBLEM\N");
{$7d}
ELSE PRINTF("0X%02x,0X%02x,0X%02x,%S%S,%2D,%1D,%2D,%1D\N",
RESsTR->d.st0, RESsTR->d.st1, RESsTR->d.st2,
jOB,RESsTR->d.st0&0Xc0?"error":"ok",
RESsTR->d.cYLINDER+1, RESsTR->d.sIDE,
RESsTR->d.sECTOR, RESsTR->d.bYTESps);
{$7d}
// RESET AND RECALIBRATE THE SPECIFIED DRIVE
//
// INPUT: DRIVE:THE DRIVE, THAT SHALL BE RESETTED
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION WAS UNSUCESSFUL
//
INT cbmRESETdRIVE(UINT8 DRIVE){$7b}
RESETdRIVE(DRIVE);
RETURN RECALIBRATEdRIVE(DRIVE,0)==null;
{$7d}
// RECALIBRATE THE SPECIFIED DRIVE
//
// INPUT: DRIVE:THE DRIVE, THAT SHALL BE RECALIBRATED
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION WAS UNSUCESSFUL
//
INT cbmRECALIBRATE(UINT8 DRIVE){$7b}
RESULTsTRING *res;
UINT I;
FOR(I=0;I<3;I++){$7b}
res=RECALIBRATEdRIVE(DRIVE,0);
IF(res==null) BREAK;
cbmPRINTsTATUS(res,"rECALIBRATE ");
{$7d}
IF(res!=null && !cbmRESETdRIVE(DRIVE)){$7b}
PRINTF("uNSUCCESSFUL ATTEMPT TO RECALIBRATE DRIVE %D\N",DRIVE);
//cbmPRINTsTATUS(res);
RETURN 0;
{$7d}
RETURN 1;
{$7d}
// PERFORM A READ/WRITE HEAD SEEK OF THE SPECIFIED DRIVE
//
// INPUT: DRIVE:THE DRIVE, WHERE THE SEEK SHALL BE DONE
// TRACK:THE CYLINDER NUMBER, WHERE THE SEEK SHALL BE DONE
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION WAS UNSUCESSFUL
//
INT cbmSEEK(UINT8 DRIVE, UINT8 CYL){$7b}
RESULTsTRING *res; //,rs;
UINT8 T=CYL-1;
UINT RETRY=3;
WHILE((res=SEEKtOcYL(DRIVE,T,0))!=null){$7b}
cbmPRINTsTATUS(res,"sEEK ");
IF(RETRY--<=0 {$7c}{$7c} !cbmRECALIBRATE(DRIVE)){$7b}
PRINTF("uNSUCCESSFUL ATTEMPT TO SEEK TO TRACK %2D ON DRIVE %D\N",CYL,DRIVE);
//cbmPRINTsTATUS(res);
RETURN 0;
{$7d}
{$7d}
RETURN 1;
{$7d}
// SETS THE FLOPPY DISK PARAMETER TABLE TO THE SELECTED TYPE
//
// INPUT: sET:THE NAME (ENUM CONSTANT) OF THE PREDEFINED PARAMETER SET
// OUTPUT: NONE
//
VOID cbmPRESETfdPRM(UINT8 DRIVE, fdPRMsET sET){$7b}
IF(sET<cbm1581 {$7c}{$7c} sET>=fdundef) RETURN;// UNKNOWN TYPE, DON'T CHANGE ANYTHING
ASSERT(fdPRMsETS[sET].sECTORS<=mAXsECTORS);
// INCREASE SECTOR BUFFER PARAMETER VIA central.h, IF ASSERTION FAULT
ASSERT((128U << fdPRMsETS[sET].bPs)*fdPRMsETS[sET].sECTORS<=tRbUFsIZE);
// INCREASE TRACK BUFFER SIZE VIA central.h, IF ASSERTION FAULT
fdPRM=fdPRMsETS[sET];
cbmRECALIBRATE(DRIVE);
{$7d}
// CHECKS, IF THE INSERTED DISK IS A cbm FORMATTED DISK AND DETECTS THE FORMAT
//
// INPUT: DRIVE:THE DRIVE, WHERE THE DISK TO BE CHECKED IS IN
// OUTPUT: non_3_5 -THE DRIVE TYPE IS NO 3,5" TYPE
// cbm1581 - THE DISK WAS DETECTED AS cbm 1581 DISK FORMAT COMPATIBLE
// cmdfd2m - THE DISK WAS DETECTED AS cmd fd2000 DISK FORMAT COMPATIBLE
// fdundef - THE DISK WAS NOT DETECTED AS A cbm FORMAT TYPE
//
fdPRMsET cbmCHECKdISK(UINT8 DRIVE){$7b}
RESULTsTRING rs;
fdcPARAMETERsET OLDfdPRM=fdPRM;// SAVE CURRENT PARAMETER SET
fdPRMsETpsET;
CHARSECmAP[mAXsECTORS];// mAXsECTORS IS DEFINED IN central.h
UINT8 WRONGid,TYPE,DObr=0Xff;
INT I,TMO;
// DO A cmos CHECK, IF IT IS A 3,5" DRIVE
// IF NOT, RETURN -1 (CAN NEVER BE A "CORRECT" DISK)
DISABLE();
OUTPORTB(0X70, 0X10);// cmos ADDRESS 0X10
TYPE=INPORTB(0X71);// READ ADDRESSED cmos VALUE
ENABLE();
SWITCH(DRIVE){$7b}
CASE 0:TYPE>>=4;BREAK;// TEST UPPER NIBBLE
CASE 1:TYPE&=0X0f;BREAK;// TEST LOWER NIBBLE
DEFAULT:TYPE=0X04;// ASSUME 1,44 mb DRIVE
{$7d}
IF(TYPE<3 {$7c}{$7c} TYPE>5) RETURN non_3_5;// CAN'T SUPPORT THESE DISK TYPES (5,25")
IF(TYPE==3) DObr&={$7e}1;// 500 KBPS ARE NOT SUPPORTED ON 720 Kb DISK DRIVES
FOR(psET=fdundef-1;psET>fdunknw;psET--){$7b}
IF(DObr&(1<<fdPRMsETS[psET].bITRATE)){$7b}// IF THE WISHED BITRATE IS SUPPORTED
cbmPRESETfdPRM(DRIVE,psET);// sET BITRATE, MODULATION AND SPECIFYcmd
IF(cbmRECALIBRATE(DRIVE)){$7b}// TRACK 0 SHOULD BE SELECTED
FOR(I=0;I<fdPRM.sECTORS;I++) SECmAP[I]=0;// DELETE SECTOR DETECTION MAP
WRONGid=0;
// WAIT FOR MORE THAN 4 TIMER TICKS (222 MS, A DISK ROUND)
I=5;
TMO=PEEKB(0X40, 0X6c);
WHILE(READsECTORid(DRIVE,0,&rs,1)){$7b}
IF(TMO!=PEEKB(0X40, 0X6c)){$7b}
TMO=PEEKB(0X40,0X6c);
IF(I--<0) BREAK;
{$7d}
IF(rs.d.cYLINDER!=0) WRONGid{$7c}=1;// tRACKhEADER WRONG
IF(rs.d.sIDE!=0) WRONGid{$7c}=2;// sIDEhEADER WRONG
IF(rs.d.sECTOR<1 {$7c}{$7c} rs.d.sECTOR>fdPRM.sECTORS)
WRONGid{$7c}=4;// sECTORhEADER WRONG
ELSE SECmAP[rs.d.sECTOR-1]=1;// MARK SECTOR READ
IF(rs.d.bYTESps!=fdPRM.bPs)
WRONGid{$7c}=8;// bPshEADER WRONG
{$7d}
IF(I>=5){$7b}// READsECTORid TIMEOUT HAPPENED
// DESELECT THE DESIRED BITRATE
#IF (messages >= 5)
FPRINTF(STDERR,"wRONG BITRATE, DESELECTING %D\N",fdPRMsETS[psET].bITRATE);
#ENDIF
DObr&={$7e}(1<<fdPRMsETS[psET].bITRATE);
// RESET CONTROLLER WITHOUT RECALIBRATING AGAIN
RESETdRIVE(DRIVE);
{$7d}
ELSE{$7b}
FOR(I=0;I<fdPRM.sECTORS;I++) IF(!SECmAP[I]) BREAK;
IF(!WRONGid && I>=fdPRM.sECTORS) BREAK;// FORMAT IS DETECTED
#IF (messages >= 5)
FPRINTF(STDERR,"fORMAT IS NOT DETECTED: 0X%02x, %D OF %D\N",WRONGid,I,fdPRM.sECTORS);
#ENDIF
{$7d}
{$7d}
{$7d}
{$7d}
fdPRM=OLDfdPRM;// RESTORE PARAMETER SET (SHOULD BE DRIVE RELATED)
cbmRECALIBRATE(DRIVE);
RETURN psET;
{$7d}
/*
// tHE ALGORITHM ABOVE IS NOT VERY WELL OPTIMIZED, ESPECIALLY NOT, IF YOU
// WANT TO DECIDE BETWEEN MUCH MORE DISK FORMATS.
// iF THERE ARE E.G. TWO FORMATS, THAT ARE VERY SIMILAR TOGETHER, THEN
// THIS ROUTINE WILL NEED TOO MUCH TIME FOR DETECTION, BECAUSE IT SCANS
// THE DISK TRACK FOR EACH FORMAT AGAIN AND AGAIN.
//
// iT WOULD BE MUCH BETTER TO FIRST DETECT THE DRIVE TYPE (3,5" OR 5.25")
// FROM THE cmos ENTRY, SO THAT STANDARD PARAMETERS CAN BE SPECIFIED FOR
// EACH BITRATE. tHEN THE RIGHT BITRATE AND MODULATION SHOULD BE DETECTED
// AND IF IT CAN BE FOUND, THE TRACK SCAN SHOULD BE DONE BY FILLING UP A
// TABLE, THAT HOLDS THE INFORMATIONS READ FROM EACH SECTOR HEADER.
// aFTER THIS, THE DRIVE TYPE, BITRATE AND TABLE ENTRIES SHOULD BE
// COMPARED AGAINST THE DIFFERENT FORMAT SPECIFICATION ENTRIES.
// iF NO FORMAT COULD BE DETECTED, THE REST OF THE UNTESTED BITRATES AND
// MODULATIONS HAS TO BE DONE (a PRIORITY TABLE WITH THE BITRATES AND
// MODULATION VALUES WOULD HELP MINIMIZING THE DETECTION TIME).
//
// tHIS WAY WE HAVE TO SCAN A DISK TRACK ONLY ONCE (EXCEPT, IF TWO OR MORE
// BITRATES ARE DETECTED ON THE SAME TRACK).
//
// tHE ALGORITHM BELOW SHOULD WORK MUCH BETTER, WHEN SUPPORTING ALL THE
// DIFFERENT FORMATS IS NEEDED, BUT i FIGURED OUT, THAT IT IS VERY LAME.
// CHECKS, IF THE INSERTED DISK IS A cbm FORMATTED DISK AND DETECTS THE FORMAT
//
// INPUT: DRIVE:THE DRIVE, WHERE THE DISK TO BE CHECKED IS IN
// OUTPUT: non_3_5 -THE DRIVE TYPE IS NO 3,5" TYPE
// cbm1581 - THE DISK WAS DETECTED AS cbm 1581 DISK FORMAT COMPATIBLE
// cmdfd2m - THE DISK WAS DETECTED AS cmd fd2000 DISK FORMAT COMPATIBLE
// fdundef - THE DISK WAS NOT DETECTED AS A cbm FORMAT TYPE
//
fdPRMsET cbmCHECKdISK(UINT8 DRIVE){$7b}
RESULTsTRING rs;
fdcPARAMETERsET OLDfdPRM=fdPRM;// SAVE CURRENT PARAMETER SET
UINT8 rATES[4]={$7b}2,0,3,1{$7d};// BITRATES 250, 500, 1000/125 AND 300 KBPS
fdPRMsETpsET;
CHARSECmAP[mAXsECTORS];// mAXsECTORS IS DEFINED IN central.h
UINT8 WRONGid;
INT I,TMO,rATE,mDLTN;
// DO A cmos CHECK, IF IT IS A 3,5" DRIVE
// IF NOT, RETURN -1 (CAN NEVER BE A "CORRECT" DISK)
DISABLE();
OUTPORTB(0X70, 0X10);// cmos ADDRESS 0X10
WRONGid=INPORTB(0X71);// READ ADDRESSED cmos VALUE
ENABLE();
SWITCH(DRIVE){$7b}
CASE 0:WRONGid>>=4;BREAK;// TEST UPPER NIBBLE
CASE 1:WRONGid&=0X0f;BREAK;// TEST LOWER NIBBLE
DEFAULT:WRONGid=0X04;// ASSUME 1,44 mb DRIVE
{$7d}
IF(WRONGid<3 {$7c}{$7c} WRONGid>5) RETURN non_3_5;// CAN'T SUPPORT THESE DISK TYPES (5,25")
fdPRM=fdPRMsETS[0];// LOAD cbm 1581 PARAMETER SET AS STANDARD VALUES
FOR(mDLTN=0;mDLTN<2;mDLTN++){$7b}
fdPRM.mODULATION=({$7e}mDLTN)&1; // TEST mfm FIRST, THEN fm
FOR(rATE=0;rATE<4;rATE++){$7b}
fdPRM.bITRATE=rATES[rATE];// 250, 500, 1000/125, 300
fdPRM.hEADS=0;
fdPRM.bPs=0;
fdPRM.sECTORS=0;
IF(cbmRECALIBRATE(DRIVE)){$7b}
FOR(I=0;I<mAXsECTORS;I++) SECmAP[I]=0;// DELETE SECTOR DETECTION MAP
WRONGid=0;
// SCAN A TRACK
// WAIT FOR MORE THAN 4 TIMER TICKS (222 MS, A DISK ROUND)
I=5;
TMO=PEEKB(0X40, 0X6c);
WHILE(READsECTORid(DRIVE,0,&rs,1)){$7b}
IF(TMO!=PEEKB(0X40, 0X6c)){$7b}
TMO=PEEKB(0X40,0X6c);
IF(I--<0) BREAK;
{$7d}
IF(!fdPRM.sECTORS++){$7b} // FIRST SECTOR READ
fdPRM.hEADS=rs.d.sIDE;// ALL SIDE AND bPs id FIELDS OF THE
fdPRM.bPs=rs.d.bYTESps;// WHOLE TRACK SHOULD BE THE SAME
{$7d}
IF(rs.d.cYLINDER!=0) WRONGid{$7c}=1;// tRACKhEADER WRONG
IF(rs.d.sIDE!=fdPRM.hEADS)
WRONGid{$7c}=2;// sIDEhEADER WRONG
IF(rs.d.sECTOR<1 {$7c}{$7c} rs.d.sECTOR>mAXsECTORS)
WRONGid{$7c}=4;// sECTORhEADER NOT SUPPORTED
ELSE SECmAP[rs.d.sECTOR-1]=1;// MARK SECTOR READ
IF(rs.d.bYTESps!=fdPRM.bPs)
WRONGid{$7c}=8;// bPshEADER WRONG
{$7d}
IF(I>=5){$7b}// READsECTORid TIMEOUT HAPPENED
// DESELECT THE DESIRED BITRATE
#IF (messages >= 5)
FPRINTF(STDERR,"nO DETECTION WITH MODULATION %D AND BITRATE %D\N",
fdPRM.mODULATION,fdPRM.bITRATE);
FPRINTF(STDERR,"tIMEOUT VALUES: TMO %D, ACT: %D\N",TMO,PEEKB(0X40, 0X6c));
#ENDIF
// RESET CONTROLLER WITHOUT RECALIBRATING AGAIN
RESETdRIVE(DRIVE);
{$7d}
ELSE{$7b}
IF(!WRONGid){$7b}// HEADERS ARE NOT "SYMMETRIC"
// CHECK THE READ TRACK AGAINST THE SUPPORTED FORMATS
FOR(psET=fdundef-1;psET>fdunknw;psET--){$7b}
// COMPARE THE SELECTED BITRATE AGAINST THE SPECIFIED
IF(fdPRMsETS[psET].bITRATE!=rATES[rATE]) CONTINUE;
// COMPARE THE SELECTED MODULATION AGAINST THE SPECIFIED
IF(fdPRMsETS[psET].mODULATION!=fdPRM.mODULATION) CONTINUE;
// COMPARE THE READ SIDE (MUST BE 0/SWAPPED)
IF(fdPRM.hEADS!=0) CONTINUE;
// COMPARE THE READ bPs AGAINST THE SPECIFIED
IF(fdPRMsETS[psET].bPs!=fdPRM.bPs) CONTINUE;
// CHECK THE SECTORS
FOR(I=0;I<fdPRMsETS[psET].sECTORS;I++){$7b}
IF(!SECmAP[I]) BREAK;
{$7d}
IF(I<fdPRMsETS[psET].sECTORS) CONTINUE;
// CHECK, IF THERE ARE NOT MORE MARKED SECTORS
FOR(;I<mAXsECTORS;I++){$7b}
IF(SECmAP[I]) BREAK;
{$7d}
IF(I<mAXsECTORS) CONTINUE;
// ALL TESTS ARE SUCCESSED, THIS SEEMS
// TO BE THE RIGHT FORMAT
fdPRM=OLDfdPRM;// RESTORE PARAMETER SET (SHOULD BE DRIVE RELATED)
cbmRECALIBRATE(DRIVE);
RETURN psET;
{$7d}
{$7d}
#IF (messages >= 5)
FPRINTF(STDERR,"cURRENT TRACK FORMAT IS NOT SUPPORTED 0X%02x %D %D %D %D\N",
WRONGid,fdPRM.mODULATION,fdPRM.bITRATE,fdPRM.hEADS,fdPRM.bPs);
FPRINTF(STDERR,"rEAD SECTOR NUMBERS:");
FOR(I=0;I<mAXsECTORS;I++) IF(SECmAP[I]){$7b}
FPRINTF(STDERR,"%D, ",I+1);
{$7d}
FPRINTF(STDERR,"\N");
#ENDIF
{$7d}
{$7d}
{$7d}
{$7d}
fdPRM=OLDfdPRM;// RESTORE PARAMETER SET (SHOULD BE DRIVE RELATED)
cbmRECALIBRATE(DRIVE);
RETURN fdunknw;
{$7d}
*/
// RETURN THE SECTOR NUMBER OF THE NEXT AVAILABLE SECTOR HEADER
//
// INPUT: DRIVE:THE DRIVE, WHERE THE DISK TO READ IS IN
// CYL:THE CYLINDER NUMBER OF THE TRACK TO READ
// SIDE:THE DISK SIDE NUMBER OF THE TRACK TO READ
// TRIES:THE NUMBER OF RETRIES FOR THIS OPERATION
// OUTPUT: 0- THE OPERATION WAS UNSUCCESSFUL
// 120- A POSSIBLY NOT cbm COMPATIBLE DISK WAS DETECTED
// 1...fdPRM.sECTORS- THE SECTOR NUMBER OF THE CURRENTLY READ SECTOR HEADER
// -1 - THE OPERATION WAS ABORTED BY USER INTERACTION
//
STATIC INT cbmpRErwv(UINT8 DRIVE, UINT8 CYL, UINT8 SIDE, UINT TRIES){$7b}
RESULTsTRING rs, *res;
UINT RETR1, RETR2, RETR3, RETR4, RETR5, OP;
OP=255;
RETR1=RETR2=RETR3=RETR4=RETR5=TRIES;
WHILE(RETR1>0 && RETR2>0 && RETR3>0 && RETR4>0 &&RETR5>0){$7b}
IF(KBHIT()){$7b}
SWITCH(GETCH()){$7b}
CASE 0X1b: RETURN -1;
CASE 0X00: WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
{$7d}
{$7d}
DO{$7b}
IF(OP--==4){$7b}
RESETdRIVE(DRIVE);
SELECTdRIVE(DRIVE);
IF((res=SEEKtOcYL(DRIVE,1,0))!=null){$7b}
cbmPRINTsTATUS(res,"sEEK ");
RETR1--;
BREAK;
{$7d}
{$7d}
OP=1;
IF((res=SEEKtOcYL(DRIVE,CYL,0))!=null){$7b}
cbmPRINTsTATUS(res,"sEEK ");
RETR2--;
BREAK;
{$7d}
OP=2;
res=&rs;
IF(!READsECTORid(DRIVE,SIDE,&rs,op_timeout)){$7b}
cbmPRINTsTATUS(&rs,"rEAD HEADER id ");
RETR3--;
BREAK;
{$7d}
#IF (messages >= 5)
FPRINTF(STDERR,"dRIVE %D, tRACK %2D, sIDE %2D --> rEADid: t %2D, h %D, s %2D, bps %D\N",
DRIVE, CYL, SIDE, rs.d.cYLINDER, rs.d.sIDE, rs.d.sECTOR, rs.d.bYTESps);
#ENDIF
OP=3;
IF(rs.d.cYLINDER!=CYL){$7b}
RETR4--;
BREAK;
{$7d}
IF(rs.d.sIDE!=SIDE {$7c}{$7c} rs.d.sECTOR<1 {$7c}{$7c} rs.d.sECTOR>fdPRM.sECTORS {$7c}{$7c} rs.d.bYTESps!=fdPRM.bPs){$7b}
PRINTF("pOSSIBLY NO cbm COMPATIBLE DISK INSERTED\N");
rs.d.sECTOR=120;
{$7d}
RETURN rs.d.sECTOR;
{$7d}WHILE(0);
IF(res!=null && res->d.st0<0) BREAK; // TIMEOUT!!!
IF((res=RECALIBRATEdRIVE(DRIVE,0))!=null){$7b}
cbmPRINTsTATUS(res,"rECALIBRATE ");
OP=4;
RETR5--;
{$7d}
{$7d}
IF(res!=null && res->d.st0<0) PRINTF("fdc IS NOT RESPONDING ON ");
ELSE PRINTF("%D UNSUCCESSFUL ATTEMPTS TO ",TRIES);
SWITCH(OP){$7b}
CASE 1: PRINTF("SEEK TO");BREAK;
CASE 2: PRINTF("READ SECTOR id FROM");BREAK;
CASE 3: PRINTF("GET A VALID id FOR"); BREAK;
CASE 4: PRINTF("RECALIBRATE");
{$7d}
IF(OP<4) PRINTF(" SIDE %1D OF CYLINDER %2D OF",SIDE,CYL);
PRINTF(" DRIVE %D\N",DRIVE);
RETURN 0;
{$7d}
// TRANSFER A TRACK WITH THE MULTIPLE SECTOR fdc FEATURE
//
// INPUT: XFER:THE TRANSFER COMMAND (rEAD, wRITE, wRITE&vERIFY)
// DRIVE:THE DRIVE, WHERE THE DISK TO IS IN
// CYL:THE CYLINDER NUMBER OF THE TRACK TO HANDLE
// SIDE:THE DISK SIDE NUMBER OF THE TRACK TO HANDLE
// BUFFER: A POINTER TO THE DATA TRANSFER BUFFER
// ILEAVE:AN INTERLEAVE FACTOR TO BE USED
// RETRIES:THE NUMBER OF RETRIES FOR THIS OPERATION
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION FAILED
// -1 - THE OPERATION WAS ABORTED BY USER INTERACTION
// -2 - WRITE PROTECT ERROR
//
// (nOTE: cbmXFERtRACKss WILL NOT BE INVOKED AUTOMATICALLY ANYMORE)
//
INT cbmXFERtRACKss(XFERm XFER, UINT8 DRIVE, UINT8 CYL, UINT8 SIDE,
UINT8 HUGE *BUFFER, UINT8 ILEAVE, UINT RETRIES){$7b}
CONST CHAR JOB[3]={$7b}'W','V','R'{$7d};
CONST CHAR *JOBERR[3]={$7b}"wRITE ","vERIFY ","rEAD "{$7d};
RESULTsTRING *res;
UINT8 HUGE *BUF;
UINT RETRY;
UINT8 V,R,I,T=CYL-1,CSEC;
INT RET;
CHAR dONE[mAXsECTORS];// mAXsECTORS IS DEFINED IN central.h
// MARKERS: 0 - TO WRITE
// 1 - TO VERIFY
// 2 - TO READ
// 3 - READ/WRITE/VERIFY ERROR
// -1- DONE
SWITCH(XFER&(wRvRFY{$7c}rEAD)){$7b}
DEFAULT:
RETURN -1;
CASE 0:
R=0;
IF(XFER&fORMAT) BREAK;
RETURN -1;
CASE rEAD:
IF(XFER&fORMAT){$7b}
RETURN -1;
{$7d}
R=2;
BREAK;
CASE wRITE:
CASE wRvRFY:
R=0;
BREAK;
CASE vERIFY:
R=1;
{$7d}
FOR(CSEC=0;CSEC<fdPRM.sECTORS;CSEC++) dONE[CSEC]=R;
// CLEAR DONE BUFFER
ILEAVE%=fdPRM.sECTORS;
IF(XFER&fORMAT){$7b}
IF(!cbmSEEK(DRIVE,CYL)) RETURN 0;
CSEC=0;
{$7d}
ELSE{$7b}
CSEC=RET=cbmpRErwv(DRIVE,T,SIDE,RETRIES);
IF(RET<0) RETURN 0;
{$7d}
RETRY=RETRIES;
WHILE(RETRY-->0){$7b}
IF(KBHIT()){$7b}
SWITCH(GETCH()){$7b}
CASE 0X1b: RETURN -1;
CASE 0X00: WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
{$7d}
{$7d}
IF(XFER&fORMAT){$7b}
PRINTF("%2D %1D F \R",CYL,SIDE);
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D F \N",CYL,SIDE);
#ENDIF
res=FORMATcbmTRACK(DRIVE,T,SIDE);
IF(res!=null){$7b}
cbmPRINTsTATUS(res,"fORMAT ");
IF(res->d.st1&0X02) RETURN -2;
IF(!cbmRECALIBRATE(DRIVE) {$7c}{$7c} !cbmSEEK(DRIVE,CYL)) BREAK;
CONTINUE;
{$7d}
SWITCH(XFER&(wRvRFY{$7c}rEAD)){$7b}
CASE rEAD:
R=2;
BREAK;
CASE wRITE:
CASE wRvRFY:
R=0;
BREAK;
CASE vERIFY:
R=1;
{$7d}
FOR(CSEC=0;CSEC<fdPRM.sECTORS;CSEC++) dONE[CSEC]=R;
IF(XFER&wRvRFY) CSEC=fdPRM.sECTORS-1;
//IF(XFER&wRvRFY) CSEC=0;
ELSE RETURN 1;
{$7d}
V=(XFER&vERIFY)?1:0;// ENDING WITH VERIFY?
R=(XFER&wRITE)?0:1;// STARTING WITH WRITING?
IF(XFER&rEAD) V=R=2;// OR IS IT READING
FOR(;R<=V;R++){$7b}// R=0 - WRITE, R=1 - VERIFY
PRINTF("%2D %1D %C \R",CYL,SIDE,JOB[R]);
FOR(I=0;I<fdPRM.sECTORS;I++){$7b}// ONE ROUND VERIFY OR WRITE
IF(KBHIT()){$7b}
SWITCH(GETCH()){$7b}
CASE 0X1b: RETURN -1;
CASE 0X00: WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
{$7d}
{$7d}
// CALCULATE THE FOLLOWING SECTOR NUMBER
CSEC+=ILEAVE;
CSEC%=fdPRM.sECTORS;
// SEARCH THE NEXT SECTOR TO DO (DEPENDEND ON WRITE OR VERIFY)
// IF READING OR WRITING, WE SEARCH FOR A TODO ENTRY (0)
// IF VERIFYING AFTER WRITING, WE SEARCH FOR A WRITTEN ENTRY (1)
// SEARCHING THE REST OF THE ARRAY
FOR(;CSEC<fdPRM.sECTORS;CSEC++) IF(dONE[CSEC]==R) BREAK;
IF(CSEC>=fdPRM.sECTORS){$7b}// NOTHING FOUND, SEARCH FROM THE BEGINNING
// SEARCHING FROM THE BEGINNING OF THE ARRAY
FOR(CSEC=0;CSEC<fdPRM.sECTORS;CSEC++) IF(dONE[CSEC]==R) BREAK;
IF(CSEC>=fdPRM.sECTORS) BREAK;// NOTHING FOUND, NOTHING MORE TO DO
{$7d}
// NEXT SECTOR TO DO IS: CSEC
// CALCULATING BUF POINTER
BUF=BUFFER+CSEC*(128U << fdPRM.bPs);
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D %C %3D \N",CYL,SIDE,JOB[R],CSEC+1);
#ENDIF
SWITCH(R){$7b}
CASE 0:// WRITING
res=WRITEcbmSECTOR(DRIVE,T,SIDE,CSEC+1,BUF);
BREAK;
CASE 1://VERIFYING
res=VERIFYcbmSECTOR(DRIVE,T,SIDE,CSEC+1,BUF);
BREAK;
CASE 2:// READING
res=READcbmSECTOR(DRIVE,T,SIDE,CSEC+1,BUF);
BREAK;
DEFAULT:
res=null;
{$7d}
IF(res!=null){$7b}
cbmPRINTsTATUS(res,JOBERR[R]);
IF(res->d.st1&0X02) RETURN -2;
dONE[CSEC]=3;
{$7d}
ELSE{$7b}// SUCCESS
IF(R<V) dONE[CSEC]=1;// WRITING DONE, VERIFY FOLLOWS
ELSE dONE[CSEC]=-1;// dONE
{$7d}
{$7d}
{$7d}
// SET ALL NOT DONE JOBS (NOT -1) IN THE DONE BUFFER TO TO DO (0)
// IF ALL SECTORS ARE DONE, WE CAN RETURN
// MARKERS: 0 - TO DO
// 0X10 - READ/WRITE/VERIFY ERROR
// wRvRFY - WRITTEN, IF VERIFY IS DONE AFTER
// OTHER - DONE
R=1;
IF(V==1 && (XFER&wRITE)) V=0;// WRITING FOLLOWS ON VERIFY, SET TO "DO WRITE"
FOR(I=0;I<fdPRM.sECTORS;I++) IF(dONE[I]!=-1){$7b}
// IF(V==1 && (XFER&wRITE)) V=0;
dONE[I]=V;// IF THERE ARE NOT DONE OR ERRORNOUS SECTORS,
R=0;// WE DO A RETRY
{$7d}
IF(R) RETURN 1;
{$7d}
PRINTF("%D UNSUCCESSFUL ATTEMPTS TO TRANSFER DATA AT SIDE %1D, CYLINDER %2D, DRIVE %D\N",RETRIES,SIDE,CYL,DRIVE);
//PRINTF("%D UNSUCCESSFUL ATTEMPTS TO FORMAT SIDE %1D, CYLINDER %2D, DRIVE %D\N",RETRIES,SIDE,CYL,DRIVE);
//PRINTF("\N%S eRROR\N",(XFER&rEAD)?"rEAD":((XFER&wRITE)?"wRITE":"vERIFY"));
RETURN 0;
{$7d}
// TRANSFER A TRACK WITH THE MULTIPLE SECTOR fdc FEATURE
//
// INPUT: XFER:THE TRANSFER COMMAND (rEAD, wRITE, wRITE&vERIFY)
// DRIVE:THE DRIVE, WHERE THE DISK TO IS IN
// CYL:THE CYLINDER NUMBER OF THE TRACK TO HANDLE
// SIDE:THE DISK SIDE NUMBER OF THE TRACK TO HANDLE
// BUFFER: A POINTER TO THE DATA TRANSFER BUFFER
// ILEAVE:AN INTERLEAVE FACTOR TO BE USED
// RETRIES:THE NUMBER OF RETRIES FOR THIS OPERATION
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION FAILED
// -1 - THE OPERATION WAS ABORTED BY USER INTERACTION
// -2 - WRITE PROTECT ERROR
//
// (nOTE: cbmXFERtRACKss WILL NOT BE INVOKED AUTOMATICALLY ANYMORE)
//
INT cbmXFERtRACKms(XFERm XFER, UINT8 DRIVE, UINT8 CYL, UINT8 SIDE,
UINT8 HUGE *BUFFER, UINT8 ILEAVE, UINT RETRIES){$7b}
RESULTsTRING *res;
CONST CHAR *JOBERR[4]={$7b}"rEAD ","wRITE ","vERIFY ","fORMAT "{$7d};
UINT RETRY;
UINT8 T=CYL-1,CSEC;
INT RET,JOB;
IF(XFER&0X01 && XFER&0X0e){$7b}
PRINTF("wOMO ISN iDIOT!!!\N");
RETURN -1;
{$7d}
IF(!(XFER&fORMAT)){$7b}
CSEC=RET=cbmpRErwv(DRIVE,T,SIDE,RETRIES);
IF(RET<0) RETURN 0;
{$7d}
ILEAVE%=fdPRM.sECTORS;
CSEC+=ILEAVE;
IF(CSEC>fdPRM.sECTORS) CSEC-=fdPRM.sECTORS;
ILEAVE+=fdPRM.sECTORS-1;// INTERLEAVE IS DECREMENTED BY 1 FOR MULTIPLE
ILEAVE%=fdPRM.sECTORS;// SECTOR OPERATIONS (DEFAULT 0)
IF(XFER&fORMAT){$7b}
IF(!cbmSEEK(DRIVE,CYL)) RETURN 0;
CSEC=1;
{$7d}
RETRY=RETRIES;
WHILE(RETRY-->0){$7b}
IF(KBHIT()){$7b}
SWITCH(GETCH()){$7b}
CASE 0X1b: RETURN -1;
CASE 0X00: WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
{$7d}
{$7d}
PRINTF("%2D %1D ",CYL,SIDE);
IF(XFER&rEAD){$7b}
PRINTF("R \R");
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D R %3D \N",CYL,SIDE,CSEC);
#ENDIF
JOB=0;
res=READcbmTRACK(DRIVE,T,SIDE,CSEC,BUFFER);
{$7d}
ELSE{$7b}
res=null;
IF(XFER&fORMAT){$7b}
PRINTF("F \R");
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D F \N",CYL,SIDE);
#ENDIF
JOB=4;
res=FORMATcbmTRACK(DRIVE,T,SIDE);
IF(XFER&wRvRFY){$7b}
CSEC=1;
PRINTF("%2D %1D ",CYL,SIDE);
{$7d}
{$7d}
IF(res==null && XFER&wRITE){$7b}
PRINTF("W \R");
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D W %3D \N",CYL,SIDE,CSEC);
#ENDIF
JOB=1;
res=WRITEcbmTRACK(DRIVE,T,SIDE,CSEC,BUFFER);
{$7d}
IF(res==null && XFER&vERIFY){$7b}
IF(XFER&wRITE){$7b}
CSEC+=ILEAVE;
IF(CSEC>fdPRM.sECTORS) CSEC-=fdPRM.sECTORS;
PRINTF("%2D %1D ",CYL,SIDE);
{$7d}
PRINTF("V \R");
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D V %3D \N",CYL,SIDE,CSEC);
#ENDIF
JOB=2;
res=VERIFYcbmTRACK(DRIVE,T,SIDE,CSEC,BUFFER);
{$7d}
{$7d}
IF(res==null) RETURN 1;
ELSE{$7b}
cbmPRINTsTATUS(res,JOBERR[JOB]);
IF(res->d.st1&0X02) RETURN -2;
IF(JOB==4 && (!cbmRECALIBRATE(DRIVE) {$7c}{$7c} !cbmSEEK(DRIVE,CYL))) BREAK;
{$7d}
CSEC+=ILEAVE;
IF(CSEC>fdPRM.sECTORS) CSEC-=fdPRM.sECTORS;
{$7d}
PRINTF("%D UNSUCCESSFUL ATTEMPTS TO TRANSFER DATA AT SIDE %1D, CYLINDER %2D, DRIVE %D\N",RETRIES,SIDE,CYL,DRIVE);
//PRINTF("%D UNSUCCESSFUL ATTEMPTS TO TRANSFER DATA, GIVING UP.\N",RETRIES);
//PRINTF("\N%S eRROR\N",(XFER&rEAD)?"rEAD":((XFER&wRITE)?"wRITE":"vERIFY"));
// VERBESSERTES cmdPRINTsTATUS: fdc TIMEOUT (IN/OUT)
// ODER st0 st1 st2 dchs
//cbmPRINTsTATUS(res);
RETURN 0;
{$7d}
// FORMAT'N'WRITE A TRACK VIA INTEL'S EXTENDED COMMAND
//
// INPUT: XFER:THE TRANSFER COMMAND (rEAD, wRITE, wRITE&vERIFY)
// DRIVE:THE DRIVE, WHERE THE DISK TO IS IN
// CYL:THE CYLINDER NUMBER OF THE TRACK TO HANDLE
// SIDE:THE DISK SIDE NUMBER OF THE TRACK TO HANDLE
// BUFFER: A POINTER TO THE DATA TRANSFER BUFFER
// RETRIES:THE NUMBER OF RETRIES FOR THIS OPERATION
// OUTPUT: 1 - THE OPERATION WAS SUCCESSFUL
// 0 - THE OPERATION FAILED
// -1 - THE OPERATION WAS ABORTED BY USER INTERACTION
// -2 - WRITE PROTECT ERROR
//
INT cbmFWVtRACK(XFERm XFER, UINT8 DRIVE, UINT8 CYL, UINT8 SIDE,
UINT8 HUGE *BUFFER, UINT RETRIES){$7b}
RESULTsTRING *res;
CONST CHAR *JOBERR[3]={$7b}"fORMAT'N'WRITE ","vERIFY "{$7d};
UINT RETRY;
UINT8 T=CYL-1;
INT JOB;
// OPERATIONS ALLOWED:
// FORMAT'N'WRITE
// FORMAT'N'WRITE WITH VERIFY
IF(XFER&{$7e}vERIFY) RETURN -1;
RETRY=RETRIES;
WHILE(RETRY-->0){$7b}
IF(KBHIT()){$7b}
SWITCH(GETCH()){$7b}
CASE 0X1b: RETURN -1;
CASE 0X00: WHILE(KBHIT()) GETCH();// EAT UP SPECIAL COMBOS
{$7d}
{$7d}
PRINTF("%2D %1D FW \R",CYL,SIDE);
res=null;
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D FW \N",CYL,SIDE);
#ENDIF
JOB=0;
res=FNWRITEcbmTRACK(DRIVE,T,SIDE,BUFFER);
IF(res==null && XFER&vERIFY){$7b}
PRINTF("%2D %1D V \R",CYL,SIDE);
#IF (messages >= 2)
FPRINTF(STDERR,"%2D %1D V \N",CYL,SIDE);
#ENDIF
JOB=1;
res=VERIFYcbmTRACK(DRIVE,T,SIDE,1,BUFFER);
{$7d}
IF(res==null) RETURN 1;
ELSE{$7b}
cbmPRINTsTATUS(res,JOBERR[JOB]);
IF(res->d.st1&0X02) RETURN -2;
{$7d}
{$7d}
PRINTF("%D UNSUCCESSFUL ATTEMPTS TO FORMAT'N'WRITE AT SIDE %1D, CYLINDER %2D, DRIVE %D\N",RETRIES,SIDE,CYL,DRIVE);
RETURN 0;
{$7d}
// GENERATE A NEW INDEXED FILENAME FROM THE PREVIOUS ONE
//
// INPUT: INsTR:THE OLD INDEXED OR UNINDEXED FILE NAME
// OUTPUT: NOT null: THE NEW INDEXED FILE NAME
// null:A NEW INDEXED FILE NAME COULDN'T BE GENERATED
//
CHAR *BUILDiNXnAME(CHAR *INsTR){$7b}
CONST INT MAXlENGTH=8;
REGISTER INT I;
INT LENGTH,DELIMITER,INDEXsTR;
UNSIGNED LONG INT INX;
CHAR OUTsTR[13], INXsTR[11], *PTR, *OP, *RS;
IF(INsTR==null) RETURN null;
RS=fILENAMErETsTR;
// SEPARATE FILENAME FROM PATH AND COPY PATH INTO RETsTRING
// SEARCH END OF STRING AND COPY PATH
FOR(PTR=INsTR,OP=fILENAMErETsTR;*PTR!='\0';PTR++,OP++) *OP=*PTR;
// SEARCH LAST ':', '\' OR '/'
WHILE(PTR>=INsTR && *PTR!=':' && *PTR!='\\' && *PTR!='/') PTR--;
IF(PTR>=INsTR){$7b}// THERE HAS BEEN A PATH DELIMITER FOUND
PTR++;// THE FOLLOWING CHAR IS THE FIRST OF THE FILENAME
// SUBRACTION OF TWO POINTERS RESULTS IN AN INTEGER
// THE PROBLEM IS, THAT IT IS A LONG INT, BUT THE FIRST
// POINTER "RETsTR" IS NO FAR POINTER, SO THAT THE CAST
// IS NEEDED (PERHAPS THIS CAUSES A BUG?)
RS=fILENAMErETsTR+(INT)(PTR-INsTR);
INsTR=PTR;
{$7d}
DELIMITER=-1;
FOR(I=0,PTR=INsTR;*PTR!='\0';I++,PTR++) IF(*PTR=='.') DELIMITER=I;
LENGTH=I;
IF(DELIMITER==-1) DELIMITER=LENGTH;
#IF (messages >= 3)
FPRINTF(STDERR,"dELIMITER: \"%S\"\N",INsTR+DELIMITER);
#ENDIF
// GET INDEX STRING PART (UP TO A MAXIMUM OF 8 CHARS)
FOR(I=DELIMITER,PTR=INsTR+DELIMITER-1;PTR>=INsTR;I--,PTR--)
IF(*PTR<'0' {$7c}{$7c} *PTR>'9' {$7c}{$7c} DELIMITER-I>=MAXlENGTH)
BREAK;
INDEXsTR=I;
#IF (messages >= 3)
FPRINTF(STDERR,"iNDEX: \"%S\"\N",INsTR+INDEXsTR);
#ENDIF
// BUILD NEW INDEX NUMBER STRING
IF(DELIMITER==INDEXsTR){$7b}
// NEW INDEX NUMBER IS 1
INXsTR[0]='1';
INXsTR[1]='\0';
#IF (messages >= 3)
FPRINTF(STDERR,"NO OLD INDEX, GENERATING \"1\"\N");
#ENDIF
{$7d}
ELSE{$7b}
INX=0l;
FOR(PTR=INsTR+INDEXsTR,I=INDEXsTR;I<DELIMITER;PTR++,I++){$7b}
INX*=10l;
INX+=(*PTR-'0');
{$7d}
//INX=STRTOUL(INsTR+INDEXsTR,null,10);
#IF (messages >= 3)
FPRINTF(STDERR,"OLD INDEX NUMBER: \"%LU\"\N",INX);
#ENDIF
INX++;// BUILD NEXT INDEX NUMBER
SPRINTF(INXsTR, "%LU", INX);// WRITE INDEX NUMBER TO STRING
#IF (messages >= 3)
FPRINTF(STDERR,"NEW INDEX NUMBER: \"%LU\"\N",INX);
#ENDIF
{$7d}
// DETERMINE THE LENGTH OF THE NEW INDEX STRING
FOR(I=0,PTR=INXsTR;*PTR!='\0';I++,PTR++);
LENGTH=I;
#IF (messages >= 3)
FPRINTF(STDERR,"NEW INDEX LENGTH: \"%D\"\N",I);
#ENDIF
IF(LENGTH>MAXlENGTH) RETURN null;// NEW FILENAME WILL BE INVALID
// COPYING BASE NAME TO OUTsTR
FOR(I=0,PTR=INsTR,OP=OUTsTR;I<DELIMITER && I<MAXlENGTH;I++,PTR++,OP++) *OP=*PTR;
// NEW COMBINED STRING WILL BE TO LONG
I-=LENGTH;
IF(I<INDEXsTR) I=INDEXsTR;// DON'T EAT UP FILE NAME CHARS, IF NOT NEEDED
IF(I+LENGTH>=MAXlENGTH) I=MAXlENGTH-LENGTH;
OP=OUTsTR+I;
// COPY INDEX NUMBER STRING ONTO THE BASE NAME
FOR(PTR=INXsTR;I<MAXlENGTH && *PTR!='\0';I++,PTR++,OP++) *OP=*PTR;
// COPY EXTENSION ONTO FILE NAME
FOR(PTR=INsTR+DELIMITER;*PTR!='\0';PTR++,OP++) *OP=*PTR;
// SETTING STRING END DELIMITER
*OP='\0';
// COPY OUTsTRING INTO STATIC RETURN sTRING, SO THE STRING CAN
// AGAING BE THE INPUT OF THIS FUNCTION WITHOUT CONFLICTS
FOR(PTR=OUTsTR,OP=RS,I=0;I<MAXlENGTH+5;PTR++,OP++,I++) *OP=*PTR;
RETURN fILENAMErETsTR;
{$7d}
// GENERATE A FILENAME WITH THE FORCED EXTENSION
//
// INPUT: INsTR:THE INPUT FILENAME
// OUTPUT: NOT null: THE NEW GENERATED FILE NAME
// null:A NEW FILE NAME COULDN'T BE GENERATED
//
CHAR *CHANGEeXTENSION(CHAR *INsTR, fdPRMsET sET){$7b}
CONST CHAR *eXTENSIONS[2]={$7b}"d81","d2m"{$7d};
CHAR *PTR, *OP;
IF(INsTR==null) RETURN null;
IF(sET<0 {$7c}{$7c} sET>1){$7b}
#IF (messages >= 3)
FPRINTF(STDERR,"sET INVALID, EXTENSION NOT CHANGED, IT'S \"%S\"\N",INsTR);
#ENDIF
RETURN INsTR;// LET IT BE UNCHANGED
{$7d}
// SEPARATE FILENAME FROM PATH AND COPY PATH INTO RETsTRING
// SEARCH END OF STRING AND COPY PATH
FOR(PTR=INsTR,OP=fILENAMErETsTR;*PTR!='\0';PTR++,OP++) *OP=*PTR;
*OP='\0';
// SEARCH LAST ':', '\' OR '/' IN THE OUTPUT STRING
WHILE(OP>=fILENAMErETsTR && *OP!=':' && *OP!='\\' && *OP!='/') OP--;
OP++;// SELECT THE FOLLOWING CHAR OF THE DELIMITER
PTR=null;// SEARCH THE LAST DELIMITING DOT '.', PTR MARKS THE DOT
WHILE(*OP!='\0'){$7b}
IF(*OP=='.') PTR=OP;
OP++;
{$7d}
IF(PTR!=null){$7b}// IF A DOT WAS FOUND DON'T CHANGE ANYTHING
#IF (messages >= 3)
FPRINTF(STDERR,"dOT FOUND, EXTENSION NOT CHANGED, IT'S \"%S\"\N",INsTR);
#ENDIF
RETURN INsTR;// LET IT BE UNCHANGED
{$7d}
*OP++='.';
PTR=(CHAR *)eXTENSIONS[sET];
#IF (messages >= 3)
FPRINTF(STDERR,"cHANGING EXTENSION TO \"%S\"\N",PTR);
#ENDIF
WHILE(*PTR!='\0') *OP++=*PTR++;
#IF (messages >= 3)
FPRINTF(STDERR,"fILENAME CHANGED TO \"%S\"\N",fILENAMErETsTR);
#ENDIF
RETURN fILENAMErETsTR;
{$7d}