home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
simtel
/
sigm
/
vols000
/
vol043
/
sd.a86
< prev
next >
Wrap
Text File
|
1984-04-29
|
15KB
|
643 lines
;
; SD.A86
; (revised 05/05/81)
;
; SUPER DIRECTORY PROGRAM
; by Bruce R. Ratoff
;
;Displays the directory of a CP/M disk, sorted alphabetically,
;with the file size in K, rounded to the nearest CP/M block size.
;
;This latest variation on a common theme will automatically adjust
;itself for any block size and directory length under CP/M 1.4 or 2.x
;or MP/M (any version). If the screen fills, program will pause until
;a key is struck (see NPL and LPS equates below). Total space used
;and number of files are printed at end.
;
;Command: SD FILENAME.FILETYPE or just SD
;
;Allows '*' or '?' type specifications. Drive name may also be
;specified. Ignores "SYS" files unless SOPT is TRUE and 'S' option
;is given (i.e., SD *.* S will print all files).
;
;05/03/81 First 8086 version. (Bruce R. Ratoff)
;
;01/21/81 Fixed print abort test so it would work like "DIR"
; [aborts on any character, or on ^S, ^C].
; (ASB)
;
;
;01/06/81 Made output go through BDOS so if the printer was on,
; you could get the output on it. The ^S test was rendered
; useless, as was the ^C test, as BDOS buffers one character
; ahead when it is writing out to the console. [You now need
; to do a ^S ^C combonation to abort, and the size message
; is not printed, but I don't think that is a major problem.]
; (Andrew S. Beals)
;
;01/06/81 Added conditional assembly to print user number when in CP/M
; 2.x. (ASB)
;
;12/15/80 Added space suppression when printing file
; totals. (KBP)
;
;12/14/80 Added logic to print space remaining on disk.
; Changed ^C test so that interrupting character is
; not echoed (makes remote use cleaner). (BRR)
;
;12/02/80 Fixed bug in print routine which compared last file
; against garbage before printing. (BRR)
;
;11/29/80 Changed to allow printing 4 file names. (Ben Bronson
; and Keith Petersen)
;
;11/22/80 Fixed bug in handling >256 files. Changed abort test in
; print routine to only abort on control-c. (brr)
;
;Based on 'DIRS' by Keith Petersen, W8SDZ
;
;Set 'RMAC' TRUE to assemble with relocating assembler (requires
;link with PAGE 0 equates in separate file).
;
FALSE EQU 0 ;DEFINE LOGICAL FALSE
TRUE EQU NOT FALSE ;DEFINE LOGICAL TRUE
;
SOPT EQU TRUE ;PUT TRUE TO ALLOW 'DIR *.* S' FORM
WIDE EQU true ;PUT TRUE TO ALLOW 4 NAMES ACROSS
user equ true ;print user numbers for cp/m 2.x also?
;
;
;
BASE EQU 0
TPA EQU 100H
;
FCB EQU 5CH
;
IF WIDE
NPL EQU 4 ;NUMBER OF NAMES PER LINE
ENDIF
;
IF NOT WIDE
NPL EQU 3 ;NUMBER OF NAMES PER LINE
ENDIF
;
LPS EQU 23 ;NUMBER OF LINES PER SCREEN
DELIM EQU ':' ;FENCE (DELIMITER) CHARACTER
;
org TPA
;
START:
cld
;
IF SOPT
mov al,byte ptr .FCB+17 ;SAVE S OPTION FLAG
mov SOPFLG,al ;(BLANK OR LETTER S)
ENDIF
;
mov USERNO,0 ;DEFAULT TO USER 0
mov LINCNT,0 ;CLEAR COUNT OF LINES ON SCREEN
mov cl,12
CALL BDOS ;CHECK CP/M VERSION
mov word ptr VERFLG,bx ;LO ORD >0 IF 2.X, HI ORD>0 IF MP/M
mov dl,0FFH
mov cl,CURUSR ;INTERROGATE USER NUMBER
CALL BDOS
mov USERNO,al
;
if not user
mov al,MPMFLG ;MP/M?
test al,al ;IF SO, TYPC HEADING LINE
JZ CHKDRV ; ELSE SKIP IT
endif
;
mov dx,offset USRMSG ;DISPLAY IT
mov cl,PRINT
CALL BDOS ;FIRST PART OF MESSAGE
mov al,USERNO
cmp al,10 ;IF USER NO. > 9 PRINT LEADING 1
JB DUX
mov al,'1'
CALL TYPC
mov al,USERNO ;PRINT LOW DIGIT OF USER NO.
sub al,10
;
DUX: add al,'0'
CALL TYPC
mov dx,offset USRMS2 ;PRINT TAIL OF MESSAGE
mov cl,PRINT
CALL BDOS
mov LINCNT,1 ;WE USED A LINE
;
CHKDRV: mov si,offset FCB
lods al ;get drive name
test al,al ;ANY SPECIFIED?
JNZ START2 ;YES SKIP NEXT ROUTINE
mov cl,CURDSK
CALL BDOS ;GET CURRENT DISK NR
inc al ;MAKE A:=1
mov byte ptr .FCB,al
;
START2: add al,'A'-1 ;MAKE IT PRINTABLE
mov DRNAM,al ;SAVE FOR LATER
mov di,offset FCB+1 ;POINT TO NAME
mov al,[di] ;ANY SPECIFIED?
cmp al,' '
JNZ GOTFCB
;No FCB - make FCB all '?'
mov cx,11 ;FN+FT COUNT
mov al,'?'
;
rep stos al ;fill fcb with '?'
;
GOTFCB:
mov byte ptr .FCB+12,'?' ;FORCE WILD EXTENT
mov al,byte ptr .FCB ;CHECK FOR EXPLICIT DRIVE
dec al
mov dl,al ;SELECT SPECIFIED DRIVE
mov cl,SELDSK
CALL BDOS
mov byte ptr .FCB,0
;
mov cl,CURDPB;IT'S 2.X OR MP/M...REQUEST DPB
push es ;save current extra segment
int 224 ;return bx=offset dpb, es=segment dpb
add bx,2
mov al,es: [bx]
mov BLKSHF,al ;GET BLOCK SHIFT
inc bx ;BUMP TO BLOCK MASK
mov al,es: [bx]
mov BLKMSK,al
add bx,2
mov ax,es: [bx]
mov BLKMAX,ax
add bx,2
mov ax,es: [bx]
mov DIRMAX,ax ;SAVE IT
pop es ;restore our extra segment
;
SETTBL: inc ax ;DIRECTORY SIZE IS DIRMAX+1
shl ax,1 ;DOUBLE DIRECTORY SIZE
add ax,offset ORDER ;TO GET SIZE OF ORDER TABLE
mov TBLOC,ax ;NAME TABLE BEGINS WHERE ORDER TABLE ENDS
mov NEXTT,ax
mov bx,word ptr .BASE+6 ;MAKE SURE WE HAVE ROOM TO CONTINUE
cmp ax,bx
jb SFIRST
JMP OUTMEM
;
;Look up the FCB in the directory
;
SFIRST: mov cl,FSRCHF ;GET 'SEARCH FIRST' FNC
mov dx,offset FCB
CALL BDOS ;READ FIRST
inc al ;WERE THERE ANY?
JNZ SOME ;GOT SOME
;
NONE: mov dx,offset FNF ;PREPARE MP/M ERROR MESSAGE
mov al,MPMFLG
test al,al ;USE IT IF REALLY MP/M
jz NOFILE
JMP ERXIT1
NOFILE: CALL ERXIT ;ELSE USE CP/M ERROR MESSAGE
DB 'NO FILE$'
FNF DB 'File not found.$'
;
USRMSG DB 'Directory for user $'
USRMS2 DB ':',13,10,'$'
;
;Read more directory entries
;
MORDIR: mov cl,FSRCHN ;SEARCH NEXT
mov dx,offset FCB
CALL BDOS ;READ DIR ENTRY
inc al ;CHECK FOR END (0FFH)
JZ SPRINT ;NO MORE - SORT & PRINT
;
;Point to directory entry
;
SOME: dec al ;UNDO PREV 'INR A'
mov cl,5
shl al,cl ;entry no. times 32
mov ah,0
add al,80h
mov bx,ax ;POINT TO BUFFER
;(SKIP TO FN/FT)
;
IF SOPT
mov al,SOPFLG ;DID USER REQUEST SYS FILES?
cmp al,'S'
JZ SYSFOK
ENDIF
;
test byte ptr 10[bx],80H ;check bit 7 of SYS byte
JNZ MORDIR ;SKIP THAT FILE
;
SYSFOK: mov al,USERNO ;GET CURRENT USER
cmp al,[bx]
JNZ MORDIR ;IGNORE IF DIFFERENT
inc bx
;
;Move entry to table
;
mov si,bx ;si points to name
mov di,NEXTT ;NEXT TABLE ENTRY TO di
mov cx,12 ;ENTRY LENGTH (NAME, TYPC, EXTENT)
;
TMOVE: lods al ;GET ENTRY CHAR
and al,7FH ;REMOVE ATTRIBUTES
stos al ;store in table
loop TMOVE
mov al,2[si] ;get sector count
MOV [di],al ;STORE IN TABLE
inc di
mov NEXTT,di ;SAVE UPDATED TABLE ADDR
inc COUNT
add di,13 ;SIZE OF NEXT ENTRY
sub di,word ptr .BASE+6 ;PICK UP TPA END
JB MORDIR ;IF TPA END>NEXTT THEN LOOP BACK FOR MORE
;
OUTMEM: CALL ERXIT
DB 'Out of memory.',13,10,'$'
;
;Sort and print
;
SPRINT: mov cx,COUNT ;GET FILE NAME COUNT
test cx,cx
jnz SPRINI
jmp NONE ;NONE, EXIT
;Init the order table
SPRINI: mov ax,TBLOC ;GET START OF NAME TABLE
mov di,offset ORDER ;POINT TO ORDER TABLE
;
BLDORD: stos ax
add ax,13
loop BLDORD
mov bx,COUNT ;GET COUNT
mov SCOUNT,bx ;SAVE AS # TO SORT
dec bx ;only 1 entry?
JZ DONE ;..YES, SO SKIP SORT
;
SORT: mov SWITCH,0 ;SHOW NONE SWITCHED
mov bx,SCOUNT ;GET COUNT
dec bx ;use 1 less
mov word ptr TEMP,bx ;SAVE # TO COMPARE
mov SCOUNT,bx ;SAVE HIGHEST ENTRY
JZ DONE ;EXIT IF NO MORE
mov bx,offset ORDER ;POINT TO ORDER TABLE
;
SORTLP: mov cx,12 ;# BYTES TO COMPARE
CALL COMPR ;COMPARE 2 ENTRIES
jbe NOSWAP
CALL SWAP ;SWAP IF NOT IN ORDER
NOSWAP: add bx,2 ;bump order table ptr
dec TEMP ;BUMP COUNT
JNZ SORTLP ;CONTINUE
;One pass of sort done
mov al,SWITCH ;ANY SWAPS DONE?
test al,al
JNZ SORT
;
;Sort is all done - print entries
;
DONE: mov bx,offset ORDER
mov NEXTT,bx
;
;Print an entry
;
IF NOT WIDE
CALL DRPRNT ;PRINT DRIVE NAME
ENDIF
mov cx,NPL ;NR. OF NAMES PER LINE
mov TOTSIZ,0 ; TOTAL K USED
mov TOTFIL,0 ; AND TOTAL FILES
;
ENTRY: mov bx,COUNT ; CHECK COUNT OF REMAINING FILES
dec bx ; skip compare if only 1 left
JZ OKPRNT
PUSH cx
;
mov cl,dconio ;get console status
mov dl,0ffh
call bdos
test al,al ;char?
jz nobrk ;no char, bypass the other stuff
jmp exit ;abort
;
NOBRK: mov bx,NEXTT
mov cx,11
CALL COMPR ;DOES THIS ENTRY MATCH NEXT ONE?
pop cx
JNE OKPRNT ;NO, PRINT IT
add bx,2 ;SKIP, SINCE HIGHEST EXTENT COMES LAST IN LIST
mov NEXTT,bx
dec COUNT ;COUNT DOWN
JMP ENTRY ;GO GET NEXT
;
OKPRNT:
push cx
;
IF NOT WIDE
CALL FENCE ;PRINT FENCE CHAR AND SPACE
ENDIF
;
mov bx,NEXTT ;GET ORDER TABLE POINTER
mov si,[bx]
add bx,2
mov NEXTT,bx ;SAVE UPDATED TABLE POINTER
mov cx,8 ;FILE NAME LENGTH
CALL TYPCIT ;TYPC FILENAME
mov al,'.' ;PERIOD AFTER FN
CALL TYPC
mov cx,3 ;GET THE FILETYPC
CALL TYPCIT
mov dl,[si]
mov dh,0
inc si
mov al,[si] ;GET SECTOR COUNT OF LAST EXTENT
mov cl,4 ;# OF EXTENTS TIMES 16K
shl dx,cl
ADD al,BLKMSK ;ROUND LAST EXTENT TO BLOCK SIZE
mov cl,3
shr al,cl ;CONVERT FROM SECTORS TO K
mov ah,0
add dx,ax ;add to total K
mov al,BLKMSK ;GET SECTORS/BLK-1
mov cl,3
shr ax,cl ;CONVERT TO K/BLK
not ax ;USE TO FINISH ROUNDING
and dx,ax
add TOTSIZ,dx ;add to total used
inc TOTFIL ;INCREMENT FILE COUNT
mov ax,dx ;GET BACK FILE SIZE
CALL DECPRT ; AND PRINT IT
mov al,'k' ;FOLLOW WITH K
CALL TYPC
;
IF NOT WIDE
CALL SPACE
ENDIF
;
;See if more entries
;
dec COUNT ;COUNT DOWN ENTRIES
pop cx
JZ PRTOTL ;IF OUT OF FILES, PRINT TOTALS
DEC CX ;ONE LESS ON THIS LINE
jz DOCRLF
;
IF WIDE
CALL FENCE ;NO CR-LF NEEDED, DO FENCE
ENDIF
;
jmps NOCRLF
;
DOCRLF: CALL CRLF ;CR-LF NEEDED
NOCRLF: JMP ENTRY
;
;Print HL in decimal with leading zero suppression
;
DECPRT: ;CLEAR LEADING ZERO FLAG
mov LZFLG,0
mov bx,1000 ;PRINT 1000'S DIGIT
CALL DIGIT
mov bx,100 ;ETC
CALL DIGIT
mov bx,10
CALL DIGIT
add al,'0' ;GET 1'S DIGIT
JMP TYPC
;
DIGIT: mov dx,0 ;init hi order dividend
div bx ;divide ax by digit value (dx gets rmdr)
add al,'0' ;convert to ASCII digit
;
cmp al,'0' ;ZERO DIGIT?
JNZ DIGNZ ;NO, TYPC IT
mov al,LZFLG ;LEADING ZERO?
test al,al
mov al,'0'
JNZ DIGPR ;PRINT DIGIT
mov al,SUPSPC ;GET SPACE SUPPRESSION FLAG
test al,al ;SEE IF PRINTING FILE TOTALS
jz DIGNP ;YES, DON'T GIVE LEADING SPACES
mov al,' '
JMPS DIGPR ;LEADING ZERO...PRINT SPACE
;
DIGNZ: mov LZFLG,0ffh ;SET LEADING ZERO FLAG SO NEXT ZERO PRINTS
DIGPR: call TYPC ;AND PRINT DIGIT
DIGNP: mov ax,dx ;set up remainder for next digit
ret
;
;Show total space and files used
;
PRTOTL: mov SUPSPC,0 ;SUPPRESS LEADING SPACES IN TOTALS
CALL CRLF ;NEW LINE (WITH PAUSE IF NECESSARY)
;
IF WIDE
mov dx,offset TOTMS1 ;PRINT FIRST PART OF TOTAL MESSAGE
ENDIF
;
IF NOT WIDE
mov dx,offset TOTMS1+1 ;PRINT FIRST PART OF TOTAL MESSAGE
ENDIF
;
mov cl,PRINT
CALL BDOS
mov ax,TOTSIZ ;PRINT TOTAL K USED
CALL DECPRT
mov dx,offset TOTMS2;NEXT PART OF MESSAGE
mov cl,PRINT
CALL BDOS
mov ax,TOTFIL ;PRINT COUNT OF FILES
CALL DECPRT
mov dx,offset TOTMS3;TAIL OF MESSAGE
mov cl,PRINT
CALL BDOS
mov cl,GALLOC ;GET ADDRESS OF ALLOCATION VECTOR
push es ;save our ES
int 224 ;return bx=offset ALV, es=segment ALV
mov dx,BLKMAX ;GET ITS LENGTH
inc dx
mov cx,0 ;INIT BLOCK COUNT TO 0
;
GSPBYT: PUSH bx ;SAVE ALLOC ADDRESS
mov al,es: [bx]
mov bl,8 ;SET TO PROCESS 8 BLOCKS
;
GSPLUP: shl al,1 ;TEST BIT
JB NOTFRE
inc cx
;
NOTFRE: dec dx ;COUNT DOWN BLOCKS
JZ ENDALC ;QUIT IF OUT OF BLOCKS
dec bl ;COUNT DOWN 8 BITS
JNZ GSPLUP ;DO ANOTHER BIT
POP bx ;BUMP TO NEXT BYTE
INC bx ;OF ALLOC. VECTOR
JMPS GSPBYT ;PROCESS IT
;
ENDALC: pop es ;restore our es
mov ax,cx
mov cl,BLKSHF ;GET BLOCK SHIFT FACTOR
sub cl,3 ;CONVERT FROM SECTORS TO K
JZ PRTFRE ;SKIP SHIFTS IF 1K BLOCKS
;
shl ax,cl ;mult blks by k/blk
;
PRTFRE: CALL DECPRT ;PRINT K FREE
mov dx,offset TOTMS4
mov cl,PRINT
CALL BDOS
JMP EXIT ;ALL DONE...RETURN TO CP/M
;
TOTMS1 DB ' : Total of $'
DRNAM equ TOTMS1
TOTMS2 DB 'k in $'
TOTMS3 DB ' files with $'
TOTMS4 DB 'k space remaining.$'
;
FENCE:
IF WIDE
CALL SPACE
ENDIF
mov al,DELIM ;FENCE CHARACTER
CALL TYPC ;PRINT IT, FALL INTO SPACE
;
SPACE: mov al,' '
;
;Type character in A
;
TYPC: PUSH cx
PUSH dx
push bx
push si
mov dl,al ;use bdos calls, that's what they're there for
mov cl,dconio
call bdos
pop si
POP bx
POP dx
POP cx
RET
;
TYPCIT: lods al
CALL TYPC
loop TYPCIT
RET
;
;Fetch character from console (without echo)
;
CINPUT: mov cl,dconio
mov al,0ffh
call BDOS
and al,7FH
jz CINPUT
RET
;
CRLF: mov al,LINCNT ;CHECK FOR END OF SCREEN
inc al
cmp al,LPS
JB NOTEOS ;SKIP MESSAGE IF MORE LINES LEFT ON SCREEN
mov dx,offset EOSMSG;SAY WE'RE PAUSING FOR INPUT
mov cl,PRINT
CALL BDOS
CALL CINPUT ;WAIT FOR CHAR.
mov al,0 ;SET UP TO ZERO LINE COUNT
;
NOTEOS: mov LINCNT,al ;SAVE NEW LINE COUNT
mov al,13 ;print cr
call TYPC
mov al,10 ;lf
call TYPC
;
IF NOT WIDE
CALL DRPRNT ;DRIVE NAME
ENDIF
;
mov cx,NPL ;RESET NUMBER OF NAMES PER LINE
RET
;
EOSMSG DB 13,10,'(Strike any key to continue)$'
;
IF NOT WIDE
DRPRNT: mov al,DRNAM
JMP TYPC
ENDIF
;
;Compare routine for sort
;
COMPR: mov si,[bx]
mov di,2[bx]
repe cmps al,al
ret
;
;
;Swap entries in the order table
;
SWAP: mov SWITCH,1 ;SHOW A SWAP WAS MADE
mov dx,[bx]
xchg dx,2[bx]
mov [bx],dx
ret
;
;Error exit
;
ERXIT: POP dx ;GET MSG
;
ERXIT1: mov cl,PRINT
;
CALLB: CALL BDOS ;PERFORM REQUESTED FUNCTION
;
;(fall into exit)
;Exit - all done, restore stack
;
EXIT: mov cl,0 ;exit is via BDOS call 0
;
BDOS: push es ;preserve es thru bdos call
int 224 ;call bdos 8086 style
pop es
ret
;
;Temporary storage area
;
BLKSHF DB 0 ;# SHIFTS TO MULT BY SEC/BLK
BLKMSK DB 0 ;SEC/BLK - 1
BLKMAX DW 0 ;HIGHEST BLOCK # ON DRIVE
DIRMAX DW 0 ;HIGHEST FILE # IN DIRECTORY
TOTSIZ DW 0 ;TOTAL SIZE OF ALL FILES
TOTFIL DW 0 ;TOTAL NUMBER OF FILES
LINCNT DB 0 ;COUNT OF LINES ON SCREEN
TBLOC DW 0 ;POINTER TO START OF NAME TABLE
NEXTT DW 0 ;NEXT TABLE ENTRY
COUNT DW 0 ;ENTRY COUNT
SCOUNT DW 0 ;# TO SORT
SWITCH DB 0 ;SWAP SWITCH FOR SORT
SUPSPC DB 0FFH ;LEADING SPACE FLAG FOR DECIMAL RTN.
BUFAD DW BASE+80H ;OUTPUT ADDR
SOPFLG db 0 ;SET TO 'S' TO ALLOW SYS FILES TO PRINT
USERNO db 0 ;CONTAINS CURRENT USER NUMBER
TEMP dw 0 ;SAVE DIR ENTRY
VERFLG db 0 ;VERSION FLAG
MPMFLG db 0 ;MP/M FLAG
LZFLG db 0 ;0 WHEN PRINTING LEADING ZEROS
ORDER EQU $ ;ORDER TABLE STARTS HERE
;
;BDOS equates
;
RDCHR EQU 1 ;READ CHAR FROM CONSOLE
WRCHR EQU 2 ;WRITE CHR TO CONSOLE
DCONIO EQU 6 ;direct console i/o
PRINT EQU 9 ;PRINT CONSOLE BUFF
CONST EQU 11 ;CHECK CONS STAT
SELDSK EQU 14 ;SELECT DISK
FOPEN EQU 15 ;0FFH=NOT FOUND
FCLOSE EQU 16 ; " "
FSRCHF EQU 17 ; " "
FSRCHN EQU 18 ; " "
CURDSK EQU 25 ;GET CURRENTLY LOGGED DISK NAME
GALLOC EQU 27 ;GET ADDRESS OF ALLOCATION VECTOR
CURDPB EQU 31 ;GET CURRENT DISK PARAMETERS
CURUSR EQU 32 ;GET CURRENTLY LOGGED USER NUMBER (2.x ONLY)
;
END