; - XDIR - ; BY S J SINGER ; ; XDIR IS A CPM UTILITY THAT DISPLAYS A DISK DIRECTORY IN A MORE ;READABLE FORM. THE DIRECTORY IS READ FROM THE SPECIFIED DISK, SORTED ;THEN DISPLAYED IN A 3 COLUMN FORMAT. BOTH THE FILE NAMES AND FILE SIZES ;IN 1 K GROUPS ARE DISPLAYED. ; THE PRESENT VERSION OF XDIR HAS CERTAIN MINOR LIMITATIONS WHICH ;MAY BE EASILY REMOVED IF THEY CAUSE PROBLEMS. ; ; 1. ONLY 48 FILES ARE DISPLAYED. THIS LIMIT IS SUFFICIENT FOR ; ALMOST ALL DISKS AND LEAVES ROOM ON THE SCREEN FOR EDITING. ; TO CHANGE THE NO OF LINES DISPLAYED, CHANGE THE LINES VARIABLE ; IN THE DATA ALLOCATION SECTION OF THE PROGRAM. FOR EXAMPLE ; TO DISPLAY A MAXIMUM OF 54 FILES CHANGE LINES TO 18. ; 2. THE PRESENT VERSION READS GROUPS 0 AND 1 DIRECTLY FOR SPEED. ; IF A DISK IS SET UP FOR MORE THAN 64 FILES OR THE BLOCK FORMAT ; IS CHANGED THE READ ROUTINE WILL HAVE TO BE MODIFIED. ; ; OCCASIONALLY THE FILE NAMES WILL BE DISPLAYED WITH THE FORMAT ;SCRAMBLED OR THE SPACE REMAINING ON THE DISK WILL NOT AGREE WITH THAT REPORTED ;BY THE STAT UTILITY. THIS ALMOST ALWAYS MEANS THE DISK DIRECTORY HAS BEEN ;MESSED UP SOMEHOW. USUALLY THE PROBLEM CAN BE CORRECTED BY COPYING ALL THE ;FILES TO ANOTHER DISK USING PIP. ; XDIR WAS ASSEMBLED USING THE NEW CP/M MACRO ASSEMBLER AND USES A LARGE ;NUMBER OF MACROS. THESE ARE CONTAINED IN A LIBRARY CALLED MACRO.LIB WHICH ;IS REQUIRED IF THE PROGRAM IS TO BE REASSEMBLED. ; ; ; COMMAND FORMAT ; ; XDIR DISPLAY DIRECTORY OF LOGGED DISK ; XDIR A: DISPLAY DIRECTORY OF DISK A ; XDIR B: DISPLAY DIRECTORY OF DISK B ; ; MACLIB MACRO ;INCLUDE MACRO LIBRARY ORG 100H ;SET PROG START LXI H,0 DAD SP ;GET OLD STACK POINTER SHLD OLDSTK ;SAVE IT LXI SP,NEWSTK ;LOAD NEW STACK POINTER JMP DIR ; ; GRPTS CONVERT CPM GROUP AND SECTOR NUMBER TO TRK AND SEC ; GRPTS: MVI H,0 ;ZERO H LDA G ;GROUP NO MOV L,A ;TO L MOV D,H ;ZERO D DAD H DAD H DAD H ;SHIFT LEFT 3 LDA S ;GET SECTOR NO MOV E,A ;TO DE DAD D ;HL HAS G*8+S LXI D,-26 ;DIVISOR MVI A,1 ;CONTAINS DIVIDEND DIV: DAD D ;SUB 26 INR A JC DIV ;LOOP TILL MINUS LXI D,TABLE+26 ;INDEX INTO TABLE DAD D STA TRACK ;STORE TRACK NO MOV A,M ;GET SECTOR NO STA BSEC ;SAVE IN BEGINNING SECTOR STA ESEC ;SAVE IN END SECTOR TOO RET ; ; START OF DIRECTORY ROUTINE READ IN GROUPS 0 AND 1 AND STORE ; DIRECTORY FILE NAMES NOT FLAGGED E5. IF EXTENT NOT ZERO STORE ; OVER PREVIOUS FILE NAME. TABLE OF POINTERS WILL BE BUILT IN PDIR ; DIR: DISKIO ?DRIVE STA NEWDRV LDA 81H ORA A ;CHECK IF INPUT BUFFER EMPTY JZ DDD LDA 82H ;CHECK NEW DRIVE CPI 'A' JNZ DX1 XRA A STA NEWDRV ;SELECT DRIVE A JMP DDD DX1: CPI 'B' JNZ DSKERR MVI A,1 STA NEWDRV DDD: PRINT LDA NEWDRV ;LOGGED DISK ORA A JNZ BDIR PRINT <'A',CR,LF,LF> JMP DIR2 BDIR: PRINT <'B',CR,LF,LF> CALL FIXB ;RESTORE DRIVE B DIR2: XRA A STA S ;SECTOR COUNT STA G ;GROUP 0 = DIRECTORY STA COUNT ;COUNT OF DIRECTORY ENTRIES FILL PDIR,PDIR+130 ;ZERO DIRECTORY POINTER TABLE LXI H,DIRBUF ;POINTS TO DIRECTORY BUFFER SHLD OUTB LXI H,PDIR ;POINTER TABLE SHLD IPOINT LDA NEWDRV MOV E,A DISKIO LOGIN ;LOG IN NEW DRIVE NO DIR4: LXI H,80H ;POINTS TO INPUT BUFFER SHLD INB CALL GRPTS ;COMPUTE TRACK AND SECTOR NO FROM G AND S SETSEC BSEC ;SET SECTOR SETTRK TRACK ;SET TRACK CALLBIOS DREAD ;READ DIRECT DIR6: LHLD OUTB ;LOAD DESTINATION POINTER XCHG ;PUT IT IN DE LHLD INB ;LOAD SOURCE POINTER MVI A,0E5H ;FLAG BYTE CMP M ;TEST FIRST BYTE JNZ DIR8 INX H CMP M ;TEST SECOND BYTE JZ SORT ;SORT DIRECTORY JMP DIR12 DIR8: INX H SAVE H,D LXI D,11 ;EXTENSION OFFSET DAD D MOV A,M ORA A JZ DIR10 ;IF EXTENT ZERO CONTINUE LXI H,0 ;ELSE, SEARCH FOR SAME NAME AND SWITCH SHLD J ;INITIALIZE INDEX DIR9: DLOAD PDIR,J MOV A,H ORA L JZ DIR10 ;ERROR TABLE EMPTY XCHG LHLD INB ;POINTER TO NEW DIR ENTRY SAVE D,H INX H MATCH ,,11 ;COMPARE 11 CHARAACTERS RESTORE H,D JZ SWITCH ;STORE NEW ENTRY OVER OLD INDEX J,2 ;INCR INDEX BY 2 JMP DIR9 SWITCH: INX H MOVE ,,15 ;OVERWRITE OLD ENTRY RESTORE H JMP DIR12 DIR10: RESTORE D,H MOVE ,,15 ;MOVE THE DIRECTORY ENTRY LDA COUNT INR A STA COUNT ;INCR COUNT OF DIRECTORY ENTRIES LHLD OUTB DSTORE 0,IPOINT ;INDEXED STORE HL INDEX OUTB,16 INDEX IPOINT,2 DIR12: INDEX INB,32 ;INCR POINTERS LXI D,100H CPHL ;LIMIT OF 4 ENTRIES JNZ DIR6 LDA S INR A STA S ;INCR DIRECTORY SECTOR COUNT JMP DIR4 ;READ ANOTHER BLOCK FROM DIRECTORY ; ; THIS ROUTINE PRINTS THE DIRECTORY IN 3 COLUMNS. NO OF LINES ; PRINTED IS CONTROLED BY VARIABLE LINES. ALL DIRECTORY NAMES ; ARE PRESENT IN TABLE BUT ONLY A MAXIMUM OF 3*LINES WILL BE ; PRINTED. ; DIR14: LXI H,0 SHLD W ;INITIALIZE ALLOCATION SHLD I ;INITIALIZE INDEX DIR16: DLOAD PDIR,I ;INDEX LOAD POINTER DJZ ENDFIL ;EXIT IF POINTER ZERO CALL DIR20 ;CALL PRINT ROUTINE PRINT ' ' DLOAD PDIR+LINES*2,I ;POINTER COL 2 DJZ DIR18 ;NO PRINT IF ZERO CALL DIR20 ;PRINT IT PRINT ' ' DLOAD PDIR+LINES*4,I ;POINTER COL 3 DJZ DIR18 CALL DIR20 ;CALL PRINT ROUTINE DIR18: PRINT CRLF,$ INDEX I,2 ;INCR INDEX BY 2 LXI D,LINES*2 ;CHECK INDEX LIMIT CPHL JZ ENDFIL ;EXIT WHEN INDEX 32 JMP DIR16 ;PRINT SOME MORE ; ; SUBROUTINE TO PRINT A SINGLE DIRECTORY ENTRY ; DIR20: MVI C,11 ;NAME LENGTH DIR22: SAVE B,H ;SAVE REGISTERS MVI C,2 MOV E,M ;CHAR TO BE PRINTER CALL 5 ;CALL BDOS RESTORE H,B ;RESTORE THE REGISTERS INX H ;INCR NAME POINTER DCR C ;DECR CHAR COUNT JZ DIR24 ;PRINT SIZE JMP DIR22 ;LOOP TILL COUNT 0 DIR24: MOV A,M ;EXTENSION TO A ADD A ADD A ADD A ADD A ;MULTIPLY BY 16 MOV B,A ;SAVE IN B INX H INX H INX H ;ADD 3 MOV A,M ;GET RECORD COUNT RRC RRC RRC ;SHIFT RIGHT 3 PUSH PSW ANI 1FH ;EXTRACT LXI H,0 MOV L,A ;NO TO HL TO PRINT POP PSW ANI 0E0H ;EXTRACT JZ DIR26 INX H DIR26: MOV A,L ADD B MOV L,A SAVE H LXI D,10 CPHL JM DIR28 PRINT ' ' JMP DIR30 DIR28: PRINT ' ' DIR30: POP H PUSH H XCHG LHLD W DAD D SHLD W POP H DECOUT PRINT 'K' RET ; ; ; THIS ROUTINE RESTORES DRIVE B ; FIXB: LDA NEWDRV ;CHECK DRIVE NO ORA A RZ ;RETURN IF DRIVE A LDA NEWDRV ;SELECT DRIVE B MOV E,A DISKIO LOGIN XRA A STA TNUM ;SELECT TRACK ZERO INR A ;SELECT SECTOR 1 STA SNUM SETSEC SNUM SETTRK TNUM CALLBIOS DHOME ;HOME DRIVES CALLBIOS DREAD ;READ TRACK ZERO DIRECT RET ; ; THIS IS THE EXIT POINT FROM THE PROGRAM. PRINT NO OF FILES AND ; SPACE REMAINING, RELOAD OLD STACK POINTER AND RETURN BACK TO CCP. ; ENDFIL: PRINT LXI H,0 LDA COUNT MOV L,A DECOUT PRINT ' FILES ' LHLD W MOV A,L CMA INR A ;NEGATE ADI 240 MOV L,A DECOUT PRINT <'K BYTES REMAINING ON DISK',CR,LF> EF1: LHLD OLDSTK SPHL ;RELOAD OLD STACK POINTER RET ;RETURN TO CCP WITHOUT REBOOT ; DSKERR: PRINT JMP EF1 ;EXIT ; ; THIS SECTION DOES THE ACTUAL SORTING OF THE DIRECTORY. DURING THE ; INPUT OF THE DIRECTORY NAMES, A TABLE OF ADDRESS POINTERS PDIR ; WAS CONSTRUCTED. THE SORT ROUTINE SORTS THE ADDRESS POINTERS ; RATHER THAN THE ACTUAL DIRECTORY. ; THIS IS AN IMPLEMENTATION OF C. A. R. HOARE'S QUICKSORT ALGORITHM. ; THE ALGORITHM IS VERY FAST AND GENERALLY USEFUL, HOWEVER CAUTION ; SHOULD BE USED WITH LARGE FILES. THE ALGORITHM IS RECURSIVE AND ; THE STACK SPACE REQUIRED IS PROPORTIONAL TO THE NO OF ITEMS TO BE ; SORTED. ; SORT: LDA COUNT ;NO OF ENTRIES IN DIR ORA A JZ ENDFIL ;EXIT IF DIRECTORY EMPTY DCR A LXI H,0 ;ZERO HL MOV L,A DAD H SHLD LAST ;END OF ARRAY LXI H,0 SHLD FIRST ;START OF ARRAY LXI H,0FFFFH PUSH H ;FLAG FOR STACK EMPTY LHLD FIRST PUSH H LHLD LAST PUSH H ;STACK CONTAINS FIRST AND LAST INDICES ; ; NOW POP STACK AND KEEP CALLING SPLIT RECURSIVELY TILL STACK EMPTY ; SORT2: POP H MOV A,H CPI 0FFH JZ DIR14 ;GO TO PRINT ROUTINE SHLD J SHLD LAST POP H SHLD I SHLD FIRST CALL SPLIT LHLD I XCHG LHLD FIRST CPHL JZ SORT4 PUSH H ;I ON STACK DCX D DCX D PUSH D ;J ON STACK SORT4: LHLD J XCHG LHLD LAST CPHL JZ SORT8 INX D INX D PUSH D ;NEW I ON STACK PUSH H ;NEW J ON STACK SORT8: JMP SORT2 ; ; SPLIT SUBROUTINE DOES A SINGLE PARTITION ON AN ARRAY OF POINTERS ; SPLIT: HALF I XCHG HALF J DAD D MOV A,L ANI 0FEH MOV L,A SHLD K ;K=I+J/2 DLOAD PDIR,K SHLD W ;W IS POINTER TO PARTITION ELEMENT OF PDIR SPLIT2: DLOAD PDIR,I ;GET ITEM FROM LEFT XCHG LHLD W ;PARTITION ELEMENT MATCH ,,11 ;CONPARE KEYS JP SPLIT4 INDEX I,2 ;INCR I JMP SPLIT2 SPLIT4: DLOAD PDIR,J ;GET ITEM FROM RIGHT XCHG LHLD W ;PARTITION ELEMENT XCHG MATCH ,,11 ;COMPARE KEYS JP SPLIT6 INDEX J,-2 JMP SPLIT4 ;LOOP BACK SPLIT6: LHLD I XCHG LHLD J CPHL ;COMPARE I AND J RZ ;RET IF I = J DLOAD PDIR,I ;SWITCH POINTERS SAVE H DLOAD PDIR,J DSTORE PDIR,I RESTORE H DSTORE PDIR,J JMP SPLIT2 ; ; DATA ALLOCATIONS ; LINES EQU 16 ;LINES PER PAGE ON DISPLAY SPACE: DB ' $' ;ASCII SPACE CRLF: DB 0DH,0AH,24H ;ASCII CR LF I: DW 0 ;PSEUDO INDEX REGISTER J: DW 0 ;PSEUDO INDEX REGISTER K: DW 0 ;PSEUDO INDEX REGISTER FIRST: DW 0 ;START OF ARRAY LAST: DW 0 ;END OF ARRAY W: DW 0 ;STORAGE FOR PARTITION INDEX LINE: DW 0 ;LINE NUMBER FOR LISTING IPOINT: DW 00 ;VARIABLE BUFFER POINTER DRVNO: DB 0 ;STORAGE FOR ORIGINALLY LOGGED DRIVE NEWDRV: DB 0 ;STORAGE FOR NEW DRIVE NO TRACK: DB 0 ;SELECTED TRACK BSEC: DB 0 ;SELECTED BEGINNING SECTOR ESEC: DB 0 ;SELECTED ENDING SECTOR TNUM: DB 0 ;TRACK NUMBER SNUM: DB 0 ;SECTOR NUMBER G: DB 0 ;CPM GROUP NO S: DB 0 ;SECTOR NO WITHIN GROUP G COUNT: DB 0 ;COUNT OF DIRECTORY ENTRIES OLDSTK: DW 0 ;STORAGE FOR OLD STACK POINTER ENDSTK: DS 60 ;STORAGE FOR NEW STACK NEWSTK: DW 0 ;NEW STACK INB: DW 0 ;STORES POINTER TO INPUT BUFFER AREA OUTB: DW 0 ;STORES POINTER TO DIRECTORY BUFFER AREA TABLE: DB 01H ;SECTOR LOOK UP TABLE DB 07H DB 0DH DB 13H DB 19H DB 05H DB 0BH DB 11H DB 17H DB 03H DB 09H DB 0FH DB 15H DB 02H DB 08H DB 0EH DB 14H DB 1AH DB 06H DB 0CH DB 12H DB 18H DB 04H DB 0AH DB 10H DB 16H PDIR DW 0 ;POINTER TABLE TO DIRECTORY (64 ENTRIES MAX) DIRBUF: EQU PDIR+130 ;START OF AREA USED TO STORE AND SORT DIRECTORY END