; ; Program: CLEANDIR ; Derivation: SAP 3.8 (see following history for authors) ; Derivation By: Richard Conn ; Version: 1.1 ; Date: 28 November 1984 ; Previous Versions: 1.0 (20 June 84) ; ; bug fix ;841201 Peter T Lyman ; Version 1.1P ; ; Search for ';841201' to locate the code ; ; CLEANDIR can and does wipe out the operating system ; (also known as a crash) whenever the maximum size of ; the directory (DRM) exceeds the available memory.... ; ; Maybe that is a good feature, since you at least don't ; hurt the disk... ; ; However on my hard disk I have two platters with ; DRM equal to 2048.... In this case CLEANDIR crashes... ; ; The fix that I have added (I did this with an early version ; of SAP) gives you a choice.... If DRM is greater than ; the space available betwwen BUF and BDOS, you are given ; a choice with proceeding if the actual number of directory ; entries is less than or equal to the space available.... ; If not you ABORT..... ; ; The down side risk of this modification is that if you ; proceed ("Y") when the actual number of files exceeds ; the space available, you lose all the directories entries ; which don't fit in the available space.... ; ; With out the fix the system crashes and you cannot clean the ; directory... With the fix you can clean the directory, but ; you can lose files if you don't pay attention.... ; vers equ 11 z3env equ 0f400h ; ; SYSLIB and Z3LIB References ; ext z3init,z3log ext eprint,cout ext codend ext phlfdc ;841201 ; ; 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 Environment ; v3.8 SORT AND PACK CP/M DISK DIRECTORY - 10/16/83 ; ; THIS PROGRAM READS THE DISK DIRECTORY TRACKS, SORTS THEM ALPHABETICALLY ; THEN REPLACES THEM ON THE DISK. ALL UNUSED OR ERASED AREAS ON THE DIR- ; ECTORY TRACK ARE REFORMATTED WITH CONTINUOUS 'E5' CHARACTERS. (THIS ; ERASES PREVIOUS FILE NAMES WHICH HAVE BEEN DEACTIVATED.) SORTING THE ; DIRECTORY IN THIS MANNER OFFERS MANY ADVANTAGES. SOME OF THEM ARE: ; ; 1) ALLOWS 'DIR' TO SHOW AN ALPHABETIZED LISTING ; 2) ELIMINATES POTENTIAL PROBLEMS WITH "UNERASE" PROGRAMS ; 3) SPEEDS UP ACCESS VIA 'SD' AND OTHER SPECIAL PROGRAMS ; 4) ASSISTS ON WORKING DIRECTLY ON THE DISK WITH 'DUU', ETC. ; 5) REMOVES FILES FROM THE DISK SOMEBODY ELSE COULD RECOVER ; ; - Notes by Irv Hoff W6FFC ; ; 1977 Written by L. E. Hughes. Modified extensively since by Bruce ; Ratoff, Keith Petersen, James Prest, Ron Fowler, Frank Gaude, ; Irv Hoff and likely others. ; ; 10/16/83 Now using a Shell-Metzner sort which speeds the sorting time ; considerably, especially on large directories. (SFK) ; ; 07/27/83 Shows an error flag for MP/M and CP/M+ both. Rewrites dir- ; tory even if previously sorted, to insure erased programs at ; v3.7 end of directory are properly cleared. ; - Irv Hoff ; TRUE EQU 0FFH FALSE EQU 0 ; BDOS EQU 5 CR EQU 0DH DPBLEN EQU 15 ;SIZE OF CP/M2 DISK PARAMETER BLOCK FCB EQU 5CH FCB2 EQU 6CH GETDSK EQU 25 ;BDOS "GET DISK #" FUNCTION LF EQU 0AH SELDRV EQU 14 ;SELECT DRIVE ;..... ; ; ; OBTAIN BIOS VECTORS ; VECTRS: JMP GETVEC ; DS 53 ;ROOM FOR JUMP VECTORS ; WBOOT EQU VECTRS+3 ;DO NOT CHANGE THESE EQUATES CSTS EQU VECTRS+6 CI EQU VECTRS+9 CO EQU VECTRS+12 LO EQU VECTRS+15 PO EQU VECTRS+18 RI EQU VECTRS+21 HOME EQU VECTRS+24 SELDSK EQU VECTRS+27 SETTRK EQU VECTRS+30 SETSEC EQU VECTRS+33 SETDMA EQU VECTRS+36 READ EQU VECTRS+39 WRITE EQU VECTRS+42 LSTS EQU VECTRS+45 ;ONLY IN CP/M2 SECTRN EQU VECTRS+48 ;ONLY IN CP/M2 ; ; GET BIOS VECTORS ; GETVEC: LXI D,WBOOT LHLD 1 MVI B,53 CALL MOVE ; ; PROGRAM STARTS HERE ; LXI H,0 DAD SP ;GET ADDRESS OF CP/M STACK SHLD STACK ;STORE IT SO WE CAN GO BACK TO IT CALL CODEND ;DETERMINE FREE SPACE LXI D,80H ;ALLOW 80H BYTES FOR STACK SHLD BUF ;SET BUFFER ADDRESS SPHL ;SET TOP OF STACK lda bdos+2 ;fetch bdos page ;841201 dcr a ; less one ; lhld buf ;fetch buf pntr ; sub h ;available space for dir ; mvi h,0 ; ; mov l,a ;number of pages available ; dad h ;x2->number of sectors ; dad h ;x2 ; dad h ;x2->number of directory ; ; entries which will fit ; shld maxdir ;save for later ; XRA A ;SET NO REVERSE OF USER AREAS STA REVERSE CALL EPRINT ;PRINT MSG: DB 'CLEANDIR, Version ' DB (vers/10)+'0','.',(vers mod 10)+'0','P' ;841201 DB 0 LDA FCB+1 ;CHECK FOR HELP REQUEST CPI '/' ;ANY OPTION MEANS HELP JZ HELP CPI 'D' ;SELECT DESCENDING ORDER? JZ DESC LDA FCB2+1 ;CHECK FOR OPTION CHAR CPI 'D' ;DESCENDING ORDER OF USER AREAS? JNZ SAP DESC: MVI A,0FFH ;ENABLE REVERSE STA REVERSE JMP SAP ; ; PRINT HELP MESSAGE ; HELP: CALL EPRINT DB CR,LF,'Syntax:' DB CR,LF,' CLEANDIR dir: o' DB CR,LF,'Options:' DB CR,LF,' D - sort in Descending Order (users and files)' DB CR,LF,'Note:' DB CR,LF,' Only disk ref is used in dir: form' DB 0 JMP EXIT1 ; ; MAIN PROGRAM ROUTINE ; SAP: CALL SETUP call ckdrsz ;check available memory space ;841201 CALL RDDIR CALL CLEAN CALL SORT CALL PACK CALL WRDIR CALL EPRINT DB 'Done',0 JMP EXIT ckdrsz: lhld drm ;fetch max dir size ;841201 xchg ; ; lhld maxdir ;fetch memory available for dir ; call hlmde ;subtract ; rnc ;return if room ; call eprint ;else... ; db lf,lf,lf,lf,lf,lf ; db cr,lf,'Your maximum directory size is ',0 ; lhld drm ;print max dir size ; inx h ; ; call phlfdc ; ; call eprint ; ; db ' directory entries.',0 ; call eprint ; ; db cr,lf,'your memory can only handle ',0 ; lhld maxdir ;print space available ; call phlfdc ; ; call eprint ; ; db ' directory entries.' ; db cr,lf,lf,'IF.....your directory DOES NOT exceed ',0; lhld maxdir ; ; call phlfdc ; ; call eprint ; ; db ' directory entries,' ; db cr,lf,' (Directory entries NOT Files)'; db cr,lf,' you may enter "Y" to proceed,' ; db cr,lf,lf,'ELSE...any other key ABORTS.' ; db cr,lf,lf,lf,lf,lf,lf,lf,lf,'..............> ',7,0; ck1: mvi c,6 ;get input ; mvi e,-1 ; ; call bdos ; ; cpi 0 ; ; jz ck1 ; ; ani 5fh ; ; cpi 'Y' ; ; jnz exit1 ; ; lhld maxdir ; ; shld drm ; ; ret ; ; ; ; hlmde: mov a,h ; ; cmp d ; ; rnz ; ; mov a,l ; ; cmp e ; ; ret ; ; ; ; SUBROUTINES ; ; CLEAN: LXI H,0 ;I = 0 ; CLNLOP: SHLD I CALL INDEX ;HL = BUF + 16 * I MOV A,M ;JUMP IF THIS IS A DELETED FILE CPI 0E5H JZ FILLE5 LXI D,12 DAD D ;HL = HL + 12 MOV A,M ;CHECK EXTENT FIELD ORA A JNZ CLBUMP ;SKIP IF NOT EXTENT ZERO INX H ;POINT TO RECORD COUNT FIELD INX H MOV A,M ;GET S2 BYTE (EXTENDED RC) ANI 0FH ; FOR CPM2, 0 FOR CPM1 MOV E,A INX H MOV A,M ;CHECK RECORD COUNT FIELD ORA E JNZ CLBUMP ;JUMP IF NON-ZERO LHLD I ;CLEAR ALL 32 BYTES OF CALL INDEX ; DIRECTORY ENTRY TO E5 INX H MOV A,M ;GET FIRST CHAR OF FILENAME DCX H ; WARD CHRISTENSONS CAT PGMS CPI '-' ; HAVE DISKNAME OF ZERO LENGTH JZ CLBUMP ; THAT START WITH '-', DON'T DELETE CPI ' ' ; DISCAT USES DISKNAME OF ZERO LENGTH JZ CLBUMP ; THAT STARTS WITH ' ', DON'T DELETE ; FILLE5: MVI C,32 ;NUMBER OF BYTES TO CLEAR ; FILLOP: MVI M,0E5H ;MAKE IT ALL E5'S INX H DCR C JNZ FILLOP ; CLBUMP: LHLD DRM ;GET COUNT OF FILENAMES INX H XCHG LHLD I ;OUR CURRENT COUNT INX H PUSH H CALL SUBDE ;SUBTRACT POP H JC CLNLOP ;LOOP TILL ALL CLEANED RET ; DODIR: STA WRFLAG LHLD SYSTRK CALL DOTRAK ;SET THE TRACK LXI H,0 SHLD SECTOR LHLD DRM ;NUMBER OF DIR ENTRIES INX H ;RELATIVE TO 1 CALL ROTRHL ;DIVIDE BY 4 CALL ROTRHL ; TO GET SECTOR COUNT SHLD DIRCNT LHLD BUF SHLD ADDR ;FOR DMA ADDRESS ; DIRLOP: LHLD SECTOR ;GET SECTORS PER TRACK INX H XCHG LHLD SPT ;CURRENT SECTOR CALL SUBDE ; SECTOR - SPT XCHG JNC NOTROV ; ; TRACK OVERFLOW, BUMP TO NEXT ; LHLD TRACK INX H CALL DOTRAK LXI H,1 ;REWIND SECTOR NUMBER ; NOTROV: CALL DOSEC ;SET CURRENT SECTOR LHLD ADDR MOV B,H ;SET UP DMA ADDRESS MOV C,L CALL SETDMA LDA WRFLAG ;TIME TO FIGURE OUT ORA A ; IF WE ARE READING JNZ DWRT ; OR WRITING ; ; ; READ ; CALL READ ORA A ;TEST FLAGS ON READ JNZ RERROR ;NZ=ERROR JMP MORE ;GOOD READ, GO DO MORE ; ; TRACK AND SECTOR UPDATE ROUTINES ; DOTRAK: SHLD TRACK MOV B,H MOV C,L CALL SETTRK RET DOSEC: SHLD SECTOR MOV B,H MOV C,L LHLD SECTBL XCHG DCX B CALL SECTRN MOV B,H MOV C,L CALL SETSEC RET ; ; WRITE ; DWRT: MVI C,1 ;FOR CPM/2 DEBLOCKING BIOS'S CALL WRITE ORA A ;TEST FLAGS ON WRITE JNZ WERROR ;NZ=BAD DIRECTORY WRITE JMP MORE ; ; Exit Program ; EXIT: LDA NOBOOT ;SEE IF BOOT IS NEEDED ORA A JNZ EXIT1 ;FLAG IS SET IF ALREADY ALPHABETIZED JMP 0000H ;A REWRITTEN DIRECTORY NEEDS A WARM BOOT ; EXIT1: LHLD STACK ;GET ADDRESS OF ORIGINAL CP/M STACK SPHL ;RESET STACK ADDRESS RET ; INDEX: DAD H DAD H DAD H DAD H DAD H XCHG LHLD BUF ;GET ADDRESS OF BUF XCHG DAD D RET ; ; GOOD READ OR WRITE ; MORE: LHLD ADDR ;BUMP DMA ADRS FOR NEXT PASS LXI D,80H DAD D SHLD ADDR LHLD DIRCNT ;COUNTDOWN ENTRIES DCX H SHLD DIRCNT MOV A,H ;TEST FOR ZERO LEFT ORA L JNZ DIRLOP ;LOOP TILL ZERO ; ; ; DIRECTORY I/O DONE, RESET DMA ADDRESS ; LXI B,80H CALL SETDMA RET ; ; MOVE UTILITY SUBROUTINE ; MOVE: MOV A,M STAX D INX H INX D DCR B JNZ MOVE RET ; ; PACK DIRECTORY ; PACK: LXI H,0 ;I = 0 ; PACK1: SHLD I CALL INDEX ;HL = BUF + 16 * I LXI D,9 DAD D ;HL = HL + 9 MOV A,M ;JUMP IF FILETYPE NOT 'X$$' SUI '0' ; WHERE 0.LE.X.LE.9 JC PACK2 CPI 10 JNC PACK2 STA J INX H MOV A,M CPI '$' JNZ PACK2 INX H MOV A,M CPI '$' JNZ PACK2 INX H ;SET EXTENT NUMBER TO X LDA J MOV M,A DCX H ;SET FILETYPE TO '$$$' MVI M,'$' DCX H MVI M,'$' DCX H MVI M,'$' ; PACK2: LHLD I ;I = I + 1 INX H XCHG LHLD DRM INX H XCHG PUSH H CALL SUBDE POP H ;LOOP UNTIL I > DRM JC PACK1 RET ; ; READ AND WRITE DIRECTORY ROUTINES ; RDDIR: CALL EPRINT DB ' --> Reading, ',0 XRA A STA NOBOOT ;ZERO THE FLAG JMP DODIR ;ZERO THE WRITE FLAG FOR NOW ; ; COME HERE IF WE GET A READ ERROR ; RERROR: CALL EPRINT ;PRINT: DB ' READ ERROR - No Change Made',0 JMP EXIT ; ; DIVIDE HL BY 2 ; ROTRHL: ORA A ;CLEAR CARRY MOV A,H RAR MOV H,A MOV A,L RAR MOV L,A RET ; ; SETUP FOR SELECTING DRIVE AND LOADING DISK PARM BLOCK ; SETUP: LXI D,FCB CALL Z3LOG ;LOG INTO DISK SPECIFIED BY USER MVI C,GETDSK ;OTHERWISE GET CURRENT DEFAULT DRIVE CALL BDOS ;SO QUERY 'BDOS' FOR DRIVE MOV C,A ;PREP FOR OBTAINING DPB CALL EPRINT DB CR,LF,' Disk ',0 MOV A,C ;GET DISK NUMBER ADI 'A' ;CONVERT TO ASCII CALL COUT CALL SELDSK ; ; GET CP/M 2.2 DPB DATA ; MOV E,M INX H MOV D,M INX H XCHG SHLD SECTBL XCHG LXI D,8 ;OFFSET TO DPB WITHIN HEADER DAD D ;RETURNED BY SELDSK IN CPM2 MOV A,M ;GET ADRS OF DPB INX H MOV H,M MOV L,A LXI D,DPB ;POINT TO DEST: OUR DPB MVI B,DPBLEN CALL MOVE RET ; ; SORT THE DIRECTORY ; SORT: CALL EPRINT DB 'Sorting (',0 LDA REVERSE ;INDICATE ASC OR DSC ORA A ;0=ASC JZ SORTASC CALL EPRINT DB 'Descending',0 JMP SORTDO SORTASC: CALL EPRINT DB 'Ascending',0 ; ; SHELL-METZNER SORT ; SORTDO: CALL EPRINT DB ' Order), ',0 LHLD I SHLD SNUMRECW LHLD BUF SHLD SSTADR PUSH H ; AND SAVE IT LXI H,32 SHLD SRECLEN PUSH H ; AND SAVE IT ; ; NOW DIVIDE # OF FIELDS BY 2 ; DIVIDE: LHLD SNUMRECW ;GET VALUE CALL ROTRHL SHLD SNUMRECW ;SAVE RESULT MOV A,L ;IF SNUMRECW<>0 ORA H ; THEN JNZ NOTDONE ; NOT DONE ; ; ALL FIELDS SORTED ; POP B ;CLEAN UP STACK POP D RET ; NOTDONE: XCHG LHLD I MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A SHLD SRECLEN LXI H,1 SHLD SSORTV1 SHLD SSTADR DCR L POP B PUSH B NDONE1: DAD D DCX B MOV A,B ORA C JNZ NDONE1 SHLD SSORTV2 XCHG POP B POP H PUSH H PUSH B NDONE2: SHLD SSORTV4 SHLD SSORTV3 XCHG DAD D XCHG COMPARE: POP B PUSH B COMPAR1: LDAX D ANI 7FH PUSH B MOV C,A MOV A,M ANI 7FH MOV B,A MOV A,C SUB B POP B JNZ NOTEQU INX H INX D DCX B MOV A,B ORA C JNZ COMPAR1 JMP NOSWITCH ; ; THE CONDITION AT NOTEQU: HAS TO ; BE CHANGED FOR DESCENDING SORT -- IF REVERSE=0, JNC TO NOSWITCH, ELSE ; JC TO NOSWITCH ; NOTEQU: PUSH PSW ;SAVE CONDITION LDAX D ;GET (DE) CPI 0E5H ;IF ERASED, SELECT ASCENDING JZ ASCENDING MOV A,M ;GET (HL) CPI 0E5H ;IF ERASED, SELECT ASCENDING JZ ASCENDING LDA REVERSE ;DESCENDING SORT? ORA A ;0=NO JZ ASCENDING POP PSW ;GET CONDITION FOR DESCENDING SORT JC NOSWITCH JMP SWITCH ASCENDING: POP PSW ;GET CONDITION FOR ASCENDING SORT JNC NOSWITCH SWITCH: PUSH B MOV B,M LDAX D MOV M,A MOV A,B STAX D INX H INX D POP B DCX B MOV A,B ORA C JNZ SWITCH LHLD SNUMRECW MOV A,H CMA MOV D,A MOV A,L CMA MOV E,A LHLD SSORTV1 DAD D JNC NOSWITCH INX H SHLD SSORTV1 LHLD SSORTV3 XCHG LHLD SSORTV2 MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A SHLD SSORTV3 JMP COMPARE ; NOSWITCH: LHLD SSTADR INX H SHLD SSTADR SHLD SSORTV1 XCHG LHLD SRECLEN MOV A,L SUB E MOV A,H SBB D JC DIVIDE LHLD SSORTV4 POP D PUSH D DAD D XCHG LHLD SSORTV2 XCHG JMP NDONE2 ; ; UTILITY SUBTRACTION SUBROUTINE... ; HL=HL-DE ; SUBDE: MOV A,L SUB E MOV L,A MOV A,H SBB D MOV H,A RET ;..... ; ; WRDIR: CALL EPRINT DB 'Writing, ',0 MVI A,1 JMP DODIR ; ; COME HERE IF WE GET A WRITE ERROR ; WERROR: CALL EPRINT ;PRINT: DB ' WRITE ERROR - Directory Left in UNKNOWN Condition',0 JMP EXIT ; ; DATA AREA ; ADDR: DS 2 BUF: DS 2 DIRCNT: DS 2 I: DS 2 J: DS 2 MAPPTR: DS 2 maxdir: ds 2 ;841201 NOBOOT: DS 1 NOSWAP: DS 1 REVERSE: DS 1 SECTBL: DS 2 SECTOR: DS 2 TRACK: DS 2 WRFLAG: DS 1 SRECLEN: DS 2 SSTADR: DS 2 SSORTV1: DS 2 SSORTV2: DS 2 SSORTV3: DS 2 SSORTV4: DS 2 SNUMRECW: DS 2 ; ; DISK PARAMETER BLOCK: ; DPB: SPT: DS 2 BSH: DS 1 BLM: DS 1 EXM: DS 1 DSM: DS 2 DRM: DS 2 AL0: DS 1 AL1: DS 1 CKS: DS 2 SYSTRK: DS 2 ; STACK: DS 2 ;SPACE FOR OLD STACK ADDRESS ; END ;