; ; DIRS.ASM ; revised 10/1/80 ; ; SORTED DIRECTORY PROGRAM ; by Keith Petersen, W8SDZ ; ;DISPLAY FORMAT IS SAME AS CP/M 2.x DIR, EXCEPT IS SORTED ;ALPHABETICALLY. SUGGESTED AS A REPLACEMENT FOR THE "DIR" ;COMMAND IN CP/M-2. PRESENT VERSION ALLOWS MAX. OF 256 NAMES. ; ;PRINTS A 4-WIDE DIRECTORY, SORTED ALPHABETICALLY. ;COMPATIBLE WITH CP/M 1.4 AND 2.x. IGNORES "SYS" FILES. ; ;BASED ON 'FMAP' BY WARD CHRISTENSEN. ; ;DIRS FILENAME.FILETYPE or just DIRS ; ;ALLOWS '*' OR '?' TYPE SPECIFICATIONS ;DRIVE NAME BY ALSO BE SPECIFIED ; ; 09/07/80 - Modified to assemble with RMAC and externalized ; page 0 for use with MP/M. (Must be linked ; with PG0EQU.ASM) ; Also modified to allow (via conditional assembly) ; 'S' option to display system files. ; (by Bruce R. Ratoff) ; 09/08/80 - CHKUSR conditional assembly added to force match of ; current user number, as required in MP/M to ; prevent user 0 files from showing up in all ; areas. Also used in CP/M 2.2 systems containing ; BDOSPAT. (BRR) ; 10/01/80 - Say 'File not found.' instead of 'NO FILE' and ; display user number heading if CHKUSR enabled. ; Take 'NO FILE' path if first search succeeds, ; but nothing qualifies for the sort. ; (BRR) ; ; FALSE EQU 0 ;DEFINE LOGICAL FALSE TRUE EQU NOT FALSE ;DEFINE LOGICAL TRUE ; ALTCPM EQU FALSE ;PUT TRUE HERE FOR H8 OR TRS-80 RMAC EQU FALSE ;PUT TRUE HERE FOR ASSEMBLY BY RMAC SOPT EQU FALSE ;PUT TRUE TO ALLOW 'DIR *.* S' FORM CHKUSR EQU FALSE ;PUT TRUE IF USER # MATCH REQUIRED ; IF ALTCPM BASE EQU 4200H TPA EQU 4300H ENDIF IF RMAC EXTRN BASE,FCB,BDOS ;MAKE BASE EXTERNAL ENDIF IF (NOT ALTCPM) AND (NOT RMAC) BASE EQU $ ;WILL DEFAULT TO 0 (OR 100H WITH MAC +R OPTION) TPA EQU 100H ENDIF ; IF NOT RMAC FCB EQU BASE+5CH BDOS EQU BASE+5 ENDIF ; NPL EQU 4 ;NUMBER OF NAMES PER LINE DELIM EQU ':' ;FENCE (DELIMITER) CHARACTER ; IF NOT RMAC ORG TPA ENDIF ; ;SAVE THE STACK START LXI H,0 DAD SP ;H=STACK SHLD STACK ;SAVE IT LXI SP,STACK ;GET NEW STACK ; IF SOPT LDA FCB+17 ;SAVE S OPTION FLAG STA SOPFLG ;(BLANK OR LETTER S) ENDIF ; IF CHKUSR MVI E,0FFH MVI C,CURUSR ;INTERROGATE USER NUMBER CALL BDOS STA USERNO LXI D,USRMSG ;DISPLAY IT MVI C,PRINT CALL BDOS LDA USERNO CPI 10 JC DUX MVI A,'1' CALL TYPE LDA USERNO SUI 10 DUX ADI '0' CALL TYPE LXI D,USRMS2 MVI C,PRINT CALL BDOS ENDIF ; LXI H,FCB MOV A,M ;GET DRIVE NAME ORA A ;ANY SPECIFIED? JNZ START2 ;YES SKIP NEXT ROUTINE MVI C,CURDSK CALL BDOS ;GET CURRENT DISK NR INR A ;MAKE A:=1 ; START2 ADI 'A'-1 ;MAKE IT PRINTABLE STA DRNAM ;SAVE FOR LATER LXI H,FCB+1 ;POINT TO NAME MOV A,M ;ANY SPECIFIED? CPI ' ' JNZ GOTFCB ;NO FCB - MAKE FCB ALL '?' MVI B,11 ;FN+FT COUNT QLOOP MVI M,'?' ;STORE '?' IN FCB INX H DCR B JNZ QLOOP ;LOOK UP THE FCB IN THE DIRECTORY GOTFCB MVI C,FSRCHF ;GET 'SEARCH FIRST' FNC LXI D,FCB CALL BDOS ;READ FIRST INR A ;WERE THERE ANY? JNZ SOME ;GOT SOME NONE CALL ERXIT IF NOT CHKUSR DB 'NO FILE$' ENDIF IF CHKUSR DB 'File not found.$' ; USRMSG DB 'Directory for user $' USRMS2 DB ':',13,10,'$' ENDIF ; ;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+81H ;POINT TO BUFFER ;(SKIP TO FN/FT) ADD L ;POINT TO ENTRY ADI 9 ;POINT TO SYS BYTE MOV L,A ;SAVE (CAN'T CARRY TO H) ; IF SOPT LDA SOPFLG ;DID USER REQUEST SYS FILES? CPI 'S' JZ SYSFOK ENDIF ; MOV A,M ;GET SYS BYTE ANI 80H ;CHECK BIT 7 JNZ MOREDIR ;SKIP THAT FILE SYSFOK MOV A,L ;GO BACK NOW SUI 9 ;BACK TO FT/FN START MOV L,A ;HL POINTS TO ENTRY NOW ; IF CHKUSR DCX H ;POINT TO USER BYTE IN FCB LDA USERNO ;GET CURRENT USER CMP M JNZ MOREDIR ;IGNORE IF DIFFERENT INX H ENDIF ; ;MOVE ENTRY TO TABLE XCHG ;ENTRY TO DE LHLD NEXTT ;NEXT TABLE ENTRY TO HL MVI B,11 ;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 LDA COUNT ;GET PREV COUNT INR A STA COUNT JMP MOREDIR ; ;SORT AND PRINT SPRINT LDA COUNT ;GET FILE NAME COUNT ORA A ;ANY FOUND? JZ NONE ;NO, EXIT ;INIT THE ORDER TABLE LXI H,ORDER LXI D,TABLE LXI B,11 ;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 DCR A ;MORE? JNZ BLDORD ;..YES LDA COUNT ;GET COUNT STA SCOUNT ;SAVE AS # TO SORT DCR A ;ONLY 1 ENTRY? JZ DONE ;..YES, SO SKIP SORT SORT XRA A ;GET A ZERO STA SWITCH ;SHOW NONE SWITCHED LDA SCOUNT ;GET COUNT DCR A ;USE 1 LESS STA TEMP ;SAVE # TO COMPARE STA SCOUNT ;SAVE HIGHEST ENTRY 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 LDA TEMP ;GET COUNT DCR A STA TEMP 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 CALL DRPRNT ;PRINT DRIVE NAME MVI C,NPL ;NR. OF NAMES PER LINE ENTRY: PUSH B MVI C,CONST ;CK STATUS OF KB CALL BDOS ;ANY KEY PRESSED? POP B ORA A JNZ ABORT ;YES, ABORT CALL FENCE ;PRINT FENCE CHAR AND SPACE 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 MVI B,8 ;FILE NAME LENGTH CALL TYPEIT ;TYPE FILENAME CALL PERIOD ;PERIOD AFTER FN MVI B,3 ;GET THE FILETYPE CALL TYPEIT CALL SPACE ;SPACE OVER ONE ;SEE IF MORE ENTRIES LDA COUNT DCR A JZ EXIT STA COUNT DCR C ;ONE LESS ON THIS LINE CZ CRLF ;PRINT CR-LF AND DRIVE NAME JMP ENTRY ; PERIOD MVI A,'.' JMP TYPE ; DRPRNT LDA DRNAM ;GET SAVED DRIVE NAME JMP TYPE ;PRINT IT ; FENCE MVI A,DELIM ;FENCE CHARACTER CALL TYPE ;PRINT IT, FALL INTO 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,13 ;PRINT CALL TYPE MVI A,10 ;LF CALL TYPE CALL DRPRNT MVI C,NPL ;NUMBER OF NAMES PER LINE 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 ; ;ERROR EXIT ERXIT POP D ;GET MSG MVI C,PRINT JMP CALLB ;PRINT MSG, EXIT ; ;ABORT - READ CHAR ENTERED ABORT MVI C,RDCHR CALLB CALL BDOS ;DELETE THE CHAR ; ;FALL INTO EXIT ;EXIT - ALL DONE , RESTORE STACK EXIT LHLD STACK ;GET OLD STACK SPHL ;MOVE TO STACK RET ;..AND RETURN ; NEXTT DW TABLE ;NEXT TABLE ENTRY COUNT DB 0 ;ENTRY COUNT SCOUNT DB 0 ;# TO SORT SWITCH DB 0 ;SWAP SWITCH FOR SORT BUFAD DW BASE+80H ;OUTPUT ADDR ORDER DS 512 ;ORDER TABLE (ROOM FOR 256 NAMES) DS 60 ;STACK AREA STACK DS 2 ;SAVE OLD STACK HERE SOPFLG DS 1 ;SET TO 'S' TO ALLOW SYS FILES TO PRINT USERNO DS 1 ;CONTAINS CURRENT USER NUMBER DRNAM DS 1 ;SAVE DRIVE NAME HERE TEMP DS 1 ;SAVE DIR ENTRY 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 FOPEN EQU 15 ;0FFH=NOT FOUND FCLOSE EQU 16 ; " " FSRCHF EQU 17 ; " " FSRCHN EQU 18 ; " " CURDSK EQU 25 ;GET CURRENTLY LOGGED DISK NAME CURUSR EQU 32 ;GET CURRENTLY LOGGED USER NUMBER (2.X ONLY) ; END