;	PROGRAMME TO RECOVER ERASED FILE
BOOT	EQU	0		;CP/M WARM BOOT JUMP VECTOR
BDOS	EQU	5		;CP/M BDOS CALL JUMP VECTOR
FCB	EQU	BOOT+5CH	;DEFAULT FILE CONTROL BLOCK
									
	ORG	100H		;START AT BASE OF TPA
	JMP	STACK		;GET AROUND THE STACK

BIN	DB	48		;48 IF CP/M 2.x, 42 IF CP/M 1.4
				; BE SURE TO SUPPLY A
				; SECTRAN ROUTINE IF 1.4

HMSG    DB      13,10,'UNERASE ALFRED VERSION 1.0 (10/2/82) (CP/M VERSION $'
MSG22   DB      '2.x)',13,10,'$'
MSG14   DB	'1.4)',13,10,'$'

        ORG     200H    ;GOOD PLACE TO START THE PROGRAM
STACK   LXI     SP, STACK       ;SET STACK POINTER
        CALL    HELLO           ;SIGN ON MESSAGE
        CALL    PCHECK          ;CHECK PARAMETERS
        CALL    TRYFIX          ;DO TH RECOVERY
        CALL    BYE             ;SIGN OFF MESSAGE
        JMP     BOOT            ;RETURN TO CP/M

;  SAY WHO WE ARE
HELLO   LXI     D,HMSG          ;POINT TO HELLO MESSAGE
        CALL    PRINT
        RET

;  CHECK FOR VALID PARAMETERS AND SAY WHICH CP/M VERSION
PCHECK  CALL    FCBCHK          ;MAKE SURE FILE SPECIFIED
        CALL    CPMCHK          ;ESTABLISH CP/M VERSION
        RET

;  LOOKS THROUGH THE DIRECTORY TRYING TO MATCH FCB FILENAME
TRYFIX  CALL    NXTSECT         ;GET A DIRECTORY SECTOR
        RZ                      ;RETURNS ZERO FLAG IF NO MORE
        CALL    CHKENT          ;CHECK IT OUT AND MABYE FIX
        JMP     TRYFIX          ;KEEP IT UP TILL DONE

;  SIGN OFF AND RESET SYSTEM
BYE     MVI     C,13            ;SYSTEM RESET
        CALL    BDOS
        LDA     FIXCNT          ;CHECK FOR ACTIVITY
        ORA     A
        JZ      NOFIND          ;SAY NONE FOUND
        LXI     D,BMSG          ;WARN FOUND
        CALL    PRINT
        RET
NOFIND  LXI     D,NFMSG
        CALL    PRINT
        RET

;  MAKES SURE A LEGAL FILENAME IS SPECIFIED
FCBCHK  LDA     FCB             ;GET DRIVE SPECIFICATION
        ORA     A                ;SEE IF DEAFAULT
        JNZ     FCBCKI          ;NO, GO CHECK FILENAME
        MVI     C,25            ;ASK FOR CURRENT DRIVE
        CALL    BDOS
        INR     A               ;OFFSET FOR NEXT INSTR
FCBCKI  DCR     A               ;CURRENT DRIVE NUMBER
        STA     FCB             ;SAVE IT
        LDA     FCB+1           ;GET 1ST BYTE OF FILENAME
        CPI     ' '             ;MAKE SURE IT IS NON BLANK
        RNC                     ;OK - KEEP GOING
;  IF NO FILE NAME IS SPECIFIED, ABORT WITH NOTICE
        LXI     D,NOFMSG
        CALL    PRINT
        JMP     BOOT            ;ABORT

;  CHECKS FOR CP/M VERSION AND SETS THINGS
CPMCHK  LXI     D,80H           ;SET DMA TO TBUFF
        MVI     C,26
        CALL    BDOS
        MVI     C,12            ;VERSION NUMBER REQUEST
        CALL    BDOS
        CPI     20H             ;EARLIER THAN 2.x?
        MVI     A,42            ;ASSUME 1.4
        LXI     D,MSG14         ;POINT TO 1.4 MSG
        CNC     CPM22           ;IF 2.x GO SET THINGS
        STA     BIN             ;SET THE MOVE LENGTH
        CALL    PRINT
        CALL    GETBIOS         ;ESTABLISH BIOS JUMP VECTOR
 ;  SELECT CALL DISK AND SETUP DISK PARAM HEADER
        LDA     FCB             ;GET THE DISK
        MOV     C,A
        MVI     B,0
        CALL    SELDSK          ;MAKE SURE DRIVE IS
        MOV     A,H             ;SELECTED
        ORA     L
        JZ      ILDISK
        LDA     BIN
        CPI     48              ;IF CP/M 1.4 SKIP REST
        RC
        MOV     E,M             ;GET THE ADDRESS
        INX     H               ; OF THE XLT0
        MOV     D,M
        XCHG
        SHLD     DPH            ;SAVE THE ADDRESS
        RET

;  IF CP/M 2.x DETERMINE NUMBER OF DIRECTORY ENTRIES ALSO
CPM22   MVI     C,31            ;GET DISK PARMS ADDRESS
        CALL    BDOS            ;DPB ADDR IN HL ON RET
        LXI     D,7             ;OFFSET TO DRM
        DAD     D
        MOV     E,M             ;GET NUMBER OF
        INX     H               ; DIRECTORY ENTRIES
        MOV     D,M
        XCHG
        INX     H               ;ACCOUNT FOR - 1
        CALL    SHFTHL2         ;SHIFT HL RIGHT 2
        MOV     A,L             ;GET NUMBER OF SECTORS
        STA     DIRMAX          ;SAVE NUMB DIR SECS
        LXI     H,5             ;NOW POINT TO SYSTEM
        DAD     D               ; TRACK OFFSET
        MOV     A,M             ;PICK UP NUMBER OF
        STA     TRACK           ;SAVE TRACK OFFSET
        MVI     A,48            ;SET MOVE LENGTH
        LXI     D,MSG22         ;POINT TO 2.x MSG
        RET

;  GET BIOS JUMP VECTORS FOR EASY REFERENCE
GETBIOS LHLD    BOOT+1          ;POINTS TO BIOS JUMP TABLE+3
        LXI     D,WBOOT         ;WHERE WE WILL KEEP A COPY
        LDA     BIN             ;NUMBER OF BYTES TO MOVE
        MOV     B,A             ;MOVE LIKES IT IN REG B
        CALL    MOVE            ;MOVE THE TABLE
        RET

;  READS NEXT SECTOR (GROUP OF 4 DIRECTORY ENTRIES)
;  RETURNS WITH ZERO FLAG SET OF NO MORE
NXTSECT LDA     DIRMAX          ;SEE IF MORE SECTORS
        ORA     A
        RZ                      ;RETURNS ZERO FLAG IF NO MORE
        LDA     TRACK           ;SET TRACK
        MOV     C,A
        MVI     B,0
        CALL    SETTRK
        LDA     SECTOR          ;SET SECTOR
        MOV     C,A
        CALL    TRANSLT
        MVI     B,0
        CALL    SETSEC
        CALL    READ            ;READ A SECTOR
        ANI     1
        XRI     1               ;REVERSE SENSE OF ERROR FLAG
        RET                     ;RETURNS WITH ZERO FLAG SET
                                ;  IF BAD READ

;  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,80H           ;BEGINNING OF BUFFER
CKLUP   MOV     A,M
        CPI     0E5H            ;CHECK FOR UNUSED
        JNZ     CKINC
        PUSH    H               ;SAVE BEGINNING ADDR
        CALL    COMPAR          ;COMPARE WITH ARGUMENT
        POP     H
        JNZ     CKINC           ;NO MATCH
        MVI     M,0             ;RESET FLAG FOR ACTIVE
        MVI     A,0FH           ;SAY NEEDS REWRITE
        STA     REWRT
        LDA     FIXCNT

        INR     A               ;BUMP COUNT OF CHANGES
        STA     FIXCNT
CKINC   LXI     D,32            ;LENGTH OF ENTRY
        DAD     D
        DCR     B
        JNZ     CKLUP
        LDA     REWRT           ;SEE OF NEED REWRITE
        ORA     A
        JZ      CKDONE          ;NO - DONE
;  WRITE THE DIRECTORY SECTOR BACK TO THE DISK
        LDA     TRACK           ;SET TRACK
        MOV     C,A
        MVI     B,0
        CALL    SETTRK
        LDA     SECTOR          ;SET SECTOR
        MOV     C,A
        CALL TRANSLT
        MVI     B,0
        CALL    SETSEC
        CALL    WRITE           ;WRITE THE SECTOR BACK
        ORA     A               ;ABORT IF ERROR
        JNZ     ERRWRT
CKDONE  LDA     DIRMAX
        DCR     A               ;REDUCE SECTORS LEFT
        STA     DIRMAX
        LDA     SECTOR          ;POINT TO NEXT SECTOR
        INR     A
        STA     SECTOR
        RET

;  COMPARE 11 BYTES OF DIRECTORY ENTRY AGAINST ARGUMENT
COMPAR  INX     H
        LXI     D,FCB+1
        XCHG
        MVI     C,11
CMPR1   mvi	a,03fh		; '?'
	cmp	m
	jz	cmpr2		; it's a wild char, anything will do
	LDAX    D               ;GET DIR ENT CHAR
        ANI     7FH             ;STRIP ANY FLAGS
        CMP     M
        RNZ                     ;DONE IF NO MATCH
cmpr2:  INX     D
        INX     H               ;BUMP TO NEXT CHAR
        DCR     C
        JNZ     CMPR1           ;LOOP FOR 11 CHAR
        RET                     ;RETURNS ZERO FLAG SET FOR MATCH

;  GENERAL PURPOSE MOVE ROUTINE.
;    FROM (HL) TO (DE) FOR COUNT OF B
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

;  SHIFT REGS HL RIGHT 2 BITS LOGICAL
SHFTHL2 CALL    SHFTHL
SHFTHL  XRA     A               ;CLEAR CARRY
        MOV     A,H
        RAR                     ;SHIFTED BIT IN CARRY
        MOV     H,A
        MOV     A,L
        RAR
        MOV     L,A
        RET

; GENERAL PRINT ROUTINE ENTER WITH REG DE POINTING TO MSG
;  RETURNS TO CALLER FROM BDOS
PRINT   MVI     C,9             ;BDOS PRINT STRING COMMAND
        JMP     BDOS            ;GO DO THE PRINT

; SPECIFIED AN ILLEGAL DISK DRIVE - ABORT
ILDISK  LXI     D,ILMSG
        CALL    PRINT
        JMP     BOOT            ;ABORT

;  ERROR OCCURED DURING DISK WRITE - ABORT
ERRWRT  LXI     D,WMSG
        CALL    PRINT
        JMP     BOOT            ;ABORT

; TRANSLATE REG C FROM LOGICAL TO PHYSICAL SECTOR NUMBER
TRANSLT LHLD    DPH             ;GET ADDRESS OF XLT0
        XCHG
        CALL    SECTRAN
        MOV     C,L
        RET

;  THIS IS THE WORKING COPY OF THE BIOS JUMP TABLE
;  IF CP/M 2.x, NO CHANGES ARE NECESSARY
;  IF CP/M 1.4, SECTRAN IS NOT COPIED FROM BIOS
;               BE SURE TO CORRECT THE INCLUDED
;                               VERSION FOR YOUR OWN DISK SYSTEM
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 JMP     STRAN
;  SECTOR TRANSLATION ROUTINE FOR
;  CP/M VERSIONS EARLIER THAN 2.0
;  REG DE CONTAINS ADDRESS OF XLT0
;  REG BC CONTAINS THE LOGICAL SECTOR NUMBER

;  RETURNS PHYSICAL SECTOR NUMBER IN REG HL
STRAN   MVI     B,0
        XCHG
        DAD     B
        MOV     L,M
        RET

;  ADDRESS OF TRANSLATE TABLE
DPH     DW      XLT0
        DS      14

;  THIS IS THE STANDARD TRANSLATE TABLE
XLT0    DB      1,7,13,19,25,5,11,17,23,3,9,15,21
        DB      2,8,14,20,26,6,12,18,24,4,10,16,22

;  WORKING STORAGE FOLLOWS

DIRMAX  DB      16              ;NUMBER OF SECTORS IN DIRECTORY =
                                ;MAXIMUM NUMBER OF DIRECTORY ENTRIES
                                ; DIVIDED BY 4 (ENTRIES PER SECTOR)

TRACK   DB      2               ;TRACK NUMBER OF DIRECTORY
SECTOR  DB      0               ;CURRENT SECTOR NUMBER

FIXCNT  DB      0               ;NUMBER OF ENTRIES FIXED
REWRT   DB      0               ;REWRITE FLAG 0=NO, F=YES

WMSG    DB      10,13,'ERROR OCCURED DURING DISK WRITE - ABORT$'
ILMSG   DB      10,13,'SPECIFIED AN ILLEGAL DISK DRIVE - ABORT$'
BMSG    DB      10,13,'RECOVERED - PLEASE DOUBLE CHECK BEFORE USING$'
NOFMSG  DB      10,13,'NO FILE NAME SPECIFIED - ABORT$'
NFMSG   DB      10,13,'FILE NOT FOUND$'
        END     100H
