;	OSPLNK70.ASM  ver 7.0  dated 11/82
;	(previous version 6.4 dated 6/14/81)
;
;OSPLINK is a CP/M transient program which allows the user to
;send/receive ASCII text files to/from a remote computer using
;a modem.  Text data will be displayed on the console and may
;be optionally printed on the CP/M list device. No error checking
;protocol (such as MODEM7) is accomodated.
;
;OSPLINK was derived from the public domain program PLINK
;originally written by L.E.Hughes (EDCAM) 7/77, with revisions
;by Keith Petersen (W8SDZ), Tom Jorgenson, Steve Vinokuruff
;(Vanc CBBS), Dennis Breckenridge (Burnaby CBBS), Bruce Ratoff
;(Iselin RCPM), and Ben Reagan (Lynnwood,WA).
;
;OSPLINK version 6.4 was submitted to the First Osborne Group
;(FOG) Disk Library by Byron McKay (OxGate, PicoNet, and FOG).
;That version used direct Osborne serial/modem port I/O.
;The author was not identified.
;
;Significant additions and corrections were made by Jim Woolley,
;FOG Disk Librarian, to create version 7.0.  In particular:
; 1. Added buffered printer output to the CP/M list device
;    configured on the Osborne parallel port. 
; 2. Corrected text file transmit routine.
; 3. Added ability to change host acknowledge (trigger)
;    character during session.
; 4. Added help reminder of control commands.
; 5. Cleaned up read-console-string routine.
; 6. Cleaned up modem routines. Added runtime logic to move
;    code above 4000h (shadow memory), thereby keeping size
;    of .COM file to minimum.
; 7. Improved user interface.
; 8. Eliminated non-Osborne related code.
;
;The following control codes (commands) may be initiated
;from the keyboard:
;
;Control-E	Exit OSPLINK to CP/M "warm-boot".
;
;Control-T	Transmit ASCII file to remote system, asks for
;		drive (A, B, etc.) and filename.typ.
;
;Control-C	Aborts transmission of file to remote system.
;               If used when asked for drive, aborts ^T or ^W.
;
;Control-Y	Switches between saving and ignoring
;		incoming ASCII data in RAM buffer,
;		for later transfer to disk.
;
;Control-W	Writes RAM buffer to disk. Asks for drive
;		and filename.typ.
;
; + + + + + +	Revisions by Jim Woolley, FOG Disk Librarian, 11/82
;
;Control-P	Toggles list device (printer) on/off. A 256 character
;		buffer is used to accomodate printer busy conditions.
;		Printer interface must be on Osborne parallel (IEEE-488
;		or Centronics) port, which is assumed much faster than
;		the modem.
;
;Control-A	Permits reset of host computer's acknowledgment
;		character. Default is linefeed. May be changed to,
;		for example, > or * or ? or @ or # or &, etc. Ack.
;		prompt is only used during ^T file trasnmission.
;
;Control-R	Displays reminder of commands.
;
;Following apply when prompted for filename (similar to keyboard
;entry at CP/M level)
;
;Control-H or <--  Backspace when in command mode (e.g. ^T or ^W).
;
;Control-U or -X   Aborts current line when in command mode.
;
; + + + + + +
;
;Note: all other control codes are passed to modem output, and
;may be interpreted by the remote system as various control
;functions.
;
;A "trigger" character is a response sent by the host
;indicating that it is ready for the next line (acknowledgment).
;The following "trigger" equate is set to "lf" (linefeed)
;by default. An optional trigger char may be passed via fcb1
;in command line;
;
; e.g.  OSPLINK B	will set trigger to "bell"
;
;The following options are allowed on the command line
;
;	1. B = bell  07h
;	2. X = xon   11h
;	3. U = upload; no trigger check at all (this option
;	       may only be entered via command line)
;
;Any other ascii character on the command line will be
;converted to upper case and taken literally as the trigger.
;Only the first character is scanned. Examples are > or * or ?.
;Control-A permits trigger character to be reset.
;
lf	equ	0ah	;line feed
trigger	equ	lf	;default value
;
;some Osborne 1 locations
;
iobyte	equ	3
mstat	equ	02a00h	;modem port status
mport	equ	02a01h	;modem port data
;
;bdos entry point and function codes
;
base	equ	0
;
bdos	equ	base+5
resdsk	equ	13	;reset disk system
offc	equ	15	;open file
cffc	equ	16	;close file
dffc	equ	19	;delete file
rrfc	equ	20	;read record
wrfc	equ	21	;write record
mffc	equ	22	;make file
;
;default fcb and field definitions
;
fcb	equ	base+5ch
fn	equ	1	;file name field (rel)
ft	equ	9	;file type field (rel)
ex	equ	12	;file extent field (rel)
nr	equ	32	;next record field (rel)
dbuf	equ	base+80h ;default disk buffer address
;
;ascii control characters
;
cr	equ	0dh	;carriage return
del	equ	7fh	;delete (rubout)
bell	equ	07h	;bell signal
bs	equ	08h	;backspace
tab	equ	09h	;horizontal tab
xon	equ	11h	;x-on character
null	equ	00h	;null char
;
;warning character for low memory when [^Y]anking incoming
;ascii data into RAM - signals user to press ^W or ^Y
;
wrnsig	equ	bell
;
;
;	** main program **
;
	org	base+100h
;
lnki:	lxi	b,movsiz ;move stack, modem routines,
	lxi	h,movfrm ;     & text buffer above
	lxi	d,movto  ;     shadow mode memory
;
lnki2:	mov	a,m	;from
	dcx	h
	xchg
	mov	m,a	;to
	dcx	h
	xchg
	dcx	b	;loop until zero
	mov	a,b
	ora	c
	jnz	lnki2
;
	lxi	sp,stack ;create local stack
	lhld	base+1	;point to CP/M jmp table
	lxi	d,3	;get ready to add 3
	dad	d	;point to con status jmp
	shld	citcal+1 ;modify call adrs
	dad	d	;point to con in jmp
	shld	rccal+1	;modify call adrs
	dad	d	;point to con out jmp
	shld	wccal+1	;modify call adrs
	dad	d	;point to lst out jmp
	shld	wlcal+1	;modify call adrs
	lxi	d,30
	dad	d	;point to lst status jmp
	shld	wltcal+1 ;modify call adrs
;
	lda	fcb+1	;see if optional trigger char
	cpi	20h	;blank.. ?
	jz	skp	;..blank so use default "lf"
	cpi	'B'	;bell wanted
	jz	trgbel
	cpi	'X'	;xon wanted
	jz	trgxon
	cpi	'U'	;uploading no checking for trigger
	jz	trgupl
;
settrg	sta	overly+1 ;store the character as is then
	jmp	skp
;
trgbel	mvi	a,bell
	jmp	settrg
;
trgxon	mvi	a,xon
	jmp	settrg
;
trgupl	xra	a	 ;zero out jump
	sta	overl1+1 ;change check for c/r to null
	sta	overl2+1 ;and send linefeeds as well
;
skp:	equ	$
;
cont:	xra	a	;clear char buffers
	sta	inch
	sta	outch
	sta	flag	;clear text save flag
	sta	lflag	;clear lst flag
	sta	lcnt	;    and char count
	lxi	h,tbuf	;set ptr to tbuf
	shld	ptr
	lxi	h,0	;size = 0
	shld	size
	lxi	h,lbuf	;set ptr to lbuf
	shld	lbufs
	shld	lbufe
	lxi	h,lnkims  ;print sign-on message
	call	wcs
;
;main loop
;
lnki3:	call	citest	;jump if no data from console
	jz	lnki4
	call	rcc	;else read console data
	cpi	20h
	cc	pcc	;call pcc if control char
	jc	lnki4	;jump if pcc handled char
	ori	80h	;else set valid data bit
	sta	inch	;and store in input char buffer
;
lnki4:	lda	outch	;jump if no data for console
	ora	a
	jp	lnki5
	ani	7fh	;else discard valid data bit
	call	wcc	;send char to console
	xra	a	;then clear output char buffer
	sta	outch
;
lnki5:	call	mitest	;jump if no data from modem
	jz	lnki6
	call	rmc	;else read modem data
	call	save	;save char in text buffer if flag on
	ori	80h	;set data valid bit
	sta	outch	;store in output char buffer
;
lnki6:	lda	inch	;jump if no data for modem
	ora	a
	jp	lnki7
	call	motest	;jump if modem xmit buffer busy
	jz	lnki7
	lda	inch
	ani	7fh	;discard valid data bit
	call	wmc
	xra	a	;clear input char buffer
	sta	inch
;
lnki7:	jmp	lnki3	;end of main loop
;
lnkims:	db	cr,lf,'OSPLINK ver 7.0 (11/82)'
lnkim2:	db	cr,lf,lf
	db	'<^Y>ank          <^W>rite    <^P>rint',cr,lf
	db	'<^T>ransmit      <^C>ancel   <^E>xit',cr,lf
	db	'<^A>cknowledge   <^R>emind',cr,lf,lf
	db	'Ready',cr,lf,lf,0
;
;pcc - process control character
;
pcc:	cpi	'E'-40h	;jump out if ctrl e
	jnz	pcc1
	push	h
	lxi	h,ays	;print 'are you sure'
	call	wcs
	pop	h
	call	rcc	;get answer
	call	wcc	;echo it
	ani	5fh	;make upper case
	cpi	'Y'	;yes?
	jz	pccex	;exit
	call	wccr	;crlf
	stc		;tell plink to ignore this character
	ret
;
;
pcc1:	cpi	'T'-40h	;jump if not control-t
	jnz	pcc2
	call	stf	;transmit text file to modem
	stc		;tell plink to ignore this character
	ret
;
pcc2:	cpi	'Y'-40h	;jump if not control-y
	jnz	pcc3
	lda	flag
	dcr	a	;was it zero?
	jnz	pcc2a	;yes
	sta	flag	;no, was 1, now 0
	lxi	h,pcmnix ;print ignore incoming stuff
	jmp	pcc2b
;
pcc2a:	mvi	a,1	;turn on text save flag
	sta	flag
	lxi	h,pccmr	;print 'saving incoming text in memory'
;
pcc2b:	call	wcs
	stc		;tell plink to ignore this character
	ret
;
pcc3:	cpi	'W'-40h	;jump if not control-W
	jnz	pcc4
	call	wtb	;write text buffer to disk
	stc
	ret
;
pcc4:	cpi	'P'-40h	;jump if not control-p
	jnz	pcc5
	lda	lflag
	dcr	a	;was it zero?
	jnz	pcc4a	;yes
	sta	lflag	;no, was 1, now 0
	lxi	h,pcptof ;print 'printer off'
	jmp	pcc4c
;
pcc4a:	lda	iobyte	;check printer port
	ori	80h	;jump if parallel
	jnz	pcc4b
	sta	lflag	;turn off list flag
	lxi	h,pcpser ;print 'must not be serial'
	jmp	pcc4c
;
pcc4b:	mvi	a,1	;turn on list flag
	sta	lflag
	lxi	h,pcpton ;print 'printer on'
;
pcc4c:	call	wcs
	stc		;tell plink to ignore this character
	ret
;
pcc5:	cpi	'R'-40h	;jump if not control-r
	jnz	pcc6
	lxi	h,lnkim2 ;print reminder
	call	wcs
	stc		;tell plink to ignore this character
	ret
;
pcc6:	cpi	'A'-40h	;jump if not control-a
	jnz	pcc7
	mvi	a,cr	;restore defaults
	sta	overl1+1
	mvi	a,lf	
	sta	overl2+1
	lxi	h,pctrig ;print 'enter trigger'
	call	wcs
	call	rcc	;read trigger character
	sta	overly+1 ;save it
	cpi	20h	;jump if not control character
	jnc	pcc6a
	push	psw
	mvi	a,'^'	;echo control character
	call	wcc
	pop	psw
	adi	40h	;make alphabetic
;
pcc6a:	call	wcc	;echo character
	call	wccr
	stc		;tell plink to ignore it
	ret
;
pcc7:	stc		;let plink handle all other cont. codes
	cmc
	ret
;
pccex:	lxi	h,disms	;print 'modem not disconnected'
	call	wcs
	jmp	base	;exit to warm boot
;
ays:	db	cr,lf,'Exit to CP/M - are you sure (Y or N)? ',0
;
disms:	db	cr,lf,'Modem connection is unchanged',cr,lf,0
;
pccmr:	db	cr,lf,'Saving incoming text in memory',cr,lf,0
pcmnix:	db	cr,lf,'Ignoring incoming text',cr,lf,0
;
pcpton:	db	cr,lf,'Printer toggled on',cr,lf,0
pcptof:	db	cr,lf,'Printer toggled off',cr,lf,0
pcpser:	db	cr,lf,'Printer must be serial - use SETUP',cr,lf,0
;
pctrig:	db	cr,lf,'Enter host acknowledgement prompt: ',0
;
;stf - send text file (to modem)
;
stf:	call	gfn	;get name of disk file to send
	jc	stf6	;jump if file name error
	call	open	;try to open specified file
	cpi	255	;jump if file not found
	jz	stf7
;
stf1:	call	read	;read next record into dbuf
	ora	a	;jump if end-of-file
	jnz	stf5
	lxi	h,dbuf	;point to disk buffer
	mvi	c,128
;
stf2:	mov	a,m	;fetch next char from dbuf
	inx	h
	cpi	'Z'-40h	;jump if end-of-file character
	jz	stf5
overl2	cpi	lf	;ignore line feeds
	jz	stf4
	push	psw
;
stf2a:	call	motest
	jz	stf2a	;wait until modem not busy
	pop	psw
	push	psw
	call	wmc	;write character to modem
	pop	psw
	call	wcc	;write character to console
overl1	cpi	cr	;jump if not carriage return
	jnz	stf4
;
stf3:	call	citest	;check console data ready
	jz	stf3a	;no data there
	call	rcc	;get console character
	cpi	'C'-40h	;control c aborts it
	jz	stf8
;
stf3a:	call	mitest	;wait for next modem character
	jz	stf3
	call	rmc	;read modem character
overly	cpi	trigger	;wait for trigger character
	jnz	stf3
	mvi	a,lf	;send lf to console
	call	wcc
;
stf4:	call	citest	;check console data ready
	jz	stf4a	;jump if no data
	call	rcc	;get character
	cpi	'C'-40h	;control c aborts
	jz	stf8
;
stf4a:	dcr	c	;loop thru rest of dbuf
	jnz	stf2
	jmp	stf1	;go get next record from disk
;
stf5:	lxi	h,stfsm	;print 'file send complete'
	call	wcs
	ret
;
stf6:	lxi	h,stfs1	;print 'file name error'
	call	wcs
	ret
;
stf7:	lxi	h,stfs2	;print 'file not found'
	call	wcs
	ret
;
stf8:	lxi	h,stfsa	;print 'file send aborted'
	call	wcs
	ret
;
stfsm:	db	'File send complete',cr,lf,0
stfs1:	db	'File name error or abort',cr,lf,0
stfs2:	db	'File not found',cr,lf,0
stfsa:	db	cr,lf,'File send aborted',cr,lf,0
;
;save - save char in text buffer if flag on
;
;  entry conditions
;     a - character to save
;
save:	push	psw
	lda	flag
	ora	a
	jnz	save1
	pop	psw
	ret
;
save1:	pop	psw
	cpi	del	;rubout (del) ?
	rz		;yes, ignore it
	cpi	20h	;test for control characters
	jnc	save2	;jump if not control char.
	cpi	cr	;allow cr to be saved
	jz	save2
	cpi	lf	;allow lf to be saved
	jz	save2
	cpi	tab	;allow tab to be saved
	jz	save2
	ret		;ignore all other control chars.
;
save2:	push	h
	lhld	size	;size = size + 1
	inx	h
	shld	size
	lhld	ptr
	mov	m,a
	inx	h
	shld	ptr
	push	psw
	lda	base+7	;get system size
	sui	1	;so we dont crash CP/M
	cmp	h	;are we out of room?
	jz	saveab	;yes, abort
	sui	4	;leave some room (1k)
	cmp	h
	mvi	a,wrnsig  ;signal console running out of space
	cc	wcc
	pop	psw
	pop	h
	ret
;
;saveab - ran out of room, issue message and flow
;	  through to disk save routine
;
savend:	db	bell,cr,lf,'No room left to save incoming text'
	db	cr,lf,'Writing memory to disk',cr,lf,0
;
saveab:	lxi	h,savend ;print 'aborting - no room left'
	call	wcs
	pop	psw	;clear stack
	pop	h
	pop	h	;pop return address
	lxi	h,lnki3	;set up new return address
	push	h	;leave it on the stack
	xra	a	;clear char buffers
	sta	inch
	sta	outch
;
;wtb - write text buffer to disk
;
wtb:	lhld	size	;jump if text buffer empty
	mov	a,l
	ora	h
	jz	wtb5
	mvi	c,resdsk ;reset in case read-only
	call	bdos
	call	gfn	;get file name
	jc	wtb6	;jump if file name error
	call	delt	;delete old file, if any
	call	make	;make new file
	lhld	size
	xchg		;de = tbuf size
	lxi	h,dbuf
	push	h	;top of stack points to dbuf
	lxi	h,tbuf	;hl points to tbuf
;
wtb1:	mvi	c,128	;disk buffer size
;
wtb2:	mov	a,m	;fetch next byte of tbuf
	inx	h
	xthl
	mov	m,a	;store in dbuf
	inx	h
	xthl
	dcx	d	;size = size - 1
	mov	a,d	;exit loop if size = 0
	ora	e
	jz	wtb3
	dcr	c	;loop until dbuf full
	jnz	wtb2
	call	write	;write full dbuf to disk
	xthl		;top of stack now points to tbuf
	lxi	h,dbuf
	xthl		;put dbuf pointer on stack
	jmp	wtb1	;loop until end of tbuf
;
wtb3:	pop	h	;hl points to current place in dbuf
;
wtb4:	mvi	m,'Z'-40h ;store eof code
	inx	h
	dcr	c	;loop thru rest of dbuf
	jnz	wtb4
	call	write	;write last sector to disk
	call	close	;clean up act and go home
	lxi	h,tbuf	;clear text buffer
	shld	ptr
	lxi	h,0
	shld	size
	lxi	h,wtbsm	;print 'buffer saved on disk'
	call	wcs
	lxi	h,pcmnix ;print 'ignoring text'
	call	wcs
	xra	a	;clear text save flag
	sta	flag
	ret
;
wtb5:	lxi	h,wtbs1	;print 'text buffer empty'
	call	wcs
	ret
;
wtb6:	lxi	h,wtbs2	;print 'file name error'
	call	wcs
	ret
;
wtbsm:	db	cr,lf,'Text memory buffer saved on disk',cr,lf,0
wtbs1:	db	'Text buffer empty',cr,lf,0
wtbs2:	db	'File name error or abort',cr,lf,0
;
;wcs - write console string
;
;  entry conditions
;     hl - points to string (term by zero byte)
;
wcs:	mov	a,m
	inx	h
	ora	a
	rz
	call	wcc
	jmp	wcs
;
;wccr - write console carriage return (and line feed)
;
wccr:	mvi	a,cr
	call	wcc
	mvi	a,lf
;
;wcc - write console character
;
;  entry conditions:
;     a - character to write
;
wcc:	push	psw
	push	b
	push	d
	push	h
	mov	c,a	;get character for cbios
	push	b
wccal:	call	$-$	;modified by init.
	pop	b	;restore character in c
	lda	lflag	;test printer toggle
	ora	a
	cnz	wlc	;skip if zero
;
wcc1:	pop	h
	pop	d
	pop	b
	pop	psw
	ret
;
;wlc - write list character
;
;  entry conditions:
;     c - character to write
;
;  lbuf provides circular buffer
;
wlc:	lda	lcnt	;count characters in buffer
	inr	a
	jnz	wlc1	;jump if buffer not full
	dcr	a
	lhld	lbufs	;incr start pointer
	inr	l	;     modulo 256
	shld	lbufs	;     and save
;
wlc1:	lhld	lbufe	;point to end of buffer
	mov	m,c	;save character
	inr	l	;incr end pointer
	shld	lbufe	;     modulo 256
	push	psw	;save character count
;
wltcal:	call	$-$	;check stat - modified by init.
	ora	a	;jump if printer not ready
	jz	wlc3
	lhld	lbufs	;point to start of buffer
	mov	c,m	;put character in c
	inr	l	;incr start pointer
	shld	lbufs	;     modulo 256
;
wlcal:	call	$-$	;print c - modified by init.
	pop	psw
	dcr	a	;decr count
	push	psw	;save character count
	jnz	wltcal	;print until buffer empty
;			      or printer busy
wlc3:	pop	psw
	sta	lcnt	;save count
	ret
;
;rcs - read console string (with echo)
;
;  exit conditions
;     b - number of characters read (<128)
;    hl - points to last char stored (cr)
;
rcs:	lxi	h,ibuf
	mvi	b,0
;
rcs1:	call	rcc	;read next char from console
	cpi	'H'-40h	;jump if not BS
	jnz	rcs2
	inr	b	;ignore BS if ibuf already empty
	dcr	b
	jz	rcs1
	dcx	h	;else discard last char
;
rcs1a:	call	wcc	;echo BS to console
	mvi	a,' '	;erase last character
	call	wcc
	mvi	a,bs
	call	wcc
	dcr	b	;decrement count
	jmp	rcs1	;	and loop
;
rcs2:	cpi	'U'-40h	;jump if control-u
	jz	rcs2a
	cpi	'X'-40h	;and if not control-x
	jnz	rcs3
;
rcs2a:	inr	b	;ignore if ibuf already empty
	dcr	b
	jz	rcs
;
rcs2b:	mvi	a,bs	;else erase current line
	call	wcc
	mvi	a,' '
	call	wcc
	mvi	a,bs
	call	wcc
	dcr	b
	jnz	rcs2b
	jmp	rcs
;
rcs3:	call	wcc	;echo char to console
	mov	m,a	;store char in ibuf
	inr	b	;increment count
	cpi	cr	;jump if carriage return
	jz	rcs4
	mov	a,b	;check count
	cpi	128	;jump if < 128
	jnz	rcs3a
	mvi	a,wrnsig ;send signal
	call	wcc
	mvi	a,bs	;send BS
	jmp	rcs1a
;
rcs3a:	inx	h	;else advance pointer
	jmp	rcs1	;	and loop
;
rcs4:	mvi	a,lf	;issue line feed and return
	call	wcc
	ret
;
;rcc - read console character
;
;  exit conditions
;     a - character read
;
rcc:	push	b
	push	d
	push	h
rccal:	call	$-$	;modified by init.
	pop	h
	pop	d
	pop	b
	ret
;
;gfn - get file name
;
gfn:	lxi	h,gfnsd	;print 'which drive?'
	call	wcs
	call	rcc	;get answer from console
	call	wcc	;echo it to console
	ani	5fh	;make upper case
	cpi	'C'-40h	;^C means abort
	jz	gfn6
	sui	'A'-1
	jc	gfn	;require alphabetic
	jz	gfn
	cpi	17	;allow 16 drives (as in CP/M 2.x)
	jnc	gfn
	sta	fcb
;
gfnb:	lxi	h,gfns1	;print 'filename? '
	call	wcs
	call	rcs	;read response into ibuf
	lxi	h,fcb+fn  ;blank fill fn and ft fields
	mvi	c,11
;
gfn1:	mvi	m,' '
	inx	h
	dcr	c
	jnz	gfn1
	lxi	h,ibuf	;point to input buffer
	lxi	d,fcb+fn  ;scan off fn field
	mvi	c,9
;
gfn2:	mov	a,m	;fetch next char from ibuf
	inx	h
	cpi	61h	;if lc, convert to uc
	jc	gfn2a
	cpi	7bh
	jnc	gfn2a
	sui	20h
;
gfn2a:	cpi	cr	;jump if end of line
	jz	gfn5
	cpi	'.'	;jump if end of name
	jz	gfn3
	stax	d	;else store char in fn field
	inx	d
	dcr	c	;loop if 8 or less chars so far
	jnz	gfn2
	jmp	gfn6	;else take error exit
;
gfn3:	lxi	d,fcb+ft  ;scan off ft field
	mvi	c,4
;
gfn4:	mov	a,m	;fetch next char from ibuf
	inx	h
	cpi	61h	;if lc, convert to uc
	jc	gfn4a
	cpi	7bh
	jnc	gfn4a
	sui	20h
;
gfn4a:	cpi	cr	;jump if end of line
	jz	gfn5
	stax	d	;else store char in ft field
	inx	d
	dcr	c	;loop if 3 or less chars so far
	jnz	gfn4
	jmp	gfn6	;else take error exit
;
gfn5:	xra	a
	sta	fcb+ex	;set extent number to zero
	sta	fcb+nr	;set record number to zero
	stc		;clear error flag and return
	cmc
	ret
;
gfn6:	stc		;set error flag and return
	ret
;
gfnsd:	db	cr,lf,'Which drive? ',0
gfns1:	db	cr,lf,'   Filename? ',0
;
;open - open disk file
;
open:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,offc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;read - read record from disk file
;
read:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,rrfc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;close - close disk file
;
close:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,cffc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;delt - delete disk file
;
delt:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,dffc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;write - write record to disk
;
write:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,wrfc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;make - make new disk file
;
make:	push	h
	push	d
	push	b
	lxi	d,fcb
	mvi	c,mffc
	call	bdos
	pop	b
	pop	d
	pop	h
	ret
;
;citest - check console input status
;
citest:	push	b
	push	d
	push	h
citcal:	call	$-$	;modified by init.
	ora	a	;set zero flag
	pop	h
	pop	d
	pop	b
	ret		;zero flag carries answer
;
;data area
;
inch:	ds	1	;input char buffer (to cyber)
outch:	ds	1	;output char buffer (from ciber)
;
;text buffer
;
flag:	db	0	;text save flag
ptr:	dw	1	;text buffer pointer
size:	dw	1	;text buffer size
;
;printer buffer
;
lflag:	db	0	;printer flag
lbufs:	dw	1	;start pointer
lbufe:	dw	1	;end pointer
lcnt:	db	0	;character count
;
	org	256*(($+255)/256) ;page boundary
lbuf:	ds	256	;printer buffer
;
;input buffer
;
ibuf:	ds	128	;input buffer
;
;"o" before label signifies location before being
;moved above shadow memory
;
;wmc - write modem character
;
;  entry conditions
;     a - character to write
;
owmc:	ani	7fh
	di
	out	0
	sta	mport
	out	1
	ei
	ret
;
;rmc - read modem character
;
;  exit conditions:
;     a - character read
;
ormc:	di
	out	0
	lda	mport
	out	1
	ei
	ani	7fh
	ret
;
;mitest - check modem input status
;
omitest:
	di
	out	0
	lda	mstat
	out	1
	ei
	ani	01h
	ret
;
;motest - check modem output status
;
omotest:
	di
	out	0
	lda	mstat
	out	1
	ei
	ani	02h
	ret
;
otbuf:	equ	$	;start of text buffer
;
;equates reflecting locations after being moved
;above shadow memory
;
offset:	equ	4000h	;shadow memory offset
stack:	equ	offset+64 ;local stack
wmc:	equ	stack+1	;calculate addrs after move to offset
rmc:	equ	wmc+ormc-owmc
mitest:	equ	rmc+omitest-ormc
motest:	equ	mitest+omotest-omitest
tbuf:	equ	motest+otbuf-omotest
movto:	equ	tbuf
movfrm:	equ	otbuf
movsiz:	equ	tbuf-stack
;
	end
