; 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 GETDSK: EQU 25 ;BDOS "GET DISK #" FUNCTION LF: EQU 0AH SELDRV: EQU 14 ;SELECT DRIVE VERNO: EQU 12 ;PROVIDES CP/M VERSION NUMBER ;..... ; ; ORG 100H ; JMP VECTRS ;JMP AROUND IDENTIFICATION MSG ; ; ; 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 ;..... ; ; GETVEC: LXI D,WBOOT LHLD 1 MVI B,53 CALL MOVE ; ;======================================================================= ; ; PROGRAM STARTS HERE ; ;======================================================================= ; ; START: LXI H,0 DAD SP ;GET ADDRESS OF CP/M STACK SHLD STACK ;STORE IT SO WE CAN GO BACK TO IT LXI SP,STACK ;NOW USE OUR OWN STACK CALL ILPRT ;PRINT MSG: DB CR,LF,'SORT AND PACK DIRECTORY v3.8 10/16/83',CR,LF,0 MVI C,VERNO ;CHECK FOR CP/M VER 2.2 CALL BDOS MOV A,H ;H=1 FOR MPM ORA A JNZ MPMYES ;EXIT IF MPM, WE CAN'T USE IT MOV A,L ;HL = 0022H IF CP/M VER 2.2 CPI 22H+1 ;CHECK FOR MPM OR CP/M+ JNC MPMYES ;EXIT IF CP/M+, WE CAN'T USE IT STA VERFLG ;STORE THE VERSION ; ; ;======================================================================= ; ; MAIN PROGRAM ROUTINE ; ;======================================================================= ; ; SAP: CALL SETUP CALL RDDIR CALL CLEAN CALL SORT CALL PACK CALL WRDIR CALL ILPRT DB 'DONE',CR,LF,0 JMP EXIT ;..... ; ; ;======================================================================= ; ; 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 FILL$E5 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 ; 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 ;..... ; ; CP/M 1.4 ROUTINE ; CPM14: LHLD BDOS+1 MVI L,0 MVI A,(JMP) STA SECTRN PUSH H LXI D,15 ;SECTRAN OFFSET FROM BDOS IN CPM 1.4 DAD D SHLD SECTRN+1 POP H LXI D,3AH ;OFFSET FROM BDOS TO 1.4 DPB DAD D MVI D,0 MOV E,M INX H XCHG SHLD SPT XCHG MOV E,M INX H XCHG SHLD DRM XCHG MOV A,M INX H STA BSH MOV A,M INX H STA BLM MOV E,M INX H XCHG SHLD DSM XCHG MOV E,M INX H XCHG SHLD AL0 XCHG MOV E,M XCHG SHLD SYSTRK RET ;..... ; ; ; CP/M 2.2 ROUTINE ; CPM22: 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 ;..... ; ; 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 LXI H,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 LDA VERFLG ORA A RZ 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: 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 ;..... ; ; ; PRINT A STRING: ADDRESS IS ON TOP OF STACK ; ILPRT: XTHL ;GET ADR FROM STACK MOV A,M ;GET CHARACTER INX H ;POINT TO NEXT ADR XTHL ;RESTORE TO STACK ORA A ;ARE WE DONE? RZ ;YES, RETURN PAST STRING PUSH H ;IN CASE CBIOS CLUBBERS IT MOV C,A ;CHARACTER TO C FOR CP/M CALL CO ;PRINT CHARACTER POP H JMP ILPRT ;CONTINUE ;..... ; ; INDEX: DAD H DAD H DAD H DAD H DAD H LXI D,BUF 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 ;..... ; ; ; MPM OR CP/M+ NOT ALLOWED WITH THIS PROGRAM ; MPMYES: CALL ILPRT DB CR,LF,'** SAP not useable with MPM or CP/M+ **',0 JMP EXIT ;..... ; ; 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 ILPRT DB CR,LF,'---> 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 ILPRT ;PRINT: DB '++ READ ERROR - Exiting to CP/M - NO CHANGE made' DB CR,LF,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: LDA FCB DCR A JP SETUP1 ;EXIT IF DISK DRIVE MENTIONED MVI C,GETDSK ;OTHERWISE GET CURRENT DEFAULT DRIVE CALL BDOS ;SO QUERY 'BDOS' FOR DRIVE ; SETUP1: MOV C,A CALL SELDSK LDA VERFLG ;IF CPM 1.4 ORA A JZ CPM14 ;IF 1.4, THEN DO IT THE 1.4 WAY JMP CPM22 ;MUST BE 2.2 THEN SINCE NOT MPM ;..... ; ; ; SORT THE DIRECTORY ; SORT: CALL ILPRT DB 'Sorting, ',0 ; ; SHELL-METZNER SORT ; LHLD I SHLD SNUMRECW LXI H,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 PUSH PSW MOV A,M ANI 7FH MOV B,A POP PSW 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. ; NOTEQU: 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 ILPRT DB 'Writing, ',0 MVI A,1 JMP DODIR ;..... ; ; ; COME HERE IF WE GET A WRITE ERROR ; WERROR: CALL ILPRT ;PRINT: DB '++ WRITE ERROR - Exiting to CP/M - directory left ' DB 'in UNKNOWN condition ++',CR,LF,0 JMP EXIT ;..... ; ; ; DATA AREA ; ADDR: DS 2 DIRCNT: DS 2 I: DS 2 J: DS 2 MAPPTR: DS 2 NOBOOT: DS 1 NOSWAP: DS 1 SECTBL: DS 2 SECTOR: DS 2 TRACK: DS 2 VERFLG: DS 1 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 ;..... ; ; DS 26 ;STACK NEVER GETS THIS DEEP STACK: DS 2 ;SPACE FOR OLD STACK ADDRESS ; ; EVEN: EQU ($+255)/256*256 ;START BUFFER ON EVEN PAGE ; ORG EVEN ; BUF: DS 0 ;..... ; ; END ; TRACTION SUBROUTINE... ; HL=