home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
ENTERPRS
/
CPM
/
UTILS
/
S
/
XLINK10.LBR
/
XLINK.1Z0
/
XLINK.180
Wrap
Text File
|
2000-06-30
|
15KB
|
516 lines
; XLINK - A routine to display names of files with cross-linked clusters.
;
; Written: 03/29/90
; By: Tony Newman
;
; Written for assembly by SLR Systems: SLR180+.
; Should assemble under Microsoft's MACRO-80 with no modification.
;
; All external references are to SYSLIB (ver. 4) routines.
;
; Released for public distribution and modification.
;
;============================================================================
;
;
; General operating system equates.
;
exit equ 0000H ;warmstart
bdos equ 0005H ;C-function entry point
stack equ 0006H ;pointer to first address used by O/S
dbuff equ 0080H ;default DMA area
;
; Character equates
;
bel equ 07H ;<bell> character
bs equ 08H ;backspace
cr equ 0DH ;carriage return
lf equ 0AH ;linefeed
spc equ 20H ;<space> character
;
; Current version
;
major equ 1
minor equ 0
jp setstk ;skip over user setable bytes
qflg: db 0 ;initially, quiet-flag is off
setstk: ld sp,(stack) ;elbow room for stack
ld de,dbuff
ld c,26 ;set DMA address
call bdos ;probably not necessary
;
; say hello to the world
;
ld hl,hello ;address of signon string
call pstr##
;
; initialize whatever needs it
;
ld hl,($memry##) ;address of first free byte
ld (bmap),hl
ld d,h ;copy into reg-DE
ld e,l
inc de ;make DE point to the next byte
ld bc,8191 ;number of bytes to clear -1
ld (hl),0 ;clear the first byte
ldir ;clear the rest
ld hl,0
ld (xclu),hl ;initialize crosslink count
ld (brec),hl ;initialize current filemap record
;
; Get DPB values for various calculations
;
ld c,31 ;get DPB address
call bdos
ld de,locdpb ;address of local DPB
ld bc,15 ;a DPB is 15 bytes long
ldir ;move into local DPB
;
; Determine if cluster numbers will be 16 or 8 bits long
;
ld a,(dsm+1) ;get high byte
ld (size),a ;any non-zero value means 16-bit cluster #'s
;
; Save current drive and user.
;
call retud## ;get drive and user
ld (du),bc ;save it
;
; Determine the maximum workfile size.
;
ld hl,(dsm) ;get highest cluster number
inc hl ;add one to get number of clusters
srl h ;divide by 64 to determine number of
rr l ;kilobytes that might be needed
srl h
rr l
srl h ;this just needs to be an estimate to allow
rr l ;user to select a drive for the work file
srl h
rr l
srl h
rr l
srl h
rr l
inc hl ;add one to account for any remainder
;
; advise user of workfile size possibility
;
ex de,hl ;save file size for a moment
ld hl,sizms ;first part of message
call pstr##
ex de,hl ;get file size back
call phlfdc## ;print it
ld hl,sizms1 ;second part of message (and question)
call pstr##
;
; ask for drive for workfile
;
ld a,0FFH ;make reg-A non-zero
call bbline## ;get users drive preference
call crlf## ;skip a line
call crlf## ;or two
or a ;any answer?
jp z,exit ;no, bail out
ld b,a
lookdr: ld a,(hl) ;get character from answer
call isalpha## ;is it alphabetic?
jp z,gotdrv ;yes, this is the drive letter
inc hl ;point to next character
djnz lookdr ;keep looking
jp exit ;quit if silly answer
gotdrv: sub 'A' ;make drive name numeric (0 = A:)
ld bc,(du) ;get current drive and user
ld b,a ;change drive field to workfile drive
;
; see if we can actually open a file on specified drive
;
ld (wdu),bc ;save workfile drive/user
call logud## ;log into workfile drive/user
ld de,wrkfcb ;address of workfile FCB
call f$delete## ;delete any pre-exixting workfile
call f$make## ;make a new file
inc a ;any errors?
jp nz,opok ;no, continue
ld hl,wofail
call pstr## ;tell user open of workfile failed
jp exit
;
; ask user if printed output is desired
;
opok:
ld hl,ptrms1 ;ask if output to printer is wanted
call pstr##
ld a,0FFH ;make reg-A non-zero
call bbline## ;get users printer preference
call crlf## ;skip a couple of lines
call crlf##
or a ;any answer?
jp z,exit ;no, bail out
ld b,a
lookpr: ld a,(hl) ;get character from answer
cp 'Y' ;printer output desired
jp z,pyes ;jump if so
cp 'N' ;printer output not desired
jp z,pno ;jump if so
inc hl ;point to next character
djnz lookpr ;keep looking
jp exit ;quit if silly answer
pyes: ld a,81H ;set printer flag to 'yes'
jp setflg
pno: ld a,01H ;set printer flag to 'no'
setflg: ld (sctlfl##),a
;
; display 'Cluster: ' message if quiet mode is off
;
ld hl,clstr ;print "Cluster: " string
ld a,(qflg) ;quiet mode?
or a
call z,pstr##
;
; log back into drive to be tested, and search for first file
;
ld bc,(du) ;recover current drive/user
call logud## ;log into it
ld c,17 ;search for first directory entry
ld de,tgtfcb ;look through all entries
call bdos
;
; Process found directory entry
;
proc: cp 0FFH ;end of directory?
jp z,finish ;yes, clean-up and get out
add a,a ;multiply directory index by 32
add a,a
add a,a
add a,a
add a,a
ld hl,dbuff ;base of DMA area
ld e,a ;put offset into reg-DE
ld d,0
add hl,de ;point to found directory entry
ld (tfcb),hl ;save this address
ld a,(hl) ;get first byte of directory entry
cp 0E5H ;deleted entry?
jp z,skip ;skip it if so
ld de,16 ;offset to allocation information
add hl,de ;point to cluster numbers
ld a,(size) ;get cluster number size flag
or a ;8-bit cluster numbers?
jp z,cl8 ;yes, use alternate routine
;
; This deals with 16-bit cluster numbers
;
ld b,8 ;8 cluster numbers per directory entry
ck16: ld e,(hl) ;get low byte of cluster number
inc hl ;point to high byte
ld d,(hl) ;get high byte of cluster number
inc hl ;point to next cluster number
call fmap ;place into map file
call c,xlrpt ;scream if already in map
djnz ck16 ;check other cluster #'s in this dir. entry
jp skip ;search for 'next' directory entry
;
; This deals with disks where each cluster number is only 8-bits long
;
cl8: ld b,16 ;16 cluster numbers per directory entry
ck8: ld e,(hl) ;get cluster number
ld d,0 ;set high byte to zero
inc hl ;point to next cluster number
call fmap ;place into map file
call c,xlrpt ;scream if already in map
djnz ck8 ;check other cluster #'s in this dir. entry
skip: ld c,18 ;search for next directory entry
call bdos
jp proc ;deal with this directory entry
;
; no more directory entries, clean-up, print total, and get out
;
finish:
ld bc,(wdu) ;get workfile drive/user
call logud## ;log into it
ld de,wrkfcb ;address of workfile FCB
call f$close## ;close the file
call f$delete## ;delete the file
ld bc,(du) ;get back to initial drive/user area
call logud## ;log into it
call crlf## ;skip a couple lines
call crlf##
ld hl,(xclu) ;get number of crosslinkings found
call phlfdc## ;print it
ld hl,str1 ;first part of 'total' message
call pstr##
ld hl,(xclu) ;get number again
dec hl ;if only 1, this will make HL = 0
ld a,h
or l ;is it zero?
jp z,essno ;yes, do not use plural form
ld a,'s'
call cout## ;make plural
essno: ld hl,str2 ;print rest of 'total' message
call pstr##
jp exit
;
; Place file name in map file according to cluster number passed in reg-DE
; Return with carry set if already marked (crosslink).
;
fmap:
ld a,d ;if cluster #0 just return
or e
ret z
push bc ;preserve registers
push hl
ex de,hl ;swap cluster number into reg-HL
ld (clnum),hl ;save cluster number for possible use later
ld a,(qflg)
or a ;'quiet' mode active?
jp nz,noscr1 ;yes, jump around cluster number printing
ld a,bs ;load-up a backspace character
ld b,5 ;length of cluster number
bakup: call cout## ;backup cursor to start of number
djnz bakup
call phldc## ;print cluster number
noscr1: ld a,l ;get low byte of cluster number
and 00000111B ;bit number to check
ld (roff),a ;save as index into record
ld b,a ;put in reg-B for countdown
inc b ;add one for fudge factor
xor a ;clear for shifting
scf ;make sure there is something to shift in
shft: rla ;shift left
djnz shft ;until reg-B is zero
ld b,a ;save mask in reg-B
srl h ;divide HL by eight
rr l
srl h
rr l
srl h
rr l
ld (rcrd),hl ;save as record number of file map
ld de,(bmap) ;base address of bit-map
add hl,de ;point to coresponding byte
ld (bptr),hl ;save pointer into bitmap
ld a,(hl) ;get byte
and b ;already allocated?
scf ;make sure carry is set
jp nz,gback ;fix stack and return
push bc ;save mask (reg-B)
ld c,26
ld de,wbuff ;set DMA address to workfile buffer
call bdos
ld bc,(wdu) ;get workfile drive/user
call logud## ;log into it
ld hl,(rcrd) ;record number of file map
ld de,(brec) ;record number of current buffer
call comphd## ;proper record already in workfile buffer?
jp z,skip2 ;yes, save some time - skip the preread
ld (brec),hl ;save record number of new current buffer
ld de,wrkfcb ;address of workfile FCB
call r$read## ;read record
skip2: ld a,(roff) ;index into record
add a,a ;multiply index by 16
add a,a
add a,a
add a,a
ld e,a ;put offset into DE
ld d,0
ld hl,wbuff ;base address of workfile buffer
add hl,de ;add offset (to make pointer)
ex de,hl ;move pointer to reg-DE
ld hl,(tfcb) ;addr of dir entry that owns this cluster
ld bc,16 ;length of directory entry (only need first 12)
ldir ;put filename into map record
ld de,wrkfcb ;address of workfile FCB
ld hl,(rcrd) ;record number of file map
call r$write## ;write updated record back to workfile
ld c,26
ld de,dbuff ;set DMA address to directory buffer
call bdos
ld bc,(du) ;get test drive/user
call logud## ;log into it
pop bc ;recover mask (reg-B)
ld hl,(bptr) ;recover pointer into bit-map
ld a,(hl) ;get byte again
or b ;set bit (and clear carry)
ld (hl),a ;update bit-map
gback: pop hl ;restore registers
pop bc
ret
;
; Notify world that a cross-link has been detected
;
xlrpt:
push hl ;preserve registers
push bc
ld a,(qflg)
or a ;quiet mode active?
jp nz,noscr2 ;yes, jump around cluster number seperation
ld a,spc ;get <space> character
call cout##
call cout## ;move off from cluster number a bit
call cout##
noscr2: ld bc,(du) ;get current drive name
ld a,b ;move drive number to reg-A
add a,'A' ;make it ASCII
call sout## ;print it
ld de,(tfcb) ;get address of current directory entry
ld a,(de) ;get user number
cp 10 ;less than 10
jp nc,nozer ;no, no leading zero needed
ld a,'0'
call sout##
ld a,(de) ;get number again
nozer: call safdc## ;print user number
ld a,':'
call sout##
inc de ;point to file name
call sfn3## ;print it
ld hl,xlmsg1 ;get 'crosslinked with' message
call spstr## ;print it
ld c,26
ld de,xbuff ;set DMA address to aux file buffer
call bdos
ld bc,(wdu) ;get workfile drive/user
call logud## ;log into it
ld de,wrkfcb ;address of workfile FCB
ld hl,(rcrd) ;record number of file map
call r$read## ;read record
ld a,(roff) ;index into record
add a,a ;multiply index by 16
add a,a
add a,a
add a,a
ld e,a ;put offset into DE
ld d,0
ld hl,xbuff ;base address of aux file buffer
add hl,de ;add offset (to make pointer)
ld (wfcb),hl ;save address of crossed filename
ld c,26
ld de,dbuff ;set DMA address to directory buffer
call bdos
ld bc,(du) ;get test drive/user
call logud## ;log into it
ld a,b ;move drive number to reg-A
add a,'A' ;make it ASCII
call sout##
ld de,(wfcb) ;get address of crossed directory entry
ld a,(de) ;get user number
cp 10 ;less than 10
jp nc,nozer2 ;no, no leading zero needed
ld a,'0'
call sout##
ld a,(de) ;get number again
nozer2: call safdc## ;print user number
ld a,':'
call sout##
inc de ;point to file name
call sfn3## ;print it
ld a,(sctlfl##) ;get switched output flag
bit 7,a ;printer active?
jp z,nptag ;nope, don't tag cluster number onto report
ld hl,tagstr ;address of tag string
call lpstr## ;send to printer
ld hl,(clnum) ;get cluster number
call lhldc## ;send to printer
ld a,'>'
call lout##
call lcrlf## ;newline
nptag: ld a,(qflg)
or a ;quiet mode active?
jp nz,noscr3 ;yes, jump around cluster string printing
call crlf## ;move to new line first
ld hl,clstr ;print "Cluster: " string again
call pstr##
jp nctag
noscr3: ld hl,tagstr ;address of tag string
call pstr## ;send to console
ld hl,(clnum) ;get cluster number
call phldc## ;send to console
ld a,'>'
call cout##
call crlf## ;newline
nctag: ld hl,(xclu) ;get number of crosslinkings
inc hl ;one more now
ld (xclu),hl ;update number
pop bc
pop hl ;restore registers
ret
;
; Various strings used within the program
;
sizms: db 'Please indicate a drive where a ',0
sizms1: db 'k temporary file can be placed.',cr,lf
db 'Do not use the drive being checked out.',cr,lf
db 'Drive name: ',0
ptrms1: db 'Send crosslink warnings to printer? ',0
tagstr: db ' <on cluster: ',0
str1: db ' cross-linked cluster',0
str2: db ' detected.',cr,lf,0
xlmsg1: db ' <crosslinked with> ',0
clstr: db 'Cluster: ',0
wofail: db cr,lf,bel,'Unable to open workfile on selected drive.'
db cr,lf,cr,lf,0
hello: db cr,lf,'XLINK v',major+30H,'.',minor+30H,cr,lf,cr,lf,0
;
; special FCB with '?' in drive select position (see BDOS function 17)
;
tgtfcb: db '????????????',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
; FCB for workfile
;
wrkfcb: db 0,'XLNAM WRK',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dseg
bmap: ds 2 ;address of start of bit-map
bptr: ds 2 ;bitmap pointer
brec: ds 2 ;number of record in workfile buffer
clnum: ds 2 ;cluster number
du: ds 2 ;drive/user of test drive
roff: ds 1 ;offset index into workfile
rcrd: ds 2 ;record number of workfile
size: ds 1 ;flag showing size of cluster numbers
tfcb: ds 2 ;pointer to head of current directory entry
wdu: ds 2 ;drive/user of workfile
wfcb: ds 2 ;pointer to head of crossed directory entry
xclu: ds 2 ;number of crosslinkings detected
wbuff: ds 128 ;buffer area for workfile
xbuff: ds 128 ;aux file buffer for workfile
;
; the following storage definitions -must not- be re-arranged.
;
locdpb:
spt: ds 2 ;number of 128-byte sectors per track
bsh: ds 1 ;block shift factor
blm: ds 1 ;block mask
exm: ds 1 ;extent mask
dsm: ds 2 ;higest cluster (block) number
drm: ds 2 ;maximum number of directory entries
al0: ds 1 ;directory allocation block map - first byte
al1: ds 1 ;directory allocation block map - second byte
cks: ds 2 ;size of directory check vector
off: ds 2 ;number of reserved tracks
; --- end of un-re-arrangable area ---
end