home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
zmodem
/
rzmplog4.lbr
/
RZMPLOG4.ZZ0
/
RZMPLOG4.Z80
Wrap
Text File
|
1989-11-02
|
37KB
|
1,771 lines
; RZMPLOG.Z80
;
;v4.0 - equate ver4 true makes rzmplog compatible with new userin.lib
; routine. ver4 false is the same as rzmplog3. Version 4 gets the
; upload category from the userin.lib insert via a low memory location
; at 4ah. If KMD is true, then the FOR file header info will show the
; drive and user that the file is uploaded to.
;v3.0 - provide patch point at KMD: to turn off du,size,date in FOR
; header line. Set to FF for KMD format.
; fixed bug in filename routine if no file extent. rkr
;
;v2.4 - please report problems or suggestions to
; Houston N/W Znode TXHOU (713)- 937-8886
; Performs log function for RZMP
; Rzmp16 writes a text file consisting of a list of names received or
; sent. Rzmp then chains to RZMPLOG, which reads the RZMP.OUT file left
; by Rzmp.
; To test this program offline, set TEST equ true and drive to store
; files on and assemble. A RZMP.OUT file must be located in the test
; directory. Format for the 0:00 b0:filename.ext 3k
; | |
; xfer time size
;
; Run by typing RZMPLOG R or RP
; or RZMPLOG S or SP
;
; Assembly requires SYSLIB.REL, preferably version 4.0.
;
; Using SLRASM and SLRNK+
; SLRASM RZMPLOG/6
; SLRNK RZMPLOG/N,/P:100,RZMPLOG,SYSLIB/S,/E
;
; Called by RZMP, which leaves 'R' or 'S' in fcb1 depending on
; whether files were received or sent. Files transferred are in
; a file called RZMP.OUT, with data on file length and transmission
; time.
;
; Started with RZMPLOG.MAC from RZMP16.LBR
; Added FOR file descriptions with code borrowed from KMD23.
; handles single or batch uploads and downloads.
; Puts DU:, filesize, and date in the header in the format
; of Gene Nolan's UFOR program.
;
; Private uploads will not have FOR entries requested.
; Zmodem tranfers can be determined by a large K in the filesize
; as opposed to a lowercase k for KMD or ZMD.
;
; set equates for test and filenames below.
; FOR name is at end of program.
version equ 40
false equ 0
true equ not false
yes equ true
no equ 0
ver4 equ true ;* set false if userin.lib is not used.
test equ false ; true for test mode to run without BYE
; using fake data
mspeed equ 003ch ; Address of mspeed byte
cseg
.z80
dma equ 080h
cr equ 0dh
lf equ 0ah
fcb1 equ 5ch
bdos equ 5
; SYSLIB routines used:
ext print, putud, getud, fname, retud, logud
ext setdma, initfcb, ialloc, alloc, f$open
ext f$exist, f$make, f$appl, f$write, f$read
ext f$close, capstr, argv, caps, eval10, mhldc
ext cout, f$delete, isalpha
;
rzmplog:
jp start
db 'Z3ENV' ; In case of ZCPR3
db 1 ; External environment
z3env: dw 0
db 0,0,0 ;filler
descrb: db 0ffh ;set to zero if descriptions not wanted
kmd: db 0h ;set to nonzero if kmd style FOR entries
;ie no DU:,size, or date.
lognam: db 'A14:KMD.LOG',0 ; du: and name of .LOG file
ds 16 - ($ - lognam)
lcname: db 'A14:LASTCALR',0
ds 16 - ($ - lcname)
dausa: db 'DATEUSA>'
dateusa:
db 0ffh ; flag: 0ffh for USA-style date
ds 16 - ($ - dausa)
;
MHZ: DB 4 ; *Clock speed, use integer (2,4,5,8, etc.)
DRIVE: DB 'A' ; Drive to store FOR file
USER: DB 14 ; User area of FOR file
;
; File categories, this will be shown when a file upload description is
; needed.
;
FILDES:
DB CR,LF,' [A] - Zcpr3 '
DB CR,LF,' [B] - Generic Cp/m '
DB CR,LF,' [C] - Modem,BBS,Rcp/m '
DB CR,LF,' [D] - Technical '
DB CR,LF,' [E] - Text & Information '
DB CR,LF,' [F] - Games & Basic '
DB CR,LF,' [G] - Wdproc & Printer '
DB CR,LF,' [H] - Pascal '
DB CR,LF,' [I] - Cstuf '
DB CR,LF,' [J] - Machine Specific '
DB CR,LF,' [K] - Business & Database '
DB CR,LF,' [L] - Msdos communication '
DB CR,LF,' [M] - Msdos Disk Utility '
DB CR,LF,' [N] - Msdos Utility '
DB CR,LF,' [O] - Msdos Game '
DB CR,LF,' [P] - Msdos Business '
DB CR,LF,' [Q] - Msdos O.S enhancement '
DB CR,LF,' [R] - Msdos Wdprocessing '
DB CR,LF,'$'
;
GUIDE EQU 'S' ; Maximun category letter + 1
;.....
start:
ld (stack),sp
ld sp,stack
;
call print
db cr,lf,'RZMPLOG v',version / 10 + '0'
db '.', version mod 10 + '0',cr,lf,0
call putud ; save current du:
if not test
ld c,32 ; is BYE running?
ld e,241
call bdos
cp 77 ; A has 77 if so
jr z,byeok
call print
db 'BYE not running -- aborted.',cr,lf,0
jp quit
endif ; not test
byeok:
ld a,(fcb1+2) ;save P for later use
ld (pvtopt),a
ld a,(fcb1+1) ; get direction
cp 'R' ; must be R or S
jr z,dirok
cp 'S'
jr z,dirok
call print
db 'Must use R or S.',cr,lf,0
jp quit
dirok:
ld (direct),a
xor a ; use all of memory
call ialloc
jr nz,stkok
jp stkok
memerr:
call print
db 'Memory allocation error.',cr,lf,0
jp quit
stkok:
ld de,128 ; 128 bytes for inbuf
call alloc
jr z,memerr
ld (inbuf),hl
ld de,128 ; 128 for outbuf
call alloc
jr z,memerr
ld (outbuf),hl
ld de,128
call alloc
jr z,memerr
ld (lcbuf),hl ; 128 for lastcalr buffer
ld de,24*128 ; 3k bytes for names buffer
call alloc
jr z,memerr
ld (nambuf),hl
ld de,128*128 ; 16k for disk buffer
call alloc
jr z,memerr
ld (dbuf),hl
if not test
ld c,81 ; get mxtime
ld e,255
call bdos
push af ; save
ld c,81 ; set to zero
ld e,0
call bdos
ld c,79 ; get rtcbuf address
call bdos
else
ld hl,fakertc ; use fake data for test
endif ; not test
ld de,rtcbuf ; transfer it
ld bc,13
ldir
if not test
pop af ; restore old mxtime
LD e,a
ld c,81
call bdos
endif
ld hl,lcname ; parse LASTCALR name
ld de,lcfcb
call fname
jr nz,lcfok
call print
db 'Invalid LASTCALR filename.',cr,lf,0
jp quit
lcfok:
call newdu ; go to new du:
ld hl,(lcbuf) ; set dma
call setdma
ld de,lcfcb ; try to open LASTCALR file
call f$open
or a
jr nz,lcerr ; error
call f$read ; read it
or a
jr nz,lcerr ; error
ld hl,(lcbuf) ; Check the file
ld b,128 ; max 128 bytes
lcck1:
ld a,(hl) ; ignore leading non-alpha
call isalpha
jr z,lcck2
inc hl
djnz lcck1
jr lcerr ; error
lcck2:
ld (lcnam1),hl ; save address of first name
inc hl
lcck3:
ld a,(hl) ; look for separator for second name
call isalpha
jr nz,lcck4
inc hl
djnz lcck3
jr lcerr ; overrun
lcck4:
ld (hl),0 ; terminate
inc hl ; point to second name
ld (lcnam2),hl ; save it
lcck5:
ld a,(hl) ; look for end
or a ; either zero,
jr z,lcck6
cp cr ; or cr
jr z,lcck6
cp lf ; or lf
jr z,lcck6
cp ' ' ; or space
jr z,lcck6
cp 01ah ; or 1a
jr z,lcck6
inc hl
djnz lcck5
lcck6:
ld (hl),0 ; terminate
jr lclrok ; ok
lcerr:
call print
db 'LASTCALR file error.',cr,lf,0
jp quit
lclrok:
ld hl,dma ; reset dma
call setdma
ld hl,lognam ; parse filename
ld de,outfcb
call fname
jr nz,fnok ; ok if nz
call print
db 'Invalid .LOG filename.',cr,lf,0
jp quit
fnok:
call newdu ; go to new du:
ld hl,innam ; move input file name
ld de,infcb+1 ; to its fcb
ld bc,11
ldir
ld de,infcb
call initfcb ; initialise
call f$open ; open it
or a
jr z,iook ; ok if Z
call print
db 'Input file not found.',cr,lf,0
jp quit
iook:
ld a,128 ; set input file counter
ld (incnt),a
ld de,outfcb ; is output file there?
call f$exist
jr nz,outex ; yes if nz
call f$make ; else make it
cp 0ffh ; ok?
jr nz,makeok
call print
db 'Error in creating output file.',cr,lf,0
jp quit
makeok:
ld hl,(outbuf) ; set output pointer
ld (outpnt),hl
xor a ; and counter
ld (outcnt),a
jr outset
outex:
ld hl,(outbuf) ; set dma
call setdma
ld de,outfcb
call f$appl ; open file for append
jr z,oldok ; ok if zero
cp 3 ; 3 means file empty
jr z,makeok ; so same as new file
call print
db 'Error in opening output file.',cr,lf,0
jp quit
oldok:
ld a,01ah ; look for closing 1a
ld hl,(outbuf)
ld bc,128
cpir
jp po,oldnf ; parity odd means not found
dec hl ; found it, point to it
ld (outpnt),hl ; use as pointer
ld bc,(outbuf) ; calculate count
or a
sbc hl,bc
ld a,l
ld (outcnt),a
jr outset
oldnf:
ld de,outfcb ; not found: must be full buffer
call f$write ; so write it
or a
jp nz,wrerr
;At this point, the output counter and pointer are set. Now we read each
; line from the input file and construct an output line for it.
outset:
ld hl,(nambuf)
LD (forpnt),HL
call print
db 'Logging ',0
ld a,(direct) ; print 'up' or 'down'
cp 'R'
jr nz,outs1
call print
db 'up',0
jr outs2
outs1:
call print
db 'down',0
outs2:
call print
db 'loads to disk',0
;Loop here for each file
mloop:
call readln ; read a line
jr nz,linok ; ok if nz
ld a,01ah ; else terminate in 1a
call putbyt
call flush ; write any output record
ld de,outfcb ; close it
call f$close
IF NOT TEST
ld de,infcb ; delete input file
call f$delete
ENDIF
ld a,(direct) ; see if uploads
cp 'R'
jp nz,quit
call getud
ld a,(gotone) ; see if we got at least one
or a
jp z,quit
jp ask ; got one, get description
linok:
ld hl,inline ; parse input line
ld de,inftok
ld a,0ffh ; null-terminate
call argv
ld a,(infnum) ; must have at least 3
cp 3
jr nc,rlinok
call print
db 'Error in input line format.',cr,lf,0
jp quit
rlinok:
ld a,1
ld (gotone),a ; show we have one
ld a,'.' ; do a dot
call cout
ld a,(pvtopt)
cp 'P'
jr nz,rlin1
call putbyt ; put P into logfile instead of R or S
jr z,rlin2
rlin1: ld a,(direct) ; send R or S
call putbyt
rlin2: ld a,(mspeed) ; modem speed
add a,'0' ; in ascii
call putbyt
ld a,' ' ; space
call putbyt
ld ix,(inftim) ; look at transmission time
ld a,(ix+1) ; if <10,
cp ':'
jr nz,sendtim
ld a,'0' ; do leading zero
call putbyt
sendtim:
ld hl,(inftim) ; rest of transmission time
call putstr
ld a,' ' ; space
call putbyt
ld hl,(inffil) ; get filename
call capstr ; capitalised
ld a,(hl) ; send drive
call putbyt
inc hl
push hl
pop ix ; user area < 10?
ld a,(ix+1)
cp ':'
jr nz,sendfn
ld a,'0' ; leading zero if so
call putbyt
sendfn:
ld a,(hl) ; send next
inc hl
cp ':' ; done user area when :
jr z,sfn1
call putbyt
jr sendfn
sfn1:
ld a,':'
call putbyt
ld b,8 ; 8 chars in filename
sfn2: ; tranfer filename
ld a,(hl)
inc hl
or a ; done if zero
jr z,sfn2a
cp '.' ; or .
jr z,sfn3
call putbyt
call putfor ;
djnz sfn2 ; do all 8
jr sfn4
sfn2a:
ld a,1
ld (tmpflg),a
sfn3:
ld a,' ' ; pad with space
call putbyt
call putfor ;
djnz sfn3
sfn4:
ld a,(hl) ; skip dot
cp '.'
jr nz,sfn5
inc hl
sfn5:
ld b,3 ; 3 bytes more
ld a,(tmpflg)
or a
jp nz,sfn7
sfn6:
ld a,(hl)
or a ; done if zero
jr z,sfn7
cp ' '
jr z,sfn7
call putbyt
call putfor ;
inc hl
djnz sfn6
jr sfn8
sfn7:
ld a,' ' ; pad with spaces
call putbyt
call putfor
djnz sfn7
sfn8:
ld a,' ' ; 11 x space (no library files!)
ld b,11
rlsplp:
call putbyt
djnz rlsplp
xor a
ld (tmpflg),a
ld a,' '
call putfor
ld hl,(infsiz) ; get filesize
call eval10 ; convert to binary
ex de,hl
ld de,numbuf ; convert to ascii
call mhldc
xor a ; zero-terminate
ld (de),a
ld hl,numbuf ; and send to buffer
call putstr
ld hl,numbuf
call forstr ;
ld a,'K' ; use uppercase so we know its from rzmp
call putbyt
call putfor ;
ld a,' '
call putbyt
call putfor ; space over to date
call putfor
call putfor
call putfor
ld ix,rtcbuf ; now do date/time
ld a,(dateusa) ; American date?
or a
jr nz,dusa ; yes if nz
ld a,(ix+6) ; day
call putbcd
ld a,(ix+6)
call forbcd ;
ld a,'/'
call putbyt
call putfor ;
ld a,(ix+5) ; month
call putbcd
ld a,(ix+5)
call forbcd ;
jr dyear
dusa:
ld a,(ix+5) ; month
call putbcd
ld a,(ix+5)
call forbcd ;
ld a,'/'
call putbyt
call putfor ;
ld a,(ix+6) ; day
call putbcd
ld a,(ix+6)
call forbcd ;
dyear:
ld a,'/'
call putbyt
call putfor ;
ld a,(ix+4) ; year
call putbcd
ld a,(ix+4)
call forbcd ;
ld a,cr
call putfor
ld a,lf
call putfor
;
ld a,' '
call putbyt
ld a,(ix) ; hours
call putbcd
ld a,':'
call putbyt
ld a,(ix+1) ; minutes
call putbcd
ld a,' '
call putbyt
ld hl,(lcnam1) ; first name
call capnam
call putstr
ld a,' '
call putbyt
ld hl,(lcnam2) ; second name
call capnam
call putstr
ld a,cr ; cr/lf
call putbyt
ld a,lf
call putbyt
LD A,(filcnt)
INC A
LD (filcnt),A
jp mloop ; then read next line
;Come here when finished
quit:
ld hl,(stack)
ld sp,hl
call getud ; restore original du:
jp 0 ; back to system: MUST do warm boot
;Read a line from the input file. Exit with Z set if eof.
readln:
ld b,40 ; max = 40
ld hl,inline ; set pointer
rlnlp:
call getbyt ; get a byte
ret z ; eof encountered
cp cr ; don't store cr
jr z,rlnlp
cp lf ; lf = end
jr z,rln1
ld (hl),a ; else store it
inc hl ; bump pointer
djnz rlnlp ; loop till full
rln1:
ld (hl),0 ; zero terminate
xor a ; ensure nz
dec a
ret ; done
;Get a byte from the input file. Read new record if necessary. Exit with
;Z set if eof
getbyt:
push de ; save de, hl
push hl
ld a,(incnt) ; need to read new record?
cp 128
jr c,gb1
ld hl,(inbuf) ; yes, set dma
call setdma
ld de,infcb
call f$read ; and read it
or a ; ok if z
jr nz,gbeof ; else eof
ld (incnt),a ; clear count
ld hl,(inbuf) ; set pointer
ld (inpnt),hl
gb1:
inc a ; bump counter
ld (incnt),a
ld hl,(inpnt) ; get pointer
ld a,(hl) ; get the byte
inc hl ; bump pointer
ld (inpnt),hl
cp 01ah ; 1a = eof
jr nz,gb2
gbeof:
xor a ; eof, so set Z
gb2:
pop hl
pop de
ret
;Pretty up a name string in (hl) by capitalising the first character
;and setting the rest to lower case.
capnam:
push af
push hl
ld a,(hl) ; do first
or a
jr z,capnex ; quit if null
call caps ; make it a capital
ld (hl),a ; and store it
capnlp:
inc hl
ld a,(hl)
or a ; done when zero
jr z,capnex
cp 'A' ; A-Z --> a-z
jr c,capnlp
cp 'Z'+1
jr nc,capnlp
or 20h
ld (hl),a ; store it back
jr capnlp
capnex:
pop hl
pop af
ret
;Write a string in (hl) to the output buffer.
putstr:
ld a,(hl)
inc hl
or a
ret z ; done if zero
call putbyt ; else send it
jr putstr
forstr: ld a,(hl)
inc hl
or a
ret z
call putfor
jr forstr
;Convert a BCD value in A to 2-byte ASCII and store in the output buffer.
putbcd:
push af ; save it
rra
rra ; do hi nybble
rra
rra
call pbcd1
pop af ; then low nybble
pbcd1:
and 0fh ; mask off
add a,'0' ; add ascii part
call putbyt ; and store
ret
forbcd: push af
rra
rra
rra
rra
call pbcd2
pop af
pbcd2: and 0Fh
add A,'0'
call putfor
ret
;Write a byte to the output buffer. Write buffer to disk if necessary.
putbyt:
push af
push hl
ld hl,(outpnt) ; get pointer
ld (hl),a ; store in buffer
inc hl ; bump pointer
ld (outpnt),hl
ld a,(outcnt) ; and counter
inc a
ld (outcnt),a
cp 128 ; flush if 128 bytes written
call z,flush
pop hl
pop af
ret
putfor:
push af
push hl
ld hl,(forpnt) ; get pointer
ld (hl),a ; store in buffer
inc hl ; bump pointer
ld (forpnt),hl
pop hl
pop af
ret
;Flush output buffer and reset pointers
flush:
push af
push de
push hl ; preserve all regs
ld hl,(outbuf)
call setdma ; set dma
ld de,outfcb
call f$write ; write it
or a
jr nz,wrerr ; error
ld (outcnt),a ; clear counter
ld hl,(outbuf) ; and set pointer
ld (outpnt),hl
pop hl
pop de
pop af
ret
wrerr:
call print
db 'Error in writing output file.',cr,lf,0
jp quit
;Log into du: in bc parsed by fname. Correct for unentered drive or user.
newdu:
push bc ; save parsed du:
pop hl
call retud ; and get current one
ld a,l ; was user area specified?
cp 0ffh
jr z,nousr
ld c,a ; yes, set it
nousr:
ld a,h ; was drive specified?
cp 0ffh
jr z,nodisk
dec a ; yes, subtract 1
ld b,a ; and set it
nodisk:
call logud ; go to correct du:
ret
;end of rzmplog
;
; FOR FILE ROUTINES
;
;
; Asks user to add description of an uploaded file
;
ASK:
LD A,(DESCRB) ;descriptions wanted?
OR A
RET Z
LD A,(PVTOPT) ; Sending to "private area"?
CP 'P'
RET Z ; If yes, do not ask for description
LD HL,(DBUF) ;
LD (BCHADR),HL ;init buffer pointers
LD (BUFADR),HL
LD (OUTADR),HL
LD HL,(NAMBUF)
LD (NBSAVE),HL ; set counter to first filename
CALL BCHDCR ; get the filname
;
ASK1:
if not ver4
CALL SHONM ; Show the file name
CALL PRINT
DEFB ' - this file is for:',13,10,0
LD C,9 ; Display the file descriptors
LD DE,FILDES
CALL 5
CALL PRINT
DEFB 13,10,'Select a category: ',0
ASK1A:
CALL INPUT ; Get a character
CALL UCASE
CP 'A'
JP C,ASK1A
CP GUIDE
JP NC,ASK1A
CALL TYPE
LD (KIND),A
endif ;not ver4
;
ASK2: CALL PRINT
DEFB 13,10,13,10
DEFB 'Please describe this file in 7 lines or less. '
DEFB 13,10,13,10,0
;
;
; Get the file name from FCB, skip any blanks
;
LD HL,HLINE ; Store short line with dashes
CALL DSTOR1 ; Store and show
LD A,CR
CALL OUTCHR
LD A,LF
CALL OUTCHR
XOR A
LD (LNCNTR),A
LD B,8 ; Get FILENAME
LD DE,NEWNAM ;source
LD HL,OLINE ;destination
CALL LOPFCB
LD A,(DE)
CP 32 ; Any file extent?
JP Z,AFIND1 ; If not, skip the period and extent
LD A,46
LD (HL),A ; Separate FILENAME and EXTENT
CALL TYPE
INC HL
LD B,3 ; Get EXTENT name
CALL LOPFCB
if not ver4
AFIND1: LD A,(KIND) ; Get the answer
else
afind1: ld a,(4ah) ;passed category selection from userin.
cp 'A'
jp c,afinda ;make sure it's in range
cp (guide)
jp c,afind2
afinda: call print
db 'No category selected',cr,lf,0
ret
endif ;userin fildes and rzmplog fildes should match
afind2: SUB 40H ; Convert to binary
LD C,A ; Store for now
LD DE,FILDES
;
ALOOP: LD A,(DE)
CP '$'
JP Z,ASK1
CP 10 ; New line yet?
INC DE
JP NZ,ALOOP ; Look for a LF
DEC C ; One less line to go
JP NZ,ALOOP
INC DE ; move past [A] in categories
INC DE
INC DE
INC DE
CALL DKIND ; move category in de to oline in hl
;
CALL DSTOR ; copy oline to FOR buffer and show
; add B0: and size and date here
;at this point lncntr has number of characters at end of category.
;we will count from there and fill spaces up to 46 where DU: will be put
;in.
ld a,(kmd) ;see if its kmd format
or a
jp nz,alignf ;yes, so skip du,size,date
align:
ld a,(lncntr) ;current position
ld b,a
ld a,46 ;location of DU: for UFOR style
sub b ;b now has # of spaces to fill
ld b,a
align1:
ld a,' '
call outchr ;not there yet so put in space
call type
djnz align1
;new routines for RZMPLOG4
ld hl,(inffil) ; get filename
call capstr ; capitalised
ld a,(hl) ; send drive
call outchr
inc hl
push hl
pop ix ; user area < 10?
sndfn:
ld a,(hl) ; send next
inc hl
cp ':' ; done user area when :
jr z,sn1
call outchr
jr sndfn
sn1:
ld a,':'
call outchr
;-------
ld a,' '
call outchr
call outchr
ld hl,newnam ;put file size and date
ld de,12 ;add offset
add hl,de
call dstor1
alignf:
ld a,cr ;end of line
call outchr
call type
ld a,lf
call outchr
call type
CALL print
DEFB 13,10,'0: ---------1---------2---------3'
DEFB '---------4---------5---------6---------',13,10,0
XOR A
LD (ANYET),A ; Reset the flag for no information yet
LD C,48
EXPLN: INC C
LD A,C
CP 56
JP NC,EXPL1
CALL TYPE
LD A,32
CALL OUTCHR
CALL OUTCHR
CALL OUTCHR
CALL print
DEFB ': ',0
CALL DESC ; Get a line of information
CALL DSTOR
;
LD A,CR
CALL OUTCHR
LD A,LF
CALL OUTCHR
JP EXPLN
;
EXPL1:
LD A,13 ; All finished, put in an extra CR-LF
CALL OUTCHR
LD A,10
CALL OUTCHR
XOR A
CALL OUTCHR
CALL print
DEFB 13,10,' Repeating to verify:',13,10,13,10,0
LD HL,(BUFADR) ; Get starting address of description
;
EXPL1A: LD A,(HL) ; Get the character
OR A ; Is it a '0' to terminate?
JP Z,EXPL1B ; If yes, exit
CALL TYPE ; Show character on CRT, send to modem
INC HL ; Next location
JP EXPL1A ; Go do next charcter
;
EXPL1B: LD HL,(OUTPTR)
DEC HL ; Skip the '0'
LD (OUTPTR),HL ; Store address at end of this entry
;
EXPL2: CALL print
DEFB 13,'Is this ok (Y/N)? ',0
CALL INPUT
AND 5FH ; Change to upper case
CP 'Y'
JP Z,EXPL4 ; Exit if this description was ok
CP 'N'
JP NZ,EXPL2
CALL TYPE
;
EXPL3: LD HL,(BCHPTR) ; Else restart at beginning of text
LD (OUTPTR),HL ; Start over at this address
JP ASK2 ; Go do this one again
;...
;
;
; See if any more batch files need descriptions
;
EXPL4: CALL TYPE
LD A,(FILCNT) ; Any more file names left in buffer?
OR A
JP Z,EXPL5 ; If not, all finished
LD HL,(BCHADR) ; Get the current output address
LD (BUFADR),HL ; Store for next verify
LD HL,(OUTPTR) ; Get end of current description
LD (BCHPTR),HL ; Store for start of next one
JP ASK1-3 ; Get the next file description
;
;
; Now open the file and put this at the beginning
;
EXPL5: LD A,(0004H) ; Get current drive/user
LD (DRUSER),A ; Store
;
;
; Set drive/user to the area listed above
;
LD A,(USER) ; Get requested user number
LD C,32
LD E,A ; Put user number into 'E' register
CALL 5
LD A,(DRIVE) ; Get requested drive
SUB 65
LD C,14
LD E,A
CALL 5
;
;
; Open source file
;
CALL PRINT
DEFB 13,10,0
LD C,15
LD DE,FILE ; Open FOR text file
CALL 5
INC A ; Check for no open
JP NZ,OFILE ; File exists, exit
LD C,22 ; None exists, make a new file
LD DE,FILE
CALL 5
INC A
JP Z,NOROOM ; Exit if cannot open new file
;
OFILE: LD HL,FILE ; Otherwise use same filename
LD DE,DEST ; With .$$$ extent for now
LD B,9
CALL MOVE
;
;
; Open the destination file
;
XOR A
LD (DEST+12),A
LD (DEST+32),A
LD HL,16*1024 ; Size of output buffer
LD (OUTSIZ),HL ; Set for comparison
LD C,19 ; Delete any existing file that name
LD DE,DEST
CALL 5
LD C,22 ; Now make a new file that name
LD DE,DEST
CALL 5
;
INC A
JP Z,NOROOM ; Cannot open file, no directory room
CALL print
DEFB 13,10,'wait a moment...',0
;
;
; Read sector from source file
;
READLP: LD C,26
LD DE,DMA
CALL 5
LD C,20
LD DE,FILE ; Read from FOR text file
CALL 5
OR A ; Read ok?
JP NZ,RERROR
LD HL,DMA ; Read buffer address
;
;
; Write sector to output file (with buffering)
;
WRDLOP: LD A,(HL) ; Get byte from read buffer
AND 127 ; Strip parity bit
CP 127 ; Del (rubout)?
JP Z,NEXT ; Yes, ignore it
CP 26 ; End of file marker?
JP Z,TDONE ; Transfer done, close, exit
CALL OUTCHR
;
NEXT: INC L ; Done with sector?
JP Z,READLP ; If yes get another sector
JP WRDLOP ; No, get another byte
;.....
;
;
; Handle a backspace character while entering a character string
;
BCKSP: CALL TYPE
LD A,B ; Get position on line
OR A
JP NZ,BCKSP1 ; Exit if at initial column
LD A,' ' ; Delete the character
JP BCKSP3
;
BCKSP1: DEC B ; Show one less column used
DEC HL ; Decrease buffer location
LD A,' '
LD (HL),A ; Clear memory at this point
CALL TYPE ; Backspace the "CRT"
;
BCKSP2: LD A,8 ; Reset the "CRT" again
;
BCKSP3: JP TYPE ; Write to the "CRT", done
;.....
;
;
; Asks for line of information
;
DESC: XOR A
LD (FIRST),A
LD B,A
LD HL,OLINE
;
DESC1: CALL INPUT ; Get keyboard character
CP CR
JP Z,DESC5
CP 9
JP Z,DESC7
CP 8 ; Backspace character?
JP Z,DESC2
CP 127 ; Delete character?
JP NZ,DESC3
;
DESC2: CALL BCKSP
JP DESC1 ; Get the next character
;
DESC3: CP ' ' ; Space character?
JP C,DESC1 ; If non-printing character, ignore
JP NZ,DESC4
LD A,(FIRST) ; Any non-space characters yet?
OR A
JP Z,DESC1 ; If not, ignore this space
LD A,' ' ; Restore the value
;
DESC4: LD (ANYET),A ; Show a character has been sent now
LD (FIRST),A
LD (HL),A
CALL TYPE ; Display the character
INC HL
INC B
LD A,B
CP 70 ; Do not exceed line length
JP C,DESC1
CALL BCKSP2
CALL BCKSP1 ; Do not allow a too-long line
JP DESC1
;
DESC5: LD A,(ANYET) ; Any text typed on first line yet?
OR A
JP NZ,DESC6 ; If yes, exit
POP HL
JP EXPL3 ; Ask again for a description
;
DESC6: LD (HL),CR
LD A,(HL)
CALL TYPE
INC HL ; Ready for next character
LD (HL),LF
LD A,(HL)
CALL TYPE ; Display the line feed
INC HL
LD A,B ; See if at first of line
OR A
RET NZ ; If not, ask for next line
POP HL ; Clear "CALL" from stack
JP EXPL1
;
DESC7: LD A,B ; At end of line now?
CP 68
JP NC,DESC1 ; If yes, disregard
LD (HL),32
LD A,(HL)
CALL TYPE
INC HL
INC B
LD A,B
AND 7
JP NZ,DESC7
JP DESC1 ; Ask for next character
;.....
;
;
; Print message then exit to CP/M
;
DEXIT: LD C,9 ; Print message
POP DE ; Get message address
CALL 5
JP RESET ; Reset the drive/user, then finished
;.....
;
DKIND: LD A,(DE) ; Get the character from the string
CALL TYPE ; Otherwise display the character
LD (HL),A ; Put in the buffer
CP LF
RET Z
INC DE ; Next position in the string
INC HL ; Next postion in the buffer
JP DKIND ; Keep going until a LF
;.....
;
;
DSTOR: LD HL,OLINE
;
DSTOR1: LD A,(HL)
CP CR
RET Z
CALL OUTCHR
INC HL
LD A,(LNCNTR) ;bump position counter
INC A
LD (LNCNTR),A
JP DSTOR1
;.....
UCASE: CP 97
RET C
CP 123
RET NC
AND 95
RET
;
;
; Disk is full, save original file, erase others.
;
FULL: LD C,19
LD DE,DEST
CALL 5
CALL DEXIT
DEFB 13,10,'++ DISK FULL, ABORTING, SAVING ORIGINAL FILE','$'
;.....
;
;
; Get a character, if none ready wait up to 3 minutes, then exit from
; the program.
;
INPUT: PUSH HL ; Save current values
PUSH DE
PUSH BC
LD A,3 ; Wait up to 3 minutes
ADD A,A ; Double the number, bell each 30 sec.
LD H,A ; Put in 'H' for 1/2 minute loops
;
INPUT1: LD DE,300 ; Outer loop count 600 loops per min.
INPUT2: LD A,(MHZ) ; Get the clock speed
LD L,A ; Put in 'L' for 'clock loops'
;
INPUT3:
;
INPUT4: PUSH HL
PUSH DE ; Save the outer delay count
PUSH BC ; Save the inner delay count
LD C,6 ; Get console character, if any
LD E,255
CALL 5
AND 127 ; Remove any parity
POP BC ; Restore the inner delay count
POP DE ; Restore the outer delay count
POP HL ; Restore the Number of minutes count
OR A ; Have a character yet?
JP NZ,INPUT5 ; If yes, exit and get it
;
DEC BC
LD A,C ; See if inner loop is finished
OR B
JP NZ,INPUT4 ; If not loop again
;
DEC L ; One less clock loop to go
JP NZ,INPUT3
;
DEC DE
LD A,E
OR D
JP NZ,INPUT2 ; If not reset inner loop and go again
;
;
; No character received, ding the bell each 1/2 minute
;
PUSH HL
call print
db 7,0
POP HL
DEC H
JP NZ,INPUT1
;
;
; Out of time, no character so abort
;
LD A,13
CALL OUTCHR
LD A,10
CALL OUTCHR
LD SP,STACK ; Restore the stack
CALL EXPL5 ; Finish appending previous information
JP EXIT ; File is closed, return to CP/M
;
INPUT5: POP BC
POP DE
POP HL
RET ; Got a character, return with it
;.....
;
;
; Stores the Filename/extent in the buffer temporarily
;
LOPFCB: LD A,(DE) ; Get FCB FILENAME/EXT character
CP 33 ; Skip any blanks
JP C,LOPF1
LD (HL),A ; Store in OLINE area
CALL TYPE ; Display on CRT
INC HL ; Next OLINE position
;
LOPF1: INC DE ; Next FCB position
DEC B ; One less to go
JP NZ,LOPFCB ; If not done, get next one
RET
;.....
;
;
BCHDCR:
LD A,(FILCNT)
DEC A
LD (FILCNT),A
BCHD1: LD HL,(NBSAVE) ; Get address of next batch filename
LD DE,NEWNAM ; Where to put it
LD B,32
CALL MOVE
LD (NBSAVE),HL ; Store address for next filename
RET
;
;--------------------------
DONE:
; Finished, clean up and return to CP/M
EXIT:
;
; Restore original drive/user area
;
EXIT2:
LD HL,DMA
CALL SETDMA
;
EXIT3: XOR A ; Clear the register and carry bit
LD HL,(STACK) ; Get original return adress back
LD SP,HL ; Put on the stack pointer
jp 0
;
;.....
;
MOVE: LD A,(HL) ; Get a byte
LD (DE),A ; Put at new home
INC DE ; Bump pointers
INC HL
DEC B ; Decrement byte count
JP NZ,MOVE ; If more, do it
RET ; If not, return
;.....
;
;
; No room to open a new file
;
NOROOM: CALL DEXIT
DEFB 13,10,'NO DIR SPACE: OUTPUT','$'
;.....
;
;
; Output error - cannot close destination file
;
OERROR: CALL DEXIT
DEFB 13,10,'CANNOT CLOSE OUTPUT','$'
;.....
;
;
; See if there is room in the buffer for this character
;
OUTCHR: PUSH HL
PUSH AF ; Store the character for now
LD HL,(OUTSIZ) ; Get buffer size
EX DE,HL ; Put in 'DE'
LD HL,(OUTPTR) ; Now get the buffer pointers
LD A,L ; Check to see if room in buffer
SUB E
LD A,H
SBC A,D
JP C,OUT3 ; If room, go store the character
LD HL,0 ; Otherwise reset the pointers
LD (OUTPTR),HL ; Store the new pointer address
;
OUT1: EX DE,HL ; Put pointer address into 'DE'
LD HL,(OUTSIZ) ; Get the buffer size into 'HL'
LD A,E ; See if buffer is max. length yet
SUB L ; By subtracting 'HL' from 'DE'
LD A,D
SBC A,H
JP NC,OUT2 ; If less, exit and keep going
;
;
; No more room in buffer, stop and transfer to destination file
;
LD HL,(OUTADR) ; Get the buffer address
ADD HL,DE ; Add pointer value
; EX DE,HL ; Put into 'DE'
CALL SETDMA
LD C,21
EX DE,HL ;kr
LD DE,DEST
CALL 5
OR A
JP NZ,FULL ; Exit with error, if disk is full now
LD DE,128
LD HL,(OUTPTR)
ADD HL,DE
LD (OUTPTR),HL
JP OUT1
;
OUT2:
LD HL,DMA
CALL SETDMA
LD HL,0
LD (OUTPTR),HL
;
OUT3: EX DE,HL
LD HL,(OUTADR)
ADD HL,DE
EX DE,HL
POP AF ; Get the character back
LD (DE),A ; Store the character
EX DE,HL
LD (BCHADR),HL
LD HL,(OUTPTR) ; Get the buffer pointer
INC HL ; Increment them
LD (OUTPTR),HL ; Store the new pointer address
POP HL
RET
;.....
;
;
RERROR: CP 1 ; File finished?
JP Z,TDONE ; Exit, then
LD C,19 ; Erase destination file, keep original
LD DE,DEST
CALL 5
CALL DEXIT
DEFB '++ SOURCE FILE READ ERROR ++$'
;.....
;
;
; Reset the Drive/User to original
;
RESET: LD A,(DRUSER) ; Get original drive/user area back
RRA
RRA
RRA
RRA
AND 15 ; Just look at the user area
LD C,32
LD E,A
CALL 5
LD A,(DRUSER) ; Get the original drive/user back
AND 15 ; Just look at the drive for now
LD C,14 ; Restore original drive
LD E,A
CALL 5
CALL PRINT ; Print CRLF before quitting
DEFB 13,10,0
JP EXIT
;.....
;
;
; Shows the Filename/extent
;
SHONM:
CALL print
DEFB 13,10,13,10,0
LD HL,NEWNAM
;
SHONM1: LD B,8 ; Maximum size of file name
CALL SHONM2
LD A,(HL) ; Get the next character
CP 32 ; Any file extent?
RET Z ; If not, finished
LD A,46
CALL CTYPE
LD B,3 ; Maximum size of file extent
;
SHONM2: LD A,(HL) ; Get FCB FILENAME/EXT character
CP 32 ; Skip any blanks
CALL NZ,CTYPE
INC HL ; Next FCB position
DEC B ; One less to go
JP NZ,SHONM2 ; If not done, get next one
RET
;.....
;
;
; Transfer is done - close destination file
;
TDONE: LD HL,(OUTPTR)
LD A,L
AND 127
JP NZ,TDONE1
LD (OUTSIZ),HL
;
TDONE1: LD A,26 ; Fill remainder of record with ^Z's
PUSH AF
CALL OUTCHR
POP AF
JP NZ,TDONE
LD C,16 ; Close FOR text file
LD DE,FILE
CALL 5
LD C,16 ; Close FOR.$$$ text file
LD DE,DEST
CALL 5
INC A
JP Z,OERROR
;
;
; Rename both files as no destination file name was specified
;
LD HL,FILE+1 ; Prepare to rename old file to new
LD DE,DEST+17
LD B,16
CALL MOVE
LD C,19 ; Delete original FOR text file
LD DE,FILE
CALL 5
LD C,23
LD DE,DEST ; Rename FOR.$$$ to FOR text file
CALL 5
JP RESET ; Reset the drive/user, finished
;.....
;
;
; Send character in 'A' register to console
;
TYPE: PUSH BC
PUSH DE
PUSH HL
PUSH AF
LD C,2 ; Write to console
LD E,A ; Character to 'E' for CP/M
CALL 5
POP AF
POP HL
POP DE
POP BC
RET
;.....
;
; end of file description area
;-----------------------------------------------------------------------
;
;
CTYPE: PUSH BC ; Save all registers
PUSH DE
PUSH HL
LD E,A ; Character to 'E' in case BDOS (normal)
LD C,2 ; BDOS console output, to CRT and modem
CALL 5 ; Since 'BYE' intercepts the char.
POP HL ; Restore all registers
POP DE
POP BC
RET
;.....
;
; Restore the old user area and drive from a received file
;
RECARE: LD E,A ; Stuff it in E
LD C,32 ; Tell BDOS what we want to do
JP 5 ; Now do it
;.....
;data
innam: db 'RZMP OUT' ; input filename
; Fake strings for test mode
if test
fakertc:
db 20h,20h,34h,19h,89h,06h,07h,02h,00h,14h,14h,14h,12h
endif ; test
;Token pointer table for input line
inftok:
db 3 ; 3 tokens
infnum: ds 1 ; # found by argv
inftim: ds 2 ; pointer to transmission time
inffil: ds 2 ; pointer to filename
infsiz: ds 2 ; pointer to filesize
direct: ds 1 ; 'R' or 'S'
inbuf: ds 2 ; pointer to input buffer
outbuf: ds 2 ; pointer to output buffer
lcbuf: ds 2 ; pointer to LASTCALR buffer
lcnam1: ds 2 ; address of first name in LASTCALR
lcnam2: ds 2 ; address of second name in LASTCALR
incnt: ds 1 ; input file counter
inpnt: ds 2 ; input file pointer
outcnt: ds 1 ; output file counter
outpnt: ds 2 ; output file pointer
numbuf: ds 6 ; number conversion buffer
outfcb: ds 36 ; FCB for .LOG file
infcb: ds 36 ; FCB for input file
lcfcb: ds 36 ; FCB for LASTCALR file
inline: ds 41 ; input line from file
rtcbuf: ds 15 ; RTC buffer from BYE
lncntr: ds 1 ; count postion in FOR header line
tmpflg: ds 1 ; flag to indicate no file extent
pvtopt: ds 1 ; is it a private upload
gotone: ds 1 ; show we have at least one upload
;
FILE: DEFB 0,'FOR ',0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0
DEST: DEFB 0,' $$$',0,0,0,0,0,0,0
DEFB 0,0,0,0,0,0,0,0,0,0,0,0,0,0
;
FORPNT: DS 2
NEWNAM: ds 80
;
; Batch stuff
;
BCHADR: DEFW 0 ; For multiple descriptions
BCHPTR: DEFW 0
BUFADR: DEFW 0 ; For multiple file display
;
;
FILCNT: DEFB 0 ; # of files in batch mode
NBSAVE: DS 2 ; Start address in NAMBUF for next file
;
ANYET: DEFB 0 ; Any description typed yet?
DRUSER: DEFB 0 ; Original drive/user, for return
FIRST: DEFB 0 ; Used in file description
KIND: DEFB 0 ; Asks what kind of file this is
OLDDRV: DEFB 0 ; Save the original drive number
OLDUSR: DEFB 0 ; Save the original user number
OUTADR: DW 0
OUTPTR: DEFW 0
OUTSIZ: DEFW 16*1024 ;kr was 16 Size of buffer (use caution)
;
;
HLINE: DEFB '----',13,10
OLINE: DEFS 80 ; Temporary buffer to store line
DEFS 100 ; Area for stack
STACK: DW 0
NAMBUF: ds 2 ; Allow room for 256 batch filenames
DBUF: ds 2 ; 16k disk buffer
;
;
END
;