; D.MAC ; Vers equ 17 ; 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 ?!?) ; ; Version 1.7 -- Gene Pizzetta -- September 6, 1990 ; Nobody ever reported it, but I discovered it myself: the U ; option was not displaying files in users above 15. It does now. ; Added configuration bytes for CP/M Plus disk label usage, for ; reverse video selection, and for register usage (separate ; versions and re-assembly no longer required). These three ; configuration bytes can be changed using ZCNFG. Changed all ; possible jumps to relative jumps, saving 80 bytes. ; 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 ; 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 ; ; Configuration area ; db 0,0 ; filler db 'D',Vers/10+'0',Vers mod 10+'0',' ' ; for ZCNFG ; ; Set the following byte to non-zero if using reverse video highlighting RevVid: db 0 ; zero for dim or bright highlighting ; ; If the following byte is set non-zero, then D will display CP/M Plus ; disk label, instead of ZCPR3 named directory DskLbl: db 0 ; zero for ZCPR3 named directory label ; ; Following is the register address where the M option will store the ; number of matching files. Since the number of files is a two-byte word, ; the next register will also be used. Any register from 0-30 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. ZReg: db 18 ; number of first register to use ; ; 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 jrnz 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? jrnz TermLp ; (no, try again) dcr b ; yes, so decrement counter mov a,b ora a ; finished? jrnz 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 jrnz 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 jrnz 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) jrz NoOpC LHLD FilCnt ; any files? MOV A,L ORA H CNZ PrtDv2 jr NoFile ; NoOpC: LHLD ExtCnt ; any files? MOV A,H ORA L jrz NoFile ; (no) LDA OpXFlg ; do we sort them? ORA A jrnz 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? jrz 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 jrnc 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? jrz NoMat ; (yes, no match) inx d ; no, keep looking cmp c ; match? jrz TMatch ; (yes) inx d ; move pointer to next entry inx d jr 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 '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 '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 b,MsgHlp ; display help message call PrtNul lda ZReg mov l,a mvi h,0 push h mvi a,2 call PrtNum mvi e,'/' call ChrOut mvi a,2 pop h inx h call PrtNum lxi b,MsgHl1 call PrtNul 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 jrnc 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 jrz 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 jrnc 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 jrnc L0375 LXI H,0 SHLD CpmRet L0375: LHLD L0D99 DCX H SHLD L0D99 LBCD L0D9F CALL L04A6 RAR jrnc 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 jrnz L0412 INR A STA L0D78 CALL L0B2B LXI B,MsgCmp MVI A,39 CALL L0AE7 MVI B,39 LDA L0DA7 ORA A jrz 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 jrz L042F DCR A jrnz L0436 LDA L0DA7 ORA A jrnz L0436 ldx a,24 ORA A jrz 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 ' ' jrnz L045B MVI A,'*' L045B: MOV E,A call ChrOut call DimOff jr 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 jrnz L048C MVI B,16 CALL L0B8E jr 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 jrz L04B9 LDAX B cpi 32 ; highest user+1 for U option JM L04B9 XRA A RET ; L04B9: LXI H,User MVI E,12 L04BE: MOV A,M CPI '?' jrz L04CC MOV D,A LDAX B ANI 7FH CMP D MVI A,0 RNZ L04CC: INX B INX H DCR E jrnz L04BE DCX B LDA OpAFlg ORA A jrz L04DF MVI E,0 jr L04E8 ; L04DF: LDA OpZFlg ORA A jrz L04EE MVI E,80h L04E8: LDAX B XRA E RLC ANI 1 RZ L04EE: DCX B DCX B LDA OpOFlg ORA A jrz L04FC MVI E,0 jr L0505 ; L04FC: LDA OpWFlg ORA A jrz 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 jrnz 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) lda DskLbl ; do we use disk label ora a rz ; (nope) 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 xra a ret ; L0536: LXI H,0 LDA L0DA7 ORA A jrnz L054E MVI E,16 L0542: LDAX B ORA A jrz L0548 INX H L0548: INX B DCR E jrnz L0542 RET ; L054E: MVI E,8 L0550: LDAX B MOV D,A INX B LDAX B ORA D jrz L0559 INX H L0559: INX B DCR E jrnz 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 jrnc 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 jrnz L05EB LHLD L0DB3 INX H SHLD L0DB3 jr 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 jrnz L060B LHLD L0DB5 DCX H SHLD L0DB5 jr L05EE ; L060B: LHLD L0DB5 LDED L0DB3 ORA A DSBC D jrc 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 jrnc L06BA LHLD L0DB3 LDED L0DB9 ORA A DSBC D jrnc 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 jrnc 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 jrc 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 jrnc 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 jr 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 jrnz 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 jr L07D3 L07CB: LXI B,MsgDlm MVI A,3 CALL L0AE7 L07D3: LXI B,MsgNam MVI A,11 CALL L0AE7 LDA OpFFlg RAR jrc L07F9 LXI B,MsgByt MVI A,6 CALL L0AE7 LDA OpUFlg RAR jrnc L07F9 LXI B,MsgUsr MVI A,3 CALL L0AE7 L07F9: LXI H,L0DFA DCR M jrnz L07CB CALL PrtDvd LDED FilCnt LBCD MaxCol MVI B,0 CALL L0AAA MOV A,L ORA H jrz 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 jrnz L082D LHLD L0DF6 INX H SHLD L0DF6 LDED L0D9D ORA A DSBC D jrc 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 jrc L08F4 LXI B,12 LHLD L0DB0 DAD B MOV E,M INX H MOV D,M LBCD L0D9B CALL L0AC4 MVI A,5 CALL PrtNum LXI B,8 LHLD L0DB0 DAD B MVI E,'k' MOV A,M ORA A JP L08D0 MVI E,'r' 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 jrnc L08F4 LXI B,11 LHLD L0DB0 DAD B MOV L,M MVI H,0 MVI A,3 CALL PrtNum 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? jrz 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 jrnc L0930 DCX H L0930: DJNZ L0928 SHLD L0DFC CALL PagBrk LHLD FilCnt ; print number of matching files MVI A,1 CALL PrtNum LXI B,MsgFil LHLD FilCnt DCX H MOV A,L ORA H jrnz 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 PrtNum LXI B,MsgK CALL PrtNul LDED L0DFC ; print disk capacity LBCD L0D9B CALL L0AC4 MVI A,1 CALL PrtNum LXI B,MsgCap CALL PrtNul MVI C,CurDsk CALL Bdos PUSH PSW MVI C,GetRO CALL Bdos POP B INR B L0991: DJNZ L0996 jr L099C ; L0996: RARR H RARR L jr L0991 ; L099C: MOV A,L ANI 1 jrz L09AE CALL DimOn LXI B,MsgRO CALL PrtNul CALL DimOff L09AE: CALL PagBrk LHLD L0D99 ; print remaining directory entries MVI A,1 CALL PrtNum LXI B,MsgDir LHLD L0D99 DCX H MOV A,L ORA H jrnz 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 PrtNum lxi b,MsgRem ; print space remaining message call PrtNul lxi d,0 mvi c,CurDsk ; get drive call Bdos push psw ; save current drive ; 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 jrz AllUsr MOV L,A MVI H,0 MVI A,1 CALL PrtNum AllUsr: mvi e,':' ; print colon call ChrOut lda DskLbl ; doing disk label? ora a jrz SkLbl ; (nope) DoLbl: pop psw ; adjust stack lda LblUsr ; check for CP/M 3 disk label ora a jrz NoLbl ; (nope) lxi h,LblNam ; there is, so print it (11 chars) mvi b,11 jr PrtLbl ; SkLbl: 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 jrz NoLbl ; (none, skip it) mvi b,8 ; got it, so print it (8 chars) 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 ; ; 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 ; ; 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 lda ZReg ; get register number adi 30h ; add offset mov e,a mvi d,0 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 jr L0A7E L0A70: DCX H MOV A,L ORA H jrz L0A88 RLCR C jrnc L0A7C DCX D L0A7C: djnz L0A70 L0A7E: MVI B,8 ldx c,0 inxix jr 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 jrnz L0AA4 INX D INX B DCR L jrnz 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 jrnc L0ABE DAD B DCX D L0ABE: POP PSW DCR A jrnz L0AAF RET ; L0AC4: LXI H,0 MVI A,16 L0AC9: DAD H XCHG DAD H XCHG jrnc L0AD1 DAD B L0AD1: DCR A jrnz L0AC9 RET ; ; PrtDvd -- print '=' screen divider ; PrtDvd: call PagBrk PrtDv2: lda RevVid ora a cz DimOn lda HorSiz mov b,a PrtDLp: push b mvi e,'=' call ChrOut pop b djnz PrtDLp lda RevVid ora a cz DimOff 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 jr 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 jrz PagBr2 ; (none yet) cpi 3 ; control-C? jz ExitOK ; (yes, return to CP/M) lxi b,MsgEra ; erase page break message jr 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 jr PrtOut ; L0B2B: lda OpPFlg ; option P? ora a jrz SkpMsk ; (no, skip option P masking) CALL OpPOff lxi b,MsgCR ; send CR to console call PrtNul jr OpPOn ; SkpMsk: lxi b,MsgCR jr 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 jr OpPOn ; DimOff: call OpPOff lxi b,RegVid call PrtNul jr 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 jr 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 jr ChrOut ; ; PrtNum -- prints number in HL with leading spaces to console and, ; if selected, to printer. A contains number of characters to print. ; The entire number is printed, but it is padded with spaces only if ; takes fewer characters than number in A. ; PrtNum: STA L0DFE CALL L0BFF STA L0E00 INR A STA L0DFF L0BC6: LDA L0DFE LXI H,L0DFF CMP M jrc L0BDC MVI E,' ' CALL ChrOut LXI H,L0DFF INR M jr 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 jrnz L0BE1 RET ; L0BFF: XRA A PUSH PSW INX SP LXI D,262 L0C05: DCR E jrz L0C16 INR D CALL L0C25 ADI '0' PUSH PSW INX SP MOV A,L ORA H jrnz L0C05 L0C16: MOV E,D DCR E LXI B,L0E01 L0C1B: DCX SP POP PSW STAX B INX B DCR D jrnz L0C1B MOV A,E RET ; L0C25: LXI B,L100A ; 4106 XRA A L0C29: DAD H RAL CMP C jrc 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 'D Z-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 ',0 MsgHl1: 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',0 ; ; 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