; MDIR.ASM ; revised 8/17/80 ; ; CP/M-2 MASTER DISK DIRECTORY PROGRAM ; by Jeff Hammersley, MD. ; ; PRINTS A COMPLETE DISK DIRECTORY INCLUDING ALL USERS, ; SORTED ALPHABETICALLY AND PRINTED 4 WIDE. ; ; Based on 'FMAP' as originally written by Ward Christensen ; and its subsequent evolution to 'SDIR' by Keith Petersen. ; ;---------------------------------------------------------------; ; ; ; Commands: ; ; ; ; MDIR returns all files on the default disk under any user. ; ; ; ; Note: optional drive name may be specified. ; ; ; ; ; ; MDIR FILENAME.FILETYPE searches for all files that match ; ; in all user areas. ; ; ; ; MDIR S???.* returns all 4 character files with any extention ; ; in any user areas. ; ; ; ;_______________________________________________________________; ; ;07/02/80 FIXED TO ALLOW MORE THAN 256 NAMES IN DIRECTORY, ; PRINT DRIVE NAME, AND ALLOW SPECIFYING DRIVE. ; BY KEITH PETERSEN, W8SDZ. ; ;07/30/80 FIXED TO ELIMINATE CRASH WHEN NO NAMES ARE IN ; DIRECTORY. REPLACED DECIMAL OUTPUT ROUTINE WITH ; SIMPLER ONE WHICH IS SMALLER AND ALLOWS USE OF ; ONE LESS LEADING SPACE SO DISPLAY CAN BE PRINTED ; ON A 72-CHARACTER PRINTER. (KBP) ; ;08/17/80 CORRECTED MISSING INR A IN SEARCH FIRST ROUTINE, ; WHICH CAUSED DUPLICATE LISTING OF THIRD DIRECTORY ; ENTRY. (KBP) ; BASE SET 0 ; ALTCPM EQU 0 ;PUT 1 HERE FOR H8 OR TRS-80 CP/M ; IF ALTCPM BASE SET 4200H ENDIF ; NAMES EQU 256 ;MAX NUMBER OF NAMES IN DIRECTORY ; FCB EQU BASE+5CH ;SYSTEM FCB NPL EQU 4 ;NUMBER OF NAMES PER LINE CR EQU 0DH ;CARRIAGE RETURN LF EQU 0AH ;LINE FEED DELIM EQU ':' ;FENCE (DELIMITER) CHARACTER ; ORG BASE+100H ; JMP START ;JUMP AROUND I.D. DB 'MDIR.COM 8/17/80 ' ; ;SAVE THE STACK START LXI H,0 DAD SP ;H=STACK SHLD STACK ;SAVE IT LXI SP,STACK ;GET NEW STACK LDA FCB ORA A ;ANY DRIVE SPECIFIED? JZ FSPEC2 DCR A ;CORRECT DISK NUMBER FOR CP/M PUSH PSW ;SAVE REQUESTED DISK NUMBER MVI C,CURDSK ;FIND OUT WHERE WE'RE LOGGED CALL BDOS STA CDSK ;SAVE IT FOR LATER POP PSW ;GET REQUESTED DISK NR. MOV E,A ;TO E FOR CP/M MVI C,SELDSK ;SELECT DISK REQUESTED CALL BDOS ; FSPEC2 MVI C,CURDSK ;FIND OUT WHERE WE'RE LOGGED CALL BDOS ADI 'A' ;MAKE PRINTABLE STA DRNAME ;PRINT HEADER CALL FSPEC3 DB CR,LF DB '.. MASTER DIRECTORY - DRIVE ' DRNAME DB 'X:' DB CR,LF,CR,LF,'$' ; FSPEC3 POP D MVI C,PRINT CALL BDOS LXI H,FCB+1 MOV A,M ;GET 1ST CHAR. OF NAME REQUEST STA SAVFCB ;SAVE FOR LATER ; ;MAKE DR FIELD OF FCB '?' TO FORCE RETURN OF ALL USER ENTRIES DCX H ;POINT TO DR FIELD MVI M,'?' ;STORE '?' IN FCB ; ;RETURN ALL DIRECTORY ENTRIES MVI C,FSRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;COMPENSATE FOR LATER DCR JMP SOME ;GOT SOME (BECAUSE OF ? IN DR FIELD) ; ;READ MORE DIRECTORY ENTRIES MOREDIR MVI C,FSRCHN ;SEARCH NEXT LXI D,FCB CALL BDOS ;READ DIR ENTRY INR A ;CHECK FOR END (0FFH) JZ SPRINT ;NO MORE - SORT & PRINT ;POINT TO DIRECTORY ENTRY SOME DCR A ;UNDO PREV 'INR A' ANI 3 ;MAKE MODULUS 4 ADD A ;MULTIPLY... ADD A ;..BY 32 BECAUSE ADD A ;..EACH DIRECTORY ADD A ;..ENTRY IS 32 ADD A ;..BYTES LONG LXI H,BASE+80H ;POINT TO BUFFER ADD L ;POINT TO ENTRY MOV L,A ;SAVE (CAN'T CARRY TO H) ;MOVE ENTRY TO TABLE MOV A,M ;GET DR FIELD CPI 0E5H ;IS IT AN ERASED FILE ? JZ MOREDIR ;YES, IGNORE AND GET ANOTHER MOV D,H ;ENTRY TO DE MOV E,L MVI A,12 ;GET OFFSET TO EXTENT BYTE ADD L ;ADD TO GET CORRECT POINTER MOV L,A MOV A,M ;GET EXTENT BYTE ORA A ;IS EXTENT OTHER THAN ZERO ? JNZ MOREDIR ;IGNORE ALL EXTENTS BEYOND THE FIRST LHLD NEXTT ;NEXT TABLE ENTRY TO HL MVI B,12 ;ENTRY LENGTH ; TMOVE LDAX D ;GET ENTRY CHAR ANI 7FH ;REMOVE ATTRIBUTES MOV M,A ;STORE IN TABLE INX D INX H DCR B ;MORE? JNZ TMOVE SHLD NEXTT ;SAVE UPDATED TABLE ADDR LHLD COUNT ;GET PREV COUNT INX H ;ADD ONE SHLD COUNT ;RESAVE COUNT JMP MOREDIR ; ;SORT AND PRINT SPRINT LHLD COUNT ;GET COUNT MOV A,H ORA L ;CHECK FOR ZERO COUNT JZ NFEXIT ;NOTHING IN DIRECTORY, EXIT SHLD OCOUNT ;SAVE FOR ORDER TABLE COUNT SHLD SCOUNT ;SAVE FOR SORT COUNT LXI H,ORDER LXI D,TABLE LXI B,12 ;ENTRY LENGTH ; BLDORD MOV M,E ;SAVE LO ORD ADDR INX H MOV M,D ;SAVE HI ORD ADDR INX H XCHG ;TABLE ADDR TO HL DAD B ;POINT TO NEXT ENTRY XCHG ;NEXT ENTRY TO DE PUSH H LHLD OCOUNT ;GET COUNT DCX H ;ONE LESS SHLD OCOUNT ;SAVE NEW COUNT MOV A,L ORA H ;MORE? POP H JNZ BLDORD ;..YES LHLD COUNT ;GET COUNT DCX H MOV A,L ORA H ;ONLY 1 ENTRY? JZ DONE ;..YES, SO SKIP SORT ; SORT XRA A ;GET A ZERO STA SWITCH ;SHOW NONE SWITCHED LHLD SCOUNT ;GET COUNT DCX H ;USE 1 LESS SHLD TEMP ;SAVE # TO COMPARE SHLD SCOUNT ;SAVE HIGHEST ENTRY MOV A,L ORA H JZ DONE ;EXIT IF NO MORE LXI H,ORDER ;POINT TO ORDER TABLE ; SORTLP CALL COMPR ;COMPARE 2 ENTRIES CM SWAP ;SWAP IF NOT IN ORDER INX H ;BUMP ORDER INX H ;..TABLE POINTER PUSH H LHLD TEMP ;GET COUNT DCX H ;ONE LESS SHLD TEMP ;SAVE COUNT MOV A,L ORA H ;DONE? POP H JNZ SORTLP ;CONTINUE ;ONE PASS OF SORT DONE LDA SWITCH ;ANY SWAPS DONE? ORA A JNZ SORT ; ;SORT IS ALL DONE - PRINT ENTRIES DONE LXI H,ORDER SHLD NEXTT ; ;PRINT AN ENTRY MVI C,NPL ;NR. OF NAMES PER LINE ; ENTRY: PUSH B MVI C,CONST ;CK STATUS OF KBD CALL BDOS ;ANY KEY PRESSED? POP B ORA A JNZ ABORT ;YES, ABORT LHLD NEXTT ;GET ORDER TABLE POINTER MOV E,M ;GET LO ADDR INX H MOV D,M ;GET HI ADDR INX H SHLD NEXTT ;SAVE UPDATED TABLE POINTER XCHG ;TABLE ENTRY TO HL LDA SAVFCB ;GET SAVED 1ST CHAR. OF FCB CPI ' ' ;WAS NAME SPECIFIED? JNZ MATCH ;YES, GO SEE IF PRESENT ;PRINT USER # PTONE MOV A,M ;GET USER NUMBER CPI 32 ;IS IT VALID ? (IE.< 32) JNC NULL ; NO, IGNORE IT ORA A ;IS IT USER 0 ? JNZ PTONE2 ;NO, SKIP NEXT ROUTINE CALL SPACE2 ;USER 0, FILL WITH SPACES JMP PTONE3 ;SKIP DECOUT PRINT ; PTONE2 PUSH H MVI H,0 MOV L,A ;NUMBER TO L FOR DECOUT CPI 10 ;LESS THAN 10? CC SPACE ;YES, ADD ONE SPACE CALL DECOUT ;PRINT USER NUMBER POP H ; PTONE3 CALL SPACE ;MAKE IT LOOK NICE INX H ;POINT TO NAME MVI B,8 ;FILE NAME LENGTH CALL TYPEIT ;TYPE FILENAME CALL PERIOD ;PERIOD AFTER FN MVI B,3 ;GET THE FILETYPE CALL TYPEIT DCR C ;ONE LESS ON THIS LINE PUSH PSW CNZ FENCE ;NO CR-LF NEEDED, DO FENCE POP PSW CZ CRLF ;CR-LF NEEDED ;SEE IF MORE ENTRIES NULL PUSH H LHLD COUNT DCX H SHLD COUNT MOV A,L ORA H POP H JNZ ENTRY ;YES, MORE JMP EXIT ; MATCH PUSH D ;SAVE DE PUSH H ;SAVE HL LXI D,FCB ;GET FCB REQUEST INX H ;MOVE TO FN.FT INX D ; MVI B,11 ;GET NUMBER OF CHARACTERS TO COMPARE ; MAT1 LDAX D ;GET CHARACTER CPI '*' ;IS FILENAME OR FILETYPE AMBIGUOUS ? JZ WHCH ; YES, DETERMINE WHICH ONE CPI '?' ;IS IT A AMBIGUOUS CHARACTER ? JZ AMBC ; YES CMP M ;COMPARE TO MEMORY JNZ NOMATCH ;MATCH FAILURE ; AMBC INX D INX H ;GET NEW CHARACTERS DCR B ;ARE WE DONE ? JNZ MAT1 ;NO, COMPARE NEXT ; FTYP POP H POP D ;RESTORE REGISTERS JMP PTONE ;GO PRINT ONE ; WHCH MOV A,B ;GET B CPI 3 ;IS IT STILL THE FILENAME ? JC FTYP ; NO, IT IS ANY TYPE SO WE ARE DONE. MVI B,3 ;YES, LOAD UP TO FILETYPE JMP MAT1 ;RETURN FOR MORE ; NOMATCH POP H POP D ;RESTORE REGISTERS JMP NULL ;GET NEW FILENAME TO TRY ; PERIOD MVI A,'.' JMP TYPE ; FENCE CALL SPACE2 MVI A,DELIM ;FENCE CHARACTER JMP TYPE ; SPACE3 CALL SPACE ; SPACE2 CALL SPACE ; SPACE MVI A,' ' ; ;TYPE CHAR IN A TYPE PUSH B PUSH D PUSH H MOV E,A MVI C,WRCHR CALL BDOS POP H POP D POP B RET ; TYPEIT MOV A,M CALL TYPE INX H DCR B JNZ TYPEIT RET ; CRLF MVI A,CR ;CARRIAGE RETURN CALL TYPE MVI A,LF ;LINE FEED CALL TYPE MVI C,NPL ;NUMBER OF NAMES PER LINE RET ; ;DECIMAL OUTPUT ROUTINE ; DECOUT: PUSH B PUSH D PUSH H LXI B,-10 LXI D,-1 ; DECOU2: DAD B INX D JC DECOU2 LXI B,10 DAD B XCHG MOV A,H ORA L CNZ DECOUT MOV A,E ADI '0' CALL TYPE POP H POP D POP B RET ; ;COMPARE ROUTINE FOR SORT COMPR PUSH H ;SAVE TABLE ADDR MOV E,M ;LOAD LO INX H MOV D,M ;LOAD HI INX H MOV C,M INX H MOV B,M ;BC, DE NOW POINT TO ENTRIES TO BE COMPARED XCHG CMPLP LDAX B CMP M INX H INX B JZ CMPLP POP H RET ;COND CODE TELLS ALL ; ;SWAP ENTRIES IN THE ORDER TABLE SWAP MVI A,1 STA SWITCH ;SHOW A SWAP WAS MADE MOV C,M INX H PUSH H ;SAVE TABLE ADDR+1 MOV B,M INX H MOV E,M MOV M,C INX H MOV D,M MOV M,B POP H MOV M,D DCX H ;BACK POINTER TO CORRECT LOC'N MOV M,E RET ; NFEXIT CALL ERXIT DB '++NO FILES ON THIS DISK',CR,LF,'$' ; ;ERROR EXIT ERXIT POP D ;GET MSG MVI C,PRINT JMP CALLB ;PRINT MSG, EXIT ; ;ABORT - READ CHAR ENTERED ABORT MVI C,RDCHR ;DELETE THE CHAR CALLB CALL BDOS ; ;FALL INTO EXIT ;EXIT - ALL DONE, RESTORE DISK LOG IN AND STACK EXIT LDA CDSK ;GET ORIGINAL DISK NR. MOV E,A ;TO E FOR CP/M MVI C,SELDSK ;RESTORE LOG-IN TO IT CALL BDOS LHLD STACK ;GET OLD STACK SPHL ;MOVE TO STACK RET ;..AND RETURN ; NEXTT DW TABLE ;NEXT TABLE ENTRY COUNT DW 0 ;ENTRY COUNT SWITCH DB 0 ;SWAP SWITCH FOR SORT SAVFCB DS 1 ;SAVED 1ST CHAR. OF FCB CDSK DS 1 ;CURRENTLY LOGGED DISK NUMBER OCOUNT DS 2 ;# NAMES TO PUT IN ORDER TABLE SCOUNT DS 2 ;# TO SORT TEMP DS 2 ;SAVE DIR ENTRY ORDER DS NAMES*2 ;ORDER TABLE (TWO BYTES PER NAME) DS 60 ;STACK AREA STACK DS 2 ;SAVE OLD STACK HERE TABLE EQU $ ;READ ENTRIES IN HERE ; ; BDOS EQUATES ; RDCHR EQU 1 ;READ CHAR FROM CONSOLE WRCHR EQU 2 ;WRITE CHR TO CONSOLE PRINT EQU 9 ;PRINT CONSOLE BUFF CONST EQU 11 ;CHECK CONS STAT SELDSK EQU 14 ;SELECT DISK DRIVE FSRCHF EQU 17 ; " " FSRCHN EQU 18 ; " " CURDSK EQU 25 ;CHECK CURRENT DISK 0=A: 1=B:, ETC. BDOS EQU BASE+5 ; END