home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
dirutl
/
wherfind.lbr
/
WHERFIND.MQC
/
WHERFIND.MAC
Wrap
Text File
|
1986-07-13
|
58KB
|
2,015 lines
.Z80
TITLE WHERFIND Version 3.01 - 07/02/86 - 20:07
PAGE
;************************************************************************
;* *
;* Written by G.B. Shaffstall, SYSOP Lakewood RCP/M *
;* *
;* Modified for use with ZCPR3 by R.T. Hilgert SYSOP XEROX RCP/M *
;* *
;* Modified for two column output, pagination, combined WHEREIS *
;* with FIND and added extensive annotation 7/2/86 by *
;* Gil Shultz Sysop the REALM - (313) 349-3408 Novi Michigan. *
;* *
;* This program allows full wildcard searches of the directories *
;* and ALL LIBRARY files on a CP/M system for a requested file, *
;* starting on drive A, user 0, working its way up and across all *
;* drive/user areas until a trapped I/O error causes exit or CTL-C *
;* or CTL-X is hit at the keyboard. Optionally, the user can *
;* specify a single drive to be searched by including the drive *
;* name as a prefix to the search file. This is based on SD-81, so *
;* credit is given to the MANY people that have worked on it in the *
;* past. *
;* *
;* Entering WHEREIS<cr> will display a brief help message. *
;* *
;* The USER AREA PATCH TABLE is the same as in SD with two *
;* exceptions: [1] if 0FFH is placed in a user location that drive *
;* will be skipped, and [2] If using with ZCPR all entries should *
;* be set to 0FFH in the source file, as the ZCPR conditional code *
;* will re-load the table on entry based on ZCPR's MAXDRIVE and *
;* MAXUSER values. *
;* *
;* Users of this program with hard disks will want to set the QUIET *
;* equate to 0 to provide the message "Searching <dn>: User <num>" *
;* so the user will know that the program is still running. With *
;* any other value, the message "+++ NO FILE ON <dn>:" will be *
;* printed as the program switches drives and no files are found. *
;* *
;* There is no page pause capability, but unless something like *
;* WHEREIS *.* is used this should be no problem. *
;* *
;************************************************************************
SUBTTL EQUATES
PAGE
USRMSK EQU 00001111B ; Mask for maximum user number
CR EQU 0DH ; carriage return character
LF EQU 0AH ; line feed character
ESC EQU 1BH ; escape character
YES EQU 0FFH ; true
NO EQU 0 ; NOT YES
;************************************************************************
;* *
;* If running with ZCPR3 with NDRS ste ZCPR3 true to display *
;* named directory information. *
;* *
ZCPR3 EQU NO ; YES *
;* *
;* Set the following equate true if using ZCPR to limit Drive *
;* user number searching. *
;* *
ZCPR EQU YES ; YES *
;* *
;* *
;* Set one and only one of the following equates true for the *
;* program you want. The programs generated will be *
;* *
;* WHEREIS or FIND *
;* *
WHERE EQU NO ; set to yes for WHEREIS *
FIND EQU YES ; set to yes for FIND *
;* *
;* Set the following equate true for two column output. *
;* *
TWOCOL EQU YES ; set to yes for two columns. *
;* *
;* Set the following equate true for pagination. *
;* *
PAGNAT EQU YES ; set true for pagination. *
;* *
;************************************************************************
QFLAG EQU 0 ; set to <> 0 for silent mode
MDRIV EQU 03DH ; ZCPR Max drive storage location
MUSR EQU 03FH ; ZCPR Max user storage location
RDCHR EQU 1 ; read char from console
WRCHR EQU 2 ; write char to console
PRINTS EQU 9 ; print string
CONST EQU 11 ; check cons stat
RESET EQU 13 ; reset disk system
SELDSK EQU 14 ; select disk
OPEN EQU 15 ; 0ffh=not found
CLOSE EQU 16 ; " "
SEARCH EQU 17 ; " "
NEXT EQU 18 ; " "
READ EQU 20 ; not 0 = eof
WRITE EQU 21 ; not 0 = disk full
MAKE EQU 22 ; 0ffh = directory full
CURDSK EQU 25 ; get currently logged disk name
SETDMA EQU 26 ; set current dma
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)
BASE EQU 0 ; default to 0
FCB EQU BASE+5CH ; force relocatable code to 5CH
BDOS EQU BASE+5 ; force relocatable code to 05H
COND ZCPR3
PAGE
.8080
INCLUDE Z3BASE.LIB
.Z80
PAGE
ENDC ; ZCPR3
;************************************************************************
;* *
;* BEGIN EXECUTABLE PROGRAM CODE *
;* *
;************************************************************************
JP START ; goto entry point
SUBTTL DRIVE / USER TABLE
PAGE
;************************************************************************
;* *
;* Drive code/user area lookup table *
;* *
;* Note that the lodrv-hidrv table is included here fully *
;* configured. For your own use, you should change the maximum *
;* user areas as appropriate for each drive on your system. *
;* Note that there are only 16 user areas available under cp/m *
;* 2, so the highest legal user area you can specify is 15 *
;* (range 0-15 = 16 areas). The program will convert anything *
;* over 15 into mod 15. Enter an 0ffh to cause a drive to be *
;* skipped on search. NOTE: set to 0FFH for ZCPR use. *
;* *
;************************************************************************
LODRV: ; mark beginning of drive/user table
DEFB 0FFH ; maximum user area for drive A
DEFB 0FFH ; " " " " " B
DEFB 0FFH ; " " " " " C
DEFB 0FFH ;---"-----"----"----"----"----D
DEFB 0FFH ; " " " " " E
DEFB 0FFH ; " " " " " F
DEFB 0FFH ; " " " " " G
DEFB 0FFH ;---"-----"----"----"----"----H
DEFB 0FFH ; " " " " " I
DEFB 0FFH ; " " " " " J
DEFB 0FFH ; " " " " " K
DEFB 0FFH ;---"-----"----"----"----"----L
DEFB 0FFH ; " " " " " M
DEFB 0FFH ; " " " " " N
DEFB 0FFH ; " " " " " O
DEFB 0FFH ;---"-----"----"----"----"----P
HIDRV: ; mark end of drive/user table
SUBTTL LOCAL STORAGE, MESSAGES ETC.
PAGE
QUIET: DEFB QFLAG ; patch to non zero for quiet mode
BDOLOC: DEFW 0
COND WHERE
VERNAME:
DEFB CR,LF,'WHEREIS v 3.01 for the REALM - 07/02/86 - 20:07',CR,LF
DEFB CR,LF,'A Total Wild-Card FILE including Libraries.',CR,LF
DEFB CR,LF,'Syntax to search all drives and user areas'
DEFB CR,LF,'is WHEREIS <Filename.type>',CR,LF
DEFB CR,LF,'Examples:'
DEFB CR,LF,'A0>WHEREIS *.AQ6 or A0>WHEREIS MBOOT*.*',CR,LF
DEFB CR,LF,'To search a single drive and all user areas'
DEFB CR,LF,'Use WHEREIS <Drivename:Filename.type>',CR,LF
DEFB CR,LF,'Examples:'
DEFB CR,LF,'A0>WHEREIS B:MDM???.* or A0>WHEREIS D:KP*.*',CR,LF
DEFB CR,LF,'Pagination is '
COND PAGNAT
DEFB 'on'
ENDC
COND (NOT PAGNAT AND 0FFH)
DEFB 'off'
ENDC
DEFB CR,LF,'Two column output is '
COND TWOCOL
DEFB 'on'
ENDC
COND (NOT TWOCOL AND 0FFH)
DEFB 'off'
ENDC
DEFB CR,LF,CR,LF+80H
PROCES: DEFB CR,LF,' Searching '
PROC1: DEFB ' : User',' '+80H
SIGNON: DEFB CR,LF,'WHEREIS v 3.01 for the REALM - 07/02/86 - 20:07',CR,LF
DEFB ' ^X or ^C to abort',CR,LF,CR,LF+80H
ENDC
COND FIND
VERNAME:
DEFB CR,LF,'FIND v 3.01 for the REALM - 07/03/86 - 20:07',CR,LF
DEFB CR,LF,'A Total Wild-Card FILE Search Utility.',CR,LF
DEFB CR,LF,'Syntax to search all drives and user areas'
DEFB CR,LF,'is FIND <Filename.type>',CR,LF
DEFB CR,LF,'Examples:'
DEFB CR,LF,'A0>FIND *.AQ6 or A0>FIND MBOOT*.*',CR,LF
DEFB CR,LF,'To search a single drive and all user areas'
DEFB CR,LF,'Use FIND <Drivename:Filename.type>',CR,LF
DEFB CR,LF,'Examples:'
DEFB CR,LF,'A0>FIND B:MDM???.* or A0>FIND D:KP*.*',CR,LF
DEFB CR,LF,'Pagination is '
COND PAGNAT
DEFB 'on'
ENDC
COND (NOT PAGNAT AND 0FFH)
DEFB 'off'
ENDC
DEFB CR,LF,'Two column output is '
COND TWOCOL
DEFB 'on'
ENDC
COND (NOT TWOCOL AND 0FFH)
DEFB 'off'
ENDC
DEFB CR,LF,CR,LF+80H
PROCES: DEFB CR,LF,' Searching '
PROC1: DEFB ' : User',' '+80H
SIGNON: DEFB CR,LF,'FIND v 3.01 for the REALM - 07/03/86 - 20:07',CR,LF
DEFB ' ^X or ^C to abort',CR,LF,CR,LF,+80H
ENDC
;********************************
;* *
;* Initialized data area *
;* *
;********************************
COND WHERE
LBRTYP: DEFB 'LBR'
ENDC
VERBAD: DEFB '+++ Needs CP/M 2.0 or Newer to RU','N'+80H
DREMSG: DEFB '+++ Driv','e' OR 80H
ERRMS1: DEFB ' '
ERRMS2: DEFB 'Erro','r' OR 80H
USRMSG: DEFB 'User ','#' OR 80H
NOFMS1: DEFB '+++ NO FILE ON '
NOFMS2: DEFB ' ',':' OR 80H
VECTBL: DEFW DSKERR ; bdos sector error intercept vector
DEFW DSKERR ; bdos select error intercept vector
DOPFLG: DEFB 0
SUBTTL UNITIALIZED STORAGE AREA
PAGE
BASUSR: DEFB 0 ; dupe of original dir. user # to search
BLKMAX: DEFW 0 ; highest block # on drive
BLKMSK: DEFB 0 ; sec/blk - 1
BLKSHF: DEFB 0 ; # shifts to mult by sec/blk
COUNT: DEFW 0 ; entry count
DIRMAX: DEFW 0 ; highest file # in directory
GAP: DEFW 0 ; sort routine storage
HITRAP: DEFB 0 ; highlight trap (previously typed char)
I: DEFW 0 ; sort routine storage
J: DEFW 0 ; sort routine storage
JG: DEFW 0 ; sort routine storage
LZFLG: DEFB 0 ; 0 when printing leading zeros
MAXUSR: DEFB 0 ; max user # for drive from lookup table
NEWUSR: DEFB 0 ; contains user # selected by "$u" option
NEXTT: DEFW 0 ; next table entry
OLDDSK: DEFB 0 ; holder for currently logged-in drive
OLDUSR: DEFB 0 ; contains user number upon invocation
SCOUNT: DEFW 0 ; # to sort
SUPSPC: DEFB 0 ; leading space flag for decimal routine
TBLOC: DEFW 0 ; pointer to start of name table
TEMP: DEFW 0 ; save dir entry
VERFLG: DEFB 0 ; cp/m version number (0=pre-cp/m 2)
FNDFLG: DEFB 0 ; file found flag
LLENLOC:
DEFW 0 ; running total of .lbr length
LCOUNT: DEFW 0
NEXTL: DEFW 0
SLFILE: DEFW 0
SEARN: DEFS 11 ; holding area for search name
COND WHERE
LBRFCB: DEFS 36 ; library FCB
LBBUF: DEFS 80H ; library buffer
ENDC
SUBTTL MAIN PROGRAM CODE
PAGE
;****************************************
;* *
;* Main program starts here. *
;* *
;****************************************
START: LD HL,0 ; clear HL
ADD HL,SP ; hl=old stack
LD (STACK),HL ; save it
LD SP,STACK ; get new stack
COND ZCPR
LD HL,LODRV ; point at drive user table
PUSH HL ; and get it to DE
POP DE ; got it
INC DE ; up bye one (setup for LDIR)
LD A,(MUSR) ; get maximum user
; DEC A ; adjust it
LD (LODRV),A ; stuff maximum user in table
LD B,0 ; clear hi byte
LD A,(MDRIV) ; get maximum drive
OR A ; test for drive A
JP Z,NOMOVE ; yep, only drive so move nothing
DEC A ; adjust drive number (gfs)
JP Z,NOMOVE ; nope, exit
LD C,A ; set up counter
DEFB 0EDH,0B0H ; LDIR
NOMOVE:
ENDC
XOR A ; get a zero
LD (FNDFLG),A ; clear file found flag
LD (NEWUSR),A ; make new user = 0
LD (BASUSR),A ; duplicate it if multi-disk mode
LD C,12 ; get and save the cp/m version #
CALL BDOS ; get version from system
LD A,L ; get it
LD (VERFLG),A ; and save it
LD (DOPFLG),A ; do not allow multi-drive yet
CP 20H ; set carry if cp/m 1.4
JP C,VERERR ; exit on earlier than 2.0
LD HL,FCB+1 ; point to name
LD A,(HL) ; any specified?
CP ' ' ; test
JP Z,NONERR ; so print help info
PUSH HL ; save fcb address
LD DE,SEARN ; point to search name holding area
LD B,11 ; size of file name, type
CALL MOVE ; move it
POP HL ; restore fcb address
LD E,0FFH ; get current user number
LD C,CURUSR ; set it up
CALL CPM ; and do it
LD (OLDUSR),A ; initialize startup user number
CLNON: LD C,CURDSK ; set it up
CALL CPM ; get current disk nr
LD (OLDDSK),A ; save for reset if needed
LD HL,FCB ; set up pointer
LD A,(HL) ; get drive name for directory search
OR A ; any specified?
JP NZ,START2 ; yes skip next routine
XOR A
LD (DOPFLG),A ; ok let multi-drive in
LD A,1 ; otherwise, get disk "a"
START2: LD (HL),A ; put the absolute drive code in
; ..directory fcb
CKREST: LD DE,SIGNON ; point to hello message
CALL PRINT ; and say hello
LD A,(DOPFLG) ; get flag
OR A ; and test it
CALL Z,SWAPEM ; swap bdos error vector tables
;********************************************************
;* *
;* Validate drive code and user area numbers *
;* from the drive table. *
;* *
;********************************************************
NOOPT: LD DE,DREMSG ; get the drive/user error message
PUSH DE ; save on stack
LD A,(FCB) ; get directory drive code
DEC A ; normalize to range of 0-15
CP HIDRV-LODRV ; compare with maximum drives on-line
JP NC,ERXIT ; take drive error exit if out of range
LD HL,USRMSG ; switch to user # error message
EX (SP),HL
LD E,A ; use drive code as index into table
LD D,0 ; clear hi byte so offset is ok
USRCK: LD HL,LODRV ; point to base of drive/user table
ADD HL,DE ; add offset into table
LD A,(HL) ; get the maximum user # for this drive
CP 0FFH ; check for skip drive
JP Z,ERXIT ; exit if not wanted
USRCK2: AND USRMSK ; make sure its in range 0 - 15 (gfs)
LD (MAXUSR),A ; save it for later
LD HL,NEWUSR ; point to the directory user area
CP (HL) ; compare it with the maximum
JP C,ERXIT ; take error exit if user number illegal
POP DE ; destroy error message pointer
LD HL,FCB+1 ; point to name
;********************************************************
;* *
;* Make fcb all '?' to search for every file *
;* *
;********************************************************
WCD: LD B,11 ; fn+ft count
QLOOP: LD (HL),'?' ; store '?' in fcb
INC HL ; bump FCB pointer
DEC B ; count off
JP NZ,QLOOP ; and loop till finished
GOTFCB: LD A,'?' ; force wild extent
LD (FCB+12),A
CALL SETSRC ; set dma for bdos media change check
LD HL,FCB ; point to fcb drive code for directory
LD E,(HL) ; get the drive code out of the fcb
DEC E ; normalize drive code for select
LD C,SELDSK ; select the directory drive to retrieve
CALL CPM ; ..the proper allocation vector
LD C,CURDPB ; it is 2.x or mp/m...request dpb
CALL BDOS ; put the system to work
INC HL ; bump pointer to
INC HL ; block shift location
LD A,(HL) ; get block shift
LD (BLKSHF),A ; save block shift factor
INC HL ; bump to block mask
LD A,(HL) ; get block mask
LD (BLKMSK),A ; get it saved
INC HL ; bump pointer to max block
INC HL ; there
LD E,(HL) ; get max block #
INC HL ; bump pointer
LD D,(HL) ; get mask
EX DE,HL ; swap pointers
LD (BLKMAX),HL ; save it
EX DE,HL ; and back, we saved it
INC HL ; bump pointer
LD E,(HL) ; get directory size
INC HL ; and bump again
LD D,(HL) ; get size
EX DE,HL ; swap pointers
LD (DIRMAX),HL ; save max # of entries in directory
;************************************************************************
;* *
;* Reenter here on subsequent passes while in the all-users mode *
;* *
;************************************************************************
SETTBL: LD A,(QUIET) ; check if in quiet mode
OR A ; test
JP NZ,SETTB1 ; yes so skip printout
LD A,(FCB) ; get drive
ADD A,'A'-1 ; ASCIFY it
LD (PROC1),A ; and stuff it away
LD DE,PROCES ; show the user what area is being
CALL PRINT ; worked on.
CALL TYPUSR ; now display user number
COND ZCPR3
LD A,' ' ; get a space
CALL TYPE ; and send it
CALL SHONDR ; now show drive
ENDC ; ZCPR3
SETTB1: LD HL,(DIRMAX) ; get directory maximum again
INC HL ; directory size is dirmax+1
ADD HL,HL ; double directory size
LD DE,ORDER ; to get size of order table
ADD HL,DE ; allocate order table
LD (TBLOC),HL ; name tbl begins where order tbl ends
LD (NEXTT),HL ; save in both places
EX DE,HL ; swap pointers
LD HL,(BDOS+1) ; make sure we have room to continue
LD A,E ; get low
SUB L ; and subtract
LD A,D ; now get hi
SBC A,H ; and subtract, carry = ok
JP NC,OUTMEM ; tell not enough memory
LD A,(NEWUSR) ; get user area for directory
LD E,A ; save it
LD C,CURUSR ; get the user function
CALL CPM ; ..and set new user number
;************************************************
;* *
;* Look up the fcb in the directory *
;* *
;************************************************
LD A,'?' ; get a question mark
LD HL,FCB+12 ; set pointer
LD (HL),A ; match all extents
INC HL ; up pointer
LD (HL),A ; match all s1 bytes
INC HL ; up pointer
LD (HL),A ; match all s2 bytes
LD HL,0 ; now clear match counter
LD (COUNT),HL ; initialize match counter
CALL SETSRC ; set dma for directory search
LD C,SEARCH ; get 'SEARCH FIRST' function
JP LOOK ; ..and go search for 1st match
;****************************************
;* *
;* Read more directory entries *
;* *
;****************************************
MORDIR: LD C,NEXT ; search next
LOOK: LD DE,FCB ; point to FCB
CALL CPM ; read directory entry
INC A ; check for end (0ffh)
JP Z,SPRINT ; if no more, sort & print what we have
;****************************************
;* *
;* Point to directory entry *
;* *
;****************************************
SOME: DEC A ; undo previous 'INR A'
AND 3 ; make modulus 4
ADD A,A ; multiply...
ADD A,A ; ..by 32 because
ADD A,A ; ..each directory
ADD A,A ; ..entry is 32
ADD A,A ; ..bytes long
LD HL,BASE+81H ; point to buffer (skip to fn/ft)
ADD A,L ; point to entry
ADD A,9 ; point to system byte
LD L,A ; save (can't carry to h)
LD A,(HL) ; get system byte
OR A ; check bit 7
JP M,MORDIR ; skip that file
SYSFOK: LD A,L ; go back now
SUB 10 ; back to user number (alloc flag)
LD L,A ; hl points to entry now
LD A,(NEWUSR) ; get current user
CP (HL) ; test it
JP NZ,MORDIR ; ignore if different
INC HL
;********************************
;* *
;* Move entry to table *
;* *
;********************************
EX DE,HL ; entry to de
LD HL,(NEXTT) ; next table entry to hl
LD B,11 ; entry length (name, type, extent)
TMOVE: LD A,(DE) ; get entry char
AND 7FH ; remove attributes
LD (HL),A ; store in table
INC DE ; bump pointers
INC HL ; both of them
DEC B ; more?
JP NZ,TMOVE ; yep, move it
INC DE ; de->> s1
INC DE ; de->> s2
LD A,(DE) ; get s2 byte, overflow=int(extents/32)
PUSH HL ; save hl
LD L,A ; set up 16-bit multiply
LD H,0 ; clear hi
LD B,5 ; set up shift factor
CALL SHLL ; hl is now # of overflow extents
DEC DE ; de->> s1
DEC DE ; de->> extent
LD A,(DE) ; get extent
ADD A,L ; add it in
LD L,A ; save in L
LD A,H ; get HI
ADC A,0 ; add in carry
LD H,A ; hl now has total extents
LD B,7 ; get shift factor
CALL SHLL ; hl now has total sectors less last ext
INC DE ; de->> s1
INC DE ; de->> s2
INC DE ; point to sector count
LD A,(DE) ; get it
ADD A,L ; add it
LD L,A ; save in L
LD A,H ; get HI
ADC A,0 ; and add in carry
LD H,A ; hl now has total sectors
EX (SP),HL ; do some fancy shuffling
EX DE,HL ; swap pointers
EX (SP),HL ; and swap with top of stack
EX DE,HL ; swap them back
LD (HL),D ; get value
INC HL ; and bump pointer
LD (HL),E ; now stuff it
POP DE ; all back to normal...
INC HL ; up pointer
LD (NEXTT),HL ; save updated table address
EX DE,HL ; swap it
LD HL,(COUNT) ; bump the # of matches made
INC HL ; up counter
LD (COUNT),HL ; and save count
LD HL,13 ; size of next entry
ADD HL,DE ; add offset
EX DE,HL ; future nextt is in de
LD HL,(BDOS+1) ; pick up tpa end
LD A,E ; get low
SUB L ; compare nextt-tpa end
LD A,D ; now get hi
SBC A,H ; now set flag
JP C,MORDIR ; if tpa end > nextt, loop back for more
OUTMEM: CALL ERXIT ; exit if directory too large
DEFB 'Memor','y' OR 80H
;************************************************
;* *
;* Shift HL left by n bits (in B) *
;* *
;************************************************
SHLL: ADD HL,HL ; shift left by one
DEC B ; count down shift count
RET Z ; return if finished
JP SHLL ; else shift again
;****************
;* *
;* Sort *
;* *
;****************
SPRINT: CALL SETFOP ; return to file output dma & user #
LD HL,(COUNT) ; get file name count
LD A,L ; do 16 bit test
OR H ; any found?
JP Z,PRTOTL ; exit if no files found
PUSH HL ; save file count
LD (SUPSPC),A ; enable leading zero suppression
;****************************************
;* *
;* Initialize the order table *
;* *
;****************************************
LD HL,(TBLOC) ; get start of name table
EX DE,HL ; into de
LD HL,ORDER ; point to order table
LD BC,13 ; entry length
BLDORD: LD (HL),E ; save low order address
INC HL ; bump pointer
LD (HL),D ; save high order address
INC HL ; bump pointer
EX DE,HL ; table address to hl
ADD HL,BC ; point to next entry
EX DE,HL ; swap
EX (SP),HL ; save tbl address, fetch loop counter
DEC HL ; count down loop
LD A,L ; do 16 bit test
OR H ; more?
EX (SP),HL ; (restore tbl address, save counter)
JP NZ,BLDORD ; yes, go do another one
POP HL ; clean loop counter off stack
LD HL,(COUNT) ; get count
LD (SCOUNT),HL ; save as # to sort
DEC HL ; only 1 entry?
LD A,L ; do test
OR H ; for all 16 bits
JP Z,NOOUT ; yes, so skip sort
;********************************************************
;* *
;* This sort routine is adapted from Software *
;* Tools by Kernigan and Plaugher. *
;* *
;********************************************************
SORT: LD HL,(SCOUNT) ; number of entries
L0: OR A ; clear carry
LD A,H ; gap=gap/2
RRA
LD H,A
LD A,L
RRA
LD L,A
OR H ; is it zero?
JP Z,NOOUT ; then none left
LD A,L ; make gap odd
OR 1
LD L,A
LD (GAP),HL
INC HL ; i=gap+1
L2: LD (I),HL
EX DE,HL
LD HL,(GAP)
LD A,E ; j=i-gap
SUB L
LD L,A
LD A,D
SBC A,H
LD H,A
L3: LD (J),HL
EX DE,HL
LD HL,(GAP) ; jg=j+gap
ADD HL,DE
LD (JG),HL
LD A,13 ; compare 13 characters {sfk}
CALL COMPARE ; compare (j) and (jg)
JP P,L5 ; if a(j)<=a(jg)
LD HL,(J)
EX DE,HL
LD HL,(JG)
CALL SWAP ; exchange a(j) and a(jg)
LD HL,(J) ; j=j-gap
EX DE,HL
LD HL,(GAP)
LD A,E
SUB L
LD L,A
LD A,D
SBC A,H
LD H,A
JP M,L5 ; if j>0 goto l3
OR L ; check for zero
JP Z,L5
JP L3
L5: LD HL,(SCOUNT) ; for later
EX DE,HL
LD HL,(I) ; i=i+1
INC HL
LD A,E ; if i<=n goto l2
SUB L
LD A,D
SBC A,H
JP P,L2
LD HL,(GAP)
JP L0
;********************************************************
;* *
;* Sort is all done - print entries that compare *
;* *
;********************************************************
NOOUT: LD HL,(COUNT) ; get count
LD (LCOUNT),HL ; and save it
LD HL,ORDER ; initialize order table pointer
LD (NEXTL),HL ; get pointer
LD (NEXTT),HL ; and save it
;********************************************************
;* *
;* Output the directory files we've matched. *
;* *
;********************************************************
ENTRY: LD HL,(COUNT) ; get count
DEC HL ; dock file count
LD (COUNT),HL ; and save it
LD A,H ; is this the last file?
OR L ; test all 16 bits
JP Z,OKPRNT ; if count=0, last file so skip compare
;****************************************************************
;* *
;* Compare each entry to make sure that it isn't part *
;* of a multiple extent file. Go only when we have the *
;* last extent of the file. *
;* *
;****************************************************************
CALL CKABRT ; check for abort code from keyboard
LD HL,(NEXTT) ; get pointer
LD A,11 ; set up length of filename.ext
CALL COMPR ; does this entry match next one?
JP NZ,OKPRNT ; no, print it
INC HL ; bump pointer
INC HL ; skip since highest extent last in list
LD (NEXTT),HL ; save it
JP ENTRY ; loop back for next lowest extent
OKPRNT: LD HL,(NEXTT) ; get order table pointer
LD E,(HL) ; get low order address
INC HL ; bump pointer
LD D,(HL) ; get high order address
INC HL ; bump pointer
LD (NEXTT),HL ; save updated table pointer
EX DE,HL ; table entry to hl
;************************************************
;* *
;* Put in user & drive printout here. *
;* *
;************************************************
PUSH HL ; save pointer on stack
LD HL,(TFILES) ; get count
INC HL ; bump it up by one
LD (TFILES),HL ; and update count
POP HL ; restore original pointer
CALL COMPS ; match what we are looking for ?
JP NZ,OKEXIT ; no, so don't print it
PUSH HL ; save pointer on stack
LD HL,(TMATCH) ; get match count
INC HL ; add one to it
LD (TMATCH),HL ; and save match count
POP HL ; restore pointer from stack
CALL GCRLF ; space it out
LD A,(FCB) ; ..precede new line with drive name
ADD A,'A'-1 ; ascify it
CALL TYPE ; and display drive
CALL TYPUSR ; now display user number
LD A,':' ; tag header with a colon and a space
CALL TYPE ; ..and exit back to entry
COND ZCPR3
CALL SHONDR
ENDC ; ZCPR3
LD A,' ' ; get a space
CALL TYPE ; and display it
LD B,8 ; file name length
CALL TYPEIT ; type filename
LD A,'.' ; period after fn
CALL TYPE ; display dot
LD B,3 ; display 3 characters of filetype
CALL TYPEIT ; now display file extension
LD D,(HL) ; now calculate size of file
INC HL ; bump pointer
LD E,(HL) ; size in de (sectors)
LD A,(BLKMSK) ; get block mask
PUSH AF ; save on stack
ADD A,E ; add to sectors
LD E,A ; and put back in E
LD A,D ; now get hi
ADC A,0 ; add in carry bit
LD D,A ; and put it back
POP AF ; restore block mask
CPL ; and test it
AND E ; mask it
LD E,A ; size in de (sectors rounded to blocksize)
LD B,3 ; set up shift factor
SHRR: LD A,D ; get value
OR A ; clear carry
RRA ; rotate (shift) i
LD D,A ; put it back
LD A,E ; get HI
RRA ; shift it with carry
LD E,A ; and put it back
DEC B ; test to see if shift is finished
JP NZ,SHRR ; no, do it again
EX DE,HL ; get file size
;********************************************************
;* *
;* Output the size of the individual file. *
;* *
;********************************************************
CALL DECPRT ; ..go print it
LD A,'K' ; ..and follow with k size
CALL TYPE ; terminate file size with a 'K'
LD A,0FFH ; get flag value
LD (FNDFLG),A ; set file found flag
;********************************************************
;* *
;* One file output - test to see if we have to *
;* output another one. *
;* *
;********************************************************
OKEXIT: LD HL,(COUNT) ; get current file counter and test it
LD A,H ; take hi byte
OR L ; and test with low
JP Z,PRTOTL ; if no more files exit to summary output
JP ENTRY ; else do next
;********************************************************
;* *
;* Compute the size of the file/library and *
;* update our summary datum. This has been changed *
;* into a subroutine so that both the file size *
;* computation and a library size (when printing *
;* out library members) can be computed in K. *
;* *
;********************************************************
DOIT: LD E,(HL) ; get extent #
LD D,0 ; clear hi
INC HL ; up pointer
LD A,(HL) ; get sector count of last extent
EX DE,HL
ADD HL,HL ; # of extents times 16k
ADD HL,HL
ADD HL,HL
ADD HL,HL
EX DE,HL ; save in de
LD HL,BLKMSK ; get block mask
ADD A,(HL) ; round last extent to block size
RRCA ; adjust it
RRCA ; convert from sectors to k
RRCA ; adjusted
AND 1FH ; now mask it
LD L,A ; add to total k
LD H,0 ; clear hi
ADD HL,DE ; add it in
LD A,(BLKMSK) ; get sectors/blk-1
RRCA ; adjust it
RRCA ; convert to k/blk
RRCA ; adjusted
AND 1FH ; now mask it
CPL ; use to finish rounding
AND L ; mask it
LD L,A ; and all finished
RET ; return, were finished
;****************************************************************
;* *
;* Print HL in decimal with leading zero suppression. *
;* *
;****************************************************************
DECPRT: XOR A ; clear leading zero flag
LD (LZFLG),A ; flag cleared
LD DE,-1000 ; print 1000'S DIGIT
CALL DIGIT ; print digit
LD DE,-100 ; etc.
CALL DIGIT ; print digit
LD DE,-10 ; print 100's digit
CALL DIGIT ; do it
LD A,'0' ; get 1'S DIGIT
ADD A,L ; add just it
JP TYPE ; and print it
DIGIT: LD B,'0' ; start off with ascii 0
DIGLP: PUSH HL ; save current remainder
ADD HL,DE ; subtract
JP NC,DIGEX ; quit on overflow
POP AF ; throw away remainder
INC B ; bump digit
JP DIGLP ; loop back
DIGEX: POP HL ; restore pointer
LD A,B ; get data
CP '0' ; zero digit?
JP NZ,DIGNZ ; no, type it
LD A,(LZFLG) ; leading zero?
OR A ; test it
LD A,'0' ; get ascii zero
JP NZ,TYPE ; print digit
LD A,(SUPSPC) ; get space suppression flag
OR A ; see if printing file totals
RET Z ; yes, don't give leading spaces
LD A,' ' ; get a space
JP TYPE ; leading zero...print space
DIGNZ: LD (LZFLG),A ; leading zero flag so next zero prints
JP TYPE ; and print digit
;****************************************
;* *
;* Now check for libraries *
;* *
;****************************************
COND WHERE
PRTOTL: LD HL,(LCOUNT) ; how many files did we see?
LD A,H ; get hi byte
OR L ; and do 16 bit test with low
CALL NZ,PRTLMEM ; skip the .lbr check if none found
XOR A ; get a zero to...
LD (SUPSPC),A ; suppress leading spaces in totals
ENDC
COND FIND
PRTOTL:
XOR A ;get a zero to...
LD (SUPSPC),A ;suppress leading spaces in totals
ENDC
;****************************************************************
;* *
;* Directory for one user area completed. If 'ALL USERS' *
;* option is selected, then go do another directory on *
;* the next user number until we exceed the maximum user *
;* # for the selected drive. *
;* *
;****************************************************************
NXTUSR: CALL CKABRT ; check for user abort first
LD A,(MAXUSR) ; no abort - get maximum user number
LD HL,NEWUSR ; bump directory user number
INC (HL)
CP (HL) ; does next user # exceed maximum?
JP NC,SETTBL ; continue if more user areas to go
LD A,(BASUSR) ; reset base user number for the
LD (HL),A ; ..next directory search
;****************************************************************
;* *
;* Directory for all user areas completed. If the *
;* multi-disk option is enabled and selected, reset to *
;* the base user area and repeat the directory for next *
;* drive on-line until we either exceed the drives in our *
;* lodrv-hidrv table, or the BDOS shuts us down with a *
;* select or bad sector error, which will be intercepted *
;* back to the exit module. *
;* *
;****************************************************************
NXTDSK: LD HL,FNDFLG ; get file found flag
LD A,(HL) ; get flag
LD (HL),0 ; clear file found flag for next drive
OR A ; test old flag
JP NZ,NDSK ; continue if at least 1 file found
LD A,(QUIET) ; check output mode
OR A ; test it
JP Z,NDSK ; if zero, next
CALL CRLF ; clean up lint
LD A,(FCB) ; stash ascii dir. drive in no file msg
ADD A,'A'-1 ; ascify it
LD (NOFMS2),A ; and stuff it
LD DE,NOFMS1 ; print "no file on ? - "
CALL PRINT ; display it
NDSK: LD A,(DOPFLG) ; get flag
OR A ; and test it
JP NZ,EXIT ; ok, exit
CALL CKABRT ; check for user abort first
LD A,HIDRV-LODRV ; get maximum drive code to search
LD HL,FCB ; bump directory fcb drive code
INC (HL) ; up pointer
CP (HL) ; does next disk exceed maximum?
JP C,EXIT ; if so, exit
LD E,(HL) ; get value
LD D,0 ; clear hi
DEC E ; count down
LD HL,LODRV ; get it
ADD HL,DE ; add offset
LD A,(HL) ; pick up value from table
CP 0FFH ; and test it
JP Z,NDSK ; search next disk if maxdr not true
JP NOOPT ; onward
;****************************************************************
;* *
;* Print the user number of the directory in decimal. *
;* *
;****************************************************************
TYPUSR: LD A,(NEWUSR) ; get user number
CP 10 ; if user no. > 9 print leading 1
JP C,DUX ; ok, print
LD A,'1' ; else set leading user number
CALL TYPE ; display it
LD A,(NEWUSR) ; print low digit of user #
SUB 10 ; adjust it
DUX: ADD A,'0' ; ascify it
JP TYPE ; and display it
COND TWOCOL
GCRLF: LD A,(HCOUNT) ; get count
CP 5 ; see if at start
RET C ; yep, exit
LD A,' ' ; get a space
CALL TYPE ; send a space
LD A,(HCOUNT) ; get count
CP 5 ; see if at start
RET C ; yep, exit
CP 30 ; see if library displayed
JP C,SPACXX ; space it out
CP 50 ; test line length
JP NC,CRLF ; else space line out
SEPCRL: LD A,(NEWUSR) ; get user number
CP 10 ; test it
JP NC,SEPLNG ; space for < 10
LD A,' ' ; get a space
CALL TYPE ; and send space
SEPLNG: LD A,'|' ; get fence character
CALL TYPE ; and display it
LD A,' ' ; get a space
CALL TYPE ; now display it
RET ; return were finished
SPACXX: PUSH HL ; save the world
PUSH DE
PUSH BC
PUSH AF
LD B,15 ; number of columns to move
LD HL,XXFIL ; space filled string
CALL TYPEIT ; send spaces
POP AF ; and restore the world
POP BC
POP DE
POP HL
JP SEPCRL ; send separator
XXFIL: DEFB ' '
ENDC
COND (NOT TWOCOL AND 0FFH)
GCRLF:
ENDC
;********************************************************
;* *
;* Send a carriage return line feed to console. *
;* *
;********************************************************
CRLF: LD A,CR ; send cr
CALL TYPE ; display it
LD A,LF ; send lf
JP TYPE ; exit to caller from type
;****************************************************************
;* *
;* Output character in a to console, and optionally *
;* to printer and/or the output file. *
;* *
;****************************************************************
TYPE: PUSH BC ; save the world
PUSH DE
PUSH HL
PUSH AF ; save the character to output
CALL TYPE1 ; send it to console
COND PAGNAT
LD A,(HCOUNT) ; get hor count
INC A ; up count
LD (HCOUNT),A ; and save updated count
POP AF ; get character
PUSH AF ; and save on stack
AND 01111111B ; kill parity bit
CP LF ; test if at end
JP NZ,TYPRET ; do exit
LD A,0 ; get a zero
LD (HCOUNT),A ; and update counter
LD A,(VCOUNT) ; get vertical count
INC A ; up count
LD (VCOUNT),A ; save new count
CP 60 ; 60 lines per page
JP C,TYPRET ; not at end, onward
LD B,6 ; 6 blank lines
FRMFED: PUSH BC ; save it
LD A,CR ; we go around the normal
CALL TYPE1 ; output routine so we
LD A,LF ; don't get trapped in
CALL TYPE1 ; a loop
; CALL CRLF ; clean line
POP BC ; get count
DJNZ FRMFED ; count it down
LD A,0 ; get a zero
LD (VCOUNT),A ; up count
ENDC ; pagnat
TYPRET: POP AF ; restore the output character
POP HL ; exit from type
POP DE
POP BC
RET ; back, were finished
;********************************
;* *
;* Output character *
;* *
;********************************
TYPE1: LD E,A ; get character into bdos entry register
LD C,WRCHR ; set up function
JP BDOS ; call conout via the bdos
;************************************************
;* *
;* Print a string at HL of length B *
;* *
;************************************************
TYPEIT: LD A,(HL) ; pick up character
AND 07FH ; mask parity bit off
CALL TYPE ; go display it
INC HL ; point to next character
DEC B ; and count down characters
JP NZ,TYPEIT ; to display
RET ; return if none left
;************************************************
;* *
;* Print string terminated with last *
;* byte high on console *
;* *
;************************************************
PRINT: LD A,(DE) ; pick up character
PUSH AF ; save on stack
AND 7FH ; mask it (no 8th bit)
CALL TYPE ; send to console
POP AF ; get original back
OR A ; test it
RET M ; back if MSB set
INC DE ; else bump pointer
JP PRINT ; and do next
;********************************************************
;* *
;* Fetch character from console (without echo) *
;* *
;********************************************************
CINPUT: LD HL,(BASE+1) ; get warm boot vector
LD L,9 ; get input offset
CALL GOHL ; go to conin routine in bios
AND 7FH ; mask any parity bit
RET ; and back to caller, we have it
;****************************************************************
;* *
;* Check for a CTL-C or CTL-S entered from the keyboard. *
;* Jump to exit if CTL-C, pause on CTL-S. *
;* *
;****************************************************************
CKABRT: LD HL,(BASE+1) ; get warm boot vector
LD L,6 ; check status of keyboard
CALL GOHL ; any key pressed?
OR A ; test
RET Z ; no, return to caller
CALL CINPUT ; get character
CP 'C'-40H ; ctl-c?
JP Z,EX0 ; if ctl-c then quit
CP 'X'-40H ; ctl-x?
JP Z,EX0 ; if ctl-x then quit
CP 'S'-40H ; ctl-s?
RET NZ ; no, return to caller
CALL CINPUT ; yes, wait for another char.
CP 'C'-40H ; might be ctl-c
JP Z,EX0 ; if ctl-c then quit
CP 'X'-40H ; might be ctl-x
JP Z,EX0 ; if ctl-x, else fall thru and continue
RET ; all finished, exit
;************************************************
;* *
;* Kludge to allow call to address in HL *
;* *
;************************************************
GOHL: JP (HL)
;********************************************************
;* *
;* Entry to BDOS saving all extended registers *
;* *
;********************************************************
CPM: PUSH BC ; save them registers
PUSH DE
PUSH HL
CALL BDOS ;
LD B,A ; save return code
LD A,(VERFLG) ; is this 3.0?
CP 30H ; see if a zero
LD A,B ; get value
JP C,CPM20 ; no, exit normally
CP 0FFH ; it is 3.0 - was return code 0FFH?
JP NZ,CPM20 ; no, exit normally
LD A,H ; 3.0 and a=0FFH - check for error code
OR A ; test it
JP NZ,DSKERR ; trap out if we got a physical error
LD A,B ; else continue normally
CPM20: POP HL ; restore the world
POP DE
POP BC
RET ; and back to caller, were finished
;
;****************************************************************
;* *
;* For file output mode, return to old user area and *
;* set dma for the file output buffer. *
;* *
;****************************************************************
SETFOP: LD A,(OLDUSR) ; get user number at startup
LD E,A ; set it up
LD C,CURUSR ; set up function
CALL CPM ; reset the old user number
RET ; and back, were finished
;****************************************************************
;* *
;* Move disk buffer dma to default buffer for directory *
;* search operations and bdos media change routines *
;* (necessary for pre-cp/m 2 systems while in file output *
;* mode with an active buffer). *
;* *
;****************************************************************
SETSRC: LD DE,BASE+80H ; point to default DMA address
SET2: LD C,SETDMA ; set up function call
JP CPM ; and set dma address
;****************************************
;* *
;* Compare routine for sort. *
;* *
;****************************************
COMPR: PUSH HL ; save table address
LD E,(HL) ; load low order
INC HL ; bump pointer
LD D,(HL) ; load high order
INC HL ; bump it again
LD C,(HL) ; pick up data
INC HL ; bump pointer
LD B,(HL) ; and last piece of information
;********************************************************
;* *
;* BC, DE now point to entries to be compared. *
;* *
;********************************************************
EX DE,HL ; swap pointers
LD E,A ; get count
CMPLP: LD A,(HL) ; get character
AND 7FH ; mask parity bit
LD D,A ; save it in D
LD A,(BC) ; get next character
AND 7FH ; mask parity bit
CP D ; test for match
INC HL ; up source pointer
INC BC ; up compare pointer
JP NZ,NOTEQL ; quit on mismatch
DEC E ; or end of count
JP NZ,CMPLP ; loop till end of string
NOTEQL: POP HL ; restore pointer
RET ; cond code tells all
;************************************************
;* *
;* Swap entries in the order table. *
;* *
;************************************************
SWAP: LD BC,ORDER-2 ; table base
ADD HL,HL ; *2
ADD HL,BC ; + base
EX DE,HL
ADD HL,HL ; *2
ADD HL,BC ; + base
LD C,(HL) ; get low address of pointer
LD A,(DE) ; and do it for other pointer
EX DE,HL ; swap pointers
LD (HL),C ; swap low pointer value
LD (DE),A ; swaped
INC HL ; bump pointer
INC DE ; bump pointers, both of them
LD C,(HL) ; get hi address
LD A,(DE) ; and the other
EX DE,HL ; swap pointers
LD (HL),C ; swap hi pointer value
LD (DE),A ; swaped
RET ; and back, were finished
;********************************
;* *
;* New compare routine. *
;* *
;********************************
COMPARE:
LD BC,ORDER-2 ; table base
ADD HL,HL ; *2
ADD HL,BC ; + base
EX DE,HL
ADD HL,HL ; *2
ADD HL,BC ; + base
EX DE,HL ; swap pointers
LD C,(HL) ; get low value
INC HL ; bump pointer
LD B,(HL) ; get low test value
EX DE,HL ; bump pointer
LD E,(HL) ; get hi value
INC HL ; bump pointer
LD D,(HL) ; get it
EX DE,HL ; swap pointers
LD E,A ; count
CMPLPE: LD A,(HL) ; get character
AND 7FH ; mask out 8th bit
LD D,A ; save it in D
LD A,(BC) ; get test character
AND 7FH ; mask out 8th bit
CP D ; see if match (z flag)
INC BC ; up pointers
INC HL ; both of them
RET NZ ; no match, exit
DEC E ; else count down string length
JP NZ,CMPLPE ; and loop till all match
RET ; if we get here, they matched
;********************************
;* *
;* --- Error exit --- *
;* *
;********************************
ERXIT: CALL CRLF ; space down
POP DE ; get pointer to message string
CALL PRINT ; print it
LD DE,ERRMS1 ; print " error"
CALL PRINT ; send message
CALL CRLF ; space down
;************************************************
;* *
;* --- Exit - all done restore stack --- *
;* *
;************************************************
EXIT: LD A,(DOPFLG) ; check multi disk mode
OR A ; set cpu flag
JP NZ,EX0 ; onward
CALL CKABRT ; check for user abort first
LD A,HIDRV-LODRV ; get maximum drive code to search
LD HL,FCB ; bump directory fcb drive code
INC (HL) ; up pointer
CP (HL) ; does next disk exceed maximum?
JP C,EX0 ; onward
JP NOOPT ; search next disk if maxdr not true
TMMSG: DEFB CR,LF,LF,'Files Matched -',' '+80H
TCMSG: DEFB CR,LF,'Files Checked -',' '+80H
TLMSG: DEFB CR,LF,'Libraries Searched -',' '+80H
TFILES: DEFW 0
TLIBRA: DEFW 0
TMATCH: DEFW 0
EX0: LD DE,TMMSG ; point to matched message
CALL PRINT ; display it
LD HL,(TMATCH) ; get count
CALL DECPRT ; and tell how many matched
LD DE,TCMSG ; point to checked message
CALL PRINT ; display it
LD HL,(TFILES) ; get checked count
CALL DECPRT ; and tell him how many
LD DE,TLMSG ; point to library message
CALL PRINT ; display it
LD HL,(TLIBRA) ; get count
CALL DECPRT ; and tell how many libraries checked
LD C,CONST ; check console status
CALL CPM ; get status
OR A ; char waiting?
LD C,RDCHR ; assume one waiting
CALL NZ,CPM ; gobble up char
LD A,(VERFLG) ; or error mode, depending on version
CP 30H ; test for match
JP C,EXIT0 ; nope, cpm 2.xx
LD C,45 ; get value
LD E,0 ; set error mode back to default
CALL CPM ; go do it
JP EXIT1 ; onward
EXIT0: LD A,(DOPFLG) ; ..if they were swapped
OR A ; test flag
CALL Z,SWAPEM ; reverse them if so
EXIT1: LD A,'L'-'@' ; form feed character
CALL TYPE1 ; go send to top of page
LD HL,(STACK) ; get old stack pointer
LD SP,HL ; move back to old stack
RET ; ..and return to ccp
VERERR: LD DE,VERBAD ; abort cp/m is version 1.?
VERER1: CALL PRINT ; display message
JP EXIT1 ; and abort
NONERR: LD DE,VERNAME ; print help info
JP VERER1 ; tell him
;********************************************************
;* *
;* Trap BDOS select and sector error vectors to *
;* our own intercept routine so we can catch a *
;* reference to an illegal drive. *
;* *
;********************************************************
SWAPEM: LD A,(VERFLG) ; check version
CP 30H ; see if error mode call is available
JP C,SWAP20 ; if not, use bdos error vectors
LD C,45
LD E,0FFH ; use set error mode call
CALL CPM ; set "return code only" mode
RET ; and back, were done
SWAP20: LD HL,(BDOLOC) ; get pointer to base of bios
LD A,L ; get low value
OR H ; test with hi
JP NZ,SWAPO0 ; yep, onward
LD HL,BASE+6 ; get bdos address
SWAPO0: LD L,9 ; set pointer to error vectors
SWAPOK: LD DE,VECTBL ; exchanging with our own vector table
LD A,4 ; 4 bytes to swap
SWAPLP: LD B,(HL) ; get byte from hl
EX DE,HL
LD C,(HL) ; get byte from de
LD (HL),B ; put byte from hl
EX DE,HL
LD (HL),C ; put byte from de
INC HL ; bump exchange pointers
INC DE
DEC A ; dock counter
JP NZ,SWAPLP ; continue swapping till done
RET
;************************************************
;* *
;* Recovery point from intercepted BDOS *
;* select and bad sector errors. *
;* *
;************************************************
DSKERR: LD SP,STACK ; get out of bdos' STACK
JP EXIT ; ..and exit back to ccp
COND WHERE
;================================================================
;= =
;= SUBROUTINES TO READ LIBRARY FILE DIRECTORY =
;= =
;================================================================
PRTLMEM:
LD HL,SEARN+8 ; get value
CALL CKLBR ; see if library entry
RET Z ; nope, exit
LD HL,ORDER ; initialize order table pointer
LD (NEXTL),HL ; save pointer
ENTRYL: LD HL,(LCOUNT) ; get fcb count
DEC HL ; decrement it
LD (LCOUNT),HL ; and update counter
LD A,H ; is this the last file?
OR L ; see if count = 0
JP Z,LBRTST ; if count=0, last file skip compare
PUSH BC ; save it
CALL CKABRT ; check for abort code from keyboard
LD HL,(NEXTL) ; get value
LD A,11 ; set up length of filename
CALL COMPR ; does this entry match next one?
POP BC ; restore it
JP NZ,LBRTST ; no, print it
INC HL ; up pointer
INC HL ; skip, highest extent comes last in list
LD (NEXTL),HL ; and save new pointer
JP ENTRYL ; loop back for next lowest extent
;****************************************
;* *
;* Exit library member printing *
;* *
;****************************************
LBEXIT: XOR A ; get a zero to...
LD (SUPSPC),A ; suppress leading spaces in totals
RET ; back, were finished
;************************************************
;* *
;* Valid entry obtained - spit it out. *
;* *
;************************************************
LBRTST: LD HL,(NEXTL) ; get order table pointer
LD E,(HL) ; get low order address
INC HL ; up pointer
LD D,(HL) ; get high order address
INC HL ; and up it again
LD (NEXTL),HL ; save updated table pointer
LD HL,8 ; set up offset
ADD HL,DE ; add offset
CALL CKLBR ; go test it
JP NZ,LBRNEX ; onward
PUSH DE ; now put DE into HL
POP HL ; done
;************************************************
;* *
;* Saves the library file name into lbrfcb *
;* *
;************************************************
LD A,(FCB)
LD DE,LBRFCB ; to
LD (DE),A
INC DE
LD B,11 ; length
CALL MOVE ; do the move
EX DE,HL
LD B,25
CLMFCB: LD (HL),0 ; clear memory <- HL
INC HL ; up it by 1
DEC B ; count down
JP NZ,CLMFCB ; and clear rest of FCB
CALL SETLDMA ; set up xfer address
LD DE,LBRFCB ; point to file
LD C,OPEN ; get function
CALL CPM ; open it
LD C,READ ; set up read function
LD DE,LBRFCB ; point to FCB
CALL CPM ; read a record
CALL SETFOP ; set it up
LD HL,LBBUF ; set up pointer
LD A,(HL) ; get byte
OR A ; and see if zero
JP Z,CKLDIR ; check directory present?
LMLEXI: CALL LBCLOSE
;********************************
;* *
;* Do next library file *
;* *
;********************************
LBRNEX: LD HL,(LCOUNT) ; check count
LD A,H ; do a 16 bit test
OR L ; tested
JP Z,LBEXIT ; no more, all done
JP ENTRYL ; else, get next .lbr file
;********************************
;* *
;* Close the library file. *
;* *
;********************************
LBCLOSE:
LD DE,LBRFCB ; point to FCB
LD C,CLOSE ; set up function
CALL CPM ; have the system close it
RET ; and back to caller, were finished
;************************************************
;* *
;* Set the library file dma address. *
;* *
;************************************************
SETLDMA:
LD A,(NEWUSR) ; get user area for directory
LD E,A ; set user up
LD C,CURUSR ; get the user function
CALL CPM ; ..and set new user number
LD DE,LBBUF ; point to buffer
LD C,SETDMA ; set up xfer address function
CALL CPM ; set xfer address
RET ; and back to caller, were finished
;********************************************************
;* *
;* Check to see if there indeed is a lbr file *
;* directory and barf if not! *
;* *
;********************************************************
CKLDIR: LD B,11 ; length of file name
LD A,' ' ; space
INC HL ; up pointer
CKDLP: CP (HL) ; see if we match
JP NZ,LMLEXI ; nope, onward
DEC B ; else count down
INC HL ; up pointer
JP NZ,CKDLP ; and loop back
;********************************************************
;* *
;* The first entry in the LBR directory is indeed *
;* blank. Now see if the directory size is >0. *
;* *
;********************************************************
LD E,(HL) ; file starting location low
INC HL ; must be zero here
LD A,(HL) ; file starting location high
OR E ; must be zero here also
JP NZ,LMLEXI ; nope, onward
INC HL ; yep, bump pointer
LD E,(HL) ; get library size low
INC HL ; point to library size high
LD D,(HL) ; get library size high
LD A,D ; set it up
OR E ; library must have some size
JP Z,LMLEXI ; yep, onward
DEC DE ; back it down
EX DE,HL ; swap pointers
LD (SLFILE),HL ; save pointer
LD B,3 ;
LD HL,17 ; set up offset
ADD HL,DE ; add offset
PUSH HL ; save on stack
LD HL,(TLIBRA) ; get count
INC HL ; increment it
LD (TLIBRA),HL ; and save it
POP HL ; restore value
JP LMTEST ; onward
LFMLOP: LD HL,(SLFILE) ; get count
LD A,L ; get low
OR H ; and do 16 bit test
JP Z,LMLEXI ; zero, exit
DEC HL ; count down
LD (SLFILE),HL ; and save new count
CALL SETLDMA ; set up the xfer address
LD C,READ ; read a block of data function
LD DE,LBRFCB ; point to library FCB
CALL CPM ; read the block in
CALL SETFOP
LD B,4 ; get file count per sector
LD HL,LBBUF ; get buffer starting address
LMTEST: LD A,(HL) ; get member open flag
OR A ; test for open
JP Z,PRMNAM ; if zero, onward
LMTESA: LD DE,32 ; member not open get offset
ADD HL,DE ; to next and add it in.
DEC B ; is buffer empty ?
JP NZ,LMTEST ; no so test next entry
JP LFMLOP ; yes get next buffer...
PRMNAM: PUSH HL ; print member name and size
PUSH BC
CALL CKABRT ; check for abort code from keyboard
PRMNA1: POP BC ; now we swap HL
POP HL ; and BC
PUSH HL ; save on the stack
PUSH BC ; for later
INC HL ; bump pointer
PUSH HL ; save as we update count
LD HL,(TFILES) ; get count
INC HL ; bump it by one
LD (TFILES),HL ; and save count
POP HL ; now restore the pointer
CALL COMPS ; match what we are looking for ?
JP NZ,LBGNXT ; nope, onward
PUSH HL ; save it on the stack
LD HL,(TMATCH) ; get match count
INC HL ; up it by one
LD (TMATCH),HL ; and save it for later
POP HL ; get pointer back from stack
CALL GCRLF ; changed for two column output
LD A,(FCB) ; ..precede new line with drive name
ADD A,'A'-1 ; ascify it
CALL TYPE ; and display drive
CALL TYPUSR ; now display user
LD A,':' ; tag header with a colon and a space
CALL TYPE ; ..and exit back to entry
COND ZCPR3
CALL SHONDR
ENDC ; ZCPR3
LD A,' ' ; get a space
CALL TYPE ; and display it after drive-user-:
LD B,8 ; file name length
CALL TYPEIT ; display file name
LD A,'.' ; period after fn
CALL TYPE ; display the dot
LD B,3 ; display 3 characters of filetype
CALL TYPEIT ; display the extension
INC HL ; bump the pointer by 2
INC HL
LD E,(HL) ; get value
INC HL ; bump pointer
LD D,(HL) ; we have the 16 bit value
EX DE,HL
;********************************************************
;* *
;* Output the size of the individual file. *
;* *
;********************************************************
PUSH DE ; save on stack
PUSH HL
PUSH HL
LD HL,(LLENLOC) ; get pointer
PUSH HL ; switch around on stack
POP DE ; swapping
POP HL ; swapped
ADD HL,DE ; add offset and form pointer
LD (LLENLOC),HL ; save new pointer
POP HL ; and restore old pointer
;********************************************************
;* *
;* New code added to convert lib members from *
;* sectors to 'K'. *
;* *
;* Upon entry member's size in sectors is in HL. *
;* *
;********************************************************
EX DE,HL ; put it in de
LD HL,0 ; zero out hl
LD A,E ; put low byte of sector count in a
ADD A,7 ; add seven to always round up 1k
RRCA ; convert it to k
RRCA
RRCA
AND 1FH ; mask it
LD E,A ; and put it back
LD L,D ; get the high byte if any
LD D,0 ; clean out the old resting place
ADD HL,HL ; multiply it by 32 to convert to
ADD HL,HL ; number
ADD HL,HL ; of
ADD HL,HL ; k
ADD HL,HL ; bytes
ADD HL,DE ; and add in the low byte
POP DE
CALL DECPRT ; ..go print it
LD A,'K' ; ..and follow with size
CALL TYPE ; display the 'K'
LD HL,INLBF ; set pointer
LD B,3 ; gfs spacing
CALL TYPEIT ; and display it
LD HL,LBRFCB+1 ; point to filename
LD B,8 ; file name length
CALL TYPEIT ; display file name
LD A,'.' ; period after fn
CALL TYPE ; display dot
LD B,3 ; display 3 characters of filetype
CALL TYPEIT ; display extension
LD A,0FFH ; get flag value
LD (FNDFLG),A ; set file found flag
;********************************************************
;* *
;* At least one more file to output - can we *
;* put it on the current line? *
;* *
;********************************************************
LBGNXT: POP BC ; restore the pointers
POP HL ; from the stack
JP LMTESA ; .. and go output another file
ENDC ; whereis
COMPS: PUSH HL ; save the world
PUSH DE
PUSH BC
LD BC,SEARN ; set pointer
LD E,11 ; set count to filename.ext length
COMPS1: LD A,(HL) ; get character
AND 7FH ; mask parity bit
LD D,A ; and save it in D
LD A,(BC) ; get test character
INC BC ; up pointers
INC HL ; both of them
AND 7FH ; mask parity from test character
CP '?' ; see if ambiguous character
JP Z,COMPS2 ; yep, onward
CP D ; else see if match
JP NZ,COMPS3 ; nope, onward
COMPS2: DEC E ; count down filename.ext length
JP NZ,COMPS1 ; loop back till finished
COMPS3: POP BC ; now we restore the world
POP DE
POP HL
RET ; and back to caller, were finished
INLBF: DEFB ' > '
;********************************************************
;* *
;* Move characters from 'HL' to 'DE' length in 'B' *
;* *
;********************************************************
MOVE: LD A,(HL) ; get a character
LD (DE),A ; store it
INC HL ; to next 'FROM'
INC DE ; to next 'TO'
DEC B ; more?
JP NZ,MOVE ; yes, loop
RET ; no, return
COND ZCPR3
SHONDR:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
PUSH IX
LD IX,Z3NDIR-18
LD BC,18
LD A,(FCB)
LD D,A
LD A,(NEWUSR)
LD E,A
SHONDR1:
ADD IX,BC
LD A,(IX+0)
OR A
JR Z,SHONDR6
LD H,(IX+0)
LD L,(IX+1)
XOR A
SBC HL,DE
JR NZ,SHONDR1
LD B,8
INC IX
LD A,'<'
CALL TYPE
SHONDR2:
INC IX
LD A,(IX+0)
CP ' '
JR Z,SHONDR3
CALL TYPE
DJNZ SHONDR2
SHONDR3:
LD A,'>'
CALL TYPE
LD A,B
OR A
JR Z,SHONDR5
SHONDR4:
LD A,' '
CALL TYPE
DJNZ SHONDR4
SHONDR5:
POP IX
POP HL
POP DE
POP BC
POP AF
RET
SHONDR6:
LD B,10
JR SHONDR4
ENDC ; ZCPR3
COND WHERE
;****************************************
;* *
;* Test file extent for LBR. *
;* *
;****************************************
CKLBR: PUSH HL ; save the world
PUSH DE
PUSH BC ;
EX DE,HL ; swap pointers
LD HL,LBRTYP ; set up pointer for test
LD C,3 ; set up extension length
CKLBL: LD A,(DE) ; get character
AND 7FH ; mask MSB
CP (HL) ; see if a match
JP NZ,CKLBX ; nope, not .LBR so exit
INC HL ; yep, up pointers
INC DE ; both source and test
DEC C ; count down length
JP NZ,CKLBL ; and loop to all matched
CKLBX: POP BC ; restore the world
POP DE
POP HL
RET ; and back to caller, were finished
ENDC
HCOUNT: DEFB 0 ; horizontal count
VCOUNT: DEFB 0 ; vertical count
PROGEND:
STACK EQU PROGEND+82H
ORDER EQU PROGEND+84H
SUBTTL SYMBOL TABLE
END