; PROGRAM: UNERASE for ZCPR3 ; AUTHOR: RICHARD CONN ; VERSION: 1.0 ; DATE: 18 May 84 ; DERIVATION: UNERA 2.2 (25 July 83) for ZCPR2 ; DERIVATION: UNERA BY GENE COTTON ; VERS EQU 10 ;version number z3env SET 0f400h ; ; PROGRAM TO RECOVER ERASED FILES, BY GENE COTTON ; ; From Interface Age December 1981 pg 146 ; ; v2.0 - 07/23/83 Modified to be consistent in the ZCPR2 tool set. ; - Rick Conn ; v1.0 - 05/18/84 Modified to be consistent in the ZCPR3 tool set. ; - Rick Conn ; ; Contributors: ; v1.6 - Dave Rand ; v1.5 - Irv Hoff ; v1.4 - Paul Traina ; v1.3 - Irv Hoff ; v1.2 - Charlie Strom ; v1.1 - Bruce Blakeslee ; v1.0 - Retyped from Interface Age (Dec 81). - Henry Rothberg ; ; ; SYSLIB AND Z3LIB ROUTINES ; EXT Z3INIT,CODEND EXT PRINT,COUT,CRLF ; ; System equates: ; BOOT EQU 0000H ;CP/M WARM BOOT JUMP VECTOR BDOS EQU BOOT+05H ;CP/M BDOS CALL JUMP VECTOR TBUFF EQU BOOT+80H ;DISK I/O BUFFER FCB EQU BOOT+5CH ;DEFAULT FILE CONTROL BLOCK FCB2 EQU BOOT+6CH ;SECONDARY FILE CONTROL AREA CR EQU 'M'-'@' ;CTL-M FOR CARRIAGE RETURN LF EQU 'J'-'@' ;CTL-J FOR LINE FEED CTRLC EQU 'C'-'@' ;ABORT ; ; Environment Definition ; if z3env ne 0 ; ; External ZCPR3 Environment Descriptor ; jmp start db 'Z3ENV' ;This is a ZCPR3 Utility db 1 ;External Environment Descriptor z3eadr: dw z3env start: lhld z3eadr ;pt to ZCPR3 environment ; else ; ; Internal ZCPR3 Environment Descriptor ; MACLIB Z3BASE.LIB MACLIB SYSENV.LIB z3eadr: jmp start SYSENV start: lxi h,z3eadr ;pt to ZCPR3 environment endif ; ; Start of Program -- Initialize ZCPR3 Environment ; call z3init ;initialize the ZCPR3 Env and the VLIB Env LXI H,0 ;SAVE STACK PTR DAD SP SHLD STACK CALL CODEND ;DETERMINE FREE SPACE SHLD FNTAB ;SET PTR TO FILE NAME TABLE LXI D,512 ;1/2 K DAD D SPHL ;NEW STACK CALL HELLO ;SIGN ON MESSAGE CALL HELPCHK ;CHECK FOR AND PRINT HELP MESSAGE CALL PCHECK ;CHECK PARAMETERS LDA FNCOUNT ;NUMBER OF FILES SPECIFIED ORA A ;0=NONE CNZ TRYFIX ;DO THE RECOVERY CALL BYE ;SIGN OFF MESSAGE JMP BOOT ;RETURN TO CP/M ; ; ** Main Routines ** ; ; ; SAY WHO WE ARE ; HELLO: CALL PRINT DB 'UNERASE Version ' DB (VERS/10)+'0','.',(VERS MOD 10)+'0',0 RET ; ; CHECK FOR VALID PARAMETERS AND SAY WHICH CP?M VERSION ; PCHECK: CALL OPTCHK ;CHECK FOR OPTIONS AND SET FLAGS CALL FCBCHK ;MAKE SURE FILE SPECIFIED CALL CPMCHK ;ESTABLISH CP/M PARAMETERS CALL PUSCHK ;CHECK IF USER WANTS TO CHANGE DISK RET ; ; LOOK THROUGH DIRECTORY ; TRYFIX: CALL NXTSEC ;GET A DIRECTORY SECTOR RZ ;RETURNS ZERO FLAG IF NO MORE CALL CHKENT ;CHECK IT OUT AND MAYBE FIX JMP TRYFIX ;KEEP IT UP TILL DONE ; ; SIGN OFF AND RESET SYSTEM ; BYE: MVI C,13 ;SYSTEM RESET CALL BDOS LDA LISTFL ;LIST ONLY? ORA A ;0=NO JNZ PRNF LDA FIXCNT ;CHECK FOR ACTIVITY ORA A JZ PRNF ;SAY NONE FOUND CALL PRINT DB CR,LF,'File(s) Recovered - DOUBLE CHECK Before Using',0 RET PRNF: CALL PRINT DB CR,LF,'NO Files Recovered',0 RET ; ; CHECKS FOR P AND 0 OPTIONS IN COMMAND LINE ; OPTCHK: XRA A ;TURN OFF FLAGS STA CURUSR STA PAUSE STA FIXCNT STA LISTFL STA FNCOUNT ;NO FILE NAMES LXI H,1 ;SET SECTOR 1 SHLD SECTOR LXI H,TBUFF ;SCAN THRU TBUFF, BUILDING A FILE NAME TABLE MOV A,M ;GET CHAR COUNT INX H ;PT TO FIRST CHAR PUSH H ;SAVE PTR ADD L ;PT TO AFTER LAST CHAR MOV L,A MVI M,0 ;STORE ENDING ZERO LHLD FNTAB ;PT TO TABLE XCHG ;... IN DE POP H ;GET PTR TO FIRST CHAR CALL SBLANK ;SKIP BLANKS FNLOOP: PUSH D ;SAVE TABLE PTR CALL GETFN ;EXTRACT FILE NAME POP D PUSH H LXI H,11 ;PT TO NEXT TABLE ENTRY DAD D XCHG POP H LDA FNCOUNT ;INCREMENT COUNT INR A STA FNCOUNT MOV A,M ;GET TERMINATING CHAR INX H ;PT TO NEXT CPI ',' ;ANOTHER FOLLOWS? JZ FNLOOP DCX H ;POINT BACK TO DELIM CALL SBLANK ;SKIP TO NON-BLANK OPTCK1: MOV A,M ;GET OPTION CALL DELCHK ;DONE IF DELIM RZ CPI 'L' ;LIST ONLY? JZ OPTCKL CPI 'P' ;PAUSE? JZ OPTCKP CPI 'Z' ;USER 0? JZ OPTCKZ CALL PRINT DB CR,LF,'Invalid Option -- ',0 MOV A,M CALL COUT JMP HCK1 OPTCKL: MVI A,0FFH ;SET FLAG STA LISTFL INX H ;PT TO NEXT JMP OPTCK1 OPTCKP: MVI A,0FFH ;SET FLAG STA PAUSE INX H ;PT TO NEXT JMP OPTCK1 OPTCKZ: MVI A,0FFH ;SET FLAG STA CURUSR INX H JMP OPTCK1 GETFN: PUSH D ;FILL TARGET FCB MVI B,11 ;11 BYTES MVI A,' ' ;SPACE FILL GETFN0: STAX D ;PUT SPACE INX D DCR B JNZ GETFN0 POP D ;PT TO ENTRY AGAIN CALL SCANCOL ;SCAN FOR COLON MVI B,8 ;8 CHARS MAX CALL GETFN1 ;GET AND FILL ENTRY MOV A,M ;GET CHAR CPI '.' ;DELIM? RNZ ;DONE INX H ;PT TO AFTER PERIOD MVI B,3 ;3 CHARS MAX AND DO IT AGAIN GETFN1: MOV A,M ;GET CHAR CPI '.' ;END OF FIELD? JZ GETFN3 CALL DELCHK ;CHECK DELIMITER RZ CPI '*' ;WILD? JZ GETFNQ STAX D ;STORE CHAR INX H ;PT TO NEXT INX D DCR B ;COUNT DOWN JNZ GETFN1 GETFN2: MOV A,M ;FLUSH CHARS TO DELIM CALL DELCHK ;CHECK FOR DELIMITER RZ INX H ;PT TO NEXT JMP GETFN2 GETFN3: INX D ;PT TO AFTER FIELD DCR B ;COUNT DOWN JNZ GETFN3 RET GETFNQ: MVI A,'?' ;FILL WITH QUESTION MARKS STAX D INX D DCR B JNZ GETFNQ JMP GETFN2 ;SKIP TO DELIM DELCHK: ORA A ;END OF LINE? RZ CPI '.' ;END OF FIELD? RZ CPI ',' ;END OF ENTRY? RZ CPI ' ' RET SBLANK: MOV A,M ;SKIP TO NON-BLANK CPI ' ' RNZ INX H JMP SBLANK SCANCOL: PUSH D ;SAVE TABLE PTR PUSH H ;SAVE PTR SCOL1: MOV A,M ;GET CHAR INX H ;PT TO NEXT CPI ':' ;COLON? JZ SCOLX CALL DELCHK ;CHECK FOR DELIMITER JNZ SCOL1 SCOL2: POP H ;RESTORE POP D RET SCOLX: XCHG ;DE PTS TO AFTER COLON POP H ;GET OLD PTR XCHG ;REPLACE IT POP D ;GET TABLE PTR RET ; ; CHECKS THE CURRENT 4 DIRECTORY ENTRIES AGAINST ARGUMENT ; IF MATCH, REWRITES SECTOR WITH REACTIVATED 1ST BYTES ; CHKENT: XRA A ;ASSUME NO REWRITE STA REWRT MVI B,4 ;NUMBER OF ENTRIES PER SECTOR LXI H,TBUFF ;BEGINNING OF BUFFER CKLUP: PUSH B MOV A,M CPI 0E5H ;CHECK FOR UNUSED JNZ CKINC PUSH H LHLD FNTAB ;PT TO POTENTIAL FILES XCHG POP H LDA FNCOUNT ;NUMBER OF ENTRIES TO COUNT MOV B,A ;... IN B CKLUP0: PUSH H ;SAVE BEGINNING ADDRESS PUSH D ;SAVE PTR PUSH B ;SET NAME COUNT CALL COMPAR ;COMPARE WITH ARGUMENT POP B ;GET NAME COUNT POP D ;GET PTR POP H JZ CKLUP1 ;MATCH! PUSH H ;SAVE PTR LXI H,11 ;PT TO NEXT ENTRY DAD D XCHG POP H DCR B ;COUNT DOWN JNZ CKLUP0 JMP CKINC CKLUP1: LDA LISTFL ;LIST ONLY? ORA A ;0=NO JNZ CKINC MVI M,0 ;SET USER 0 LDA CURUSR ;CHECK FOR CURRENT USER CPI 0FFH JZ CKLUP2 PUSH H ;SAVE HL MVI E,0FFH ;GET USER VALUE MVI C,32 ;GET USER AREA FUNCTION CALL BDOS ;BDOS RETURNS CURRENT AREA IN 'A' REG. POP H ;RESTORE HL MOV M,A ;POKE IN CURRENT USER AREA CKLUP2: MVI A,0FH ;SAY NEED REWRITE STA REWRT MVI A,0FFH ;SET COUNT FLAG STA FIXCNT CKINC: POP B LXI D,32 ;LENGTH OF ENTRY DAD D DCR B JNZ CKLUP LDA REWRT ;SEE IF NEED REWRITE ORA A JZ CKDONE ;NO - DONE ; ; WRITE THE DIRECTORY SECTOR BACK TO THE DISK ; LHLD TRACK ;SET TRACK MOV C,L MOV B,H CALL SETTRK LHLD SECTOR ;SET SECTOR MOV B,H MOV C,L CALL TRNSLT CALL SETSEC CALL WRITE ;WRITE THE SECTOR BACK ORA A JNZ ERRWRT ;ABORT IF ERROR CKDONE: LHLD DIRMAX DCX H ;REDUCE SECTORS LEFT SHLD DIRMAX LHLD SECTOR ;POINT TO NEXT SECTOR INX H SHLD SECTOR XCHG LHLD MAXSEC ;REACHED LIMIT? INX H ;ONE MORE MOV A,H ;CHECK HIGH CMP D RNZ MOV A,L ;CHECK LOW CMP E RNZ LHLD TRACK ;NEXT TRACK INX H SHLD TRACK LXI H,1 ;FIRST SECTOR OF NEXT TRACK SHLD SECTOR RET ; ; COMPARE 11 BYTES OF DIRECTORY ENTRY AGAINST ARGUMENT ; COMPAR: SHLD TEMP ;Hold pointer in case of match INX H XCHG MVI C,11 CMPR1: LDAX D ;GET DIRECTORY ENTRY CHARACTER ANI 7FH ;STRIP ANY FLAGS CMP M JNZ CMPCKAM CMPR2: INX D INX H ;BUMP TO NEXT CHARACTER DCR C JNZ CMPR1 ;LOOP FOR 11 CHARACTERS LDA FIXCNT ;CHECK FLAG ORA A ;0=FIRST TIME CZ PRFIX LHLD TEMP CALL PRINTFCB XRA A RET ;RETURNS 'ZERO' FLAG SET FOR MATCH PRFIX: LDA LISTFL ;LIST ONLY? ORA A ;0=NO JNZ PRFIX1 CALL PRINT DB CR,LF,'File(s) Recovered --',0 RET PRFIX1: MVI A,0FFH ;DON'T PRINT THIS AGAIN STA FIXCNT CALL PRINT DB CR,LF,'Erased File(s) --',0 RET CMPCKAM: LDAX D CPI 0E5H ;NON-ALLOCATED ENTRY? JZ SKIP MOV A,M CPI '?' RNZ JMP CMPR2 SKIP: ORA A RET ;SET NZ FLAG ; ; CHECK FOR CP/M VERSION AND SET THINGS ; CPMCHK: LXI D,80H ;SET DMA TO TBUFF MVI C,26 CALL BDOS CALL CPM22 ;IF 2.2 GO SET THINGS CALL GTBIOS ;ESTABLISH BIOS JUMP VECTOR ; ; SELECT DISK AND SETUP DISK PARAMETER HEADER ; LDA FCB ;GET THE DISK MOV E,A MVI C,14 CALL BDOS LDA FCB MOV C,A MVI B,0 CALL SELDSK ;MAKE SURE DRIVE IS MOV A,H ; SELECTED ORA L JZ ILDISK MOV E,M ;GET THE ADDRESS INX H ; OF THE XLTO MOV D,M XCHG SHLD DPH ;SAVE THE ADDRESS RET ; ; DETERMINE NUMBER OF DIRECTORY ENTRIES ; CPM22: MVI C,31 ;GET DISK PARAMETERS ADDRESS CALL BDOS ;DPB ADDRESS IN 'HL' ON RETURN MOV E,M ;NUMBER OF SECTORS/TRACK INX H ;AS 2-BYTE QUANTITY IN DE MOV D,M INX H XCHG SHLD MAXSEC ;SET MAX SECTORS/TRACK XCHG INX H INX H MOV A,M ;GET EXM STA EXTENT INX H ;PT TO DRM INX H INX H MOV E,M ;GET NUMBER OF INX H ; DIRECTORY ENTRIES MOV D,M XCHG INX H ;ACCOUNT FOR - 1 CALL SHFHL2 ;SHIFT 'HL' RIGHT 2 SHLD DIRMAX ;SAVE NUMBER DIRECTORY SECTORS LXI H,5 ;NOW POINT TO SYSTEM DAD D ; TRACK OFFSET MOV A,M ;PICK UP NUMBER OF INX H MOV H,M MOV L,A SHLD TRACK RET ; ; ERROR OCCURED DURING DISK WRITE - ABORT ; ERRWRT: CALL PRINT DB CR,LF,'ABORT - Error During Disk Write',0 JMP BOOT ;ABORT ; ; MAKE SURE A LEGAL DISK IS SPECIFIED AND CHECK FOR HELP ; FCBCHK: LDA FCB ;GET DRIVE SPECIFICATION ORA A ;SEE IF DEFAULT JNZ FCBCK1 ;NO, GO CHECK FILENAME MVI C,25 ;ASK FOR CURRENT DRIVE CALL BDOS INR A ;OFFSET FOR NEXT INSTRUCTION FCBCK1: DCR A ;CURRENT DRIVE NUMBER STA FCB ;SAVE IT RET ; ; CHECK FOR HELP REQUEST ; HELPCHK: LDA FCB+1 ;GET 1ST BYTE OF FILENAME CPI '/' ;HELP? JZ HCK1 CPI ' ' ;MAKE SURE IT IS NON-BLANK RNZ ;OK - KEEP GOING ; ; IF NO FILE NAME IS SPECIFIED, ABORT WITH NOTICE ; HCK1: CALL PRINT db cr,lf,'Syntax:' DB CR,LF,' UNERASE afn,afn,afn,... o' db cr,lf,'Options:' DB CR,LF,' L - List Erased Files Only' DB CR,LF,' P - Pause for disk change' DB CR,LF,' Z - Place file in User 0 ' DB '(default is current)' DB 0 CLEANRET: LHLD STACK ;QUIET RETURN SPHL RET ; ; GET BIOS JUMPS VECTORS FOR EASY REFERENCE ; GTBIOS: LHLD BOOT+1 ;POINTS TO BIOS JUMP TABLE+3 LXI D,WBOOT ;WHERE WE WILL KEEP A COPY MVI B,16*3 ;MOVE 48 BYTES AND FALL THRU TO MOVE ; ; GENERAL PURPOSE MOVE ROUTINE ; FROM 'HL' TO 'DE' FOR COUNT OF 8 ; MOVE: MOV A,M ;GET A BYTE STAX D ;PUT A BYTE INX D ;INCREMENT TO NEXT INX H DCR B ;COUNT DOWN JNZ MOVE RET ; ;SPECIFIED AN ILLEGAL DISK DRIVE - ABORT ; ILDISK: CALL PRINT DB CR,LF,'ABORT - Illegal Disk Requested',0 JMP BOOT ;ABORT ; ; READS NEXT SECTOR (GROUP OF FOUR DIRECTORY ENTRIES) ; RETURNS WITH ZERO FLAG SET IF NO MORE ; NXTSEC: LHLD DIRMAX ;SEE IF MORE SECTORS MOV A,H ORA L RZ ;RETURNS ZERO FLAG IF NO MORE LHLD TRACK ;SET TRACK MOV C,L MOV B,H CALL SETTRK LHLD SECTOR ;SET SECTOR MOV B,H MOV C,L CALL TRNSLT CALL SETSEC CALL READ ;READ A SECTOR ANI 1 ;REVERSE SENSE OF ERROR FLAG XRI 1 ;RETURNS WITH ZERO FLAG SET RET ;IF BAD READ ; ; FCB PRINTING ROUTINE ; PRINTFCB: PUSH H LXI D,1+8+3 DAD D LDA EXTENT ;GET EXTENT MASK CMP M ;COMPARE TO TARGET POP H RC ;PRINT ONLY FIRST EXTENT CALL PRINT ;NEW LINE WITH 2 LEADING SPACES DB CR,LF,' ',0 INX H MVI B,8 CALL PR1 MVI A,'.' CALL COUT MVI B,3 PR1: MOV A,M ANI 7FH CPI ' ' ;Check for blanks CNZ COUT INX H DCR B JNZ PR1 RET ; ; DOES USER WANT TO PAUSE TO CHANGE DISKS OR SELECT USER 0? ; PUSCHK: LDA PAUSE ;GET OPTION ORA A RZ ;NOPE, SO RETURN CALL PRINT ;PRINT PAUSE MESSAGE DB CR,LF,'Change Disk - Hit ^C to Abort, Anything Else to Cont - ' DB 0 MVI C,01 CALL BDOS ;INPUT A CHAR CPI CTRLC ;ABORT? JZ CLEANRET CALL CRLF MVI C,0DH JMP BDOS ;RESET THE DISK ; ; SHIFT REGS 'HL' RIGHT 2 BITS LOGICAL ; SHFHL2: CALL SHFHL ;ROTATE RIGHT 1 BIT AND FALL THRU SHFHL: XRA A ;CLEAR CARRY MOV A,H RAR ;SHIFTED BIT IN CARRY MOV H,A MOV A,L RAR MOV L,A RET ; ; TRANSLATE REG 'BC' FROM LOGICAL TO PHYSICAL SECTOR NUMBER ; TRNSLT: LHLD DPH ;GET ADDRESS OF XLTO XCHG CALL SECTRAN ;USE BIOS ROUTINE MOV C,L ;RETURN VALUE IN BC MOV B,H RET ; ; THIS IS THE WORKING COPY OF THE BIOS JUMP TABLE ; WBOOT: DS 3 CONST: DS 3 CONIN: DS 3 CONOUT: DS 3 LIST: DS 3 PUNCH: DS 3 READER: DS 3 HOME: DS 3 SELDSK: DS 3 SETTRK: DS 3 SETSEC: DS 3 SETDMA: DS 3 READ: DS 3 WRITE: DS 3 LISTST: DS 3 SECTRAN: DS 3 ; STACK: DS 2 ;LOCATION OF STACK ; ; DATA AREAS ; FNCOUNT: DS 1 ;NUMBER OF FILE NAMES IN COMMAND LINE CURUSR: DS 1 ;0 IF NOT IN CURRENT USER PAUSE: DS 1 ;0 IF NO PAUSE FOR DISK CHANGE LISTFL: DS 1 ;0 IF NOT LIST ONLY DIRMAX: DS 2 ;NUMBER OF SECTORS IN DIRECTORY = ; ; MAXIMUM NUMBER OF DIRECTORY ENTRIES ; ; DIVIDED BY 4 (ENTRIES PER SECTOR) TEMP: DS 2 ;TEMP STORAGE FOR FCB PRINT EXTENT: DS 1 ;EXTENT MASK MAXSEC: DS 2 ;MAXIMUM NUMBER OF SECTORS/TRACK FIXCNT: DS 1 ;CHANGE FLAG REWRT: DS 1 ;REWRITE FLAG 0=NO, F=YES SECTOR: DS 2 ;CURRENT SECTOR NUMBER TRACK: DS 2 ;TRACK NUMBER OF DIRECTORY ; ; ADDRESS OF THE TRANSLATE TABLE ; DPH: DS 16 FNTAB: DS 2 ;FILE NAME BUFFER END