home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
cpm86
/
lu86-2.lbr
/
LDIR86.AQ6
/
ldir6.a86
Wrap
Text File
|
1987-11-22
|
10KB
|
478 lines
;******************************************************************************
;
; PROGRAM: LDIR86.A86
; VERSION: 1.05
; DATE: 10 September 1984
; AUTHOR: Charlie Godet-Ceraolo
;
; DESCRIPTION: This is a version of LDIR for CP/M86 systems.
; It displays a directory of a LBR file. It accepts
; the LBR name on the command line, with or without
; the LBR extension. The Library filename can be
; followed by a (possibly ambiguous) filespec
; to search for in the library.
; Entering nothing on the command line will display
; a brief summary of the above.
;
; NOTES:
; I wrote the program with a view towards simplicity and clarity
; rather than speed or compactness. If you want to modify it,
; here are some things to keep in mind:
;
; 1. It uses the 8080 Model
; 2. It depends heavily on ALL the Segment Registers
; pointing to the same area of memory.
; 3. the ES register is saved across BDOS calls.
; 4. most routines save all scratch registers except
; those returning values.
;
;*******************************************************************************
;
; cpm86 equates
;
WCCFC EQU 02 ; write console character
OPNFC EQU 15 ; open file
RSRFC EQU 20 ; read sequential record from disk
;
; LU Dir entry equates and offsets
;
ENTRYLEN EQU 32
ACTIVE EQU 00H
UNUSED EQU 0FFH
DELETED EQU 0FEH
STATUS EQU 0
NAME EQU 1
EXTENSION EQU 9
INDEX EQU 12
COUNT EQU 14
CRC EQU 16
;
; Ascii equates
;
TAB EQU 09H
CR EQU 0DH
LF EQU 0AH
SPACE EQU ' '
ASCII_ZERO EQU '0'
EOS EQU 0H
NUM_ACROSS EQU 3 ; three across on a line
;
; CP/M86's BasePage
;
RB 5CH
FCB EQU $ ; default fcb
FCBDN RB 1
FCBFN RB 8
FCBFT RB 3
FCBEX RB 1
FCBS1 RB 1
FCBS2 RB 1
FCBRC RB 1
FCB2 EQU $ ; second fcb
FCBD0 RB 16
FCBCR RB 1
FCBRNO RB 3
BUFF EQU $
RB 80H ; default buffer
;
; Set up local stack
;
LDIR:
MOV DX,DS
MOV SS,DX
MOV SP,OFFSET LOCAL_STACK
CLD ; direction flg for increment
;
; Print signon message
;
MOV SI,OFFSET SIGNON
CALL PSTRING
CALL CRLF
;
; check for command line, display usage if none
;
MOV BX,OFFSET BUFF
MOV AL,[BX]
OR AL,AL ; zero means no command
JNZ cmdok ; we got one, proceed
;
; no command line, show usage and exit
;
CALL CRLF
MOV SI,OFFSET USEMSG
CALL PSTRING
CALL CRLF
JMP FINIS
;
; check for extension, add LBR if none
;
cmdok:
MOV AL,FCBFT
CMP AL,SPACE
JNZ extok
MOV SI,OFFSET LIBEXT
MOV CX,3
MOV DI,OFFSET FCBFT
REP MOVSB
;
; check for search request, use Joker (*.*) if none
;
extok:
MOV CX,11 ; bytes to move
MOV DI,OFFSET SEARCH_STR ; destination
MOV SI,OFFSET FCB2+1 ; assume fcb2
MOV AL,[SI]
CMP AL,SPACE ; anything there?
JNZ gotaname ; yes, move it
MOV SI,OFFSET JOKER ; no, move the joker
gotaname:
REP MOVSB ; move it
;
; try to open the file
;
CALL OPEN_FILE
CMP AL,255
JNZ OPENOK
;
; No file, send message and leave
;
MOV SI,OFFSET OPNMSG
CALL PSTRING
JMP FINIS
;
; file found and opened, get dir info
;
OPENOK:
XOR AX,AX ; initialize variables
MOV MAX_ENTRIES,AX
MOV IN_USE,AX
MOV AL,NUM_ACROSS
MOV ENTRIES_PRINTED,AL
CALL CRLF
;
CALL READ_SECTOR ; Get first sector
OR AL,AL
JZ readok ; if non-zero, we're at eof
;
; premature end of file, send message, and exit
;
MOV SI,OFFSET EOFMSG
CALL PSTRING
JMP FINIS
readok:
MOV BX,OFFSET BUFF ; point to first entry
MOV AX,COUNT[BX] ; get dir size in sectors
MOV CL,2
SHL AX,CL ; sectors * 4 = MAX_ENTRIES
MOV MAX_ENTRIES,AX ; save it
MOV ENTRIES_TO_DO,AX ; and our counter
INC IN_USE ; for the dir header
DEC ENTRIES_TO_DO ; likewise
;
ADD BX,ENTRYLEN ; point to next entry
MOV CX,3 ; allow for dir header
;
; Read and analyze entries until eof
;
MAIN:
MOV AL,STATUS[BX]
CMP AL,UNUSED ; first unused entry?
JZ FINALE ; yes, we're done
;
CMP AL,ACTIVE ; active entry?
JNZ skipit ; no, don't process it
;
INC IN_USE ; yes, bump counter
LEA DI,NAME[BX] ; point to name
CALL COMPARE ; does it match?
OR AL,AL
JNZ skipit ; nope, skip it
CALL DOENTRY ; else display info
skipit:
DEC ENTRIES_TO_DO ; have we read em all?
JZ FINALE ; yes, leave
ADD BX,ENTRYLEN ; no, point to next entry
LOOP MAIN ; and continue processing
;
CALL READ_SECTOR ; Get another sector
OR AL,AL ; Eof?
JNZ FINALE ; Yes, leave
MOV BX,OFFSET BUFF ; no, reset buffer pointer
MOV CX,4 ; and entries per buffer
JMP MAIN ; and process this sector
;
; display summary information
;
FINALE:
CALL CRLF
CALL CRLF
MOV SI,OFFSET MAXMSG
CALL PSTRING
MOV BX,MAX_ENTRIES
CALL DECIMAL_OUT
MOV SI,OFFSET FREEMSG
CALL PSTRING
SUB BX,IN_USE ; free slots = max - in use
CALL DECIMAL_OUT
CALL CRLF
;
; back to CP/M86, the easy way
;
FINIS:
MOV CL,0
MOV DX,0
INT 224
;
; SUBROUTINES
;
; compare filenames, including wildcards
; on entry DI points to the filename to match with Search_str
; all registers saved. Returns AL = 0 if a match, else AL = FF
;
COMPARE:
PUSH CX
PUSH SI
PUSH DI
MOV SI,OFFSET SEARCH_STR ; source
MOV CX,11 ; number of bytes to compare
cmploop:
LODS SEARCH_STR
CMP AL,'?'
JZ itmatches
CMP AL,[DI]
JNZ nomatch
itmatches:
INC DI
LOOP cmploop
MOV AL,0 ; if we got this far
JMP cmpexit ; it's a match, send 0
nomatch:
MOV AL,0FFH ; send FF, no match
cmpexit:
POP DI
POP SI
POP CX
RET
;
; process the entry pointed to by BX, all registers saved
;
DOENTRY:
PUSH BP ; save scratch registers
PUSH SI
PUSH AX
PUSH CX
MOV BP,BX ; for easier processing
LEA SI,NAME[BP] ; point to the name
CALL PFNAME ; print it
MOV BX,COUNT[BP] ; get the value
OR BX,BX ; is it zero?
JZ print_size ; yes, print it
MOV CL,3
SHR BX,CL ; convert to k
JNZ print_size ; print it, if non-zero
INC BX ; otherwise, make it at least one
print_size:
CALL DECIMAL_OUT ; print it
MOV AL,'k'
CALL WCC
DEC ENTRIES_PRINTED
JNZ do_separator
CALL CRLF
MOV AL,NUM_ACROSS
MOV ENTRIES_PRINTED,AL
JMP no_sep
do_separator:
MOV SI,OFFSET SEPARATOR
CALL PSTRING
no_sep:
MOV BX,BP ; restore caller's pointer
POP CX
POP AX
POP SI ; and scratch registers
POP BP
RET
;
; do bdos call, saving ES
;
BDOS:
PUSH ES
INT 224
POP ES
RET
;
WCC:
PUSH BX
PUSH DX
PUSH CX
MOV CL,WCCFC
MOV DL,AL
CALL BDOS
POP CX
POP DX
POP BX
RET
;
PSPACE:
PUSH AX
MOV AL,SPACE
CALL WCC
POP AX
RET
;
CRLF:
PUSH AX
MOV AL,CR
CALL WCC
MOV AL,LF
CALL WCC
POP AX
RET
;
OPEN_FILE:
XOR AL,AL
MOV FCBCR,AL
MOV FCBEX,AL
MOV FCBRC,AL
MOV DX,OFFSET FCB
MOV CL,OPNFC
CALL BDOS
RET
;
READ_SECTOR:
PUSH BX
PUSH DX
PUSH CX
MOV DX,OFFSET FCB
MOV CL,RSRFC
CALL BDOS
POP CX
POP DX
POP BX
RET
;
; Print null-terminated string pointed to by SI, saves all
;
PSTRING:
PUSH AX
PUSH SI
pstrloop:
LODS BYTE PTR [SI] ; get a character
OR AL,AL ; machine zero?
JZ pstrexit ; yes, exit
CALL WCC ; print it
JMP pstrloop ; get another
pstrexit:
POP SI
POP AX
RET
;
; Print filename pointed to by SI, all regs saved
;
PFNAME:
PUSH AX
PUSH CX
PUSH SI
MOV CX,8 ; number of chars in name
fnameloop:
LODS BYTE PTR [SI]
CALL WCC
LOOP fnameloop
MOV AL,'.'
CALL WCC
MOV CX,3 ; number of chars in extension
extloop:
LODS BYTE PTR [SI]
CALL WCC
LOOP extloop
POP SI
POP CX
POP AX
RET
;
; Print binary number in BX as Ascii decimal digits,
; replacing leading zeros by blanks. All regs saved
;
DECIMAL_OUT:
PUSH AX
PUSH BX ; save number
PUSH CX ; and scratch regs
PUSH DX
PUSH SI
;
MOV SI,0 ; 0 = no digit printed yet
; FF = digit already printed
MOV CX,10000
CALL PRINT_DIGIT ; 10 thousands
MOV CX,1000
CALL PRINT_DIGIT ; thousands
MOV CX,100
CALL PRINT_DIGIT ; hundreds
MOV CX,10
CALL PRINT_DIGIT ; tens
MOV AL,BL ; units
ADD AL,ASCII_ZERO ; Ascii bias
CALL WCC
;
POP SI
POP DX ; restore registers
POP CX
POP BX
POP AX
RET ; and back.
;
; divide number in bx by power of ten in cx. Return remainder
; in bx, and print quotient in al as an ascii digit.
;
PRINT_DIGIT:
XOR DX,DX ; clear high 16-bits
MOV AX,BX ; number into low 16-bits
DIV CX ; divide by word in cx
MOV BX,DX ; return remainder in bx
ADD AL,ASCII_ZERO ; Ascii bias
;
; Check for zero
;
CMP AL,ASCII_ZERO ; zero or less?
JA nonzero ; no
OR SI,SI ; yes, check digit printed flag
JZ spacexit ; leading zero --> leading blank
CALL WCC ; print interior zero
RET
spacexit:
CALL PSPACE ; print leading blank
RET
;
nonzero:
MOV SI,0FFH ; set flag for digit printed
CALL WCC ; print it
RET
;
; initialized data area
;
SIGNON DB 'LDIR86 v1.06',EOS
JOKER DB '???????????' ; = '*.*'
USEMSG DB TAB,'USAGE: LDIR86 LibName[.LBR] [afn]',CR,LF
DB TAB,TAB,'afn = ambiguous file name',EOS
OPNMSG DB 'Library file not found',EOS
LIBEXT DB 'LBR',EOS
EOFMSG DB 'Premature End of File',EOS
SEPARATOR DB ' | ',EOS
MAXMSG DB 'Max Slots:',EOS
FREEMSG DB ', Free Slots:',EOS
;
; uninitialized data area
;
MAX_ENTRIES RW 1 ; size of dir
IN_USE RW 1 ; Max - inuse = free
ENTRIES_TO_DO RW 1 ; how many so far
ENTRIES_PRINTED RB 1 ; on a line
SEARCH_STR RS 11 ; for fcb2 fname
;
; stack area
;
RB 100
LOCAL_STACK EQU $
DB 0 ; so GENCMD will save data area
;
END