home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
programs
/
wstar
/
wsmulcop.lbr
/
WSMULCOP.ZQ0
/
WSMULCOP.Z80
Wrap
Text File
|
1985-11-24
|
14KB
|
473 lines
title 'WSMULCOP.Z80'
listw 95
;WSMULCOP.Z80
;A program to make unattended multiple printouts from WordStar
; using EX15.COM, a public-domain substitute for SUBMIT.COM.
;WSMULCOP.Z80 copyright 11-19-85 by M. L. Halbert
; 104 Morgan Road
; Oak Ridge, TN 37830
;
; Permission granted for unlimited private use.
;Usage: A>WSMULCOP
;------
;WSMULCOP asks name of file to be printed and no. of copies desired
; (up to 99 copies).
;Method: WSMULCOP.COM generates a disk file PR.SUB. This file is
;------- executed by EX15.COM. PR.SUB consists of:
;
; A:WS
; p B:document.ext^[ (or other drivecode,
; p B:document.ext^[ if specified)
; . . . (n times)
; Y PR.SUB
;
; (EX15 converts ^[ to <ESC>, which tells WordStar to
; use the defaults for its 6 questions for a P command.)
;
; WSMULCOP.COM places a reference to PR.SUB in the command
; tail buffer at 80h and moves part of itself to
; high storage (2000H),well above the top of EX15.COM.
; (EX15 later relocates itself as well, but that is of no
; concern for WSMULCOP.COM.) The moved segment of WSMULCOP.COM
; then loads EX15.COM at 0100H and jumps there, thereby
; starting EX15 in motion.
;
; After the n copies are printed, EX15 erases PR.SUB and
; leaves the user at the Opening Menu in WordStar.
;Restrictions:
;-------------
;Both WSMULCOP.COM and EX15.COM are assumed to be on A:.
;The default drivecode of the file to be printed is B:, but
; any code may be prefixed to the filename. Validity of the
; drivecode and the existence of the file are not checked until
; EX15 tries to execute PR.SUB.
;Assembly:
;---------
;Written for the modified Crowe Z80 assembler as supplied by
; Micro Cornucopia on their Kaypro User Disk K-25, identified
; as CROWE(JH/DC/JGO) Z80 1.3e. Although the program is written
; with Zilog Z80 mnemonics, only instructions common to the 8080
; have been used.
;Making the .COM file may be accomplished as follows:
; *****
;Equates
;-------
wboot equ 0 ;start Warm Boot
stsize equ 20 ;stack size
tpa equ 100h ;start of TPA
tail equ 80h ;CCP puts command tail here
bdos equ 05h ;jump to start of bdos
dfcb equ 05Ch ;default file control block
cr equ 0Dh ;carriage return
lf equ 0Ah ;line feed
;Next two are for segment of code to be moved out of the way
; so EX15.COM can be loaded.
high equ 2000h ;well above top of EX15.COM
lenth equ 20h ;length of segment to be moved
org tpa
;Initialization.
;---------------
ld sp,stack ;set stack pointer
;Set up default fcb for pr.sub
ld hl,prsub ;filename in fcb format
ld de,dfcb ;dest. is default fcb
ld c,12 ;loop counter
call copy
;Complete dfcb by inserting 24 nulls
ld c,24
sub a ;clear 'a'
loop0: ld (de),a ;insert null character
inc de
dec c
jp nz,loop0
;Delete old pr.sub if it exists.
ld de,dfcb
ld c,19 ;BDOS service 19, delete file
call bdos ;(no need to check response)
;Make a directory entry.
ld de,dfcb
ld c,22 ;BDOS service 22, make a file
call bdos
cp 0FFh ;a=FFh if unsuccessful
jp nz,query1
ld de,mess1 ;'dir. full' message
ld c,9 ;BDOS service 9:
call bdos ; Write a string to console
jp wboot ;quit
;Dialog with user, process responses.
;---------------------------------------
;Ask for document filename
query1: ld de,q1 ;first query
ld c,9
call bdos
ld de,ans1 ;first answer
ld c,10 ;BDOS service 10:
call bdos ; Get a line from console
;Fill out WordStar print-command line
ld de,combuf ;start of command-line buffer
ld a,'p'
ld (de),a
inc de
ld a,' '
ld (de),a
inc de
;Check if user has supplied optional drivecode
ld hl,ans1+3 ;get 4th byte
ld a,(hl)
cp ':' ;is it a colon?
jp z,chars ;yes, include in buffer
ld a,'B' ;no, setup B: as default
ld (de),a
inc de
ld a,':'
ld (de),a
inc de
chars: ld hl,ans1+1 ;2nd byte = no. of chars.
ld a,(hl)
ld c,a ;put no. of char. in loop counter
ld hl,ans1+2 ;start of filename.ext
call copy
;Insert ^[ after filename.ext, which EX15 will convert to <ESC>,
; to tell WordStar to choose default print options.
ld a,'^'
ld (de),a
inc de
ld a,'['
ld (de),a
inc de
ld a,cr
ld (de),a
inc de
ld a,lf
ld (de),a
;Calculate and save total character count in print-command line
ld hl,ans1+3 ;first retrieve 4th byte of ans1
ld a,(hl)
sub ':'-1 ;= +1 if user supplied colon
ld b,a
ld hl,ans1+1 ;get no. of chars. in ans1
ld a,(hl)
add a,6 ;6 added chars: p, ,^,[,cr,lf
dec b
jp z,storl ;was colon present?
add a,2 ;no, so 2 more added chars (B,:)
storl: ld de,length
ld (de),a ;save in 'length'
jp query2 ;skip over beep first time
;Ask for number of copies
beep: ld e,07 ;07h for beep
ld c,2 ;BDOS service 2, output a byte
call bdos
query2: ld de,q2 ;second query
ld c,9
call bdos
ld de,ans2 ;second answer
ld c,10
call bdos
;Decode decimal digits for no. of copies, ncop
sub a ;clear A register
ld (ncop),a ;initialize ncop to zero
ld hl,ans2+1 ;2nd byte has digit count
ld a,(hl) ;digit count
cp 3 ;less than 3 digits?
jp nc,beep ;no, try again
ld b,a ;ok, save for later
ld c,a ;use in loop below
loopc: inc hl ;next position
dec c
jp nz,loopc ;c=0 means units digit
ld a,(hl) ;get units digit
call chkdig ;check for valid ASCII digit
sub '0' ;convert from ASCII to hex
ld (ncop),a ;store result
dec b ;finished when b=0
jp z,conf ;yes: only one digit present
dec hl ;no, get tens digit
ld a,(hl)
call chkdig ;check for valid ASCII digit
sub '0' ;convert from ASCII to hex
;Multiply by 10 by adding 10 the correct no. of times
ld c,a ;addition counter
sub a ;clear 'a'
loop3: add a,10
dec c
jp nz,loop3 ;nonzero: not finished
ld c,a ;save for addition to units
ld a,(ncop) ;retrieve units value
add a,c
ld (ncop),a ;cumulative result
;Ask for confirmation
; First retrieve ASCII digits for message
conf: ld de,conf1+11 ;location of tens digit
ld a,' ' ;blank in case no tens digit
ld (de),a ;store blank
ld hl,ans2+1 ;get number of digits
ld a,(hl)
cp 1 ;1 digit only?
jp z,one ;yes
inc hl ;no, get tens digit
ld a,(hl)
ld (de),a ;enter tens digit
one: inc hl
inc de
ld a,(hl) ;get units digit
ld (de),a ;enter it in message
;Initialize filename part of message to blanks
ld de,conf1+24 ;location in message for name
ld c,14 ;max no. of chars.
loopb: ld a,' ' ;blank
ld (de),a ;enter blank
inc de
dec c
jp nz,loopb
;Enter filename over the blanks
ld de,conf1+24 ;location in message for name
ld hl,combuf+2 ;start of d:filename
ld a,(length) ;no. of chars. in command line
sub 6 ;extra chars.
ld c,a ;initialize loop counter
call copy
;Show message on screen
ld de,conf1
ld c,9
call bdos
ld de,conf2
ld c,9
call bdos
;Response: need check only for Y or y.
ld c,1 ;BDOS service 1, get a byte
call bdos ;byte returned in 'a' register
cp 'y'
jp z,enter1
cp 'Y'
jp z,enter1
jp query1 ;go back for another dialog
;Enter WordStar print-command lines into write buffer.
;-----------------------------------------------------
;Initialize disk-write buffer to 1Ah (EOF char. for ASCII files)
enter1: call init
ld de,wbuf ;initialize buffer pointer
ld b,128 ;initialize buffer counter
;Copy first command line (A:WS,cr,lf)
ld c,6 ;char. count of first command
ld hl,line1 ;location of 1st command line
enter2: ld a,(hl) ;get char. from command line
ld (de),a ;enter character into buffer
inc hl ;increment command line counter
inc de ;increment buffer pointer
dec b ;decrement buffer counter
dec c ;decrement loop counter
jp nz,enter2
;Insert print command ncop times.
;When counter shows end of write buffer, have to write to disk
; and start a new buffer.
loop4: ld a,(length)
ld c,a ;char. count of command line
ld hl,combuf ;start of command-line buffer
loop5: ld a,(hl) ;get next character
ld (de),a ;enter character
inc hl ;set up next char. to get
inc de ;dest. pointer for next time
dec b ;at end of buffer?
jp nz,contin ;no, continue with next char.
call write ;yes, go write on disk
call init ;initialize buffer to EOF (1Ah)
ld de,wbuf ;reset buffer pointer
ld b,128 ;reinitialize buffer counter
contin: dec c ;check character counter
jp nz,loop5 ;if c=0, job is complete
;Use ncop to count no. of lines remaining to be entered
ld hl,ncop ;get ncop
dec (hl) ;decrement ncop
jp nz,loop4 ;if 0, no more copies needed
;Enter last line of pr.sub
ld hl,erapr ;command to erase pr.sub
ld c,12 ;12 characters in this line
loop6: ld a,(hl)
ld (de),a
inc hl
inc de
dec b
jp nz,keepon ;if buffer not full, keep on
call write ;buffer full, so write on disk
call init ;initialize buffer to EOF
ld de,wbuf ;reset buffer pointer
ld b,128 ;reinitialize buffer counter
keepon: dec c
jp nz,loop6 ;continue with next character
call write ;write last buffer onto disk
;Close PR.SUB file
ld de,dfcb
ld c,16 ;BDOS service 16:
call bdos ; Close a file
;PR.SUB now ready. Set up command tail, load EX15, and go!
;----------------------------------------------------------
;Set up fcb for EX15.COM in dfcb location
ld de,dfcb
ld hl,exfcb ;'1EX15 COM'
ld c,12 ;character count
call copy
;Set remaining 24 bytes in dfcb to nulls
ld c,24 ;character count
sub a ;null
loopz: ld (de),a
inc de
dec c
jp nz,loopz
;Set up command tail to simulate what CCP does
ld de,tail ;start of command tail
ld a,9 ;char. count incl. blank
ld (de),a ;goes into 1st byte of tail
inc de
ld hl,erapr+1 ;' A:PR.SUB'
ld c,9 ;char. count incl. blank
call copy
sub a ;get a null
ld (de),a ;null to terminate tail
;Open file EX15.COM
ld de,dfcb
ld c,15 ;BDOS service 15:
call bdos ; Open a file
cp 0FFh ;a=FFh if file not found
jp nz,setadd
ld de,mess3 ;"file not found" message
ld c,9 ;write to console
call bdos
jp wboot ;quit
;Set buffer address (destination for read)
setadd: ld de,tpa
ld c,26
call bdos
jp hicop ;skip over subr., data
;Subroutines.
;------------
;Subroutine to copy from one part of memory to another.
; hl is source pointer, de is DEstination pointer,
; c is loop counter. Set up these registers prior to call.
copy: ld a,(hl) ;get character from source
ld (de),a ;put character into destination
inc hl ;increment source pointer
inc de ;increment destination pointer
dec c ;decrement loop counter
jp nz,copy
ret
;Subroutine to check for valid ASCII digit in 'a' register
chkdig: cp '0' ;carry flag set if a < '0'
jp c,beep ;if so, prompt for new input
cp '9'+1 ;carry = 0 if a .ge. '9'+1
jp nc,beep
ret
;Subroutine to initialize buffer to EOF character (1Ah)
init: push bc
push hl
ld c,128 ;size of wbuf
ld hl,wbuf ;start of buffer
initbf: ld a,1Ah
ld (hl),a
inc hl
dec c
jp nz,initbf
pop hl
pop bc
ret
;Subroutine to write buffer onto disk.
write: push bc ;save in case loops not done
push hl ;also this--bdos changes hl
;Set buffer address to start of write buffer.
ld de,wbuf ;start of buffer
ld c,26 ;BDOS service 26:
call bdos ; Set buffer address
ld de,dfcb ;fcb address
ld c,21 ;BDOS service 21:
call bdos ; Sequential write
cp 0 ;a=0 means no error
pop hl ;restore before return
pop bc
ret z ;return if a = 0 (no error)
ld de,mess1 ;direc-full message (if a=1)
cp 1 ;a=1 means directory full
jp z,err ;a not 0 or 1, so must be 2
ld de,mess2 ;a=2 means disk full
err: ld c,9 ;show error message ...
call bdos
jp wboot ;... and quit
;Data and message storage
;------------------------
defs stsize-1 ;lower locations in stack
stack: defb 0 ;stack "top" (first loc. used)
prsub: defb 1 ;drivecode for A: in fcb
defm 'PR SUB' ;filename and type for fcb
wbuf: defs 128 ;disk-write buffer
line1: defm 'A:WS'
q1: defb cr ;double duty: end of line1:
defb lf ; start of q1:
defb cr ;skip a line before query1
defb lf
defm 'File to be printed (give drivecode if not B:): $'
q2: defb cr
defb lf
defm 'Number of copies (max=99): $'
ans1: defb 16 ;answer to q1, 16 chars. max.
defs 15
ans2: defb 06 ;answer to q2
defs 5
combuf: defs 24 ;for print-command buffer
length: defb 0 ;chars. in print-command line
ncop: defb 0 ;no. of copies to be printed
mess1: defm 'Directory A: full!$'
mess2: defm 'Disk A: full!$'
mess3: defm 'EX15.COM not found on A:!$'
conf1: defb cr ;start a new line
defb lf
defb cr ;skip a line
defb lf
defm 'Making xx copies of d:document.ext -- $'
conf2: defm 'OK? (y/n): $'
erapr: defm 'Y A:PR.SUB' ;WordStar delete-file command
defb cr
defb lf
exfcb: defb 1 ;drivecode for A:
defm 'EX15 COM' ;file name
;Copy to high storage
;--------------------
;Copy part of code (from start: to start:+lenth)
; to high location to avoid being overwritten
; when EX15.COM is read in.
hicop: ld de,high ;'high' is above top of EX15
ld hl,start ;start of segment to be moved
ld c,lenth ;length of segment to be moved
call copy
jp high ;execute the moved segment
org high
;Read in EX15.COM at tpa
start: ld de,dfcb
ld c,20 ;BDOS service 20:
call bdos ; Sequential read
cp 0 ;a.NE.0 means no more records
jp z,start ;read another record
jp tpa ;start execution of EX15
end