; NEW-D.MAC -- Version 1.5 -- October 6, 1989 ; Vers equ 16 ; current version SubVers equ ' ' ; modification level ; ; The original version of this file was the result of a disassembly ; of NEW-D.COM using DASM 1.6 by Richard Conn and Joe Wright. ; ; The original binary version of NEW-D.COM is copyright (c) 1984 by ; Source Maverick. According to that copyright, you may use NEW-D.COM ; for your own purposes other than selling it. You may distribute ; it as you wish, as long as you do not charge for the program. ; NEW-D.COM may be distributed on a disk with other programs, for ; which there is a copy charge only associated with the disk. The ; copy charge may not exceed US $2.00 in 1984 dollars, however. The ; author assumes no liability whatsoever with respect to another ; party's usage of NEW-D.COM, your acceptance of this statement being ; a prerequisite to said party's use of the program. ; ; The changes made since the original version are numerous and are not ; copyright, but they would be of little use by themselves. ; ; For usage information, see accompanying documentation file, or type ; "D //" on the command line. ; ; This has long been my favorite directory program, even without DU ; support. Originally it required a "[Gnn]" option (like CP/M Plus's ; PIP option) to see other user areas. For a long time I used an ; ARUNZ alias to get DU support. I finally decided to disassemble and ; modify the program. In the process it turned into a major project ; to make the code more efficient and add enhancements. ; ; This file may be assembled using SLRMAC. DRI's MAC and Microsoft's ; M80 will probably also work, if you have Z80.LIB. ; ; Gene Pizzetta ; 481 Revere St. ; Revere, MA 02151 ; ; Voice: (617) 284-0891 ; Newton Center Z-Node: (617) 965-7259 ; Lilliput Z-Node: (312) 649-1730 ; ; Version 1.0 -- Hank Blake -- 1984 ; For CP/M 2 and 3. Source code not released. ; ; Version 1.1 -- Gene Pizzetta -- June 25, 1989 ; For ZCPR3. Source code derived from disassembly of original ; COM file. Added DU and DIR support under ZCPR3. Added "//" ; help screen. Option delimiter changed from "[" to "/". "G" ; (specific user area) option eliminated. Several other ; cosmetic changes. ; ; Version 1.2 -- Gene Pizzetta -- July 29, 1989 ; Now searches for filenames containing slashes, but not filenames ; beginning with a slash unless it is preceded by a DU specification ; (actually, a single colon will do). Added R option to reset disk ; system. Renamed old R option to O option (to include only read-only ; files). Added TCAP support for dim or reverse video; no installation ; required. ; ; Version 1.3 -- Gene Pizzetta -- August 21, 1989 ; No longer sends initial formfeed to printer; instead sends formfeed ; after every 62 lines and a final formfeed after printing directory, ; unless "N" option is used. Changed "Ext" to "Typ" in display. Now ; prints ZCPR3 named directory following DU specification, if the ; DSKLBL label below is set to FALSE, otherwise looks for CP/M Plus ; disk label. ; ; Version 1.4 -- Gene Pizzetta -- September 8, 1989 ; Horizontal lines in dim video. Added equate for reverse video ; version. Revamped command line parser: slash (/) no longer ; required before options, if option list is second token on the ; command line; and if a filetype is given, but not a filename, ; the filename is automatically wildcarded. ; ; Version 1.5 -- Gene Pizzetta -- October 6, 1989 ; Corrected problem with file mask, DU, and option selection that ; only occurred under Backgrounder ii. Now reads environment to ; determine the number of lines on the screen, number of screen ; columns, and number of lines on printer page. Now re-entrant for ; use with the "GO" command. ; ; Version 1.6 -- Gene Pizzetta -- December 3, 1989 ; Now sets error flag if no matching files are found or if it runs ; out of memory. Added M option to store number of matching files ; in user registers. Added Q option to suppress screen and ; printer output. (I know, I know, a directory program with a ; quiet option ?!?) ; Bdos equ 05h MemTop equ 06h ; top of memory vector CpmFcb equ 05Ch ; default file control block FcbNam equ CpmFcb+1 ; filename in FCB FcbTyp equ CpmFcb+9 ; filetype in FCB FcbUsr equ CpmFcb+13 ; user number set in FCB by ZCPR3 DmaBuf equ 080h ; command tail and default DMA buffer L100A EQU 100AH ; 4106 Z3Env equ 0000h ; default SYSENV address ; ; BDOS functions ... ; ConOut equ 2 LstOut equ 5 ConRaw equ 6 PrtStr equ 9 GetVer equ 12 RstDsk equ 13 SelDsk equ 14 FSrchF equ 17 FSrchN equ 18 CurDsk equ 25 AllocV equ 27 GetRO equ 29 GetDpb equ 31 GetUsr equ 32 FreeSp equ 46 ; CP/M Plus only ; lf equ 0Ah ff equ 0Ch cr equ 0Dh esc equ 1Bh ; False equ 0 True equ Not False ; ;------------------------------------------------------------------------- ; USER OPTIONS: ;------------------------------------------------------------------------- ; ; If the following equate is set TRUE, then D will display CP/M Plus ; disk label, instead of ZCPR3 named directory ; DskLbl equ False ; ; set the following True if using reverse video highlighting ; RevVid equ False ; ; Following is the register address where the M option will store the ; number of matching files. Since the number is a two-byte word, the ; next register will also be used. Any register from 0-31 may be used, ; but I recommend the user registers beginning at 16. Since ZDE uses ; the 16-17 pair, the default for here is 18-19. ; REG equ 18 ; and 19 -- for storing number of matching files ; ; ------------------------------------------------------------------------ ; MACLIB Z80 ; org 0100h ; jmp Start ; jump to start of program ; db 'Z3ENV' ; ZCPR3 ID (not yet used) db 1 ; external environment descriptor Z3EAdr: dw Z3Env ; environment address ; ; Start of program . . . ; Start: pop h ; get return address from stack shld CpmRet ; ..and save it sspd CpmStk ; save old stack pointer lxi sp,CpmStk ; ..and point to new stack ; xra a ; initialize some data lxi h,OpAFlg mvi b,66 IniLp: mov m,a inx h djnz IniLp sta HorSiz ; lda FcbUsr ; get user number from ZCPR FCB sta User ; ..and store it mvi c,GetVer ; get current CP/M version call Bdos mvi a,0F0h ana l sui 20h sta CpmVer ; store current version ; mvi a,4 ; default to 4 column display sta MaxCol lhld Z3EAdr ; get environment address lxi d,31h ; offset to CRT columns dad d ; add to HL mov a,m ; get columns cpi 78 jrnc GetLn2 ; (use default) cpi 58 jrnc GetLn1 mvi a,2 sta MaxCol jr GetLn2 GetLn1: mvi a,3 ; use 3 columns instead sta MaxCol GetLn2: inx h ; now point to CRT lines mov a,m ; get number lines dcr a ; minus 1 sta LinCnt ; ..and store it sta CrtRow lxi d,6 ; offset to PRT lines (38h) dad d mov a,m ; get number of lines sui 4 ; subtract 4 sta LstCnt ; call GetOpt ; get user options and set flags lda CpmFcb ; was a drive given? ora a jnz GotDrv ; (yes) mvi c,CurDsk ; no, get current drive (A=0) call Bdos inr a ; increment it (A=1) sta CpmFcb ; ..and store it ; GotDrv: lhld Z3EAdr ; get environment address lxi d,97h ; offset to TCAP term table dad d ; add to HL mvi b,3 ; set B for 3 iterations TermLp: mov a,m ; get character inx h ; ..and increment pointer ora a ; is it nul? jnz TermLp ; (no, try again) dcr b ; yes, so decrement counter mov a,b ora a ; finished? jnz TermLp ; (no, try again) lxi d,DimVid DimLp: mov a,m ; yes, so now we move dim video inx h ; string to internal storage stax d inx d ora a jnz DimLp lxi d,RegVid RegLp: mov a,m ; then we move regular video inx h ; string to internal storage stax d inx d ora a jnz RegLp ; lda OpRFlg ; check reset flag ora a ; ..non-zero? cnz DReset ; (yes, do it) call SetFcb call GetFns lda OpCFlg ; using option C? ora a ; (no) jz NoOpC LHLD FilCnt ; any files? MOV A,L ORA H CNZ PrtDv2 jmp NoFile NoOpC: LHLD ExtCnt ; any files? MOV A,H ORA L JZ NoFile ; (no) LDA OpXFlg ; do we sort them? ORA A JNZ NoSort ; (no) DCX H ; more than 1 file? MOV A,H ORA L cnz FnSort ; (yes, sort them) NoSort: call L06F7 call PrFlNm call PrStat ExitOK: xra a ; reset error flag Exit: call SetErr lspd CpmStk ; restore old stack pointer lhld CpmRet ; restore return address pchl ; ..and return to CP/M ; NoFile: call PrStat mvi a,10 ; set error flag for file not found jr Exit ; ; Subroutines ... ; ; GetOpt -- Gets user supplied options and sets various option flags ; GetOpt: lxi h,DmaBuf+1 ; point to command tail lda DmaBuf ; anything there? ora a rz ; (no) mov b,a ; yes, put number of chars in B call EatSpc ; gobble spaces cpi '/' ; is it a slash? jz IsSlsh ; (yes, there's no filename) FnLp: inx h dcr b mov a,m ora a rz cpi ' ' jrnz FnLp call EatSpc ora a rz ; (no options) mov a,m ; get first char of second token cpi '/' ; a slash? jrnz ScnOpt ; (no, so get options) inx h ; yes, move past it dcr b jr ScnOpt ; ..and get options IsSlsh: mvi a,' ' ; no filename, so put space in sta FcbNam ; ..filename of FCB inx h ; ..move past slash dcr b ; ..and fall into option scanning ; ScnOpt: call ScnTbl xchg ; point back to options inx h djnz ScnOpt ; loop through options lda OpFFlg ; F option chosen? rar jnc SkipF ; (no, skip) lxi h,MaxCol ; yes, increase display columns inr m ret ; SkipF: lda OpUFlg ; U option chosen? rar rnc ; (no) lxi h,MaxCol ; yes, decrease display columns dcr m ret ; ScnTbl: mov c,m ; put option in C lxi d,OptTbl ; point DE to option table ScnTLp: ldax d ; get table option ora a ; end of table? jz NoMat ; (yes, no match) inx d ; no, keep looking cmp c ; match? jz TMatch ; (yes) inx d ; move pointer to next entry inx d jmp ScnTLp ; ..and keep looking ; NoMat: xchg ret ; TMatch: push h ; save option pointer ldax d ; put address from table into HL mov l,a inx d ldax d mov h,a pop d ; recover option pointer in DE mvi a,1 ; set option flag by jumping to pchl ; ..table routine and returning ; ; Option Jump Table ; OptTbl: db 'A' ; A = archived files dw OptA db 'B' ; B = include system files dw OptB db 'C' ; C = comprehensive FCB info dw OptC ; db 'D' ; D = display file date (not yet supported) ; dw OptD db 'F' ; F = suppress file size dw OptF db '/' ; / = help dw OptH db 'M' ; M = store number of matching files dw OptM db 'N' ; N = suppress initial formfeed to printer dw OptN db 'O' ; O = read-only files only dw OptO db 'P' ; P = send output to printer dw OptP db 'Q' ; Q = quiet (no display) dw OptQ db 'R' ; R = reset disk system dw OptR db 'S' ; S = system files only dw OptS ; db 'T' ; T = sort by filetype (not yet supported) ; dw OptT db 'U' ; U = include all user areas dw OptU db 'W' ; W = read/write files only dw OptW db 'X' ; X = don't sort file listing dw OptX db 'Z' ; Z = non-archived files only dw OptZ db 0 ; end of option jump table ; ; Option flag setting routines ; OptA: sta OpAFlg ret OptB: sta OpBFlg ret OptC: sta OpCFlg ret OptF: sta OpFFlg ret OptM: sta OpMFlg ret OptN: sta OpNFlg ret OptO: sta OpOFlg ret OptP: sta OpPFlg ret OptQ: sta OpQFlg ret OptR: sta OpRFlg ret OptS: sta OpSFlg ret OptU: sta OpUFlg ret OptW: sta OpWFlg ret OptX: sta OpXFlg ret OptZ: sta OpZFlg ret ; OptH: lxi d,MsgHlp ; display help message mvi c,PrtStr call Bdos jmp ExitOK ; ..and return to CP/M ; ; DReset -- resets disk system ; DReset: mvi c,RstDsk call Bdos ret ; ; EatSpc -- gobbles up spaces. Expects address of string in HL, length of ; string in B ; EatSpc: mov a,m ; get character inx h ; increment pointer dcr b ; decrement counter cpi ' ' ; is it a space? jrz EatSpc ; (yes, eat it) dcx h ; no, back up pointer inr b ; ..and counter, and ret ; ..return with character ; ; SetFcb -- ; SetFcb: lda CpmFcb ; get drive (A=1) dcr a ; make A=0 mov e,a mvi d,0 mvi c,SelDsk ; make it the default drive call Bdos lda FcbNam ; check for space in first character cpi ' ' jrnz NoSpc ; (no space) mvi a,'?' ; set filename to ?'s lxi h,FcbNam mov m,a lxi d,FcbNam+1 lxi b,7 ldir lda FcbTyp ; check for filetype cpi ' ' jrnz NoSpc ; (we've got one) lxi h,FcbNam ; set filetype to ?'s lxi d,FcbTyp lxi b,3 ldir NoSpc: lda OpUFlg ; all users? rar jnc NoOpU ; (no) lxi h,User ; make user a question mark mvi m,'?' NoOpU: LXI B,11 LXI D,FnSav LXI H,FcbNam LDIR MVI A,'?' LXI H,CpmFcb MOV M,A LXI D,FcbNam LXI B,12 LDIR lda CpmVer ; check version flag ora a jz NoCpm3 ; (not CP/M 3 lxi d,CpmFcb ; initialize DPB for CP/M Plus mvi c,FSrchF call Bdos NoCpm3: mvi C,GetDpb ; move DPB to storage call Bdos lxi b,15 lxi d,DpbSav ldir LHLD L0DA8 INX H INX H DAD H LXI D,L0E2B DAD D SHLD L0DB0 LDA L0DA4 INR A RRC RRC RRC MOV L,A MVI H,0 SHLD L0D9B LHLD L0DA8 INX H SHLD L0D99 RET ; GetFns: lxi d,CpmFcb mvi c,FSrchF call Bdos L0336: ORA A RM ADD A ADD A ADD A ADD A ADD A ADI 128 MOV L,A MVI H,0 SHLD L0D9F MOV A,M CPI 229 JZ L03DD LHLD L0DB0 LXI D,30 DAD D XCHG LHLD MemTop ORA A DSBC D JNC L0367 mvi c,PrtStr ; say directory is too big lxi d,MsgBig call Bdos mvi a,12 ; set error flag for TPA overflow jmp Exit ; ..and return to CP/M L0367: LXI D,2064 DSBC D JNC L0375 LXI H,0 SHLD CpmRet L0375: LHLD L0D99 DCX H SHLD L0D99 LBCD L0D9F CALL L04A6 RAR JNC L03DD LDA OpCFlg ORA A CNZ L03E5 LXI B,16 LHLD L0D9F DAD B MOV B,H MOV C,L CALL L0536 PUSH H LXI B,12 LHLD L0DB0 DAD B POP B MOV M,C INX H MOV M,B LHLD L0D7B DAD B SHLD L0D7B LXI B,11 LDED L0DB0 LHLD L0D9F INX H LDIR LHLD L0D9F MOV A,M STAX D LHLD ExtCnt INX H SHLD ExtCnt DAD H XCHG LXI H,L0E2B DAD D LDED L0DB0 MOV M,E INX H MOV M,D LXI D,14 LHLD L0DB0 DAD D SHLD L0DB0 L03DD: MVI C,FSrchN CALL Bdos JMP L0336 L03E5: LDA L0D78 ORA A JNZ L0412 INR A STA L0D78 CALL L0B2B LXI B,MsgCmp MVI A,39 CALL L0AE7 MVI B,39 LDA L0DA7 ORA A JZ L0406 MVI B,31 L0406: MOV A,B LXI H,HorSiz ADD M MOV M,A CALL PrtDvd CALL PagBrk L0412: LIXD L0D9F ldx a,12 ORA A JZ L042F DCR A JNZ L0436 LDA L0DA7 ORA A JNZ L0436 ldx a,24 ORA A JZ L0436 L042F: LHLD FilCnt INX H SHLD FilCnt L0436: MVI B,1 CALL L0B8E CALL SpcOut MVI B,11 L0440: PUSH B ldx a,0 inxix ORA A JP L0465 ANI 7FH PUSH PSW call DimOn POP PSW call RvsCse CPI ' ' JNZ L045B MVI A,'*' L045B: MOV E,A call ChrOut call DimOff JMP L046C L0465: call RvsCse mov e,a call ChrOut L046C: POP B DJNZ L0440 CALL SpcOut CALL SpcOut MVI B,4 CALL L0B8E CALL SpcOut LDA L0DA7 ORA A JNZ L048C MVI B,16 CALL L0B8E JMP L04A2 L048C: MVI B,8 L048E: PUSH B ldx a,1 CALL L0BA1 ldx a,0 CALL L0B9B inxix inxix POP B DJNZ L048E L04A2: CALL PagBrk RET L04A6: call SavLbl ; check if disk label rz ; (it is, skip it) LDA OpUFlg ORA A JZ L04B9 LDAX B CPI 16 JM L04B9 XRA A RET L04B9: LXI H,User MVI E,12 L04BE: MOV A,M CPI '?' JZ L04CC MOV D,A LDAX B ANI 7FH CMP D MVI A,0 RNZ L04CC: INX B INX H DCR E JNZ L04BE DCX B LDA OpAFlg ORA A JZ L04DF MVI E,0 JMP L04E8 L04DF: LDA OpZFlg ORA A JZ L04EE MVI E,80h L04E8: LDAX B XRA E RLC ANI 1 RZ L04EE: DCX B DCX B LDA OpOFlg ORA A JZ L04FC MVI E,0 JMP L0505 L04FC: LDA OpWFlg ORA A JZ L050B MVI E,80h L0505: LDAX B XRA E RLC ANI 1 RZ L050B: LDA OpBFlg ORA A RNZ INX B LDA OpSFlg ORA A LDAX B JNZ L051E CMA RLC ANI 1 RET L051E: RLC ANI 1 RET ; ; SavLbl -- checks for CP/M 3 disk label (user 32) and saves it if found. ; Entry: BC -> user and filename ; Exit: Zero flag set if label found ; SavLbl: ldax b ; check user number cpi 32 ; is it 32? rnz ; (no, not disk label) IF DSKLBL sta LblUsr ; store it inx b ; increment pointer mov l,c ; ..move pointer to HL mov h,b lxi d,LblNam ; ..and store disk label (11 chars) lxi b,11 ldir ENDIF xra a ret ; L0536: LXI H,0 LDA L0DA7 ORA A JNZ L054E MVI E,16 L0542: LDAX B ORA A JZ L0548 INX H L0548: INX B DCR E JNZ L0542 RET L054E: MVI E,8 L0550: LDAX B MOV D,A INX B LDAX B ORA D JZ L0559 INX H L0559: INX B DCR E JNZ L0550 RET FnSort: LXI H,L0DBF MVI M,1 LXI H,1 SHLD L0DC2 LHLD ExtCnt SHLD L0DDA L0570: LDA L0DBF ORA A RZ DCR A STA L0DBF INR A ADD A MOV C,A MVI B,0 LXI H,L0DC0 DAD B MOV E,M INX H MOV D,M SDED L0DB7 LXI H,L0DD8 DAD B MOV E,M INX H MOV D,M SDED L0DB9 L0594: LHLD L0DB7 LDED L0DB9 ORA A DSBC D JNC L0570 LHLD L0DB7 SHLD L0DB3 LDED L0DB9 SDED L0DB5 DAD D MOV A,L ANI 0FEH MOV L,A LXI D,L0E2B DAD D MOV E,M INX H MOV D,M SDED L0DBB L05BF: LHLD L0DB5 LDED L0DB3 ORA A DSBC D JC L0660 MOV L,E MOV H,D L05CE: DAD H LXI D,L0E2B DAD D MOV C,M INX H MOV B,M LDED L0DBB CALL L0A90 INR A JNZ L05EB LHLD L0DB3 INX H SHLD L0DB3 JMP L05CE L05EB: LHLD L0DB5 L05EE: DAD H LXI D,L0E2B DAD D MOV E,M INX H MOV D,M LBCD L0DBB CALL L0A90 INR A JNZ L060B LHLD L0DB5 DCX H SHLD L0DB5 JMP L05EE L060B: LHLD L0DB5 LDED L0DB3 ORA A DSBC D JC L05BF LHLD L0DB3 DAD H LXI D,L0E2B DAD D MOV E,M INX H MOV D,M SDED L0DBD LHLD L0DB5 DAD H LXI D,L0E2B DAD D PUSH H LHLD L0DB3 DAD H LXI D,L0E2B DAD D XTHL MOV C,M INX H MOV B,M POP H MOV M,C INX H MOV M,B LHLD L0DB5 DAD H LXI D,L0E2B DAD D LDED L0DBD MOV M,E INX H MOV M,D LHLD L0DB3 INX H SHLD L0DB3 LHLD L0DB5 DCX H SHLD L0DB5 JMP L05BF L0660: LHLD L0DB5 LDED L0DB7 ORA A DSBC D PUSH H LHLD L0DB9 LDED L0DB3 ORA A DSBC D XCHG POP H ORA A DSBC D JNC L06BA LHLD L0DB3 LDED L0DB9 ORA A DSBC D JNC L06B1 LDA L0DBF INR A STA L0DBF ADD A MOV C,A MVI B,0 LXI H,L0DC0 DAD B LDED L0DB3 MOV M,E INX H MOV M,D LHLD L0DBF MVI H,0 LXI B,L0DD8 DAD H DAD B LDED L0DB9 MOV M,E INX H MOV M,D L06B1: LHLD L0DB5 SHLD L0DB9 JMP L0594 L06BA: LHLD L0DB7 LDED L0DB5 ORA A DSBC D JNC L06EE LDA L0DBF INR A STA L0DBF ADD A MOV C,A MVI B,0 LXI H,L0DC0 DAD B LDED L0DB7 MOV M,E INX H MOV M,D LHLD L0DBF MVI H,0 LXI B,L0DD8 DAD H DAD B LDED L0DB5 MOV M,E INX H MOV M,D L06EE: LHLD L0DB3 SHLD L0DB7 JMP L0594 L06F7: LXI H,0 SHLD L0DF0 SHLD L0DF2 L0700: LHLD L0DF2 LDED ExtCnt ORA A DSBC D JC L0714 LHLD L0DF0 SHLD FilCnt RET L0714: LHLD L0DF2 INX H SHLD L0DF2 DAD H LXI D,L0E2B DAD D PUSH H LHLD L0DF0 INX H SHLD L0DF0 DAD H LXI D,L0E2B DAD D XTHL MOV C,M INX H MOV B,M POP H MOV M,C INX H MOV M,B L0735: LHLD L0DF2 LDED ExtCnt ORA A DSBC D SBB A PUSH PSW LHLD L0DF0 DAD H LXI D,L0E2B DAD D PUSH H LHLD L0DF2 LXI B,2 DAD H DAD B LXI D,L0E2B DAD D MOV E,M INX H MOV D,M POP H MOV C,M INX H MOV B,M CALL L0A90 SUI 0 SUI 1 SBB A POP B ANA B RAR JNC L0700 LHLD L0DF2 INX H SHLD L0DF2 DAD H LXI D,L0E2B DAD D MOV E,M INX H MOV D,M XCHG LXI B,12 DAD B MOV E,M INX H MOV D,M SDED L0DF4 LHLD L0DF0 DAD H LXI D,L0E2B DAD D MOV E,M INX H MOV D,M XCHG DAD B PUSH H MOV E,M INX H MOV D,M LHLD L0DF4 DAD D MOV C,L MOV B,H POP H MOV M,C INX H MOV M,B JMP L0735 ; ; PrFlNm -- prints matching filenames in columns ; PrFlNm: lda OpQFlg ; quiet option? ora a rnz ; (yes) CALL L0B2B LHLD FilCnt MOV A,H ORA H JNZ L07C2 MOV A,L RRC RRC RRC ANI 31 INR A MOV B,A LDA MaxCol CMP B JM L07C2 mov a,b sta MaxCol L07C2: lda MaxCol sta L0DFA jmp L07D3 L07CB: LXI B,MsgDlm MVI A,3 CALL L0AE7 L07D3: LXI B,MsgNam MVI A,11 CALL L0AE7 LDA OpFFlg RAR JC L07F9 LXI B,MsgByt MVI A,6 CALL L0AE7 LDA OpUFlg RAR JNC L07F9 LXI B,MsgUsr MVI A,3 CALL L0AE7 L07F9: LXI H,L0DFA DCR M JNZ L07CB CALL PrtDvd LDED FilCnt LBCD MaxCol MVI B,0 CALL L0AAA MOV A,L ORA H JZ L0816 INX D L0816: SDED L0D9D LXI H,0 SHLD L0DF6 L0820: CALL PagBrk LXI H,0 SHLD L0DF8 XRA A STA L0DFA L082D: LXI B,MsgDlm LDA L0DFA ORA A CNZ PrtNul LDED L0DF8 LHLD L0DF6 DAD D INX H XCHG LHLD FilCnt ORA A DSBC D XCHG CNC L0875 LDED L0D9D LHLD L0DF8 DAD D SHLD L0DF8 LXI H,L0DFA INR M LDA MaxCol CMP M JNZ L082D LHLD L0DF6 INX H SHLD L0DF6 LDED L0D9D ORA A DSBC D JC L0820 JMP PrtDvd L0875: DAD H LXI D,L0E2B DAD D MOV E,M INX H MOV D,M SDED L0DB0 LXI H,9 DAD D MOV A,M STA L0DB2 ORA A CM DimOn LHLD L0DB0 MVI B,11 L0892: MOV A,M ANI 7FH CALL RvsCse MOV E,A PUSH B PUSH H CALL ChrOut POP H POP B INX H DJNZ L0892 LDA OpFFlg RAR JC L08F4 LXI B,12 LHLD L0DB0 DAD B MOV E,M INX H MOV D,M LBCD L0D9B CALL L0AC4 MVI A,5 CALL L0BB9 LXI B,8 LHLD L0DB0 DAD B MVI E,6BH ; 107 MOV A,M ORA A JP L08D0 MVI E,72H ; 114 L08D0: INX H INX H MOV A,M ORA A JP L08DB MOV A,E SUI ' ' MOV E,A L08DB: CALL ChrOut LDA OpUFlg RAR JNC L08F4 LXI B,11 LHLD L0DB0 DAD B MOV L,M MVI H,0 MVI A,3 CALL L0BB9 L08F4: LDA L0DB2 ORA A JM DimOff RET ; ; RvsCse -- reverses case of alpha character ; Entry: A=char ; Exit: A=char ; RvsCse: cpi ' ' ; is it control char? jm IsCtrl ; (yes) cpi 7Fh ; or DEL? jz IsCtrl ; (yes) cpi 'A' ; number of symbol rm ; (yes, skip it) cpi '[' ; is it uppercase? jp NotUpp ; (no) adi 32 ; change uppercase to lowercase ret NotUpp: cpi 'a' ; less than 'a' rm ; (yes, skip it) cpi '{' ; is it lowercase? rp ; (no, skip it) sui 32 ; change lowercase to uppercase ret IsCtrl: mvi a,'?' ; change control char to '?' ret ; ; PrStat -- Print disk statistics: number of matching files, space they ; use, total disk space, number of free directory entries, and free ; disk space ; PrStat: lda OpMFlg ; load user registers? ora a cnz SetReg ; (yes) lda OpQFlg ; quiet option? ora a rnz ; (yes) LHLD L0DA6 INX H LDED L0DAA MVI B,16 ORA A L0928: RALR E RALR D JNC L0930 DCX H L0930: DJNZ L0928 SHLD L0DFC CALL PagBrk LHLD FilCnt ; print number of matching files MVI A,1 CALL L0BB9 LXI B,MsgFil LHLD FilCnt DCX H MOV A,L ORA H JNZ L0955 STA MsgFi2 CALL PrtNul LXI B,MsgFi3 L0955: CALL PrtNul LDED L0D7B ; print total space used by files LBCD L0D9B CALL L0AC4 MVI A,1 CALL L0BB9 LXI B,MsgK CALL PrtNul LDED L0DFC ; print disk capacity LBCD L0D9B CALL L0AC4 MVI A,1 CALL L0BB9 LXI B,MsgCap CALL PrtNul MVI C,CurDsk CALL Bdos PUSH PSW MVI C,GetRO CALL Bdos POP B INR B L0991: DJNZ L0996 JMP L099C L0996: RARR H RARR L jr L0991 L099C: MOV A,L ANI 1 JZ L09AE CALL DimOn LXI B,MsgRO CALL PrtNul CALL DimOff L09AE: CALL PagBrk LHLD L0D99 ; print remaining directory entries MVI A,1 CALL L0BB9 LXI B,MsgDir LHLD L0D99 DCX H MOV A,L ORA H JNZ L09D3 STA MsgDi3 MVI A,'y' STA MsgDi2 CALL PrtNul LXI B,MsgDi4 L09D3: CALL PrtNul CALL PrtNul LDA CpmVer ORA A CNZ FrSp3 CZ FrSp2 MVI A,1 CALL L0BB9 lxi b,MsgRem ; print space remaining message call PrtNul lxi d,0 mvi c,CurDsk ; get drive call Bdos IF NOT DSKLBL push psw ; save current drive ENDIF ; for uppercase drive letter change next line to ; adi 65 adi 97 ; make it printable mov e,a ; ..and print it call ChrOut lda User ; get user cpi '?' ; don't print it, if it's all users jz AllUsr MOV L,A MVI H,0 MVI A,1 CALL L0BB9 AllUsr: mvi e,':' ; print colon call ChrOut IF DSKLBL lda LblUsr ; check for CP/M 3 disk label ora a jz NoLbl ; (nope) lxi h,LblNam ; there is, so print it (11 chars) mvi b,11 ELSE pop psw ; get back current drive mov b,a ; put it in B lda User ; get user mov c,a ; put it in C call GetNdr ; get named directory jz NoLbl ; (none, skip it) mvi b,8 ; got it, so print it (8 chars) ENDIF PrtLbl: mov a,m ; get character ; comment out next line for uppercase named directory or disk label call RvsCse ; reverse case push h ; save pointer and counter push b mov e,a ; move char to E and print it call ChrOut pop b pop h inx h ; increment pointer djnz PrtLbl ; ..and loop NoLbl: lda OpPFlg ; check print flag ora a rz call PagBrk ; (yes, send CR/LF) lda OpNFlg ; option N? ora a rnz ; (yes, skip formfeed) mvi e,ff ; send formfeed to list device call PrtOut PrtLb2: ret IF NOT DSKLBL ; ; GetNdr -- gets named directory ; Entry: B=disk, C=user ; Exit: HL=address of directory name; Z flag set if not found ; GetNdr: inr b ; make A=1, etc. lhld Z3EAdr ; get environment address lxi d,15h ; add named directory offset dad d mov e,m ; get address into DE inx h mov d,m inx h mov a,m ; get size in A xchg ; address in HL ora a jrnz IsNdr ; (got it) NoNdr: xra a ; named directory not found ret IsNdr: mov a,m ; get drive ora a ; 0=end of directory jrz NoNdr ; (not found) cmp b ; check drive jrnz SkpNdr ; (no match) inx h mov a,m ; get user dcx h ; point back to drive cmp c ; check user jrnz SkpNdr ; (no match) inx h inx h xra a dcr a ret ; SkpNdr: push b ; save BC lxi b,18 ; point to next entry dad b pop b ; restore BC jr IsNdr ENDIF ; ; FrSp3 -- calls BDOS Function 46 under CP/M 3 to get disk free space ; FrSp3: mvi c,CurDsk call Bdos mov e,a mvi c,FreeSp call Bdos LHLD DmaBuf LDED DmaBuf+2 RARR E RARR H RARR L RARR E RARR H RARR L RARR E RARR H RARR L ORI 1 RET ; ; SetErr -- sets ZCPR3 error flag ; SetErr: push psw ; save error code call MsgAdr ; get message buffer address lxi d,6 ; offset to error flag dad d pop psw ; get back error code mov m,a ; ..and store it in flag ret ; ; SetReg -- sets two user registers to number of matching files found ; (a word value) ; SetReg: lhld FilCnt ; get file count push h ; ..and save it on stack call MsgAdr ; get message buffer address lxi d,REG+30h ; offset to register dad d pop d ; get back file count into DE mov m,e ; ..and store it inx h mov m,d ret ; ; MsgAdr -- returns address of message buffer in HL ; MsgAdr: lhld Z3EAdr ; get environment address lxi d,34 ; offset to message buffer address dad d mov a,m ; get message address inx h mov h,m mov l,a ret ; ; FrSp2 -- determines disk free space under CP/M 2.x ; FrSp2: mvi c,AllocV call Bdos push h popix LHLD L0DA6 INX H MOV E,L MOV D,H JMP L0A7E L0A70: DCX H MOV A,L ORA H JZ L0A88 RLCR C JNC L0A7C DCX D L0A7C: DJNZ L0A70 L0A7E: MVI B,8 ldx c,0 inxix JMP L0A70 L0A88: LBCD L0D9B CALL L0AC4 RET ; L0A90: MVI L,12 L0A92: LDAX D ANI 7FH MOV H,A LDAX B ANI 7FH SUB H JNZ L0AA4 INX D INX B DCR L JNZ L0A92 RET L0AA4: MVI A,0FFH RC MVI A,1 RET L0AAA: LXI H,0 MVI A,16 L0AAF: PUSH PSW XRA A XCHG DAD H XCHG DADC H DSBC B INX D JNC L0ABE DAD B DCX D L0ABE: POP PSW DCR A JNZ L0AAF RET L0AC4: LXI H,0 MVI A,16 L0AC9: DAD H XCHG DAD H XCHG JNC L0AD1 DAD B L0AD1: DCR A JNZ L0AC9 RET ; ; PrtDvd -- print '=' screen divider ; PrtDvd: call PagBrk PrtDv2: IF NOT RevVid call DimOn ENDIF lda HorSiz mov b,a PrtDLp: push b mvi e,'=' call ChrOut pop b djnz PrtDLp IF NOT RevVid call DimOff ENDIF ret L0AE7: LXI H,HorSiz ADD M MOV M,A ; ; PrtNul -- prints NUL-terminated string on console ; Entry: BC points to string ; PrtNul: ldax b ; get character ora a ; is it NUL? rz ; (yes, we're through) push b mov e,a call ChrOut pop b inx b jmp PrtNul ; ; PagBrk -- sends CR/LF to console and keeps track of number of lines for ; page break. Page break is skipped if print option ; PagBrk: mvi e,cr call ChrOut mvi e,lf call ChrOut lda OpPFlg ; print option? ora a jrnz LstBrk ; (yes, check list page break) lxi h,LinCnt ; point to line count dcr m ; decrement it rnz ; (more to go) lda CrtRow ; get CRT lines mov m,a ; reset page count lxi b,MsgMor call PrtNul PagBr2: mvi c,ConRaw ; wait for console response mvi e,0FFh call Bdos ora a jz PagBr2 ; (none yet) cpi 3 ; control-C? jz ExitOK ; (yes, return to CP/M) lxi b,MsgEra ; erase page break message jmp PrtNul ; ..and return to caller ; ; LstBrk -- keeps track of printer lines and sends formfeed if page is ; filled. ; LstBrk: lda OpNFlg ; check formfeed flag ora a rnz ; (no formfeed) lxi h,LstCnt ; check line count dcr m rnz ; (no formfeed yet) mvi m,62 ; restore line count mvi e,ff jmp PrtOut ; L0B2B: lda OpPFlg ; option P? ora a jz SkpMsk ; (no, skip option P masking) CALL OpPOff lxi b,MsgCR ; send CR to console call PrtNul JMP OpPOn SkpMsk: lxi b,MsgCR jmp PrtNul ; ; SpcOut -- outputs space char to console and, if printer flag, to list device ; SpcOut: mvi e,' ' ; space char in E, fall through to ChrOut ; ; ChrOut -- outputs char in E to console and, if print flag, to list device ; ChrOut: mvi c,ConOut push d call Bdos pop d lda OpPFlg ; check print flag ora a rz rm ; ; PrtOut -- outputs char in E to list device ; PrtOut: mvi c,LstOut jmp Bdos ; jump to BDOS, return to caller ; DimOn: call OpPOff lxi b,DimVid call PrtNul jmp OpPOn ; DimOff: call OpPOff lxi b,RegVid call PrtNul jmp OpPOn ; OpPOff: lda OpPFlg ori 80h sta OpPFlg ret ; OpPOn: lda OpPFlg ani 7Fh sta OpPFlg ret L0B8E: PUSH B ldx a,0 inxix CALL L0B9B POP B DJNZ L0B8E RET L0B9B: CALL L0BA1 JMP SpcOut L0BA1: PUSH PSW RLC RLC RLC RLC CALL L0BAA POP PSW L0BAA: ANI 0FH ADI '0' CPI ':' JM L0BB5 ADI 7 L0BB5: MOV E,A JMP ChrOut L0BB9: STA L0DFE CALL L0BFF STA L0E00 INR A STA L0DFF L0BC6: LDA L0DFE LXI H,L0DFF CMP M JC L0BDC MVI E,' ' CALL ChrOut LXI H,L0DFF INR M JMP L0BC6 L0BDC: LXI H,L0DFF MVI M,0 L0BE1: LDA L0E00 DCR A LXI H,L0DFF CMP M RC LHLD L0DFF MVI H,0 LXI B,L0E01 DAD B MOV E,M CALL ChrOut LXI H,L0DFF INR M JNZ L0BE1 RET L0BFF: XRA A PUSH PSW INX SP LXI D,262 L0C05: DCR E JZ L0C16 INR D CALL L0C25 ADI '0' PUSH PSW INX SP MOV A,L ORA H JNZ L0C05 L0C16: MOV E,D DCR E LXI B,L0E01 L0C1B: DCX SP POP PSW STAX B INX B DCR D JNZ L0C1B MOV A,E RET L0C25: LXI B,L100A ; 4106 XRA A L0C29: DAD H RAL CMP C JC L0C31 SUB C INX H L0C31: DJNZ L0C29 RET ; ; messages ... ; MsgCR: db cr,0 MsgMor: db '[More]',0 MsgEra: db cr,' ',cr,0 MsgNam: db 'Name Typ',0 MsgByt: db ' Bytes',0 MsgUsr: db ' U#',0 MsgDlm: db ' | ',0 ; MsgFil: db ' File' MsgFi2: db 's' MsgFi3: db ', occupying ',0 ; MsgK: db 'k of ',0 MsgCap: db 'k total capacity',0 MsgRO: db ' -- Disk is Read Only --',0 ; MsgDir: db ' directory entr' MsgDi2: db 'i' MsgDi3: db 'es' MsgDi4: db ' and ',0 ; MsgRem: db 'k bytes remain on ',0 ; MsgCmp: db 'Us Fn Ft Ex S1 S2 RC Group #''s',0 ; MsgBig: db cr,lf,'Sorry, directory too big.',cr,lf,'$' ; MsgHlp: db cr,'NEW D Version ' db Vers/10+'0','.',Vers mod 10+'0',SubVers,cr,lf db 'Usage:',cr,lf db ' D {dir:}{{afn}.aft} {{/}options}',cr,lf db 'Options:',cr,lf db ' A archived files only Q no display (quiet)',cr,lf db ' B include system files R reset disk system',cr,lf db ' C include FCB information S system files only',cr,lf db ' F suppress file size U include all user areas',cr,lf db ' M put matches in reg ' db REG/10+'0',REG mod 10+'0','/',(REG+1)/10+'0',(REG+1) mod 10+'0' db ' W read/write files only',cr,lf db ' N no formfeeds X do not sort',cr,lf db ' O read-only files only Z non-archived files only',cr,lf db ' P output to printer$' ; ; data ... ; OpAFlg: ds 1 OpBFlg: ds 1 OpCFlg: ds 1 OpFFlg: ds 1 OpMFlg: ds 1 OpNFlg: ds 1 OpOFlg: ds 1 OpPFlg: ds 1 OpQFlg: ds 1 OpRFlg: ds 1 OpSFlg: ds 1 OpUFlg: ds 1 OpWFlg: ds 1 OpXFlg: ds 1 OpZFlg: ds 1 CpmVer: ds 1 L0D78: ds 1 MaxCol: ds 1 ; maximum number of directory display columns CrtRow: ds 1 LinCnt: ds 1 ; number of screen lines (minus 1) LstCnt: ds 1 ; number of printer lines (minus 4) L0D7B: ds 2 FilCnt: ds 2 ExtCnt: ds 2 User: ds 1 FnSav: ds 11 ; filename LblUsr: ds 1 ; 0=disk label not found, 32=label found LblNam: ds 11 ; CP/M Plus disk label L0D99: ds 2 ; remaining directory entries L0D9B: ds 2 L0D9D: ds 2 L0D9F: ds 2 DpbSav: ds 3 L0DA4: ds 2 L0DA6: ds 1 L0DA7: ds 1 ; ; uninitialized data ; L0DA8: ds 2 L0DAA: ds 6 L0DB0: ds 2 L0DB2: ds 1 L0DB3: ds 2 L0DB5: ds 2 L0DB7: ds 2 L0DB9: ds 2 L0DBB: ds 2 L0DBD: ds 2 L0DBF: ds 1 L0DC0: ds 2 L0DC2: ds 22 L0DD8: ds 2 L0DDA: ds 22 L0DF0: ds 2 L0DF2: ds 2 L0DF4: ds 2 L0DF6: ds 2 L0DF8: ds 2 L0DFA: ds 1 HorSiz: ds 0 ; size of horizontal dashed line L0DFC: ds 2 L0DFE: ds 1 L0DFF: ds 1 L0E00: ds 1 DimVid: ds 8 ; dim video string RegVid: ds 8 ; normal video string L0E01: ds 38 CpmStk: ds 2 CpmRet: ds 2 L0E2B: ds 3 ; end