; CP4UTL.ASM
;	KERMIT - (Celtic for "FREE")
;
;	This is the CP/M-80 implementation of the Columbia University
;	KERMIT file transfer protocol.
;
;	Version 4.0
;
;	Copyright June 1981,1982,1983,1984,1985
;	Columbia University
;
; Originally written by Bill Catchings of the Columbia University Center for
; Computing Activities, 612 W. 115th St., New York, NY 10025.
;
; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
; others. 
;
;	Utility routines, pure and impure data.
;
; revision history:
; edit 6: February 6, 1985
;	Added a storage location for the port value (PORT, just below
;	SPEED) which is used by the port status routine, and moved the
;	printer copy flag (PRNFLG:) into the communications area so
;	that the machine dependant overlay can toggle it. [Hal Hostetler]
;	Added ffussy flag for filename checking.  Generate the version
;	string from 'verno', which is set in CP4KER, because CP4KER has the
;	list of modules and their edit numbers. [Charles Carvalho]
;
; edit 5: 13-Jan-85 by Vanya J.Cooper Pima Commun. College Tel: 602-884-6809
;
;pcc002	28-Dec-84	modules:cp4tt,cp4utl
;	Add connect mode <esc>P command to toggle printer on
;	and off.  Conflicts with "official" recommended commands
;	in protocol manual, but I don't think CP/M will ever get
;	a PUSH command.
;
;pcc003-pcc005	2-Jan-85	vjc	modules:cp4mit,cp4tt,cp4utl
;	These edits must all be installed together and change the way
;	logging is handled.  The log file spec is moved to a separate
;	fcb, and not opened until an actual CONNECT command is given.
;	This takes care of a NASTY bug that if you used any other file
;	command between the LOG and CONNECT, the log file would get
;	written over the last file used.  This also allows logging to
;	be "permanently" enabled until an CLOSE (new command) for all
;	CONNECT sessions, like most other kermits do.  If a log file
;	already exists, it will be appended to.  Also add two new
;	CONNECT mode commands <esc>Q to suspend logging and <esc>R to
;	resume.  <esc>R means something else during TRANSMIT, but
;	logging is never on then, so there shouldn't be any conflict.
;	I also changed the write code, so that it can handle one more
;	character after the XOFF is send to stop the host.  This allows
;	a little "slop" for systems that don't stop immediately (such
;	as TOPS10), but it didn't help much.
;
;pcc006	2-jan-85	VJC	modules:cp4cmd,cp4utl
;	Problems with "?" in filespecs.  On reparse, may cause action
;	flag to be reset at wrong point, requiring multiple <CR>'s
;	to terminate the line or other weird stuff.  Also need to
;	check flag and complain if wild-cards illegal.
;
;pcc008	2-Jan-85	vjc	modules:cp4def,cp4tt,cp4utl
;	Keyboard input during CONNECT mode can get locked out if
;	there is enough input from the modem port to keep prtchr
;	busy.  This can happen for example, if the printer is running
;	at the same speed as the modem line, leaving you helpless to
;	turn it off or abort the host.  Add a fairness count, so that
;	at least every prfair characters we look at console input.
;
;pcc012	4-Jan-85	vjc	modules:cp4mit,cp4tt,cp4utl
;	Use the big buffer for the log file.  Move the log file back
;	into the common fcb and only save the drive, name, and
;	extension between connects.  Add new routines to cp4utl to
;	create or append to an existing file, and to conditionally
;	advance buffers only if in memory.  Remove edit pcc003 that
;	allows one more character after the xoff, since it didn't
;	really work very well and does not fit in well with the way
;	the buffer advancing routines are set up.  If someone still
;	thinks this would be useful, it could be put back in with a
;	little more work.
;	
;	While testing this edit, I also noticed another bug that
;	the command parsing routines do not limit or check the
;	length of command lines or file specs, trashing what ever
;	comes after them.  Currently because of where the fcb and
;	command buffer are located, this does not usually cause a
;	problem, but could if an extremely long line was typed in,
;	or in the future multiple fcbs defined elsewhere in memory
;	were used.  Maybe this should be put on the bug list
;	somewhere.
;
;pcc013	8-Jan-85	vjc	modules:cp4mit,cp4utl,cp4typ
;	Replace CLOSE command to cancel session logging to SET
;	LOGGING ON/OFF.  This seems to fit in with the command
;	structure better.  Default the log file to KERMIT.LOG
;	incase no previous LOG command.  Logging is also enabled
;	by LOG command, as before.
;
; edit 4: September 9, 1984
;	Move command tables and associated help text to CP4MIT.  Add
;	makfil/clofil routines and modify outbuf to write files in big
;	chunks.  Update Kermit's version to 4.03.
;
; edit 3: August 21, 1984
;	Make inbuf read files in big chunks to minimize disk start/stop
;	delays.  Buffer size and address is specified by system-dependent
;	overlay.
;
; edit 2: August 3, 1984
;	move "mover" to CP4SYS to allow use of Z80 block move instruction.
;
; edit 1: July 27, 1984
;	extracted from CP4MIT.M80 edit 2, as part of LASM support.  This is
;	the last file linked for the system-independent code.
;
utlver:	db	'CP4UTL.ASM (5)  13-Jan-85$'

;	Set the parity for a character in A.
;	called by: spack, rexmit, logit, vt52, conchr, intchr

setpar:	push	h		;Save HL.
	push	b
	lxi	h,parity
	mov	c,m		;Get the parity routine.
	mvi	b,0
	lxi	h,parjmp	;Get the first address.
	dad	b
	pchl

parjmp:	jmp	even
	jmp	mark
	jmp	none
	jmp	odd
	jmp	space

none:	jmp	parret		;Don't touch the parity bit.

even:	ani	7FH		;Strip parity.
	jpe	parret		;Already even, leave it.
	ori	80H		;Make it even parity.
	jmp	parret

mark:	ori	80H		;Turn on the parity bit.
	jmp	parret

odd:	ani	7FH		;Strip parity.
	jpo	parret		;Already odd, leave it.
	ori	80H		;Make it odd parity.
	jmp	parret

space:	ani	7FH		;Turn off the parity bit.
	jmp	parret

parret:	pop	b
	pop	h		;Restore HL.
	ret
;
;	Print the escape char.
;	called by: stat01, xmit, telnet, intchr

escpr:	lda	escchr		;Get the escape char.
	cpi	' '		;Is it a control char?
	jp	escpr2
	lxi	d,inms10	;Output "Control-".
	call	prtstr
	lda	escchr
	ori	100O		;De-controlify.
escpr2:	mvi	c,conout	;Output the char
	mov	e,a
	call	bdos
	ret

;	fetch keyword; if unsuccessful, return to command level.
;	called by: kermit, setcom

keycmd:	mvi	a,cmkey
	call	comnd
	 jmp	keycm2		;no match
	ret

keycm2:	lxi	d,ermes1	;"Unrecognized Command"
	call	prtstr
	jmp	kermit		;Do it again.

;	request confirmation; if unsuccessful, return to command level
;	called by: bye, exit, help, log, setcom, show, status, send,
;		finish, logout, xmit, telnet

cfmcmd:	mvi	a,cmcfm
	call	comnd
	 jmp	kermt3		;"Not confirmed"
	ret
;

;	This routine prints the number in HL on the screen in decimal.
;	Uses all ACs.
;	called by: cp4sys, read, send, updrtr, dir

nout:	lxi	b,-10		;Get some useful constants.
nout1:	lxi	d,-1

nout2:	dad	b		;Subtract as many 10s as possible.
	inx	d		;Count them.
	jc	nout2		;If some left keep going.
	push	h		;save remainder - 10
	xchg			;Swap the remainder and the quotient.
	mov	a,h		;Get the number of 10s found.
	ora	l		;check for quotient non zero
	cnz	nout1		;If non zero, recurse.
	pop	h		;Get the remainder - 10
	mov	a,l		;in a
	adi	'0'+10		;Make the number printable and add the 10 back
	mov	e,a		;Output the digit.
	mvi	c,conout
	jmp	bdos

; prcrlf - print a CR/LF.  (Saves no registers.) [Toad Hall]
; prtstr - print string pointed to by DE
;	called by: lots of places.
prcrlf:	lxi	d,crlf		;Point to the CR/LF
prtstr:	mvi	c,prstr		; output string
	jmp	bdos		;a CALL followed by a RET becomes a JMP

;	Jumping to this location is like retskp.  It assumes the instruction
;	after the call is a jmp addr.
;	here from: many places.
rskp:	pop	h		;Get the return address.
	inx	h		;Increment by three.
	inx	h
	inx	h
	pchl

;	Jumping here is the same as a ret.  'jmp r' is used after routines
;	that have skip returns, where the non-skip instruction must be 3 bytes.
;	here from: many places.
r:	ret
;
;	Open a file for reading (with inbuf).  The filename is already
;	in fcb;	upon return, the end of file flag is cleared and chrcnt
;	is set to zero, so inbuf will be called to get a buffer when we
;	next attempt to get a character.
;	called by: sinit, seof, xmit

getfil: xra	a
	sta	chrcnt		;Buffer is empty.
	sta	seccnt		;No sectors buffered.
	sta	eoflag		;Not the end of file.
	sta	endsts		;No EOF/error pending.
	sta	fcb+0CH		;Zero the extent.
	sta	fcb+0EH		;Must be zero for MAKEF or OPENF.
	sta	fcb+20H		;Zero the current record.
	mvi	c,openf		;Open the file.
	lxi	d,fcb
	call	bdos
	ret

;	Get next sector.  If necessary, read some more from disk.
;	preserves bc, de, hl
;	returns nonskip if EOF or error;
;	returns skip with chrcnt and bufpnt updated if success.
;	called by: gtchr, xnext

inbuf:	lda	eoflag		;Have we reached the end?
	ora	a
	rnz			;Return if so.
	push	b
	push	d
	push	h
inbuf1:	lda	seccnt		; Do we have any sectors left?
	ora	a
	jz	inbuf3		; If not, go get some more.
inbuf2:	lhld	nxtbuf		; Yes.  Get address of next sector
	shld	bufpnt		; Update current buffer pointer
	lxi	b,bufsiz	; Get number of bytes in sector
	dad	b		; Update HL to point to next sector
	shld	nxtbuf		; Save for next time
	dcr	a		; Decrement count of buffered sectors
	sta	seccnt		; Put it back
	mvi	a,bufsiz-1	; Number of bytes in buffer (pre-decremented)
	sta	chrcnt		; Store for our caller
	pop	h
	pop	d
	pop	b
	jmp	rskp		; Return success

; We don't have any sectors buffered.  If we've already hit an error or
; EOF, return that status to the user.

inbuf3:	lda	endsts		; Check status from previous read
	ora	a
	jz	inbuf4		; It was OK.  Get some more sectors.
	sta	eoflag		; End of file or error.  Set the flag.
	xra	a
	sta	chrcnt		; Say no characters in buffer.
	pop	h
	pop	d
	pop	b
	ret			; Return failure

; Read sectors until we fill the buffer or get an error or EOF, then return
; the first buffer to the user.  (seccnt is zero)

inbuf4:	lhld	bufadr		; Get address of big buffer
	shld	nxtbuf		; Store as next buffer address to give user
inbuf5:	shld	bufpnt		; Store as next buffer address to read into
	xchg			; Move buffer address to DE
	mvi	c,setdma	; Tell CP/M where to put the data
	call	bdos		;  ...
	mvi	c,readf		; Read a record.
	lxi	d,fcb
	call	bdos
	sta	endsts		; Save ending status
	ora	a		; 00H => read O.K
	jnz	inbuf6		; EOF/error: stop reading.
	lxi	h,seccnt	; Success.  Get addr of sector count
	inr	m		; Bump sector count by one
	lda	bufsec		; Get max number of sectors in buffer
	cmp	m		; Are we there yet?
	jz	inbuf7		; Yes, can't read any more.
	lhld	bufpnt		; No, try for another.  Get buffer address,
	lxi	d,bufsiz	;  and size of sector,
	dad	d		;  giving next buffer address in HL
	jmp	inbuf5		; Go read another sector.

; We hit EOF or got an error.  Put the DMA address back where it belongs,
; then go see if we have any sectors (before the one that got the error)
; to return to the caller.  Nxtbuf points to the first good sector, if
; any; seccnt contains the count of good sectors.

inbuf6:	call	rstdma
	jmp	inbuf1		; Go see if we have some data to return

; We've filled the big buffer.  Reset the DMA address, then go return a
; sector to the caller.  nxtbuf points to the beginning of the buffer;
; seccnt contains the number of sectors successfully read (except that
; if we've read 256 sectors, seccnt contains zero, so we can't just go
; to inbuf1).

inbuf7:	call	rstdma		;[pcc012]
	lda	seccnt		; Get sector count again.
	jmp	inbuf2		; Return a sector.

;;[pcc012]
;   appfil - Create or append to an existing file.  File name is in FCB.
;	Non-skip return if could not be done.  Skip return with file
;	open and bufpnt pointing to end of file.
;	called by logopn
appfil:	xra	a		;[pcc012] zero out stuff for open
	sta	fcb+0CH		;[pcc012] extent
	sta	fcb+0EH		;[pcc012] Must be zero for MAKEF or OPENF.
	sta	fcb+20H		;[pcc012] Zero the current record.
	mvi	c,openf		;[pcc012] Try to open the file
	lxi	d,fcb		;[pcc012]
	call	bdos		;[pcc012]
	cpi	0FFH		;[pcc012] Did we find it?
	jz	makfi1		;[pcc012] If not, go create it
	mvi	c,cflsz		;[pcc012] Compute the file size
	lxi	d,fcb		;[pcc012]
	call	bdos		;[pcc012]
	lhld	fcb+21H		;[pcc012] random record pointer
	mov	a,h		;[pcc012] See if zero length file
	ora	l		;[pcc012]
	jz	makfi2		;[pcc012] set up pointers if null file
	dcx	h		;[pcc012] backup to last record written
	shld	fcb+21H		;[pcc012] store rec ptr back
	lhld	bufadr		;[pcc012] get buffer address
	xchg			;[pcc012] to DE
	mvi	c,setdma	;[pcc012] set dma address
	call	bdos		;[pcc012] for read
	mvi	c,rrand		;[pcc012] read the last block
	lxi	d,fcb		;[pcc012]
	call	bdos		;[pcc012]
	ora	a		;[pcc012] check results
	jnz	rstdma		;[pcc012] reset dma and return if error
	lhld	bufadr		;[pcc012] get address again
	lxi	d,bufsiz	;[pcc012] and and size
	mvi	a,'Z'-40H	;[pcc012] control-Z for comparison
appcz:	cmp	m		;[pcc012] Is this the EOF?
	jz	appxit		;[pcc012] Jump if yes
	inx	h		;[pcc012] no, bump
	dcr	e		;[pcc012] and grind
	jnz	appcz		;[pcc012] until find or buffer empty
appxit:	shld	bufpnt		;[pcc012] store buffer pointer
	dad	d		;[pcc012] compute next buffer adr
	shld	nxtbuf		;[pcc012] and store
	mov	a,e		;[pcc012] updated chr count
	sta	chrcnt		;[pcc012]
	xra	a		;[pcc012] reset sector count
	sta	seccnt		;[pcc012]
	call	rstdma		;[pcc012] reset normal dma
	jmp	rskp		;[pcc012] and give good return

;	Create a file, deleting any previous version.  The filename is in
;	fcb.
;	Returns nonskip if file could not be created.
;	If successful, takes skip return with bufpnt and chrcnt initialized
;	for output; buffers should be output via outbuf.
;	called by: gofil
makfil:	mvi	c,delf		; delete the file if it exists.
	lxi	d,fcb
	call	bdos
	xra	a
	sta	fcb+0CH		; zero the extent.
	sta	fcb+0EH		; must be zero for MAKEF or OPENF.
	sta	fcb+20H		; zero the current record.
;[pcc012] here from appfil above if file does not exist
makfi1:	mvi	c,makef		;[pcc012] now create it.
	lxi	d,fcb
	call	bdos
	cpi	0FFH		; is the disk full?
	rz			; take error return if so.
; success. set up pointers and counters for multisector buffering.
;[pcc012] also here from appfil if found zero length file
makfi2:	lhld	bufadr		;[pcc012] find beginning of buffer space.
	shld	bufpnt		; make it current buffer.
	lxi	d,bufsiz	; get sector size.
	dad	d		; find beginning of next buffer.
	shld	nxtbuf		; store for later.
	mov	a,e		; store buffer size
	sta	chrcnt		;  for caller.
	xra	a
	sta	seccnt		; no sectors stored yet.
	jmp	rskp		; take success return.

;[pcc012]
;   outadv - conditionally advance output buffer if disk write not needed.
;	preserves BC
;	skip return with with next output buffer set up
;	non-skip return if memory buffer full and must write to disk.
;	called by:logit

outadv:	push	b		;[pcc012] save BC as advertised
	lxi	h,seccnt	;[pcc012] point to sectors buffered
	inr	m		;[pcc012] count this one
	lda	bufsec		;[pcc012] how many we can hold
	cmp	m		;[pcc012] check if full
	jnz	outbf2		;[pcc012] continue if not
	dcr	m		;[pcc012] full, un-advance sector count
	pop	b		;[pcc012] restore bc
	ret			;[pcc012] and give non-skip return

;	get a fresh output buffer, flushing big buffer if necessary.
;	returns nonskip if disk full.
;	if successful, returns skip with bufpnt and chrcnt updated.  Note
;	that chrcnt holds one less than the buffer size.
;	preserves BC.
;	called by: ptchr,logwrt

outbuf:	push	b
	lxi	h,seccnt	; count another buffered sector
	inr	m		;  ...
	lda	bufsec		; get number of sectors we can hold
	cmp	m		; full?
	jnz	outbf2		; if not, set up pointers and return
	call	outmbf		; flush the big buffer
	 jmp	outbf9		; disk error.
;[pcc012] also here from outadv to advance buffer
outbf2:	lhld	nxtbuf		; get pointer to fresh buffer
	shld	bufpnt		; store for caller
	lxi	d,bufsiz	; advance our pointer to next buffer
	dad	d
	shld	nxtbuf
	mvi	a,bufsiz-1	; get buffer size (pre-decremented)
	sta	chrcnt		; store for caller
	pop	b
	jmp	rskp		; return success.

outbf9: pop	b		; clean up stack
	ret			; and take error return.

;	flush incore output buffers.
;	returns nonskip if disk full.
;	if successful, returns skip with nxtbuf reset to start of buffer and
;	seccnt zero.
;	destroys all ac's.
;	called by: outbuf, clofil.

outmbf:	lhld	bufadr		; get start of buffer
	shld	nxtbuf		; store for next fill cycle
	shld	bufpnt		; store for empty loop
outmb2:	lhld	bufpnt		; get address of current sector
	xchg			;  into DE
	lxi	h,bufsiz	; advance HL to next sector
	dad	d		;  ...
	shld	bufpnt		;  and store for later
	mvi	c,setdma
	call	bdos		; point CP/M at current sector
	lxi	d,fcb
	mvi	c,writef
	call	bdos		; output the sector
	ora	a		; test for error (A non-zero)
	jnz	rstdma		;[pcc012] reset dma and take nonskip return if so
	lxi	h,seccnt
	dcr	m		; count down buffered sectors
	jnz	outmb2		; loop if more saved
	call	rstdma		;[pcc012] restore normal dma
	jmp	rskp		; return success.

;	output current buffer, flush incore buffers, and close output file.
;	returns nonskip if disk full; skip if successful.
;	called by: rdata

clofil:
	lda	chrcnt		; get the number of chars left in the buffer.
	cpi	bufsiz		; Virgin buffer?
	jz	clofl3		; yes, don't output it.
	lhld	bufpnt		; get the buffer pointer.
clofl1:	dcr	a		; lower the count.
	jm	clofl2		; if full then stop.
	mvi	m,'Z'-100O	; put in a ^Z for EOF.
	inx	h		; point to the next space.
	jmp	clofl1

clofl2:	call	outbuf		; output the last buffer.
	 jmp	r		; give up if the disk is full.
clofl3:	lda	seccnt		; any sectors buffered in memory?
	ora	a
	jz	clofl4		; if not, don't try to flush.
	call	outmbf		; flush buffers
	 jmp	r		; disk full.
clofl4:	mvi	c,closf		; close up the file.
	lxi	d,fcb
	call	bdos
	jmp	rskp		; return success.


; Reset DMA address to the default buffer
; called from inbuf,appfil,outmbf
rstdma:	lxi	d,buff		;[pcc012]
	mvi	c,setdma	;[pcc012]
	jmp	bdos		;[pcc012]

;

version:db	'Kermit-80 v4.'
	db	(verno/10) + '0'	; tenth's digit of version number
	db	(verno MOD 10) + '0'	; hundredth's digit
	db	' $'
kerm:	db	'Kermit-80  '
kerm1:	db	'x:>$'		;'x' filled in at startup with DRIVE name
crlf:	db	cr,lf,'$'
ermes1:	db	cr,lf,'?Unrecognized command$'
ermes3:	db	cr,lf,'?Not confirmed$'
ermes4:	db	'?Unable to receive initiate',cr,lf,'$'
ermes5:	db	'?Unable to receive file name',cr,lf,'$'
ermes6:	db	'?Unable to receive end of file',cr,lf,'$'
erms10:	db	'?Unable to receive data',cr,lf,'$'
erms11:	db	'?Disk full',cr,lf,'$'
erms14:	db	'?Unable to receive an acknowledgement from the host',cr,lf,'$'
erms15:	db	cr,lf,'?Unable to find file',cr,lf,'$'
erms16:	db	'?Unable to rename file$'
erms17: db	cr,lf,'?Disk full$'
erms18: db	cr,lf,'?Unable to tell host that the session is finished$'
erms19: db	cr,lf,'?Unable to tell host to logout$'
erms20: db	cr,lf,'?Kermit has not been configured for a target system$'
erms21: db	cr,lf,'?Consistency check on configuration failed$'
erms22:	db	cr,lf,'?Error writing to log file',cr,lf,'$'	;[pcc005]

infms3:	db	bell,'Completed$'
infms4:	db	bell,'Failed$'
infms5:	db	'%Renaming file to $'
infms6:	db	cr,lf,'[Closing the log file]$'
infms7:	db	cr,lf,'[Connected to remote host.  Type $'
infms8:	db	'C to return;',cr,lf,' type $'
inms8a:	db	'? for command list]',cr,lf,'$'
infms9:	db	cr,lf,'[Connection closed, back at micro]$'
inms10:	db	'Control-$'
inms12:	db	' (Not implemented)',cr,lf,'$'
inms13:	db	bell,'Interrupted$'
inms14:	db	TAB,TAB,'    Directory for drive '
dnam14:	db	'x:',cr,lf,'$'		;filled in by dir routine.
inms15:	DB	CR,LF,TAB,TAB,'Drive $'
inms16:	DB	'  has $';filled in by summary code with drive letter
inms17:	DB	'K bytes free',CR,LF,'$'
inms18:	DB	CR,LF,'File(s) erased$',CR,LF
inms19:	db	cr,lf,'[Transmitting file to host:'
	db	cr,lf,' 1. Type any character to send a line.'
	db	cr,lf,' 2. Type RETURN to terminate the line '
	db	'and to get the next line (go back to 1.)'
	db	cr,lf,'    (You may send other characters '
	db	'before RETURN.),'
	db	cr,lf,'   or type $'
inms20:	db	'R to send the same line again,'
	db	cr,lf,'   or type $'
inms21: db	'C to abort transmission.]',cr,lf,'$'
inms22:	db	cr,lf,'[Transmission done. Connected normally '
	db	'to remote host,'
	db	cr,lf,' type $'
inms23:	db	'Sending...$'
inms24:	db	'Receiving...$'
inms25:	db	bell,'Warning: eighth bit cannot be sent$'
inms26:	db	cr,lf,'For help, type ? at any point in a command$'
inms27:	db	cr,lf,'[Logging suspended]',cr,lf,'$'	;[pcc003]
inms28:	db	cr,lf,'[Logging resumed]',cr,lf,'$'	;[pcc003]

escmes:	db	cr,lf,'Type the new escape character:  $'
tacmes:	db	cr,lf,'Type the new TAC intercept character:  $'

xmthlp:	db	cr,lf,'R Send the same line again$'
loghlp:	db	cr,lf,'Q  Suspend logging'		;[pcc003]
	db	cr,lf,'R  Resume logging$'		;[pcc003]
inthlp:	db	cr,lf,'?  This message'
	db	cr,lf,'C  Close the connection'
	db	cr,lf,'0  (zero) Transmit a NULL'
	db	cr,lf,'P  Toggle printer on/off'	;[pcc002]
	db	cr,lf,'S  Status of the connection$'
inhlp1:	db	cr,lf,'Typing another $'
inhlp2:	db	' will send it to the host'
	db	cr,lf,cr,lf,'Command>$'

xmtst:	db	cr,lf,'Transmitting a file$'
locst:	db	cr,lf,'Local echo$'
onstr:	db	' on$'
offstr:	db	' off$'
vtemst:	db	cr,lf,'VT52 emulation$'
cpmst:	db	cr,lf,'File Mode$'
defstr: db	' default$'
ascstr: db	' ASCII$'
binstr:	db	' binary$'
ibmst:	db	cr,lf,'IBM flag$'
filst:	db	cr,lf,'File warning$'
prst:	db	cr,lf,'Printer copy$'
logst:	db	cr,lf,'Logging is$'		;[pcc003]
susstr:	db	' suspended$'			;[pcc003]
escst:	db	cr,lf,'Escape char: $'
bckst:	db	cr,lf,'Block check type: $'
bckst1:	db	'-character$'
parst:	db	cr,lf,'Parity: $'
pnonst:	db	'none$'
pmrkst:	db	'mark$'
pspcst:	db	'space$'
poddst:	db	'odd$'
pevnst:	db	'even$'
porst:	db	cr,lf,'Port in use is: $'
spdst:	db	cr,lf,'Current baud rate is: $'
spdust:	db	'indeterminate (not SET)$'
timmsg:	db	'Timer$'
tacst:	db	cr,lf,'Current TACTrap Status/Intercept Character:  $'

cmer00:	db	cr,lf,'?Program error:  Invalid COMND call$'
cmer01:	db	cr,lf,'?Ambiguous$'
cmer02:	db	cr,lf,'?Illegal CP/M file specification$'
cmer03:	db	cr,lf,'?Wild-cards not allowed in file specification$'	;[pcc006]
cmin00:	db	' Confirm with carriage return$'
;
	;Impure data

;COMND storage

cmstat:	ds	1		;What is presently being parsed.
cmaflg:	ds	1		;Non-zero when an action char has been found.
cmccnt:	ds	1		;Non-zero if a significant char is found.
cmsflg:	ds	1		;Non-zero when the last char was a space.
cmostp:	ds	2		;Old stack pointer for reparse.
cmrprs:	ds	2		;Address to go to on reparse.
cmprmp:	ds	2		;Address of prompt.
cmptab:	ds	2		;Address of present keyword table.
cmhlp:	ds	2		;Address of present help.
cmdbuf:	ds	80H		;Buffer for command parsing.
cmfcb:	ds	2		;Pointer to FCB.
cmfcb2:	ds	2		;Pointer to position in FCB.
cmfwld:	ds	1		;Wildcard flag
cmcptr:	ds	2		;Pointer for next char input.
cmdptr:	ds	2		;Pointer into the command buffer.
cmkptr:	ds	2		;Pointer to keyword.
cmsptr:	ds	2		;Place to save a pointer.
;
oldsp:	ds	2		;Room for old system stack.
	ds	40H		;Room for 32 levels of calls.
stack:	ds	2
eoflag:	ds	1		;EOF flag;non-zero on EOF.
curdsk:	db	0		;holds "logged" disk
prtcnt:	db	0		;[pcc008] prtchr fairness count
timflg:	db	0		;[jd] timer flag: 0 -> no timer
timval:	dw	0		;[jd] timer value
wrn8:	db	0		;[jd] non-zero if 8-bit-lost warning sent
qbchr:	db	'&'		;[jd] binary quote character.
quot8:	db	0		;[jd] non-zero if doing 8-bit quoting
logflg:	db	0		;Flag for a log file.
				;[pcc005] 0 = no log
				;[pcc005] x1 = logging on
				;[pcc005] x2 = suspended
				;[pcc005] 8xH (bit 7) = file open
lognam:	db	0		;[pcc013] File to use for session logging
	db	'KERMIT  '	;[pcc013]
	db	'LOG'		;[pcc013]
escflg:	db	0		;Escape flag (start off).
fileio:	db	0		;Line-by-line from file (default off).
xofflg:	db	0		;X-OFF (=^S) received from COMM-line
;				;X-ON (=^Q) received resets this
vtyval:	ds	1		; holds row number for VT52 cursor positioning
chrcnt:	ds	1		;Number of chars in the file buffer.
filcnt:	ds	1		;Number of chars left to fill.
outpnt:	ds	2		;Position in packet.
bufpnt:	ds	2		;Position in file buffer.
fcbptr:	ds	2		;Position in FCB.
datptr:	ds	2		;Position in packet data buffer.
cbfptr:	ds	2		;Position in character buffer.
pktptr:	ds	2		;Position in receive packet.
size:	ds	1		;Size of data from gtchr.
curchk:	ds	1		;Current checksum type
inichk:	ds	1		;Agreed upon checksum type
czseen:	ds	1		;Flag that control-Z was typed
pktnum:	ds	1		;Packet number.
numpkt:	ds	2		;Total number of packets sent.
numrtr:	ds	2		;Total number of retries.
numtry:	ds	1		;Number of tries on this packet.
oldtry:	ds	1		;Number of tries on previous packet.
state:	ds	1		;Present state of the automaton.
packet:	ds	4		;Packet (data is part of it).
data:	ds	5AH		;Data and checksum field of packet.
recpkt:	ds	65H		;Receive packet storage (use the following).
recpkx:	db	cr,'$'		;=	=	= buffer limit
filbuf:	ds	65H		;Character buffer.
fnbuf:	ds	20h		;[jd] file name buffer
;** Temp 1 & 2 must be in order
temp1:	ds	1		;Temporary storage.
lstchr	EQU	temp1		;Last console input character.
temp2:	ds	1
temp3:	ds	1
temp4:	ds	1

argblk:	ds	20H		;Used for subroutine arguments

maxfil	EQU	2		; currently, only two names used.
fcbblk:	ds	maxfil*10H	;Used for a list of FCB's

; Bookkeeping storage for multiple-sector buffering.  The actual buffer
; is somewhere in the system-dependent overlay. (at the end, I hope).
nxtbuf:	ds	2		; Pointer to next sector
seccnt:	ds	1		; Number of sectors buffered
endsts:	ds	1		; Status for last read into buffer

patch:	ds	100		; Guarantee some patch space

	ORG	($ + 0ffH) AND 0ff00H	; move to start of next page
;
;	hooks for system-dependent routines:
;	This area is overwritten by the system-dependent overlay.
;
lnkflg:	dw	0	; linkage information for consistency check.
lnkent:	dw	0	; more of the same.
ovlver:	dw	0	; pointer to overlay's version string
;
; Input/output routines.  Note that outmdm and outcon may actually be the
;	same routine if selmdm and selcon do anything.  (the same is true
;	of inpmdm and inpcon).
;
selmdm:	jmp	$-$	; select modem for I/O
outmdm:	jmp	$-$	; output character in E to modem
inpmdm:	jmp	$-$	; read character from modem. return character or 0 in A.
flsmdm:	jmp	$-$	; flush pending input from modem
selcon:	jmp	$-$	; select console for I/O
outcon:	jmp	$-$	; output character in E to console
inpcon:	jmp	$-$	; read char from console. return character or 0 in A
outlpt:	jmp	$-$	; output character in E to printer
;
; screen formatting routines
clrlin:	jmp	$-$	; erase current line
clrspc:	jmp	$-$	; erase current position (after backspace)
delchr:	jmp	$-$	; make delete look like backspace
clrtop:	jmp	$-$	; erase screen and go home
;
; these routines are called to display a field on the screen.
scrend:	jmp	$-$	; move to prompt field
screrr:	jmp	$-$	; move to error message field
scrfln:	jmp	$-$	; move to filename field
scrnp:	jmp	$-$	; move to packet count field
scrnrt:	jmp	$-$	; move to retry count field
scrst:	jmp	$-$	; move to status field
rppos:	jmp	$-$	; move to receive packet field (debug)
sppos:	jmp	$-$	; move to send packet field (debug)
;
sysinit: jmp	$-$	; program initialization
sysexit: jmp	$-$	; program termination
syscon:	jmp	$-$	; remote session initialization
syscls:	jmp	$-$	; return to local command level
sysinh:	jmp	$-$	; help text for interrupt (escape) extensions
sysint:	jmp	$-$	; interrupt (escape) extensions, including break
sysflt:	jmp	$-$	; filter for incoming characters.
			;  called with character in E.
sysbye:	jmp	$-$	; terminate remote session
sysspd:	jmp	$-$	; baud rate change routine.
			; called with value from table in DE
sysprt:	jmp	$-$	; port change routine.
			; called with value from table in DE
sysscr:	jmp	$-$	; screen setup for file transfer
			; called with Kermit's version string in DE
csrpos:	jmp	$-$	; move cursor to row B, column C
sysspc:	jmp	$-$	; calculate free space for current disk
mover:	jmp	$-$	; block move
;
; Data initialized by system-dependent overlay:
;
pttab:	ds	2	; points to local equivalents to VT52 escape sequences
spdtab:	ds	2	; address of baud rate command table, or zero
spdhlp:	ds	2	; address of baud rate help table, or zero
prttab:	ds	2	; address of port command table, or zero
prthlp:	ds	2	; address of port help table, or zero
timout:	ds	2	; Initial value for fuzzy timeout
vtflg:	ds	1	; VT52 emulation flag
escchr:	ds	1	; Storage for the escape character.
speed:	ds	2	; storage for the baud rate
port:	ds	2	; storage for port value
prnflg:	ds	1	;[hh] printer copy flag (overlay may need it)
dbgflg:	ds	1	; debugging flag
ecoflg:	ds	1	; Local echo flag (default off).
flwflg:	ds	1	; File warning flag (default on).
ibmflg:	ds	1	; IBM flag (default off).
cpmflg:	ds	1	; File mode flag (ascii/binary/default)
parity:	ds	1	; Current parity.
spsiz:	ds	1	; Send packet size.
rpsiz:	ds	1	; Receive packet size.
stime:	ds	1	; Send time out.
rtime:	ds	1	; Receive time out.
spad:	ds	1	; Send padding.
rpad:	ds	1	; Receive padding.
spadch:	ds	1	; Send padding char.
rpadch:	ds	1	; Receive padding char.
seol:	ds	1	; Send EOL char.
reol:	ds	1	; Receive EOL char.
squote:	ds	1	; Send quote char.
rquote:	ds	1	; Receive quote char.
chktyp:	ds	1	; Checksum type desired
tacflg:	ds	1	; TACTrap flag (zero=off, nonzero=on; when non-zero,
			;  contains current TAC intercept character)
tacchr:	ds	1	; TAC intercept character
bufadr:	ds	2	; Pointer to big buffer for multiple-sector I/O
bufsec:	ds	1	; Number of sectors big buffer can hold (0 means 256)
ffussy:	ds	1	; if nonzero, don't permit <>.,;?*[] in CP/M filespec.
; space used by directory command; here because space calculation is
;  (operating) system-dependent
bmax:	ds	2	; highest block number on drive
bmask:	ds	1	; (records/block)-1
bshiftf: ds	1	; number of shifts to multiply by rec/block
nnams:	ds	1	; counter for filenames per line

lnksiz	equ	$-lnkflg ; length of linkage section, for consistency check.

	END	START
