;------------------------------------------------------------------------------ ; ; A simple DIR program (with some extra features) ; ; Written to provide a substitute for the simple DIR and DIRSYS ; commands not supported internally by CCP103+. ; ; dir {du:}{filespec} or dirsys {du:}{filespec} ; ; du: is optional and can be any combination of a valid drive ; and/or user number, e.g. 13:, b:, b13:, 13b: or even 1b3: ; ; filespec is also optional and is a standard ambiguous or unambiguous ; file name. ; ; Program automatically adjusts directory display to the size of the ; host system's console screen. ; ; Create two versions of this program, DIR.COM and DIRSYS.COM (or ; DIRS.COM if you prefer the shorter form of the DIRSYS command). ; Put the two commands in COMMAND.LBR if you wish, and rename the ; standard DIR.COM to something else, e.g. XD.COM. ; ; To create the two versions, alter the byte at label 'dirsys:' ; appropriately and reassemble. Alternatively you may patch the ; fourth byte in the object code (103h) to zero for DIR or non-zero ; for DIRSYS. ; ; This program can be assembled with either Microsoft's M80 or the ; ex-Cromemco public domain ZASM assembler without altering the source ; code. (Note the /z switch and the .z80 extension in the M80 case.) ; ; For M80/L80 :- or ZASM/PROLINK :- ; ; m80 =dir.z80/z zasm dir.@@z ; l80 dir,dir/n/e pl link dir;exit ; ; Jon Saxton, ; P.O. Box 242, ; Dural, NSW 2158 ; Australia ; ;------------------------------------------------------------------------------ ; ; 19 Apr 87 - JRS ; ; Amended to sidestep an occasional weirdness which caused program ; to erroneously report "Invalid drive/user". ; ;------------------------------------------------------------------------------ BS equ 8 HT equ 9 CR equ 13 LF equ 10 BDOS equ 5 CONIN equ 1 CONOUT equ 2 PRINT equ 9 SRCH1ST equ 17 SRCHNXT equ 18 GETDRV equ 25 GSUSER equ 32 GSSCB equ 49 PARSEFN equ 152 PAGEMODE equ 2Ch ;Index of page mode byte in SCB PAGELEN equ 1Ch ;Index of console page length in SCB CONWIDTH equ 1Ah ;Index of console width in SCB ;begin: ;Linker inserts jp setStack at the beginning ; jp setStack ;of the object file (see 'end' statement) dirsys: defb 0 ;Set non-0 to display system files setStack: ld hl,(BDOS+1) ;Set stack up under the BDOS ld l,0 ld sp,hl ld a,(dirsys) ;Normalise the DIRSYS flag to 0 or 80h or a jr z,getLPS ld a,80h ld (dirsys),a getLPS: ld de,scbpb ;Get number of lines on screen push de ld a,PAGELEN ld (de),a ld c,GSSCB call cpm dec a ;One less to allow for [more] prompt ld (lpp),a ld (lines),a pop de ;Get console width ld a,CONWIDTH ld (de),a ld c,GSSCB call cpm ld b,8 ld c,a ld a,15*8+1 getNPL: ;Calculate names per line (maximum 8) cp c jr c,setNPL sub 15 djnz getNPL setNPL: ld a,b ld (npl),a ld (count),a xor a ;Clear the user number ld ix,du ld (ix+1),a ld c,GSUSER ;Get current user number ld e,0FFh call cpm ld (curUsr),a ;Store it as default ld c,GETDRV ;Get current disk call cpm inc a ld (ix+0),a ;Store it as default ld hl,80h ;Look at command-line tail skipWs: inc hl ld a,(hl) ;Get a character cp ' ' ;Skip leading white space jr z,skipWs cp HT jr z,skipWs ld b,4 ;Colon must be in first 4 characters push hl findColon: ld a,(hl) ;Fetch byte from command tail or a jr z,noColon ;Exit [not found] if end of command tail cp ':' jr z,colon ;Exit [found] inc hl ;Step the pointer djnz findColon noColon: inc a colon: pop hl ;Point back at command line jr nz,duDone ;Skip if there wasn't a colon ;If we get here then there was a colon in the command tail. We will ;rescan that part of the command tail preceeding the colon and attempt ;to extract a drive/user specification. nxtChr: ld a,(hl) ;Pick up a byte from the command tail inc hl cp ':' ;Test for colon terminator jr z,duDone ;Exit if done cp '0' ;Check for a digit jr c,chkDrv cp '9'+1 jr nc,chkDrv call cnvUsr ;Build user number jr nxtChr chkDrv: cp 'A' ;Check for A-P jr c,badDU ;Error if out of range cp 'Q' jr nc,badDU sub 'A'-1 ;Convert A-P to 1-16 ld (ix+0),a jr nxtChr badDU: ld de,invDU prtXit: ld c,PRINT call cpm rst 0 cnvUsr: sub '0' ld c,a ld a,(ix+1) add a,a ;x2 add a,a ;x4 add a,(ix+1) ;x5 add a,a ;x10 add a,c ld (ix+1),a ld a,1 ld (gotUsr),a ret duDone: ld a,(gotUsr) ;Did we get user number from command line? or a jr z,noUsr ld a,(ix+1) ld e,a ld (curUsr),a ld c,GSUSER ;Set user number to match command line push hl call cpm ;Just a temporary change pop hl noUsr: ; At this point we are in the correct user area for the DIR command, ; the byte at DU: holds the required disk drive number (or zero for ; current drive) and HL points at the beginning of the file spec. ld a,(hl) ;If file specification is empty then or a ;we leave the default *.* alone jr z,setDrv ld (pfcb),hl ;Let CP/M 3 do all the hard work ld de,pfcb ;in setting up the FCB for the ld c,PARSEFN ;directory search call cpm setDrv: ld a,(ix+0) ;Pick up drive number ld de,fcb ld (de),a ;Plug into directory FCB getDir: ld hl,dirFn ld c,(hl) ld a,SRCHNXT ld (hl),a call cpm ;Get directory data cp 0FFh ;Test for end jr z,others? ld de,81h ;Offset to first byte of file name rept 5 ;Build pointer to file name add a,a endm ld l,a ld h,0 add hl,de push hl ;Save file name pointer ld de,9 ;Offset to T2 byte of file name [SYS|DIR] add hl,de ld a,(dirsys) xor (hl) bit 7,a ;Test if SYS or DIR matches dirsys jr z,printIt ld a,1 ld (others),a pop hl jr getDir printIt: ld hl,npl ld a,(count) ;Count files displayed on this line cp (hl) ;At end of line? call z,newLine ;Yes - start new line, .. call z,putDU ;.. and print drive/user call nz,fence ;No - print separator inc a ;Increment count of files on this line ld (count),a ;Store count for next time pop hl ;Recover file name pointer call printFn ;Display current file name ld a,1 ;Signal that we have displayed some files ld (some),a jr getDir others?: ld a,(others) ;See if we found ANY files at all ld b,a ld a,(some) or b ld de,noFiles jp z,prtXit ;Tell user if none xor a or b ;See if any undisplayed files jp z,0 ;Exit if none ld de,crlf ;Start a new line ld c,PRINT call cpm ld de,s ld a,(dirsys) or a jp z,prtXit ld de,nonS ld c,PRINT call cpm ld de,ystem jp prtXit newLine: ld a,(some) ;Is this the first time through? or a jr z,noNL ;Yes - do nothing ld de,crlf ;No - start new line ld c,PRINT call cpm ld a,(lines) ;Count number of lines displayed dec a ld (lines),a jr nz,noNL ;Skip if not at end of screen ld c,GSSCB ;Find out if console paging is in effect ld de,scbpb ld a,PAGEMODE ld (de),a call cpm or a jr nz,noNL ;Skip if not paging ld de,more ;Display [more] prompt ld c,PRINT call cpm ld c,CONIN ;Wait for a keystroke call cpm ld de,backSpace ;Backspace over the prompt and response ld c,PRINT call cpm ld a,(lpp) ;Reset lines per page ld (lines),a noNL: xor a ret fence: ;Display file name separator push af ld de,separator ld c,PRINT call cpm pop af ret printFn: ;Display file name @HL ld b,8 call outStr push hl ld e,'.' call outChr pop hl ld b,3 call outStr ret outStr: ;Print string @HL for B bytes ld e,(hl) res 7,e inc hl push hl push bc call outChr pop bc pop hl djnz outStr ret outChr: ;Print a single character from E register ld c,CONOUT call cpm ret putDU: push af call putDrv call putUsr ld e,':' call outChr pop af ret putDrv: ;Display drive letter ld a,(ix+0) add a,'A'-1 ld e,a call outChr ret putUsr: ld a,(curUsr) cp 10 ;Two digits? jr c,uLow ;No - just one sub 10 ;Yes - output '1' and then the low-order digit push af ld e,'1' call outChr pop af uLow: add a,'0' ld e,a call outChr ret cpm: push ix call BDOS pop ix ret ;---------------------------------------------- crlf: defb CR,LF,'$' separator: defb ' | $' count: defs 1 lines: defs 1 lpp: defs 1 npl: defs 1 some: defb 0 others: defb 0 dirFn: defb SRCH1ST du: defw 0 ;Drive/user from command line curUsr: defs 1 ;Current user number gotUsr: defb 0 ;Flag for command-line user number fcb: defb 0 defb '????????' defb '???' defw 0,0,0,0,0,0,0,0,0,0 pfcb: defw 0 defw fcb scbpb: defs 1 defb 0 defs 2 invDU: defb 'Illegal drive/user$' nonS: defb 'Non-s$' S: defb 'S' ystem: defb 'ystem files exist$' noFiles: defb 'No files found$' more: defb '[more] $' backSpace: rept 15 defb BS endm defb '$' end setStack