
	page	,132
IF1
%OUT *Starting Pass 1*
ENDIF
IF2
%OUT *Starting Pass 2*
ENDIF
;	.XLIST
; KERMIT - KL10	Error-free Reciprocal Micro Interconnect over TTY-lines
; 
;	Program	Version	2.0, Kermit Protocol Version 2
;	February 1, 1983
;	UNO Version 1, October 17, 1983 
; 
;	Based on the KERMIT Protocol.
; 
;	Copyright (C) 1982,1983	Trustees of Columbia University
;
;	Daphne Tzoar
;	Columbia University Computer Center
;	612 W. 115th St.
;	New York City, NY  10025
; 
;  Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen,
;  Vace	Kundakci, and Bernie Eiben for their help and contributions.
 
;
;	Z-100 modifications made at
;
;		University of New Orleans
;		Computer Research Center
;		New Orleans La, 70148
;
;	by Anthony L. Petit.
;

	page	+

	;[uno1]	Various and sundry things.
	;[uno2]	Tell the other guy that we don't do 8-bit quoting.
	;[uno3]	Add file group handling (wildcarding).
	;[uno4] Add server-talker ability
	;[uno5] Add 8-bit quoting. Delete [uno2]
	;[uno6] No more automatic ^Z at end of files

	page +


;  This	file is	the global data	area for all the Kermit	modules.
 
 
IBMPC	EQU	0		; For IBM PC conditional assembly.
Z100	EQU	1		; For Heath/Zenith Z-100
STEVE	EQU	0		; For Steve's homebrew assembly.

; System dependent parameters

IF IBMPC
 
DEFESC	EQU	']'-100Q	; The default escape character.

MDMDAT	EQU	03F8H		; Address of modem port (data)
MDMSTS	EQU	03FDH		; Address of modem port status
MDMCOM	EQU	03FBH		; Address of modem port command

MDMINP	EQU	1		; Input ready bit

MDMINTV	EQU	0030H		; Address of modem port interrupt vector
MDMINTO	EQU	0EFH		; Mask to enable interrupt for modem port
MDMINTC	EQU	010H		; Bit to set to disable interrupts for modem
INTCONT	EQU	0021H		; Address of 8259 interrupt controller ICW2-3
INTCON1	EQU	0020H		; Address of 8259 ICW1
EOICOM	EQU	0064H		; End of interrupt

TIMER	EQU	40H		; Use to issue short beep.
PORT_B	EQU	61H		; Port B address.
B0300	EQU    180H		; Variables for 300 baud, 1200, etc.
B1200	EQU	60H
B1800	EQU	40H
B2400	EQU	30H
B4800	EQU	18H
B9600	EQU	0CH
; Interrupt types for extra system functions

BIOS	EQU	10H
COMM	EQU	14H
KEYB	EQU	16H
ENDIF

IF Z100

DEFESC	EQU	']'-100Q	; The default escape character.

; BIOS entry points

BIOS_SEG SEGMENT AT 40H		; Define segment where BIOS really is

	ORG	6*3
BIOS_AUXOUT LABEL FAR		; AUX output routine

	ORG	26*3
BIOS_AUXFUNC LABEL FAR		; AUX: function

BIOS_SEG ENDS			; End of BIOS segment defs

; Function codes for BIOS_AUXFUNC

CHR_READ	EQU	1	; Read character
CHR_STATUS	EQU	2	; Get status
  CHR_SFGS	EQU	0	; Get status subfunction
  CHR_SFGC	EQU	1	; Get config subfunction
CHR_CONTROL	EQU	3	; Control function
 CHR_CFSU	EQU	0	; Set new configuration	parameters
 CHR_CFCI	EQU	1	; Clear input buffer
 CHR_CFCO	EQU	2	; Clear output buffer


B00455	EQU	0		; 45.5 baud
B0050	EQU	1		; 50 baud
B0075	EQU	2		; 75 baud
B0110	EQU	3		; 110 baud
B01345	EQU	4		; 134.5 baud
B0150	EQU	5		; 150 baud
B0300	EQU	6		; 300 baud
B0600	EQU	7		; 600 baud
B1200	EQU	8		; 1200 baud
B1800	EQU	9		; 1800 baud
B2000	EQU	10		; 2000 baud
B2400	EQU	11		; 2400 baud
B4800	EQU	12		; 4800 baud
B9600	EQU	13		; 9600 baud
B19200	EQU	14		; 19200 baud
B38400	EQU	15		; 38400 baud
ENDIF
 
BELL	EQU	07Q
TAB	EQU	11Q
LF	EQU	12Q
FF	EQU	14Q
CR	EQU	15Q
XON	EQU	21Q
XOFF	EQU	23Q
ESC	EQU	33Q
DEL	EQU	177Q
BS	EQU	08H
 
DOS	EQU	21H

CONIN	EQU	01H
CONOUT	EQU	02H
RDRIN	EQU	03H
PUNOUT	EQU	04H
LSTOUT	EQU	05H
DCONIO	EQU	06H
GTIOB	EQU	07H
PRSTR	EQU	09H
CONSTAT	EQU	0BH
OPENF	EQU	0FH
CLOSF	EQU	10H
SFIRST	EQU	11H
SNEXT	EQU	12H
DELF	EQU	13H
READF	EQU	14H		; Read from the	file.
WRITEF	EQU	15H
MAKEF	EQU	16H
SETDMA	EQU	1AH		; Set disk transfer address
CFLSZ	EQU	23H

	page +
; These are the constants for KERMIT

 
MAXPKT	EQU	'~'-' '+2Q	; Maximum size of a packet.
MAXTRY	EQU	05Q		; Default number of retries on a packet.
IMXTRY	EQU	20Q		; Default number of retries send initiate.
DRPSIZ	EQU	5EH		; Default receive packet size.
DSPSIZ	EQU	20H		; Default send packet size.
DSTIME	EQU	08H		; Default send time out	interval.
DRTIME	EQU	05H		; Default receive time out interval.
DSPAD	EQU	00H		; Default send padding.
DRPAD	EQU	00H		; Default receive padding.
DSPADC	EQU	00H		; Default send padding char.
DRPADC	EQU	00H		; Default receive padding char.
DSEOL	EQU	CR		; Default send EOL char.
DREOL	EQU	CR		; Default receive EOL char.
DSQUOT	EQU	'#'		; Default send quote char.
DRQUOT	EQU	'#'		; Default receive quote	char.
DERQOT	EQU	'&'		; Default 8-bit receive quote character
DESQOT	EQU	'&'		; Default 8-bit send quote character
 
SOH	EQU	01H		; Start	of header char.
 
BUFSIZ	EQU	80H		; Size of DMA.
MAXFIL	EQU	50H		; Maximum number of files allowed.
 
DIASW	EQU	01H		; Default is diagnostics on.
 
CMKEY	EQU	01H		; Parse	a keyword.
CMIFI	EQU	02H		; Parse	an input file spec (can	be wild).
CMOFI	EQU	03H		; Parse	an output file spec.
CMCFM	EQU	04H		; Parse	a confirm.
CMTXT	EQU	05H		;[uno4] Get a buffer of characters


STACK	SEGMENT	PARA STACK 'STACK'
	DW	200 DUP(0)	; Initialize stack to all zeros.
STK	EQU	THIS WORD
STACK	ENDS
	page +
 
DATAS	SEGMENT	PARA PUBLIC 'DATAS'
 
	; Pure storage.
 
versio	db	'CUCCA'
IF IBMPC
	db	' IBM-PC'
ENDIF
IF Z100
	db	'/UNO Heath/Zenith Z-100'
ENDIF
	db	' Kermit-86 - ver 2.0',cr,lf,'$'
kerm	db	'Kermit-86>$'
spmes	db	'Spack:  $'
rpmes 	db	'Rpack:  $'
rptmes	db	'Rtype:  $'
hibit	db	'Warning - Non Ascii char$'
tmp	db	?
foo	db	'$'
crlf	db	cr,lf,'$'
tmsg1	db	cr,lf,'[Connecting to host,' 
	db	'type Ctrl-'
eschr	db	']'
IF Z100
	db	'-C to return to Z-100]',cr,lf,'$'
ELSE
	db	'-C to return to PC]',cr,lf,'$'
ENDIF
tmsg2	db	cr,lf,'[Back at micro]',cr,lf,'$'
ermes1	db	cr,lf,'?Unregonized command$'
ermes2	db	cr,lf,'?Illegal character$'
ermes3	db	cr,lf,'?Not confirmed$'
ermes4	db	'?Unable to rename file$'
ermes5	db	cr,lf,'?Disk full$'
ermes7	db	'?Unable to receive initiate$'
ermes8	db	'?Unable to receive file name$'
ermes9	db	'?Unable to receive end of file$'
erms10	db	'?Unable to receive data$'
erms11	db	'?Disk full$'
erms14	db	'?Unable to receive an acknowledgement from the host$'
erms15	db	'?Unable to find file$'
erms19	db	'?Record length exceeds size of buffer$'
erms20	db	'?File groups not allowed on RECEIVE$'
erms21	db	cr,lf,'?Not in Server Talker mode$'
erms22	db	'?Unable to tell the Host that the session is FINISHED$'
erms23	db	'?Unable to tell Host to LOGOUT$'
dimsg1	db	'%Bad checksum$'
dimsg2	db	'%Too many files in group. Not all will be transfered.$' ;[uno3]
infms0	db	'Waiting .....$'
infms1	db	'Receiving ...$'
infms2	db	'Sending .....$'
infms3	db	'Completed    $'
infms4	db	'Failed       $'
infms5	db	'Renaming file to $'
 
cfrmes	db	' Confirm with carriage return $'
filhlp  db	' Input file spec (possibly wild) $'
;filhlp	db	' Input file spec $'
;spchar	db	$,&,#,@,!,%,',(,),-,<,>,{,},_,\,^,~,|,`
spchar	db	24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
	db	3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
escmes	db	cr,lf,'Type the new escape character:  $'
eschlp	db	cr,lf,'Enter literal value (ex: Cntrl ])  $'
tophlp	db	cr,lf,'BYE to HOST (LOGOUT) and exit to MSDOS'	;[uno4]
	db	cr,lf,'CONNECT to host on selected port'
	db	cr,lf,'EXIT to DOS'
	db	cr,lf,'FINISH runnung KERMIT on the Host'	;[uno4]
	db	cr,lf,'HELP by giving this message'
	db	cr,lf,'LOGOUT the Host'		;[uno4]
	db	cr,lf,'RECEIVE file from host'
	db	cr,lf,'SEND file to host'
	db	cr,lf,'SET a parameter'
;	 db	 cr,lf,'SHOW the parameters'
	db	cr,lf,'STATUS of Kermit$'
sethlp	db	cr,lf,'BAUD rate'
	db	cr,lf,'DEBUG'
	db	 cr,lf,'ESCAPE character change'
	db	cr,lf,'FILE-WARNING'
	db	cr,lf,'IBM'
	db	cr,lf,'LOCAL-ECHO echoing (half-duplex)'
;	db	cr,lf,'SERVER'	;[uno4]
;	 db	 cr,lf,'RECEIVE parameter'
;	 db	 cr,lf,'SEND parameter'
IF IBMPC
	db	cr,lf,'VT52-EMULATION$'
ENDIF
IF Z100
	db	'$'
ENDIF
stshlp	db	cr,lf,'PAD-CHAR'
	db	cr,lf,'PADDING$'
onhlp	db	cr,lf,'OFF	ON$'
yeshlp	db	cr,lf,'NO	YES$'
IF IBMPC
bdhlp	db	cr,lf,'300   1200   1800   4800$'
ENDIF
IF Z100
bdhlp	db	cr,lf,'45.5	50	75	110	134.5	150	300'
	db	'	600	1200	1800'
	db	cr,lf,'	2000	2400	4800	9600	19200	38400$'
ENDIF
inthlp	db	cr,lf,'?  This message'
	db	cr,lf,'C  Close the connection'
	db	cr,lf,'S  Status of the connection'
	db	cr,lf,'Typing the escape character will send it to the host'
	db	cr,lf,cr,lf,'Command>$'
locst	db	cr,lf,'Local echo on$'
remst	db	cr,lf,'Local echo off$'
IF IBMPC
vtemst	db	cr,lf,'VT52 emulation on$'
novtst	db	cr,lf,'VT52 emulation off$'
ENDIF
ibmst	db	cr,lf,'IBM on$'
noibm	db	cr,lf,'IBM off$'
IF Z100
b04st	db	cr,lf,'Baud rate is 45.5$'
b05st	db	cr,lf,'Baud rate is 50$'
b07st	db	cr,lf,'Baud rate is 75$'
b11st	db	cr,lf,'Baud rate is 110$'
b13st	db	cr,lf,'Baud rate is 134.5$'
b15st	db	cr,lf,'Baud rate is 150$'
ENDIF
b03st	db	cr,lf,'Baud rate is 300$'
IF Z100
b06st	db	cr,lf,'Baud rate is 600$'
ENDIF
b12st	db	cr,lf,'Baud rate is 1200$'
b18st	db	cr,lf,'Baud rate is 1800$'
IF Z100
b20st	db	cr,lf,'Baud rate is 2000$'
ENDIF
b24st	db	cr,lf,'Baud rate is 2400$'
b48st	db	cr,lf,'Baud rate is 4800$'
b96st	db	cr,lf,'Baud rate is 9600$'
IF Z100
b19st	db	cr,lf,'Baud rate is 19200$'
b38st	db	cr,lf,'Baud rate is 38400$'
ENDIF
debon	db	cr,lf,'Debug mode on$'
deboff	db	cr,lf,'Debug mode off$'
flwon	db	cr,lf,'File Warning on$'
flwoff	db	cr,lf,'File Warning off$'
srvon	db	cr,lf,'Server mode is on$'	;[uno4]
srvoff	db	cr,lf,'Server mode is off$'	;[uno4]
escsta	db	cr,lf,'Escape character is Ctrl-$' ;[uno1]
 
 
outlin	db	cr,lf,'	    CUCCA'
IF IBMPC
	db	' IBM-PC'
ENDIF
IF Z100
	db	'/UNO Heath/Zenith Z-100'
ENDIF
	db	' Kermit-86 V2.0',
	db	cr,lf
	db	cr,lf,'Number of packets         (hex)'
	db	cr,lf,'Number of retries         (hex)',lf
outln1	db	cr,'File name $'

	page
; Cursor addressing items

delstr	db	10O,' ',10O,'$'    	; Delete string.
clrspc	db	' ',10O,'$'		; Clear	space.
escspc	db	10O,' ',10O,'$'		; Clear escape.
IF IBMPC
clrlin	db	cr,'$'			; Clear line (just the	cr part).
ENDIF
IF Z100
clrlin	db	cr,esc,'K$'		; Clear line on Z-100
clrscr	db	esc,'H',esc,'J$'	; Home and clear screen
homcur	db	esc,'H$'		; Home cursor
ENDIF
prsp	db	' $'			; Print a space.


IF IBMPC
scrhi	dw	0434H			; Err when 8th	bit is on.
scrrpr	dw	0700H			; Prompt when	Kermit ends.
screrr	dw	0600H 		       ; Place for error msgs. 
scrfln	dw	050CH			; Place	for file name.
scrnrt	dw	0415H	 	       ; Place for number of retries.
scrnp	dw	0315H 			; Place	for number of packets.
scrfr	dw	0600H			; Rename file.
scrst	dw	0334H			; Place for status.
scrsp	dw	0800H			; Place for send packet.
scrrp	dw	0A00H			; Place for receive packet.
ttab	label	word			; Table for cursor movement.
ta	dw	curup			; Cursor up.
tb	dw	curdwn			; Cursor down.
tc	dw	currt  			; Cursor right.
td	dw	curlft			; Cursor left.
te	dw	curskp			; Clear display.
tf	dw	curskp			; Enter graphics mode.
tg	dw	curskp			; Exit graphics mode.
th	dw	curhm			; Cursor home.
ti	dw	curup			; Reverse line feed.
tj	dw	curscr			; Clear to end of screen.
tk	dw	curln			; Clear to end of line.
tl	dw	inslin			; Insert line.
tm	dw	dellin			; Delete line.	
ENDIF

IF Z100
scrhi	db	esc,'Y',23H,54H,lf,'$'	; 8th bit on in	character
scrrpr	db	esc,'Y',27H,20H,'$'	; Prompt when Kermit ends
screrr	db	esc,'Y',26H,20H,'$'	; Error messages
scrfln	db	esc,'Y',25H,2CH,'$'	; File name
scrnrt	db	esc,'Y',23H,35H,lf,'$'	; Number of retries
scrnp	db	esc,'Y',23H,35H,'$'	; Number of packets
scrfr	db	esc,'Y',26H,20H,'$'	; Rename file
scrst	db	esc,'Y',23H,54H,'$'	; Status
scrsp	db	esc,'Y',2FH,20H,'$'	; send packet
scrsp1	db	esc,'Y',30H,29H,'$'	;  The rest of the send packet
scrrp	db	esc,'Y',31H,20H,'$'	; Receive packet
scrrp1	db	esc,'Y',32H,29H,'$'	;  The rest of the receive packet
scrrpt	db	esc,'Y',33H,20H,'$'	; The receive packet type
ENDIF
 
	page
	; COMND	tables

comtab	db	10		; Ten entries.
	db	03H,'BYE$'	;[uno4]
	dw	bye		;[uno4]
	db	07H,'CONNECT$'
	dw	telnet
	db	04H,'EXIT$'
	dw	exit
	db	06H,'FINISH$'	;[uno4]
	dw	finish		;[uno4]
	db	04H,'HELP$'
	dw	help
	db	06H,'LOGOUT$'	;[uno4]
	dw	logout		;[uno4]
	db	07H,'RECEIVE$'
	dw	read
	db	04H,'SEND$'
	dw	send
	db	03H,'SET$'
	dw	setcom
	db	06H,'STATUS$'
	dw	status

 
IF IBMPC
settab	db	08H		; eight	entries.
ENDIF
IF Z100
settab	db	07H		; Only seven entries for Z-100
ENDIF
	db	04H,'BAUD$'
	dw	baudst
	db	05H,'DEBUG$'
	dw	debst
	db	06H,'ESCAPE$'
	dw	escape
	db	0CH,'FILE-WARNING$'
	dw	filwar
	db	03H,'IBM$'
	dw	ibmset
	db	0AH,'LOCAL-ECHO$'
	dw	lcal
;	db	06H,'SERVER$'	;[uno4]
;	dw	setsrv		;[uno4]
IF IBMPC
	db	cr,lf,'VT52-EMULATION$'
ENDIF
IF Z100
	db	'$'
ENDIF
IF IBMPC
	dw	vt52em
ENDIF
 
ontab	db	02H		; Two entries.
	db	02H,'ON$'
	dw	01H
	db	03H,'OFF$'
	dw	00H
 
yestab	db	02H		; Two entries.
	db	02H,'NO$'
	dw	00H
	db	03H,'YES$'
	dw	01H

IF IBMPC
bdtab	db	06H		;	Six entries.
	db	04H,'1200$'
	dw	B1200
	db	04H,'1800$'
	dw	B1800
	db	04H,'2400$'
	dw	B2400
	db	03H,'300$'
	dw	B0300
	db	04H,'4800$'
	dw	B4800
	db	04H,'9600$'
	dw	B9600
ENDIF
IF Z100
bdtab	db	010H		; 16 entries
	db	03H,'110$'
	dw	b0110
	db	04H,'1200$'
	dw	b1200
	db	05H,'134.5$'
	dw	b01345
	db	03H,'150$'
	dw	b0150
	db	04H,'1800$'
	dw	b1800
	db	05H,'19200$'
	dw	b19200
	db	04H,'2000$'
	dw	b2000
	db	04H,'2400$'
	dw	b2400
	db	03H,'300$'
	dw	b0300
	db	05H,'38400$'
	dw	b38400
	db	04H,'45.5$'
	dw	b00455
	db	04H,'4800$'
	dw	b4800
	db	02H,'50$'
	dw	b0050
	db	03H,'600$'
	dw	b0600
	db	02H,'75$'
	dw	b0075
	db	04H,'9600$'
	dw	b9600
ENDIF
	page
 
; COMND	storage
 
cmer00	db	cr,lf,'?Program error	Invalid COMND call$'
cmer01	db	cr,lf,'?Ambiguous$'
cmer02	db	cr,lf,'?Illegal input file spec$'
cmer03	db	cr,lf,'?Unrecognized instruction$'
cmin00	db	' Confirm with carriage return$'
cmcrlf	db	cr,lf,'$'
 
cmstat	db	?		; What is presently being parsed.
cmaflg	db	?		; Non-zero when	an action char has been	found.
cmccnt	db	?		; Non-zero if a	significant char is found.
cmsflg	db	?		; Non-zero when	the last char was a space.
cmostp	dw	?		; Old stack pointer for	reparse.
cmrprs	dw	?		; Address to go	to on reparse.
cmprmp	dw	?		; Address of prompt.
cmptab	dw	?		; Address of present keyword table.
cmhlp	dw	?		; Address of present help.
cmdbuf	db	80H DUP(?)	; Buffer for command parsing.
cmfcb	dw	?		; Pointer to FCB.
cmfcb2	dw	?		; Pointer to position in FCB.
cmcptr	dw	?		; Pointer for next char	input.
cmdptr	dw	?		; Pointer into the command buffer.
cmsiz	dw	?		; Size info of user input.
cmkptr	dw	?		; Pointer to keyword.
cmsptr	dw	?		; Place	to save	a pointer.
cmchr	db	?		; Save char when checking ambiguity.
 
	page
; Program storage.
 
oldstk	dw	?		; Storage for system stack.
oldsts	dw	?		; System stack segment.
ssp	dw	0		; Save SP in Telnet.
bufhex	dw	80H
filsiz	dd	0		; Double word for filesize	(in bytes.)
eoflag	db	?		; EOF flag; non-zero on	EOF.
debug	db	0		; Debugging mode (default off).
hierr	db	0		; Non-ascii char (non-zero if yes).
filflg	db	?		; Non-zero when	nothing	in DMA buffer.
ecoflg	db	0		; Local	echo flag (default off).
escflg	db	0		; Escape flag (start off).
IF IBMPC
vtflg	db	1		; VT52 emulation flag (default on).
ENDIF
flwflg	db	0		; File warning flag (default off).
ibmflg	db	0		; IBM flag (default off).
srvflg	db	1		;[uno4] Server mode flag
ufname	db	0		;[uno4] Length of the user given file naeme
extflg	db	0		; Exit flag (default off).
escchr	db	defesc		; Storage for the escape character.
incnt	dw	?		; Number of chars read in from port.
chrcnt	dw	?		; Number of chars in the file buffer.
filcnt	dw	?		; Number of chars left to fill.
outpnt	dw	?		; Position in packet.
bufpnt	dw	?		; Position in file buffer.
fcbptr	dw	?		; Position in FCB.
datptr	dw	?		; Position in packet data buffer.
cbfptr	dw	?		; Position in character	buffer.
pktptr	dw	?		; Poistion in receive packet.
siz	dw	?		; Size of data from gtchr.
IF IBMPC
baud	db	B4800		; Use default of 4800.
ENDIF
IF Z100
auxcnf	db	4 dup(?)	; AUX port configuration info
baud	db	?		; Baud rate
auxcnf1	db	12 dup(?)	; Rest of configuration info
ENDIF
spsiz	db	dspsiz		; Send packet size.
rpsiz	db	drpsiz		; Receive packet size.
stime	db	dstime		; Send time out.
rtime	db	drtime		; Receive time out.
spad	db	dspad		; Send padding.
rpad	db	drpad		; Receive padding.
spadch	db	dspadc		; Send padding char.
rpadch	db	drpadc		; Receive padding char.
seol	db	dseol		; Send EOL char.
reol	db	dreol		; Receive EOL char.
squote	db	dsquot		; Send quote char.
rquote	db	drquot		; Receive quote	char.
pktnum	dw	?		; Packet number.
erqote	db	derqot		;[uno5] 8-bit receive quote char.
esqote	db	desqot		;[uno5] 8-bit send quote char.
ebitflg	db	0		;[uno5] 8-bit flag
numpkt	dw	?		; Total	number of packets sent.
numrtr	dw	?		; Total	number of retries.
numtry	db	?		; Number of tries on this packet.
oldtry	db	?		; Number of tries on previous packet.
state	db	?		; Present state	of the automaton.
packet	db	?,?,?,?		; Packet (data is part of it).
data	db	5AH DUP(?)	; Data and checksum field of packet.
recpkt	db	60H DUP(?)	; Receive packet storage (use the following).
filbuf	db	60H DUP(?)	; Character buffer.
fcb	db	25H DUP(?)	; Use as our FCB.
buff	db	80H DUP(?)	; Use as our DAT.
rdbuf	db	80H DUP(?)
fcblist	db	(maxfil+1)*13 DUP(?) ;[uno3] File name storage
cnt	dw	0
temp	dw	0
temp1	dw	?		; Temporary storage.
temp2	dw	?
temp3	dw	?
temp4	dw	?
argblk	dw	?		; For subroutine arguments.
argbk1	dw	?
argbk2	dw	?
argbk3	dw	?
fcbnum	dw	?		; Number of FCB's left in the list.
 
DATAS	ENDS			; End data segment
 
	page +
MAIN	SEGMENT	PARA PUBLIC 'MAIN'
START	PROC  FAR
	ASSUME	CS:MAIN,DS:DATAS,SS:STACK,ES:DATAS
 
	push ds			; Save system data area.
	sub ax,ax		; Get a	zero.
	push ax			; Put zero return addr on stack.

	mov ax,datas		; Initialize DS.
	mov ds,ax
	sub ax,ax

	mov oldstk,sp		; Save old stack pointer.
;	 mov ax,ss
;	 mov oldsts,ax


;	 mov ax,stack		 ; Initialize SS.
;	 mov ss,ax
;	 mov sp,offset ss:stk
;	 sub ax,ax

	call cmblnk		; Clear	the screen.
	call locate

	mov ah,prstr		; Print	the version header.
	mov dx,offset versio
	int dos

	mov ah,setdma		; Set disk transfer address.
	mov dx,offset buff
	int dos

IF IBMPC
	mov dx,mdmcom		; LCR -- Initialize baud rate.
	in al,dx
	mov bl,al
	or ax,80H
	out dx,al
	mov dx,mdmdat
	mov ax,baud
	out dx,al
	inc dx
	mov al,ah
	out dx,al
	mov dx,mdmcom
	mov al,bl
	out dx,al
ENDIF

IF Z100
	mov bx,ds		; Set up pointer to	config info
	mov es,bx		;  .  .  .
	mov bx,offset auxcnf	;	 .  .  .
	mov ah,chr_status	; Get the function code
	mov al,chr_sfgc		; And	the subfunction	to get config
	call bios_auxfunc	; Get the block
	mov bx,ds		;[uno1]	Set up pointer to config info
	mov es,bx		;[uno1]	...
	mov bx,offset auxcnf	;[uno1]	...
	mov ah,chr_control	;[uno1]	Get the control function
	mov al,chr_cfci		;[uno1]	 and the clear input que subfunction
	call bios_auxfunc	;[uno1]	Clear the input queue
	mov bx,ds		;[uno1]	Once more ...
	mov es,bx		;[uno1]	...
	mov bx,offset auxcnf	;[uno1]	...
	mov ah,chr_control	;[uno1]	...
	mov al,chr_cfco		;[uno1]	 and the clear output queue subfunction
	call bios_auxfunc	;[uno1]	Clear the output queue
ENDIF



; This is the main KERMIT loop.	 It prompts for	and gets the users commands.

kermit:	mov dx,offset kerm
	call prompt		; Prompt the user.
	mov dx,offset comtab
	mov bx,offset tophlp
	mov ah,cmkey
	call comnd
	 jmp kermt2
	call bx			; Call the routine returned.
	 jmp kermt3
	cmp extflg,0		;  Check if the	exit flag is set.
	jne done		; if so jump to DONE
	jmp kermit		; Do it	again.
 
kermt2:	mov ah,prstr
	mov dx,offset ermes1	;  Give	an error.
	int dos
	jmp kermit

kermt3:	mov ah,prstr
	mov dx,offset ermes3	;  Give	an error.
	int dos
	jmp kermit
 
done:	
; 	 mov	ax,oldsts	    ; Restore the old stack.
;	 mov ss,ax
	mov sp,oldstk
	ret
 
START	ENDP
 
	page +
; These	are some utility routines.
 
;	Abort
 
ABORT	PROC	NEAR
	mov state,'A'		; Otherwise abort.
	ret
ABORT	ENDP
 
;	NAK
 
NAK	PROC	NEAR
	mov ax,pktnum		; Get the packet number	we're waiting for.
	mov argblk,ax
	mov argbk1,0
	mov ah,'N'		; NAK that packet.
	call spack
	ret			; Go around again.
NAK	ENDP

; Position cursor for an error message.

ERPOS	PROC 	NEAR
IF IBMPC
	mov ah,2
	mov bh,0
	mov dx,screrr
	int bios
	ret
ENDIF

IF Z100
	mov dx,offset screrr	;	Get address of string to position cursor
	mov ah,prstr		; Get the function code
	int dos			; Print the addressing string
	ret			; And return
ENDIF
ERPOS	ENDP

; Position cursor for number of	retries	message.

RTPOS	PROC 	NEAR
IF IBMPC
	mov ah,2
	mov bh,0
	mov dx,scrnrt
	int bios
	ret
ENDIF

IF Z100
	mov ah,prstr		; Get the function to print string
	mov dx,offset scrnrt	;	Get the	address	of the string
	int dos			; Print the string
	ret			; And return
ENDIF
RTPOS	ENDP

; Print	err message that found a non-standard-Ascii char in the	file.

BITERR	PROC	NEAR
	push bx
IF IBMPC
	mov ah,2
	mov bh,0
	mov dx,scrhi
	int bios
ENDIF

IF Z100
	mov ah,prstr		; Get the function to print string
	mov dx,offset scrhi	; Get the address of the string
	int dos			; Print the string
ENDIF
	mov ah,prstr
	mov dx,offset hibit
	int dos
	pop bx
	ret
BITERR	ENDP		
 
;	This routine sets up the data for init packet (either the
;	Send_init or ACK packet).
 
RPAR	PROC	NEAR
	mov ah,rpsiz		; Get the receive packet size.
	add ah,' '		; Add a	space to make it printable.
	mov [bx],ah		; Put it in the	packet.
	mov ah,rtime		; Get the receive packet time out.
	add ah,' '		; Add a	space.
	mov 1[bx],ah		; Put it in the	packet.
	mov ah,rpad		; Get the number of padding chars.
	add ah,' '
	mov 2[bx],ah		; Put it in the	packet.
	mov ah,rpadch		; Get the padding char.
	add ah,100O		; Uncontrol it.
	and ah,7FH
	mov 3[bx],ah		; Put it in the	packet.
	mov ah,reol		; Get the EOL char.
	add ah,' '
	mov 4[bx],ah		; Put it in the	packet.
	mov ah,rquote		; Get the quote	char.
	mov 5[bx],ah		; Put it in the	packet.
	mov ah,derqot		;[uno5] Get the eight bit quote char
	cmp state,'R'		;[uno5] Use it?
	jne rpar1		;[uno5] Yes
	mov ah,'Y'		;[uno5] In receive init, agree
rpar1:	mov 6[bx],ah		;[uno5]
	mov ah,07H		; Seven pieces of data.
	ret
RPAR	ENDP
 
;	This routine reads in all the send_init	packet information.
 
SPAR	PROC	NEAR
	mov temp4,ax		; Save the number of arguments.
	mov ah,[bx]		; Get the max packet size.
	sub ah,' '		; Subtract a space.
	mov spsiz,ah		; Save it.
	mov ax,temp4
	cmp al,3		; Fewer	than three pieces?
	jge spar1
	ret			; If so	we are done.
spar1:	mov ah,2[bx]		; Get the number of padding chars.
	sub ah,' '
	mov spad,ah
	mov ax,temp4
	cmp al,4		; Fewer	than four pieces?
	jge spar2
	ret			; If so	we are done.
spar2:	mov ah,3[bx]		; Get the padding char.
	add ah,100O		; Re-controlify	it.
	and ah,7FH
	mov spadch,ah
	mov ax,temp4
	cmp al,5		; Fewer	than five pieces?
	jge spar3
	ret			; If so	we are done.
spar3:	mov ah,4[bx]		; Get the EOL char.
	sub ah,' '
	mov seol,ah
	mov ax,temp4
	cmp al,6		; Fewer	than six pieces?
	jge spar4
	ret			; If so	we are done.
spar4:	mov ah,5[bx]		; Get the quote	char.
	mov squote,ah
	mov ax,temp4		;[uno5] Fewer than seven peices
	cmp al,7		;[uno5]
	jge spar5		;[uno5]
	ret			;[uno5] If so, we are done
spar5:	mov ah,6[bx]		;[uno5] Get the 8-bit quote char.
	cmp ah,'Y'		;[uno5] Does the other agree with us?
	jne spar7		;[uno5] No, see if he disagrees
	mov ah,derqot		;[uno5] Yes, use the default
spar6:	mov erqote,ah		;[uno5]
	ret
spar7:	cmp ah,'N'		;[uno5] Does he not do 8 bit quoting?
	jne spar6		;[uno5] He does with this char
	mov esqote,ah		;[uno5] We won't either then
	jmp spar6		;[uno6]
SPAR	ENDP
 
 
;	Initialize buffers and clear line.
 
INIT	PROC	NEAR
	call cmblnk
	call locate
	mov ah,prstr		; Put statistics headers on the	screen.
	mov dx,offset outlin
	int dos
	call init1
	ret
INIT	ENDP
 
INIT1	PROC	NEAR
	mov chrcnt,bufsiz	;* Number of chars left.
	mov bufpnt,offset buff	       ; Addr for beginning.
	ret
INIT1	ENDP

;  Clear out the old filename on the screen. 

CLRFLN	PROC	NEAR
IF IBMPC
	mov ah,2
	mov bh,0
	mov dx,scrfln
	int bios
	mov ax,0920H			; Clear	out the	old filename.
	mov bx,7
	mov cx,12
	int bios
ENDIF
IF Z100
	mov ah,prstr
	mov dx,offset scrfln
	int dos
	mov ah,prstr		;[uno3]	Clear the file name line
	mov dx,offset clrlin	;[uno3]
	int dos			;[uno3]
	mov ah,prstr		;[uno3]	Locate at the file name again
	mov ah,prstr		;[uno3]	Print "File name"
	mov dx,offset outln1	;[uno3]
	int dos			;[uno3]
	mov dx,offset scrfln	;[uno3]
	int dos			;[uno3]
ENDIF
	ret
CLRFLN	ENDP

	page +
;	RECEIVE	command
 
READ	PROC	NEAR
	mov ah,cmtxt		;[uno4] Get some text that may be a file
	mov bx,offset data	;[uno4] name into the data buffer
	call comnd		;[uno4]
IFE 1				;[uno4]
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r
ENDIF				;[uno4]
	mov ufname,0		;[uno4] No user file name given yet.
	cmp al,0		;[uno4] Was a file name given?
	je read05		;[uno4] No, just go on with normal life
	cmp srvflg,0		;[uno4] Are we in Server mode?
	jne read03		;[uno4] Yes.  Go send the file name
	mov bx,ds		;[uno4] Save the file name we wish
	mov es,bx		;[uno4] to receive the incoming file
	mov bx,offset data	;[uno4] under.
	mov si,bx		;[uno4] Move the file name with a MOVS
	mov bx,offset fcblist	;[uno4] into the file name holding area.
	mov di,bx		;[uno4]
	mov cl,al		;[uno4] The length of the file name
	cld			;[uno4] Insure the direction of the move
read00:	cmp BYTE PTR [si],'*'	;[uno4] One of the wild card characters?
	jne read02		;[uno4] Not this one, so try the other
read01:	call erpos		;[uno4] Tell the user that we can't receive
	mov ah,prstr		;[uno4] a file with a file group for a 
	mov dx,offset erms20	;[uno4] file name
	int dos			;[uno4]
	jmp r			;[uno4] return in error
read02:	cmp BYTE PTR [si],'?'	;[uno4] Is it the other file group character
	je read01		;[uno4] Yes, go complain
	movs fcblist,data	;[uno4] Save the character
	dec cl			;[uno4] Done?
	jne read00		;[uno4] Nope, do it again
	mov ufname,al		;[uno4] Say we have a user specified file
				;[uno4] name, and how long it is
	jmp read05		;[uno4] On with the show

read03:	sub ah,ah		;[uno4]
	mov argbk1,ax		;[uno4] Set up the number of bytes to send
	call init		;[uno4]
	mov argblk,0		;[uno4] Set no packets sent 
	mov numpkt,0		;[uno4] More initialization
	mov pktnum,0		;[uno4]
	mov numrtr,0		;[uno4] dot dot dot
	mov numtry,0		;[uno4]
	call rtpos		;[uno4]
	mov ax,numrtr		;[uno4] Display the number of retrys
	call nout		;[uno4]
	mov ah,'R'		;[uno4] Send the packet
	call spack		;[uno4]
	jmp read1		;[uno4] Join the main line
read05:
	call init		; Clear	the line and initialize	the buffers.
	mov numpkt,0		; Set the number of packets to zero.
	mov numrtr,0		; Set the number of retries to zero.
	mov pktnum,0		; Set the packet number	to zero.
	mov numtry,0		; Set the number of tries to zero.
read1:	call rtpos		; Position cursor.
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov state,'R'		; Set the state	to receive initiate.
read2:
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrst
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov ah,prstr		 ; Be informative.
	mov dx,offset infms1
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrnp
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrnp	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov ax,numpkt
	call nout		; Write	the number of packets.
	mov ah,state		; Get the state.
	cmp ah,'D'		; Are we in the	data send state?
	jne read3
	call rdata
	jmp read2
read3:	cmp ah,'F'		; Are we in the	file receive state?
	jne read4
	call rfile		; Call receive file.
	jmp read2
read4:	cmp ah,'R'		; Are we in the	receive	initiate state?
	jne read5
	call rinit
	jmp read2
read5:	cmp ah,'C'		; Are we in the	receive	complete state?
	jne read6
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrst
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov dx,offset infms3	; Plus a little	cuteness.
	mov ah,prstr
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrrpr		; Put prompt here.
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrrpr	;	and string to move cursor
	int dos			; Print the string
ENDIF
	jmp rskp
read6:
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrst
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov dx,offset infms4	 ; Plus	a little cuteness.
	mov ah,prstr
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrrpr
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrrpr	;  and string to move cursor
	int dos			; Print the string
ENDIF
	jmp rskp
READ	ENDP
 
 
	page
;	Receive	routines
 
;	Receive	init
 
RINIT	PROC	NEAR
	mov ah,numtry		; Get the number of tries.
	cmp ah,imxtry		; Have we reached the maximum number of	tries?
	jl rinit2
	call erpos		; Position cursor.
	mov dx,offset ermes7
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rinit2:	inc ah			; Increment it.
	mov numtry,ah		; Save the updated number of tries.
	call rpack		; Get a	packet.
	 jmp nak		;  Trashed packet: nak,	retry.
	cmp ah,'S'		; Is it	a send initiate	packet?
	jne rinit3		; If not see if	its an error.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov ax,argblk		; Returned packet number.  (Synchronize	them.)
	inc ax			; Increment it.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	mov bx,numpkt
	inc bx			; Increment the	number of packets.
	mov numpkt,bx
	mov ax,argbk1		; Get the number of arguments received.
	mov bx,offset data	; Get a	pointer	to the data.
	call spar		; Get the data into the	proper variables.
	mov bx,offset data	; Get a	pointer	to our data block.
	call rpar		; Set up the receive parameters.
	xchg ah,al
	mov ah,0
	mov argbk1,ax		; Store	the returned number of arguments.
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	mov ah,'F'		; Set the state	to file	send.
	mov state,ah
	ret
rinit3:	cmp ah,'E'		; Is it	an error packet?
	jne rinit4
	call error
rinit4:	jmp abort
RINIT	ENDP
 

	page
;	Receive	file
 
RFILE	PROC	NEAR
	cmp numtry,maxtry	; Have we reached the maximum number of	tries?
	jl rfile1
	call erpos		; Position cursor.
	mov dx,offset ermes8
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rfile1:	inc numtry		; Save the updated number of tries.
	call rpack		; Get a	packet.
	 jmp nak		;  Trashed packet: nak,	retry.
	cmp ah,'S'		; Is it	a send initiate	packet?
	jne rfile2		;  No, try next	type.
	cmp oldtry,imxtry	; Have we reached the maximum number of	tries?
	jl rfil12		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes7
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rfil12:	inc oldtry		; Save the updated number of tries.
	mov ax,pktnum		; Get the present packet number.
	dec ax			; Decrement.
	cmp ax,argblk		; Is the packet's number one less than now?
	je rfil13
	jmp nak			; No, NAK and try again.
rfil13:	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries.
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov numtry,0		; Reset	the number of tries.
	mov bx,offset data	; Get a	pointer	to our data block.
	call rpar		; Set up the parameter information.
	xchg ah,al
	mov ah,0
	mov argbk1,ax		; Save the number of arguments.
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	ret
rfile2:	cmp ah,'Z'		; Is it	an EOF packet?
	jne rfile3		;  No, try next	type.
	cmp oldtry,maxtry	; Have we reached the maximum number of	tries?
	jl rfil21		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes9
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rfil21:	inc oldtry		; Increment it.
	mov ax,pktnum		; Get the present packet number.
	dec ax			; Decrement.
	cmp ax,argblk		; Is the packet's number one less than now?
	je rfil24
	jmp nak			; No, NAK and try again.
rfil24:	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov numtry,0
	mov argbk1,0		; No data.  (The packet	number is in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	ret
rfile3:	cmp ah,'F'		; Start	of file?
	jne rfile4
	mov ax,argblk		; Get the packet number.
	cmp ax,pktnum		; Is it	the right packet number?
	je rfil32
	jmp nak			; No, NAK it and try again.
rfil32:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	call gofil		; Get a	file to	write to.
	 jmp abort
	call init1		; Initialize all the buffers.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov argbk1,0		; No data.  (The packet	number is in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	mov state,'D'		; Set the state	to data	receive.
	ret
rfile4:	cmp ah,'B'		; End of transmission.
	jne rfile5
	mov ax,pktnum
	cmp ax,argblk		; Do we	match?
	je rfil41
	jmp nak			; No, NAK it and try again.
rfil41:	mov argbk1,0		; No data.  (Packet number already in argblk).
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	mov state,'C'		; Set the state	to complete.
	ret
rfile5:	cmp ah,'E'		; Is it	an error packet.
	jne rfile6
	call error
rfile6:	jmp abort
RFILE	ENDP
 
 
	page
;	Receive	data
 
RDATA	PROC	NEAR
	cmp numtry,maxtry	; Get the number of tries.
	jl rdata1
	call erpos		; Position cursor.
	mov dx,offset erms10
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rdata1:	inc numtry		; Save the updated number of tries.
	call rpack		; Get a	packet.
	 jmp nak		;  Trashed packet: nak,	retry.
	cmp ah,'D'		; Is it	a data packet?
	jne rdata2		;  No, try next	type.
rdat11:	mov ax,pktnum		; Get the present packet number.
	cmp ax,argblk		; Is the packet's number correct?
	jz rdat14
	cmp oldtry,maxtry	; Have we reached the maximum number of	tries?
	jl rdat12		; If not proceed.
	call erpos		 ; Position cursor.
	mov dx,offset erms10
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rdat12:	inc oldtry		; Save the updated number of tries.
	mov ax,pktnum		;[uno1]	Get the current packet number
	dec ax			;[uno1]	 and decrement it
	cmp ax,argblk		; Is the packet's number one less than now?
	je rdat13
	jmp nak			; No, NAK it and try again.
rdat13:	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov numtry,0		; Reset	number of tries.
	mov argbk1,0		; No data.  (The packet	number is in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	ret
rdat14:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov ax,argbk1		; Get the length of the	data.
	call ptchr
	 jmp abort		;  Unable to write out chars; abort.
	mov numtry,0		; Reset	the number of tries.
	mov argbk1,0		; No data.  (Packet number still in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	ret
rdata2:	cmp ah,'F'		; Start	of file?
	jne rdata3		;  No, try next	type.
	cmp oldtry,maxtry	; Have we reached the maximum number of	tries?
	jl rdat21		; If not proceed.
	call erpos		; Position cursor.
	mov dx,offset ermes8
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
rdat21:	inc oldtry		; Save the updated number of tries.
	mov ax,pktnum
	cmp ax,argblk		; Is the packet's number one less than now?
	je rdat22
	jmp nak			; No, NAK it and try again.
rdat22:	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov numtry,0		; Reset	number of tries.
	mov argbk1,0		; No data.  (The packet	number is in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	ret
rdata3:	cmp ah,'Z'		; Is it	a EOF packet?
	jne rdata4		; Try and see if its an	error.
	mov ax,pktnum		; Get the present packet number.
	cmp ax,argblk		; Is the packet's number correct?
	je rdat32
	jmp nak			; No, NAK it and try again.
rdat32:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt
rdat33:	mov bx,bufpnt		; Get the dma pointer.
	mov ax,80H
	sub ax,chrcnt		; Get the number of chars left in the DMA.
;[uno6]	mov cl,'Z'-100O		; Put in a ^Z for EOF.
;[uno6]	mov [bx],cl
;[uno6]	inc ax
;[uno6]	dec chrcnt
	mov cx,chrcnt
	mov temp,cx
;[uno6]	inc bx
rdt3:	inc ax
	cmp ax,80H
	jg rdat35		; Pad till full.
	mov cl,0		; Use nulls.
	mov [bx],cl
	inc bx
	jmp rdt3
rdat35:	call outbuf		; Output the last buffer.
	 jmp abort		;  Give	up if the disk is full.
	call fixfcb
	mov ah,closf		; Close	up the file.
	mov dx,offset fcb
	int dos
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov argbk1,0		; No data.  (The packet	number is in argblk.)
	mov ah,'Y'		; Acknowledge packet.
	call spack		; Send the packet.
	mov state,'F'
	ret
rdata4:	cmp ah,'E'		; Is it	an error packet.
	je rdata5
	call error
rdata5:	jmp abort
RDATA	ENDP

	page
FIXFCB	PROC	NEAR	
	mov bx,offset fcb+18
	mov di,offset filsiz
	mov ax,[bx]
	mov [di],ax
	mov bx,offset fcb+16
	mov ax,[bx]
	mov 2[di],ax
	mov ax,temp		; Get number of chars in last buffer full.
	sub filsiz+2,ax		; Get real file size.
	sbb filsiz,0
	mov bx,offset fcb+18
	mov di,offset filsiz
	mov ax,[di]
	mov [bx],ax
	mov bx,offset fcb+16
	mov ax,2[di]
	mov [bx],ax
	ret
FIXFCB	ENDP
 

	page +
;	Send command
 
SEND	PROC	NEAR
	mov ah,cmifi		; Parse	an input file spec.
	mov dx,offset fcb	; Give the address for the FCB.
	call comnd
	 jmp r			;  Give	up on bad parse.
send1:	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r			;  Didn't get a	confirm.
IFE 1				;[uno3]
send11:	mov fcbnum,0		; Zero the fcb list number.
	mov ah,sfirst		; Get the first	file.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Any found?
	jne send12
	mov ah,prstr
	mov dx,offset crlf
	int dos
	mov ah,prstr
	mov dx,offset erms15
	int dos
	ret
ENDIF				;[uno3]
	call find_files		;[uno3]	Get all of the files in the group
	 jmp r			;[uno3]	If none, exit
	call gtnfil		;[uno3]	Get a file name into the fcb
	 jmp r			;[uno3]	If none, exit. This should never happen
;* This	must all be redone for MS-DOS.	Hopefully wild card file stepping
;* in MS-DOS works.  If	so most	of the following is unnecessary.
send12:	
;*
	call init		; Clear	the line and initialize	the buffers.
	mov pktnum,0		; Set the packet number	to zero.
	mov numtry,0		; Set the number of tries to zero.
	mov numpkt,0		; Set the number of packets to zero.
	mov numrtr,0		; Set the number of retries to zero.
	call rtpos		; Position cursor.
	mov ax,0
	call nout		; Write	the number of retries.
	mov state,'S'		; Set the state	to receive initiate.
send2:
IF IBMPC
	mov ah,2		 ; Position cursor.
	mov bh,0
	mov dx,scrst
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	;  and string to move cursor
	int dos			; Print the string
ENDIF
	mov ah,prstr		; Be informative.
	mov dx,offset infms2
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrnp
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrnp	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov ax,numpkt
	call nout		; Write	the packet number.
	cmp state,'D'		; Are we in the	data send state?
	jne send3
	call sdata
	jmp send2
send3:	cmp state,'F'		; Are we in the	file send state?
	jne send4
	call sfile		; Call send file.
	jmp send2
send4:	cmp state,'Z'		; Are we in the	EOF state?
	jne send5
	call seof
	jmp send2
send5:	cmp state,'S'		; Are we in the	send initiate state?
	jne send6
	call sinit
	jmp send2
send6:	cmp state,'B'		; Are we in the	eot state?
	jne send7
	call seot
	jmp send2
send7:	cmp state,'C'		; Are we in the	send complete state?
	jne send8
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrst
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov dx,offset infms3	; Plus a little	cuteness.
	mov ah,prstr
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrrpr
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrrpr	;  and string to move cursor
	int dos			; Print the string
ENDIF
	jmp rskp
send8:
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrst
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrst	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov dx,offset infms4	; Plus a little	cuteness.
	mov ah,prstr
	int dos
IF IBMPC
	mov ah,2
	mov dx,scrrpr
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrrpr	; and string to move cursor
	int dos			; Print the string
ENDIF
	jmp rskp
SEND	ENDP
 
 
	page
;	Send routines
 
;	Send initiate
 

SINIT	PROC	NEAR
	cmp numtry,imxtry	; Have we reached the maximum number of	tries?
	jl sinit2
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
sinit2:	inc numtry		; Save the updated number of tries.
	mov bx,offset data	; Get a	pointer	to our data block.
	call rpar		; Set up the parameter information.
	xchg ah,al
	mov ah,0
	mov argbk1,ax		; Save the number of arguments.
	mov ax,numpkt		; Get the packet number.
	mov argblk,ax
	mov ah,'S'		; Send initiate	packet.
	call spack		; Send the packet.
	call rpack		; Get a	packet.
	 jmp r			;  Trashed packet don't	change state, retry.
	cmp ah,'Y'		; ACK?
	jne sinit3		; If not try next.
	mov ax,pktnum		; Get the packet number.
	cmp ax,argblk		; Is it	the right packet number?
	je sini22
	ret			; If not try again.
sini22:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ax,argbk1		; Get the number of pieces of data.
	mov bx,offset data	; Pointer to the data.
	call spar		; Read in the data.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov state,'F'		; Set the state	to file	send.
	call getfil		; Open the file.
	 jmp abort		;  Something is	wrong, die.
	ret
sinit3:	cmp ah,'N'		; NAK?
	jne sinit4		; If not see if	its an error.
	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov ax,pktnum		; Get the present packet number.
	inc ax			; Increment.
	cmp ax,argblk		; Get the packet's number.
	je sini32
	ret			; If not assume	its for	this packet, go	again.
sini32:	mov numtry,0		; Reset	number of tries.
	mov state,'F'		; Set the state	to file	send.
	ret
sinit4:	cmp ah,'E'		; Is it	an error packet.
	jne sinit5
	call error
sinit5:	jmp abort
SINIT	ENDP
 


	page
;	Send file header
 
SFILE	PROC	NEAR
	cmp numtry,maxtry	; Have we reached the maximum number of	tries?
	jl sfile1
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
sfile1:	inc numtry		; Increment it.
	mov datptr,offset data	; Get a	pointer	to our data block.
	mov bx,offset fcb+1	; Pointer to file name in FCB.
	mov fcbptr,bx		; Save position	in FCB.
	mov cl,0		; Counter for chars in file name.
	mov ch,0		; Counter for number of chars in FCB.
sfil11:	cmp ch,8H		; Ninth char?
	jne sfil12
	mov ah,'.'
	mov bx,datptr
	mov [bx],ah		; Put dot in data packet.
	inc bx
	mov datptr,bx		; Save new position in data packet.
	inc cl
sfil12:	inc ch
	cmp ch,0CH		; Twelve?
	jns sfil13
	mov bx,fcbptr
	mov ah,[bx]		; Get char of filename.
	inc bx
	mov fcbptr,bx		; Save position	in FCB.
	cmp ah,'!'		; Is it a good char?
	jl sfil11		; If not, get the next.
	mov bx,datptr
	mov [bx],ah		; Put char in data buffer.
	inc cl			; Increment counter.
	inc bx
	mov datptr,bx		; Save new position. 
	jmp sfil11		; Get another char.
sfil13:	mov ch,0
	mov argbk1,cx		; Save number of char in filename.
	mov bx,datptr
	mov ah,'$'
	mov [bx],ah		; Put dollar sign for printing.
IF IBMPC
	mov ah,2
	mov dx,scrfln		; Put cursor in proper place
	mov bh,0
	int bios
ENDIF
IFE 1				;[uno3]
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrfln	; and string to move cursor
	int dos			; Print the string
ENDIF
ENDIF				;[uno3]
	call clrfln
	mov ah,prstr
	mov dx,offset data	; Print file name.
	int dos

	mov ax,pktnum		; Get the packet number.
	mov argblk,ax
	mov ah,'F'		; File header packet.
	call spack		; Send the packet.
	call rpack		; Get a	packet.
	 jmp r			;  Trashed packet don't	change state, retry.
	cmp ah,'Y'		; ACK?
	jne sfile2		; If not try next.
	mov ax,pktnum		; Get the packet number.
	cmp ax,argblk
	je sfil14
	ret			; If not hold out for the right	one.
sfil14:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
;* More	file I/O.  Anything to do with the CP/M	FCB must be checked for	MS-DOS.
sfil15:	mov ah,0		; Get a	zero.
	mov bx,offset fcb
	add bx,20H
	mov [bx],ah		; Set the record number	to zero.
	mov eoflag,ah		; Indicate not EOF.
	mov ah,0FFH
	mov filflg,ah		; Indicate file	buffer empty.
	call gtchr
	 jmp sfil16		; Error	go see if its EOF.
	jmp sfil17		; Got the chars, proceed.
sfil16:	cmp ah,0FFH		; Is it	EOF?
	je sfl161
	jmp abort		; If not give up.
sfl161:	mov ah,'Z'		; Set the state	to EOF.
	mov state,ah
	ret
sfil17:	mov siz,ax
;*
	mov state,'D'		; Set the state	to data	send.
	ret
sfile2:	cmp ah,'N'		; NAK?
	jne sfile3		; Try if error packet.
	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov ax,pktnum		; Get the present packet number.
	inc ax			; Increment.
	cmp ax,argblk		; Is the packet's number one more than now?
	jz sfil14		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try	again.
sfile3:	cmp ah,'E'		; Is it	an error packet.
	jne sfile4
	call error
sfile4:	jmp abort
SFILE	ENDP
 
 
	page
;	Send data
 
SDATA	PROC	NEAR
	cmp numtry,maxtry	; Have we reached the maximum number of	tries?
	jl sdata1
	call erpos
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
sdata1:	inc numtry		; Increment it.
	mov datptr,offset data	; Get a	pointer	to our data block.
	mov cbfptr,offset filbuf ; Pointer to chars to be sent.
	mov cx,1		; First	char.
sdat11:	mov bx,cbfptr
	mov ah,[bx]
	inc cbfptr
	mov bx,datptr
	mov [bx],ah		; Put the char in the data packet.
	inc datptr		; Save position	in data	packet.
	inc cx			; Increment the	count.
	cmp cx,siz		; Have we transfered that many?
	jle sdat11		; If not get another.
	mov ax,siz		; Number of char in char buffer.
	mov argbk1,ax
	mov ax,pktnum		; Get the packet number.
	mov argblk,ax
	mov ah,'D'		; Data packet.
	call spack		; Send the packet.
	call rpack		; Get a	packet.
	 jmp r			;  Trashed packet don't	change state, retry.
	cmp ah,'Y'		; ACK?
	jne sdata2		; If not try next.
	mov ax,pktnum		; Get the packet number.
	cmp ax,argblk		; Is it	the right packet number?
	jz sdat12
	ret			; If not hold out for the right	one.
sdat12:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	call gtchr
	 jmp sdat13		; Error	go see if its EOF.
	mov siz,ax		; Save the size	of the data gotten.
	ret
;* File	I/O.
sdat13:	cmp ah,0FFH		; Is it	EOF?
	je sdt131
	jmp abort		; If not give up.
;*
sdt131:	mov state,'Z'		; Set the state	to EOF.
	ret
sdata2:	cmp ah,'N'		; NAK?
	jne sdata3		; See if is an error packet.
	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov ax,pktnum		; Get the present packet number.
	inc ax			; Increment.
	cmp ax,argblk		; Is the packet's number one more than now?
	jz sdat12		; Just as good as ACK; goto ACK	code.
	ret			; If not go try	again.
sdata3:	cmp ah,'E'		; Is it	an error packet.
	jne sdata4
	call error
sdata4:	jmp abort
SDATA	ENDP
 
 
	page
;	Send EOF
 
SEOF	PROC	NEAR
	cmp numtry,maxtry	; Have we reached the maximum number of	tries?
	jl seof1
	call erpos		; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
seof1:	inc numtry		; Increment it.
	mov ax,pktnum		; Get the packet number.
	mov argblk,ax
	mov argbk1,0		; No data.
	mov ah,'Z'		; EOF packet.
	call spack		; Send the packet.
	call rpack		; Get a	packet.
	 jmp r			;  Trashed packet don't	change state, retry.
	cmp ah,'Y'		; ACK?
	jne seof2		; If not try next.
	mov ax,pktnum		; Get the packet number.
	cmp ax,argblk		; Is it	the right packet number?
	jz seof12
	ret			; If not hold out for the right	one.
seof12:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov ah,closf		; Close	the file.
	mov dx,offset fcb
	int dos
;* Check if successful
	call gtnfil		; Get the next file.
	 jmp seof13		;  No more.
	call getfil		;[uno3]	Open the file
	 jmp abort		;[uno3]	Can't get here, so die
	mov state,'F'		; Set the state	to file	send.
	ret
seof13:	mov state,'B'		; Set the state	to EOT.
	ret
seof2:	cmp ah,'N'		; NAK?
	jne seof3		; Try and see if its an	error packet.
	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov ax,pktnum		; Get the present packet number.
	inc ax			; Increment.
	cmp ax,argblk		; Is the packet's number one more than now?
	jz seof12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try	again.
seof3:	cmp ah,'E'		; Is it	an error packet?
	jne seof4
	call error
seof4:	jmp abort
SEOF	ENDP
 
 
	page
;	Send EOT
 
SEOT	PROC	NEAR
	cmp numtry,maxtry	; Have we reached the maximum number of	tries?
	jl seot1
	call erpos		; Position cursor.
	mov dx,offset erms14
	mov ah,prstr
	int dos			; Print	an error message.
	jmp abort		; Change the state to abort.
seot1:	inc numtry		; Increment it.
	mov ax,pktnum		; Get the packet number.
	mov argblk,ax
	mov argbk1,0		; No data.
	mov ah,'B'		; EOF packet.
	call spack		; Send the packet.
	call rpack		; Get a	packet.
	 jmp r			; Trashed packet don't change state, retry.
	cmp ah,'Y'		; ACK?
	jne seot2		; If not try next.
	mov ax,pktnum		; Get the packet number.
	cmp ax,argblk		; Is it	the right packet number?
	jz seot12
	ret			; If not hold out for the right	one.
seot12:	inc ax			; Increment the	packet number.
	and ax,3FH		; Turn off the two high	order bits.
	mov pktnum,ax		; Save modulo 64 of the	number.
	inc numpkt		; Increment the	number of packets.
	mov ah,numtry		; Get the number of tries.
	mov oldtry,ah		; Save it.
	mov numtry,0		; Reset	the number of tries.
	mov state,'C'		; Set the state	to file	send.
	ret
seot2:	cmp ah,'N'		; NAK?
	jne seot3		; Is it	error.
	call rtpos		; Position cursor.
	inc numrtr		; Increment the	number of retries
	mov ax,numrtr
	call nout		; Write	the number of retries.
	mov ax,pktnum		; Get the present packet number.
	inc ax			; Increment.
	cmp ax,argblk		; Is the packet's number one more than now?
	jz seot12		; Just as good as a ACK; go to the ACK code.
	ret			; If not go try	again.
seot3:	cmp ah,'E'		; Is it	an error packet.
	jne seot4
	call error
seot4:	jmp abort
SEOT	ENDP
 

	page+
;* Here	is the bulk of the file	I/O.  Good luck.
 
;	File routines
 
;	Output the chars in a packet.

FILEIO	PROC	NEAR 	

ptchr:	mov temp1,ax		; Save the size.
	mov bx,offset data	; Beginning of received	packet data.
	mov outpnt,bx		; Remember where we are.
ptchr1:	dec temp1		; Decrement # of chars in packet.
	jnl pt1
	jmp rskp		; Return successfully if done.
pt1:	dec chrcnt		; Decrement number of chars in dta.
	jns ptchr2		; Continue if space left.
	call outbuf		; Output it if full.
	 jmp r			;  Error return	if disk	is full.
ptchr2:	mov bx,outpnt		; Get position in output buffer.
	mov ah,[bx]		; Grab a char.
	inc bx
	mov outpnt,bx		; and bump pointer.
	mov BYTE PTR ebitflg,0	;[uno5] Not 8 bit quote to begin with
	cmp ah,erqote		;[uno5] 8 bit quote char?
	jne ptchr3		;[uno5] No, go on
	cmp ah,'N'		;[uno5] No eight bit quoting?
	je ptchr3		;[uno5] True, so don't quote
	mov BYTE PTR ebitflg,1	;[uno5] Set the flag
	dec temp1		;[uno5] Less one char in packet
	mov ah,[bx]		;[uno5] Get the next one
	inc bx			;[uno5] Update the pointer
	mov outpnt,bx		;[uno5]
ptchr3:	cmp ah,rquote		;[uno5] Normal quote char
	jne ptchr4		;[uno5] No, go on
	dec temp1		;[uno5] Less one char
	mov bx,outpnt		;[uno5] Point to packet
	mov ah,[bx]		;[uno5] Get the next char
	inc bx			;[uno5] Update the pointer
	mov outpnt,bx		;[uno5]
	cmp ah,erqote		;[uno5] 8 bit quote char?
	je ptchr4		;[uno5] then leave it alone
	cmp ah,rquote		;[uno5] Normal quote char?
	je ptchr4		;[uno5] Yes, leave it alone
	add ah,40H		;[uno5] No, make it a control char
	and ah,7FH		;[uno5]
ptchr4:	cmp BYTE PTR ebitflg,0	;[uno5] Set the 8 bit?
	je ptchr5		;[uno5] No, go on
	or ah,80H		;[uno5] Yes, set it
ptchr5:	mov bx,bufpnt		;[uno5] Store the character
	mov [bx],ah		;[uno5]
	inc bx			;[uno5] Update the pointer
	mov bufpnt,bx		;[uno5]
	jmp ptchr1		;[uno5] Do it over again


	page

	; output the buffer, reset bufpnt and chrcnt
 
outbuf:	push bx
	mov ah,writef		; The write code.
	mov dx,offset fcb
	int dos			; Write the record.
	pop bx
	cmp al,0		; Successful.
	jz outbf1
	cmp al,01
	jz outbf0
	call erpos
	mov ah,prstr
	mov dx,offset erms19	; Record length exceeds dta.
	int dos
	ret
outbf0:	call erpos
	mov ah,prstr		; Tell about it.
	mov dx,offset erms11	; Disk full error.
	int dos
	ret
outbf1:	mov bx,offset buff	; Addr for beginning.
	mov bufpnt,bx		; Store	addr for beginning.
	mov ax,bufsiz-1		; Buffer size.
	mov chrcnt,ax		; Number of chars left
	jmp rskp



	page
;	Get the	chars from the file.
 
gtchr:
	mov ah,filflg		; Get the file flag.
	cmp ah,0		; Is there anything in the DMA?
	jz gtchr0		; Yup, proceed.
	mov cl,0		; No chars yet.
	call inbuf
	 jmp gtceof		; No more chars, go return EOF.
gtchr0:	mov al,spsiz		; Get the maximum packet size.
	sub al,8		; Subtract the overhead. and some for quoting
	mov ah,0
	mov temp1,ax		; Number of chars we're	to get.
	mov bx,offset filbuf	; Where to put the data.
	mov cbfptr,bx		; Remember where we are.
	mov cl,0		; No chars.
gtchr1:	dec temp1		; Decrement the	number of chars	left.
	jns gtchr2		; Go on	if there is more than one left.
	mov al,cl		; Return the count in A.
	mov ah,0
	jmp rskp
gtchr2:	mov ax,chrcnt
	dec ax
	jl gtchr3
	mov chrcnt,ax
	jmp gtchr4
gtchr3:	call inbuf		; Get another buffer full.
	 jmp gtceof
	cmp chrcnt,0
	jne gtchr4
	sub cl,2		; Don't count controllified Z.
	mov al,cl
	mov ah,0
	jmp rskp
gtchr4:	mov bx,bufpnt		;[uno5] Point to the char
	mov ah,[bx]		;[uno5] Get a char
	inc bx			;[uno5] Update the pointer
	mov bufpnt,bx		;[uno5]
	mov dh,ah		;[uno5] Save it for a moment
	and ah,80H		;[uno5] Is the 8th bit set?
	jz gtchr5		;[uno5] No, go on
	mov bx,cbfptr		;[uno5] Point to where to put char
	mov ch,esqote		;[uno5] Put the 8-bit quote char in
	mov [bx],ch		;[uno5]
	inc bx			;[uno5] Update the pointer
	mov cbfptr,bx		;[uno5]
	dec temp1		;[uno5] Less space in buffer
	inc cl			;[uno5] One more character to go
	and dh,7FH		;[uno5] Clear the 8th bit
gtchr5:	mov ah,dh		;[uno5] Restore the character
	cmp ah,esqote		;[uno5] Is it the 8-bit quote char?
	jne gtchr7		;[uno5] No, go on
gtchr6:	mov bx,cbfptr		;[uno5] Point to where chars go
	mov ch,squote		;[uno5] Stuff the quote char in
	mov [bx],ch		;[uno5]
	inc bx			;[uno5] Update the pointer
	mov cbfptr,bx		;[uno5]
	inc cl			;[uno5] One more char to go
	dec temp1		;[uno5] Less in buffer
	jmp gtchr8		;[uno5] Go stuff the quote character
gtchr7:	cmp ah,squote		;[uno5] Is it the regular quote char?
	je gtchr6		;[uno5] Yes, go quote it
	cmp ah,del		;[uno5] Is it the delete char?
	je gtchr9		;[uno5] Yes, go quote a ^char
	cmp ah,' '		;[uno5] Is it a control char?
	jl gtchr9		;[uno5] Yes, go quote it
gtchr8:	mov bx,cbfptr		;[uno5] Point to where to put chars
	mov [bx],ah		;[uno5] Put it in the buffer
	inc bx			;[uno5] Update the pointer
	mov cbfptr,bx		;[uno5]
	inc cl			;[uno5] One more to go
	jmp gtchr1		;[uno5] Do it all again
gtchr9:	mov bx,cbfptr		;[uno5] Point to where characters go
	mov ch,squote		;[uno5]
	mov [bx],ch		;[uno5] Stuff the quote character
	inc bx			;[uno5] Update the pointer
	mov cbfptr,bx		;[uno5]
	inc cl			;[uno5] One more to go
	dec temp1		;[uno5] One less to send
	add ah,40H		;[uno5] Make into normal char
	and ah,7FH		;[uno5]
	jmp gtchr8		;[uno5] stuff it away

 
	page
gtceof:	cmp cl,0		; Had we gotten any data?
	je gteof0		; Nope.
	mov al,cl
	mov ah,0
	jmp rskp
gteof0:	mov ah,0FFH		; Get a	minus one.
	ret


	page
inbuf:	mov ah,eoflag		; Have we reached the end?
	cmp ah,0
	jz inbuf0
	ret			; Return if set.
inbuf0:	push bx			
	push cx
	mov bx,offset buff	; Set the r/w buffer pointer.
	mov bufpnt,bx
	mov ah,readf		; Read a record.
	mov dx,offset fcb
	int dos
	mov cx,filsiz
	cmp cx,0		; Check for 128 chars or less left.
	jne inbuf1		; Still have data left.
	mov ax,ds
	mov es,ax
	mov si,offset filsiz+2
	mov di,offset bufhex
	cmps filsiz+2,es:bufhex
	ja inbuf1		; More than 128 chars.
	mov eoflag,0FFH		; Set End-of-file.
	mov cx,filsiz+2
	mov chrcnt,cx		; Return proper	number of chars.
	mov filflg,0		; Buffer not empty.
	pop cx
	pop bx
	jmp rskp
inbuf1:	sub filsiz+2,80H	; Sent	another	128 chars.
	sbb filsiz,0		; Account for the doubleword.
	mov al,80H		; Use as counter for number of chars read.
	pop cx
	pop bx
	cmp filflg,0		; Ever used DMS?
	jnz inbf21		; Nope, then don't change count.
	dec al			; Fix	boundary error.
inbf21:	mov ah,0		; Zero the flag	(buffer	not empty).
	mov chrcnt,ax		; Number of chars read from file.
	mov filflg,0		; Buffer not empty.
	jmp rskp

	page
getfil:	mov ah,0FFH
	mov filflg,ah		; Nothing in the DMA.
	mov ax,0
	mov eoflag,ah		; Not the end of file.
	mov bx,offset fcb+0CH
	mov [bx],ax		; Zero the current block number.
	mov bx,offset fcb+0EH
	mov [bx],ax		; Ditto	for Lrecl.
	mov bx,offset fcb+20H
	mov [bx],ah		; Zero the current record (of block).
	inc bx
	mov [bx],ax		; Same for record (of file). 
	mov bx,offset fcb+23H
	mov [bx],ax
	mov ah,openf		; Open the file.
	mov dx,offset fcb
	int dos
	mov bx,offset fcb+18	; File size in bytes (hi order word).
	mov di,offset filsiz	; Where to put the info. 
	mov ax,[bx]
	mov [di],ax
	mov bx,offset fcb+16	; Lo order word.
	mov ax,[bx]
	mov 2[di],ax
	sub filsiz+2,1		; Don't count the ^Z.
	sbb filsiz,0
	jmp rskp


	page
; This routine gets the next file name into the FCB from the
;file name list.  The list should have been built by FIND_FILES
; before this routine is called.

gtnfil:
	cmp fcbnum,-1		;[uno3]	Out of file names?
	jne gtnfl1		;[uno3]	No, return one
	ret			;[uno3]	Return in error
gtnfl1:	mov ax,12		;[uno3]	Get the number of bytes in a file name
	mul fcbnum		;[uno3]	Make it an index into the list
	add ax,offset fcblist	;[uno3]	Point into the file name list
	mov si,ax		;[uno3]	Set up for the block move
	push ds			;[uno3]
	pop es			;[uno3]
	mov bx,offset fcb	;[uno3]	...
	mov di,bx		;[uno3]	...
	mov cx,13		;[uno3]	...
	cld			;[uno3] Assure the direction of the transfer
	rep movs fcb,fcblist	;[uno3] ...
	dec fcbnum		;[uno3]	One less file name
	jmp rskp		;[uno3]	Return good


	page
;	Get the	file name (including host to micro translation)
 
gofil:	cmp ufname,0		;[uno4] Did the user specify a file name?
	je gofil0		;[uno4] No, proceed as usual
	push cx			;[uno4] Yes, use the filename he specified
	sub ch,ch		;[uno4] Get a 0 for the upper length count
	mov cl,ufname		;[uno4] The number of characters in the naem
	mov bx,ds		;[uno4] Set up for a block move
	mov es,bx		;[uno4]
	mov bx,offset fcblist	;[uno4]
	mov si,bx		;[uno4]
	mov bx,offset data	;[uno4]
	mov di,bx		;[uno4]
	cld			;[uno4] Insure the direction of the move
	rep movs data,fcblist	;[uno4] Put his file name in the buffer
	mov BYTE PTR [di],0	;[uno4] Terminate the string
	inc di			;[uno4] Make sure
	mov BYTE PTR [di],'$'	;[uno4] ...
	pop cx			;[uno4] put the stack back together
gofil0:	mov bx,offset data	; Get the address of the file name.
	mov datptr,bx		; Store	the address.
	mov bx,offset fcb+1       ; Address of the FCB.
	mov fcbptr,bx		; Save it.
	mov ax,0
	mov temp1,ax		; Initialize the char count.
	mov temp2,ax
	mov si,offset fcb
	mov [si],ah		; Set the drive	to default to current.
	mov ch,' '
gofil1:	mov [bx],ch		; Blank the FCB.
	inc bx
	inc ah
	cmp ah,0BH		; Twelve?
	jl gofil1
gofil2:	mov bx,datptr		; Get the NAME field.
	mov ah,[bx]
	inc bx
	mov datptr,bx
	cmp ah,'.'		; Separator?
	jne gofil3
	mov bx,offset fcb+9H
	mov fcbptr,bx
	mov ax,temp1
	mov temp2,ax
	mov temp1,9H
	jmp gofil6
gofil3:	cmp ah,0		; Trailing null?
	jz gofil7		; Then we're done.
	mov bx,fcbptr
	mov [bx],ah
	inc bx
	mov fcbptr,bx
	mov ax,temp1		; Get the char count.
	inc ax
	mov temp1,ax
	cmp ax,8H		; Are we finished with this field?
	jl gofil2
gofil4:	mov temp2,ax
	mov bx,datptr
	mov ah,[bx]
	inc bx
	mov datptr,bx
	cmp ah,0
	jz gofil7
	cmp ah,'.'		; Is this the terminator?
	jne gofil4		; Go until we find it.
gofil6:	mov bx,datptr		; Get the TYPE field.
	mov ah,[bx]
	inc bx
	mov datptr,bx
	cmp ah,0		; Trailing null?
	jz gofil7		; Then we're done.
	mov bx,fcbptr
	mov [bx],ah
	inc bx
	mov fcbptr,bx
	inc temp1		; Increment char count.
	cmp temp1,0CH		; Are we finished with this field?
	jl gofil6
gofil7:	mov bx,datptr
	mov ah,'$'
	mov [bx],ah		; Put in a dollar sign for printing.
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrfln
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrfln	; and string to move cursor
	int dos			; Print the string
ENDIF
	call clrfln
	mov ah,prstr		; Print	the file name.
	mov dx,offset data
	int dos
	mov ah,flwflg		; Is file warning on?
	cmp ah,0
	jnz gf7x
	jmp gofil9		; If not, just proceed.
gf7x:	mov ah,openf		; See if the file exists.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Does it exist?
	jnz gf8x
	jmp gofil9		; If not create it.
gf8x:
IF IBMPC
	mov ah,2		; Position cursor.
	mov dx,scrfr
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get print string function
	mov dx,offset scrfr	; and string to move cursor
	int dos			; Print the string
ENDIF
	mov ah,prstr		; Inform the user we are renaming the file.
	mov dx,offset infms5
	int dos
	mov ax,temp2		; Get the number of chars in the file name.
	cmp ax,0
	jne gofil8
	mov ax,temp1
	mov temp2,ax
gofil8:	mov ch,0
	mov cl,al
	mov al,0		; Says if first field is full.
	cmp cl,9H		; Is the first field full?
	jne gofl81
	mov al,0FFH		; Set a	flag saying so.
	dec cl
gofl81:	mov bx,offset fcb+1	; Get the FCB.
	add bx,cx		; Add in the character number.
	mov ah,'&'
	mov [bx],ah		; Replace the char with	an ampersand.
	push ax
	push bx
	mov ah,openf		; See if the file exists.
	mov dx,offset fcb
	int dos
	pop bx
	cmp al,0FFH		; Does it exist?
	pop ax
	jz gofl89		; If not create	it.
	cmp al,0	   	; Get the flag.
	jz gofl83
	dec cl			; Decrement the	number of chars.
	cmp cl,0
	jz gofl88		; If no	more, die.
	jmp gofl81
gofl83:	inc cl			; Increment the	number of chars.
	cmp cl,8		; Are we to the end?
	jl gofl81		; If not try again ; else fail.	
 
gofl88:	call erpos		; Position cursor.
	mov ah,prstr		; Tell the user that we can't rename it.
	mov dx,offset ermes4
	int dos
	ret
 
gofl89:	mov bx,offset fcb+0CH	; Point past the end of the file name.
	mov dh,[bx]		; Save the present contents.
	mov ah,'$'
	mov [bx],ah		; Put in a dollar sign.
	push dx
	mov ah,prstr		; Print	the file name.
	mov dx,offset fcb+1
	int dos
	pop dx
	mov bx,offset fcb+0CH	; Restore over the dollar sign.
	mov [bx],dh
gofil9:	mov ah,delf		; Delete the file if it	exists.
	mov dx,offset fcb
	int dos
	mov ax,0
	mov si,offset fcb+0CH
	mov [si],ax		; Zero current block.
	mov si,offset fcb+0EH
	mov [si],ax		; Same for Lrecl.
	mov si,offset fcb+20H
	mov [si],ah		; Zero the current record (within block).
	inc si
	mov [si],ax		; Zero record (within file).
	mov si,offset fcb+23H
	mov [si],ax
	mov ah,makef		; Now create it.
	mov dx,offset fcb
	int dos
	cmp al,0FFH		; Is the disk full?
	je gf9x
	jmp rskp
gf9x:	call erpos		; Position cursor.
	mov ah,prstr		; If so tell the user.
	mov dx,offset erms11
	int dos
	ret

	page
; This routine makes a list of file names from a group specified
;by the user.  This list is used by the get next file (gtnfil) routine
;to selext the file to be transmitted next.

find_files:
	mov fcbnum,0		;[uno3]	There are none to start with

	mov ah,sfirst		;[uno3]	Get the first file name
	mov dx,offset fcb	;[uno3]	...
	int dos			;[uno3]	...
	cmp al,0FFH		;[uno3]	Not found?
	jne findf1		;[uno3]	No, there was one, so save it
	mov ah,prstr		;[uno3]	Tell the user not found...
	mov dx,offset crlf	;[uno3]
	int dos			;[uno3]
	mov ah,prstr		;[uno3]
	mov dx,offset erms15	;[uno3]
	int dos			;[uno3]
	ret			;[uno3]	...and return in error

findf1:	mov bx,offset fcblist	;[uno3]	Point to the file name list
	mov di,bx		;[uno3]	Set up for block move
	push ds			;[uno3]
	pop es			;[uno3]
	jmp findf21		;[uno3]	Skip the decrement the first time
findf2:	dec di			;[uno3]	Adjust to point to the end of the last file name
findf21:			;[uno3]
	mov bx,offset buff	;[uno3]	Point to where we get the file name from
	mov si,bx		;[uno3] Set up for block move
	mov cx,13		;[uno3]	The length of a file name
	cld			;[uno3] Assure transfer direction
	rep movs fcblist,buff	;[uno3]	Put the file name into the list

	mov ah,snext		;[uno3]	Let's get another file name
	mov dx,offset fcb	;[uno3]
	int dos			;[uno3]
	cmp al,0FFH		;[uno3]	Found another file?
	je findf3		;[uno3]	No, exit good
	inc fcbnum		;[uno3]	Bump the number of file names in the lsit
	cmp fcbnum,maxfil	;[uno3]	Found all we have room for?
	jne findf2		;[uno3]	No, get another
	call erpos		;[uno3]	Yes, tell the user we won't send all
	mov ah,prstr		;[uno3]
	mov dx,offset dimsg2	;[uno3]
	int dos			;[uno3]
findf3:	jmp rskp		;[uno3]	Return good

FILEIO	ENDP
;*
 
 
	page	+
;	Packet routines
 
; Send_Packet
; This routine assembles a packet from the arguments given and sends it
; to the host.
;
; Expects the following:
;	AH     - Type of packet	(D,Y,N,S,R,E,F,Z,T)
;	ARGBLK - Packet	sequence number
;	ARGBK1 - Number	of data	characters
; Returns: +1 always
 
SPKT	PROC	NEAR

spack:	push ax			; Save the packet type.
	mov bx,offset packet	; Get address of the send packet.
	mov ah,soh		; Get the start	of header char.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	mov ax,argbk1		; Get the number of data chars.
	xchg ah,al
	add ah,' '+3		; Real packet character	count made printable.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	mov cl,ah		; Start	the checksum.
	mov ax,argblk		; Get the packet number.
	xchg ah,al
	add ah,' '		; Add a	space so the number is printable.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	add cl,ah		; Add the packet number	to the checksum.
	pop ax			; Get the packet type.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	add cl,ah		; Add the type to the checksum.
	mov dx,argbk1		; Get the packet size.
spack2:	cmp dx,0		; Are there any	chars of data?
	 jz spack3		;  No, finish up.
	dec dx			; Decrement the	char count.
	mov ah,[bx]		; Get the next char.
	inc bx			; Point	to next	char.
	add cl,ah		; Add the char to the checksum.
	cmp ah,0
	jns spack2
	mov hierr,0FFH		; set err flag. 
	jmp spack2		; Go try again.
spack3:	cmp hierr,0
	je sp3x			; Nothing special to do.
	call biterr
	mov hierr,0		; Reset.
sp3x:	mov ah,cl		; Get the character total.
	mov ch,cl		; Save here too (need 'cl' for shift).
	and ah,0C0H		; Turn off all but the two high	order bits.
	mov cl,6
	shr ah,cl		; Shift	them into the low order	position.
	mov cl,ch
	add ah,cl		; Add it to the	old bits.
	and ah,3FH		; Turn off the two high	order bits.  (MOD 64)
	add ah,' '		; Add a	space so the number is printable.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	mov ah,seol		; Get the EOL the other	host wants.
	mov [bx],ah		; Put in the packet.
	inc bx			; Point	to next	char.
	mov ah,0		; Get a	null.
	mov [bx],ah		; Put in the packet.
	cmp debug,0		; debug mode.
	je spack4
	inc bx
	mov ah,'$'
	mov [bx],ah
IF IBMPC
	mov ah,2
	mov dx,scrsp
	mov bh,0
	int bios
ENDIF
IF Z100
	mov ah,prstr		;[uno1]	Get print string function
	mov dx,offset scrsp	;[uno1]	and string to move cursor
	int dos			;[uno1]	Print the string
	mov ah,prstr		;[uno1]	Clear the line
	mov dx,offset clrlin	;[uno1]	...
	int dos			;[uno1]	...
	mov ah,prstr		;[uno1]	Locate to second line
	mov dx,offset scrsp1	;[uno1]	...
	int dos			;[uno1]	...
	mov ah,prstr		;[uno1]	Clear that line also
	mov dx,offset clrlin	;[uno1]	...
	int dos			;[uno1]	...
ENDIF
	push bx			;[uno1]	save the packet length
	sub bx,offset packet	;[uno1]	If it is less than 30H long
	cmp bx,30H		;[uno1]	 then
	jl spack35		;[uno1]	  print only the first line
IF Z100
	mov ah,prstr		;[uno1]	Otherwise locate to secon line
	mov dx,offset scrsp1	;[uno1]	...
	int dos			;[uno1]	...
ENDIF
	mov ah,prstr		;[uno1]	Print the second line
	mov dx,offset packet+30H ;[uno1]	...
	int dos			;[uno1]	...
spack35:
IF Z100
	mov ah,prstr		;[uno1]	Locate to first line
	mov dx,offset scrsp	;[uno1]	...
	int dos			;[uno1]	...
ENDIF
	mov ah,prstr		;[uno1]	Print the line title
	mov dx,offset spmes	;[uno1]	...
	int dos			;[uno1] ...
	pop bx			;[uno1]	restore packet length
	mov al,packet+30H	;[uno1]	Get the character that the terminator
				;[uno1]	will replace
	push ax			;[uno1]	save it
	mov BYTE PTR packet+30H,'$' ;[uno1]	terminate the first line
	mov ah,prstr
	mov dx,offset packet	;[uno1]	Print it
	int dos			;[uno1]	...
	pop ax			;[uno1]	Put everything back together
	mov BYTE PTR packet+30H,al ;[uno1]	...
spack4:	call outpkt		; Call the system dependent routine.
	ret
 
SPKT	ENDP 

	page
;	Write out a packet.
 
OUTPKT	PROC	NEAR
	mov dh,spad		; Get the number of padding chars.
outpk2:	dec dh
	cmp dh,0
	jl outpk3		; If none left proceed.
	mov ah,spadch		; Get the padding char.
	call outchr		; Output it.
	jmp outpk2
outpk3:	mov bx,offset packet	; Point	to the packet.
outlup:	mov ah,[bx]		; Get the next character.
	cmp ah,0		; Is it	a null?
	jnz outlp2
	ret
outlp2:	call outchr		; Output the character.
	inc bx			; Increment the	char pointer.
	jmp outlup
OUTPKT	ENDP
 
 
	page
;************************System	Dependent****************************
;	Put a char in AH to the	port.
PORT	PROC  NEAR	
IF IBMPC
outchr:	mov al,ah		; Char must be in al.
	mov cx,0
	cmp ibmflg,0
	je outch1
	or al,080H
outch1:	mov ah,1		; Output it.
	mov dx,0
	int comm
	cmp ah,00H
	je outch3
	loop outch1
	ret
ENDIF

IF Z100
outchr:	mov al,ah		; Yes, get the character into al
	mov cx,0
	cmp ibmflg,0		; IBM mode?
	je outch1		; No, skip this
	or al,080H		; Yes, turn on parity bit
outch1:	call bios_auxout	; Send	the character
ENDIF

outch3:	ret
;	cmp ibmflg,0
;	je outch2		; Only wait for the IBM.
;	cmp al,CR
;	je outch2
;	mov cx,0A00H
;clup:	loop clup	
;outch2:	ret
 
 
	page
;************************System	Dependent****************************
;
;	Get a char from	the port and return in A.
 
inchr:
IF IBMPC
	mov dx,mdmsts		; Get port status.
	in al,dx
	test al,mdminp		; Data available?
	jnz inchr3		; Read char ok.
ENDIF
IF Z100
	push	bx		; Save BX
	mov ah,chr_status	; Get the function
	mov al,chr_sfgs		; And	the subfunction
	call bios_auxfunc	; Determine if anything to input
	cmp bl,0		; Is there?
	jnz inchr3		; Yes, go get it
	pop bx			; And	restore	BX
ENDIF
	mov ah,constat		; Is a char on the console?
	int dos
	cmp al,0
	jz inchr		; If not go look for another char.
	mov ah,conin		; Get the char.
	int dos
	mov ah,al 
	cmp ah,cr		; Is it a carriage return?
	je inchr4		; If not go look for another char.
	jmp inchr		; Wait for some kind of input.
inchr4:	ret

inchr3:
IF IBMPC
	mov dx,mdmdat		; Read in the char.
	in al,dx
ENDIF
IF Z100
	mov ah,chr_read		; Get the function to read
	call bios_auxfunc	; Get a character
	pop bx			; Restore BX
ENDIF
	mov ah,al
	cmp ibmflg,0
	je inchr5
	and ah,7FH		 ; Turn off the parity bit.
inchr5:	jmp rskp
PORT	ENDP
;*
 
 
	page
; Receive_Packet
; This routine waits for a packet arrive from the host.	 It reads
; chars	until it finds a SOH.

RPACK	PROC	NEAR
IF IBMPC
	mov ah,2
	mov dx,scrst		; Position cursor.
	mov bh,0
	int bios
ENDIF

IF Z100
	mov ah,prstr		; Get the function to print string
	mov dx,offset scrst	; Get the string address
	int dos			; Position the cursor
ENDIF
	mov ah,prstr
	mov dx,offset infms0
	int dos
	call inpkt		; Read up to a carriage	return.
	 jmp r			;  Return bad.
rpack0:	call getchr		; Get a	character.
	 jmp r			;  Hit the carriage return, return bad.
	cmp ah,soh		; Is the char the start	of header char?
	 jne rpack0		;  No, go until	it is.
rpack1:	call getchr		; Get a	character.
	 jmp r			;  Hit the carriage return, retuset infms0
	cmp ah,soh		; Is the char the start	of header char?
	 jz rpack1		;  Yes,	then go	start over.
	mov cl,ah		; Start	the checksum.
	sub ah,' '+3		; Get the real data count.
	mov dh,ah		; Save it for later.
	mov al,ah		; Swap halves.
	mov ah,0
	mov argbk1,ax		; Save the data	count.
	call getchr		; Get a	character.
	 jmp r			;  Hit the carriage return, return bad.
	cmp ah,soh		; Is the char the start	of header char?
	 jz rpack1		;  Yes,	then go	start over.
	add cl,ah		; Add it to the	checksum.
	sub ah,' '		; Get the real packet number.
	mov al,ah		; Swap halves.
	mov ah,0
	mov argblk,ax		; Save the packet number.
	call getchr		; Get a	character.
	 jmp r			;  Hit the carriage return, return bad.
	cmp ah,soh		; Is the char the start	of header char?
	 jz rpack1		;  Yes,	then go	start over.
	push ax			; Save the message type.
	add cl,ah		; Add it to the	checksum.
	mov bx,offset data	; Point	to the data buffer.
rpack2:	dec dh			; Any data characters?
	 js rpack3		;  If not go get the checksum.
	call getchr		; Get a	character.
	 jmp rpax		;[uno1]  Hit the carriage return, return bad.
	cmp ah,soh		; Is the char the start	of header char?
	 jz rpack1		;  Yes,	then go	start over.
	mov [bx],ah		; Put the char into the	packet.
	inc bx			; Point	to the next character.
	add cl,ah		; Add it to the	checksum.
	jmp rpack2		; Go get another.
rpack3:	call getchr		; Get a	character.
	 jmp rpax		;[uno1]  Hit the carriage return, return bad.
	cmp ah,soh		; Is the char the start	of header char?
	 jz rpack1		;  Yes,	then go	start over.
	sub ah,' '		; Turn the char	back into a number.
	mov dh,cl		; Get the character total.
	and dh,0C0H		; Turn off all but the two high	order bits.
	mov ch,cl
	mov cl,6
	shr dh,cl		; Shift	them into the low order	position.
	mov cl,ch
	add dh,cl		; Add it to the	old bits.
	and dh,3FH		; Turn off the two high	order bits.  (MOD 64)
	cmp dh,ah		; Are they equal?
	 jz rpack4		;  If so finish	up.
	call erpos		;[uno1] Put this message somewhere nice
	mov dx,offset dimsg1
	mov ah,prstr
	int dos			; Print	a diagnostic message.
rpax:	pop ax			;[uno1] fix up stack
	ret
rpack4:	cmp debug,0		;[uno1] If no debugging
	je rpack5		;	exit
	push dx			;	save whatever
IF Z100
	mov ah,prstr		;	Point to the first debugging line
	mov dx,offset scrrp	;	...
	int dos			;	...
	mov ah,prstr		;	Clear it
	mov dx,offset clrlin	;	...
	int dos			;	...
	mov ah,prstr		;	point to second debugging line
	mov dx,offset scrrp1	;	...
	int dos			;	...
	mov ah,prstr		;	clear it alos
	mov dx,offset clrlin	;	...
	int dos			;	...
ENDIF
	mov ah,'$'		;	terminate the packet
	mov [bx],ah		;	...
	push bx			;	save the length
	sub bx,offset data	;	if the data is less
	cmp bx,30H		;	 than 30H characters
	jl rpack35		;	  then only display the first line
IF Z100
	mov ah,prstr		;	locate to the second line
	mov dx,offset scrrp1	;	...
	int dos			;	...
ENDIF
	mov ah,prstr		;	print the second line
	mov dx,offset data+30H	;	...
	int dos			;	...
rpack35:
IF Z100
	mov ah,prstr		;	locate to the first line
	mov dx,offset scrrp	;	...
	int dos			; 	...
ENDIF
	mov ah,prstr		;	print the title
	mov dx,offset rpmes	;	...
	int dos			;	...
	pop bx			; get the length back
	mov ah,data+30H		;	save the character to be replaced
	push ax			;	by the terminator
	mov BYTE PTR data+30H,'$' ;	Terminate the string
	mov ah,prstr		;	print it
	mov dx,offset data	;	...
	int dos			;	...
	pop ax			;	put things back together
	mov BYTE PTR data+30H,ah ;	...
IF Z100
	mov ah,prstr		;	locate to the type location
	mov dx,offset scrrpt	;	...
	int dos			;	...
ENDIF
	mov ah,prstr		;	print the title
	mov dx,offset rptmes	;	...
	int dos			;	...
	pop dx			;	get the message type the hard way
	pop ax			;	...
	push ax			;	...
	push dx			;	...
	mov dl,ah		;	print it
	mov ah,offset conout	;	...
	int dos			;	...
	pop dx			;[uno1]	clean up our trash
rpack5:	mov ah,0
	mov [bx],ah		; Put a	null at	the end	of the data.
	pop ax			; Get the type.
	jmp rskp
RPACK	ENDP
 
 
	page
INPKT	PROC	NEAR
	mov bx,offset recpkt	; Point	to the beginning of the	packet.
	mov incnt,0
inpkt2:	call inchr		; Get a	character.
	 jmp r			;  Return failure.
	mov [bx],ah		; Put the char in the packet.
	inc bx
	inc incnt
	cmp ah,reol		; Is it	the EOL	char?
	jne inpkt2		; If not loop for another.
	cmp ibmflg,0		; Is this the (dumb) IBM mainframe?
	jz inpkt4		; If not then proceed.
	cmp incnt,1		; Ignore bare CR.
	jne inpkt5
	mov incnt,0
	mov bx,offset recpkt
	jmp inpkt2
inpkt5:	cmp state,'S'		; Check	if this	is the Send-Init packet.
	jz inpkt4		; If so	don't wait for the XON.
inpkt3:	call inchr		; Wait for the turn around char.
	 jmp inpkt4
	cmp ah,xon		; Is it	the IBM	turn around character?
	jne inpkt3		; If not, go until it is.
inpkt4:	mov bx,offset recpkt
	mov pktptr,bx		; Save the packet pointer.
	jmp rskp		; If so	we are done.
INPKT	ENDP

 
	page
GETCHR	PROC	NEAR
	push bx
	mov bx,pktptr		; Get the packet pointer.
	mov ah,[bx]		; Get the char.
	inc bx
	mov pktptr,bx
	pop bx			; Restore BX.
	cmp ah,reol		; Is it	the EOL	char?
	jne getcr2		; If not return	retskp.
	ret			; If so	return failure.
getcr2:	jmp rskp
GETCHR	ENDP
 
 
	page
; This is where	we go if we get	an error packet.
 
ERROR	PROC	NEAR
	mov state,'A'		; Set the state	to abort.
	call erpos		; Position the cursor.
	mov bx,argbk1		; Get the length of the	data.
	add bx,offset data	; Get to the end of the	string.
	mov ah,'$'		; Put a	dollar sign at the end.
	mov [bx],ah
	mov ah,prstr		; Print	the error message.
	mov dx,offset data
	int dos
	ret
ERROR	ENDP
 
 
	page	+
; This is the 'exit' command.  It leaves KERMIT	and returns to CP/M.
 
EXIT	PROC	NEAR
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r
	mov extflg,1		;  Set the exit	flag.
	jmp rskp		; Then return to system.
EXIT	ENDP
 
 
	page	+
; This is the 'help' command.  It gives	a list of the commands.
 
HELP	PROC	NEAR
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r
	mov ah,prstr		; Print	a string to the	console.
	mov dx,offset tophlp	; The address of the help message.
	int dos
	jmp rskp
HELP	ENDP
 
IF IBMPC
source	db	2048 DUP(?)	; Buffer for data from port.
srcpnt	dw	0		; Pointer in buffer (DI).
count	dw	0		; Number of chars in int buffer.
savesi	dw	0		; Save SI register here.
ENDIF


	page	+
;	This is	the CONNECT command.
 
TELNET	PROC	NEAR
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r			;  Didn't get a	confirm.
	mov ah,prstr		; Output
	mov dx,offset crlf	; a crlf.
	int dos
	mov dx,offset tmsg1
	int dos
IF IBMPC
	cld			; Do increment in string operations.
	cli			; Disable interrupts.
	xor ax,ax
	mov cx,ds		; Save DS in CX.
	mov ds,ax		; Use low core.
	mov bx,mdmintv
	push [bx]		; Serial Card Interrupt vector.
	mov bx,mdmintv+2
	push [bx]
	mov bx,6CH		; "break" interrupt vector.
	push [bx]
	mov bx,6EH
	push [bx]
	mov bx,mdmintv
	mov ax,offset serint
	mov es,ax
	mov [bx],es		; Setup int addr.
	mov bx,mdmintv+2
	mov [bx],cs
	mov bx,6CH
	mov ax,offset intret
	mov es,ax
	mov [bx],es		; ignore break int's (pt to "iret").
	mov bx,6EH
	mov [bx],cs
	mov ds,cx
	mov ssp,sp		; Save SP to make an easy return.
	lea ax,cs:source
	mov cs:srcpnt,ax
	mov cs:savesi,ax	; Source of data starts at buffer head.
	mov cs:count,0	
	mov di,cs:srcpnt   	; Address (for int) to put chars.
	mov ax,cs
	mov es,ax
	mov si,0		; Place to get chars from.
	in al,intcont		; Set up 8259 interrupt	controller.
	and al,MDMINTO		; Enable INT4.
	out intcont,al
	mov dx,mdmcom		; Set up baud, parity, etc.
	mov al,3		; (baud set independently)
	out dx,al
	mov dx,03F9H		; Interrupt enable register.
	mov al,1
	out dx,al
	mov dl,0FCH		; Enable int's from serial card.
	mov al,0BH
	out dx,al
	sti	 		; Enable interrupts.
	mov dl,0F8H
	in al,dx
ENDIF
IF Z100
	mov ssp,sp		; Save current stack pointer
ENDIF
telnoe:	call plup		; Char at port (type to console) ?
IF IBMPC
	cmp al,ESC
	jne telx
	jmp telesc
ENDIF
telx:	cmp al,DEL		; Don't bother with deletes.
	je telnoe
	cmp al,XOFF		; Skip all the following too.
	je telnoe
	cmp al,XON	
	je telnoe
	cmp al,00H		; Null.
	je telnoe
IF IBMPC
	cmp al,BELL
	jne nobell
	call beep
	jmp telnoe
nobell:	mov ah,14	
	mov bx,0
	int bios
	jmp telnoe
ENDIF
IF Z100
	mov dl,al		; Get the character
	mov ah,dconio		; and the function
	int dos			; type the character
	jmp telnoe		; Get next character
ENDIF
TELNET	ENDP


	page	+
EXTLN	PROC	NEAR
IF IBMPC
	cli			; Disable interrupts.
;	push ax
	mov dx,03FCH	
	mov al,3		; Disable modem interrupts.
	out dx,al
	in al,intcont		; Interrupt control.
	or al,mdmintc		; Inhibit IRQ4.
	out intcont,al
	mov sp,ssp
	xor bx,bx
	mov cx,ds		; Save DS register.
	mov ds,bx		; Address low memory.
;	pop ax
	mov bx,6EH
	pop [bx]
	mov bx,6CH
	pop [bx]
	mov bx,mdmintv+2	; Restore old interrupt vectors.
	pop [bx]
	mov bx,mdmintv
	pop [bx]
	mov ds,cx		; Restore DS.
	xor bx,bx
	sti
ENDIF
IF Z100
	mov sp,ssp
ENDIF
	mov ah,prstr
	mov dx,offset tmsg2
	int dos
	jmp rskp
EXTLN	ENDP

	page +
IF IBMPC
; *********** serial port interrupt routine ********

SERINT	PROC  NEAR
	push dx
	push ax
	push es
	push di
	cld
	mov di,cs:srcpnt	; Registers for storing data.
	mov ax,cs
	mov es,ax
	mov dx,mdmsts		; Asynch status	port.
	in al,dx
	test al,mdminp		; Data	available?
	jz retint		; Nope.
	mov dx,mdmdat
	in al,dx
	and al,7FH		; Only want 7 bits.
	jz retint		; Ignore nulls.
	cmp al,7FH		; Ignore rubouts, too.
	jz retint
	stosb			; Store char in buffer.
	lea ax,cs:source
	sub di,ax
	and di,7FFH		; Truncate buffer here.
	add di,ax
	inc cs:count
retint:	mov cs:srcpnt,di
	sti
	mov al,eoicom
	out intcon1,al		 ;Send End-of-Interrupt to 8259.
	pop di
	pop es
	pop ax
	pop dx
intret:	iret
SERINT	ENDP
ENDIF

	page	+
PLUP	PROC	NEAR
	call prtchr
	  ret			; Got a char.
	  nop			; Use up three	bytes.
	  nop
	call conchr		;	See if char at cons (type to port).
	  jmp extln		;	Go back	to Kermit on micro.
	nop			; Make sure we have 3 bytes
	jmp plup 
PLUP	ENDP

	page	+
;************************System	Dependent****************************
 
;* These I/O routines are similar to those just	above.
 
PRTCHR	PROC	NEAR
IF IBMPC
	cmp cs:count,0
	jnz prtch2
	jmp rskp		; No data - check console.
prtch2:	cli			; Disable int's.
	mov cx,ds
	mov ax,cs
	mov ds,ax
	mov si,cs:savesi
	lodsb			; Get char from buffer.
	lea dx,cs:source
	sub si,dx
	and si,7FFH		; Truncate buffer after here.
	add si,dx
	dec cs:count
	mov cs:savesi,si 
	mov ds,cx
	sti			; Renable int's.
ENDIF
IF Z100
	push bx			; Save BX
	mov ah,chr_status	; Get the function we want
	mov al,chr_sfgs		; Get the subfunction to get status
	call bios_auxfunc	; Perform the function
	cmp bl,0		; Anything in queue?
	jne prtch1		; Yes, go get it
	pop bx			; Restore BX
	jmp rskp		; No, give skip return

prtch1:	mov ah,chr_read		; Want	to read	character
	call bios_auxfunc	; Do	it
	and al,07FH		;	Strip off parity bit
	pop bx			; And	restore	BX
ENDIF
	ret
PRTCHR	ENDP


IF IBMPC
	page	+
; Generate a short beep.

BEEP	PROC	NEAR
	mov al,10110110B	; Gen a short beep (long one losses data.)
	out timer+3,al		; Code snarfed from Technical Reference.
	mov ax,533H
	out timer+2,al
	mov al,ah
	out timer+2,al
	in al,port_b
	mov ah,al
	or al,03
	out port_b,al
	sub cx,cx
	mov bl,1
beep0:	loop beep0
	dec bl		
	jnz beep0
	mov al,ah
	out port_b,al
	ret
BEEP	ENDP 
ENDIF
 
	page	+
CONCHR	PROC	NEAR
IF IBMPC
	mov ah,1		; Get keyboard status.
	int keyb
	jnz cnc0x	
	jmp rskp
cnc0x:	mov ah,0		; Read	a char.
	int keyb
	cmp al,0		; Special char (cntrl-break)?
	jnz nobrk		; Nope.
	cmp ah,3		; 3 in ah means nul code.
	jz cnc1y		; Skip nulls.
	cmp ah,0		; Cntrl-Break?
	jne cnc1y
	xor cx,cx
	mov dx,03fbH
	in al,dx
	or al,40H		; Set send-break bit
	out dx,al
pause:	loop pause
	xor al,40H
	out dx,al
cnc1y:	jmp rskp	
ENDIF
IF Z100
	mov ah,dconio		; Determine if character present
	mov dl,0ffH		; Want input
	int dos			; Get status
	cmp al,00H		; Any characters there?
	jne nobrk		; if not, forget it
	jmp rskp		; Give skip return
ENDIF

nobrk:	mov dl,al		; Store char here.
	mov ah,escchr		; Get the escape char.
	cmp ah,dl		; Is it	an escape char?
	jz intchr		; If so	go process it.
	cmp ibmflg,0
	je conch0
	or dl,080H		; Turn on eighth bit.
conch0:	push dx
	call prtout		; Output the char to the port.
	pop dx
	mov ah,ecoflg		; Get the echo flag.
	cmp ah,0		; Is it turned on?
	jnz cnc1x
	jmp rskp		; If not we're done here.
cnc1x:	and dl,7FH
	cmp dl,BS		; Backspace?
	je cnc2x
	cmp dl,CR		; Carriage return?
	je cnc2x
IF IBMPC
	cmp dl,BELL
	jne cnc2y
	call beep
	jmp rskp
ENDIF
cnc2y:	cmp dl,20H		; Is it a control char?
	jge cnc2x	
	jmp rskp
cnc2x:	mov ah,dconio		; Direct console output.
	int dos			; Echo the char.
	jmp rskp
CONCHR	ENDP
 
CONN	PROC	NEAR		
intchr:	mov ah,dconio		; Direct console I/O.
	mov dl,0FFH		; Input.
	int dos			; Get a	char.
	mov ah,al
	cmp ah,0		 ; Is the char a null?
	jz intchr		; If so, go until we get a char.
	mov bh,ah		; Save the actual char.
	and ah,137O		; Convert to upper case.
	cmp ah,'C'		; Is it close?
	jne intch0
	ret
intch0:	cmp ah,'S'		; Is it status?
	jnz inc0x
	jmp stat01		 ; If so, jump to stat01 (it will return).
inc0x:	mov ah,bh		; Get the char.
	cmp ah,'?'		; Is it help?
	jne intch1		; If not, go to	the next check.
	mov dx,offset inthlp	; If so, get the address of the	help message.
	mov ah,prstr		; Print	it.
	int dos
	jmp intchr		; Get another char.
intch1:	mov ch,ah		; Put the char into another reg.
	mov ah,escchr		; Get the escape char.
	cmp ah,ch		; Is it	the escape char?
	jne intch2		; If not, go send a beep to the	user.
	cmp ibmflg,0
	je intc11
	or ch,080H		; Turn on high order bit. 
intc11:	mov dl,ch
	call prtout		; Output it.
	jmp rskp		; Return, we are done here.
intch2:	mov dl,'G'-100O		; Otherwise send a beep.
	mov ah,dconio
	int dos
	jmp rskp

;* Another similar I/O routine.
 
;************************System	Dependent****************************
 
prtout:	mov al,dl		; Char must be in al.
IF IBMPC
	mov dx,mdmdat
	out dx,al
ENDIF
IF Z100
	call bios_auxout	; Send the character
ENDIF
	ret
CONN	ENDP
;*

	page	+
TELESC	PROC	NEAR
IF IBMPC
	cmp vtflg,0		; Is vt52 flag on?
	jne vt0
	jmp telnoe		; Don't do	escape stuff if	it's off.
vt0:	call plup
	mov ah,al			; Get the char.
	cmp ah,'Y'		; Special char - move cursor.
	jne vt1
	jmp movcur
vt1:	cmp ah,'A'		; Less than an 'A'?
	jl vtig			; Yes -	ignore.
	cmp ah,'M'+1		; Greater than 'M'?
	jns vtig		; Yes -	ignore.
	mov al,'A'
	sub ah,al		; Else make into index.
	shl ah,1
	mov bx,offset ttab	; Load base addr of table.
	mov cl,ah		; Move a into cx.
	mov ch,00H		; Zero out high	byte.
	add bx,cx		; Double add index+offset.
	mov bx,[bx]		; Get address of routine to call.
	jmp bx
vtig:				; Ignore escape	sequence.
	push ax			; Push the char	to be output.
	mov dl,esc		; Load an escape.
	mov ah,conout		; The function code
	int dos			; and the syscal.
	pop ax			; Restore the character
	mov dl,ah		; and move to output register.
	mov ah,conout		; The function
	int dos			; and the syscall.
ENDIF
	jmp telnoe		; Return home.
TELESC	ENDP

IF IBMPC
TEL	PROC	NEAR
movcur:	call plup
	sub al,32
	mov dh,al
	mov temp,dx		; Save row position here.
	call plup
	mov dx,temp		; Restore
	sub al,32		; Comes with 37Q added on (& starts	at 1).
	mov dl,al
	mov bh,0
	mov ah,2
	int bios
	jmp telnoe

curup:	mov ah,3		; Cursor up function.
	mov bh,0
	int bios
	cmp dh,0
	je cup0
	sub dh,1
	mov ah,2
	int bios
cup0:	jmp telnoe

curdwn:	mov ah,3		; Cursor down.
	mov bh,0
	int bios
	cmp dh,24
	je cdn0
	add dh,1
	mov ah,2
	int bios
cdn0:	jmp telnoe

currt:	mov ah,3		; Cursor right.
	mov bh,0
	int bios
	cmp dl,79
	je crt0
	add dl,1
	mov ah,2
	int bios
crt0:	jmp telnoe

curlft:	mov ah,3		; Cursor left.
	mov bh,0
	int bios
	cmp dl,0
	je clt0
	sub dl,1
	mov ah,2
	int bios
clt0:	jmp telnoe

curskp:	jmp vtig		; Ignore for now.

curhm:	call locate
	jmp telnoe

curscr:	mov ah,3		; Clear to end of screen.
	mov bh,0
	int bios
	cmp dx,0
	jne csr0
	call cmblnk
	jmp telnoe
csr0:	cmp dl,0
	je csr1
	push dx
	call curln
	pop dx
	add dh,1
	mov dl,0
csr1:	mov cx,dx
	mov dx,184FH
	mov bh,7
;	mov al,25
;	sub al,ch
	mov al,0
	mov ah,7
	int bios
	jmp telnoe

curln:	mov ah,3		; Clear to end of line.
	mov bh,0
	int bios		; Get current cursor position
	mov cx,dx
	mov dl,79
	mov ah,7
	mov al,0
	mov bh,7
	int bios
	jmp telnoe

inslin:	mov ah,3		; Get cursor position.
	mov bh,0
	int bios
	mov temp,dx		; Save here.
	mov cx,dx
	mov cl,0		; Start at beginning of row.
	mov dx,184FH		; End at lower corner of screen.
	mov ax,0701H
	mov bh,7
	int bios		; Scroll down one line.
	mov dx,temp		; Get back where we were.
	mov dl,0
	mov ah,2
	mov bh,0
	int bios
	jmp telnoe

dellin:	mov ah,3
	mov bh,0
	int bios		; Get current cursor position. 
	mov temp,dx		; Remember the place.
	mov ax,0601H		; Scroll up one line.
	mov cx,dx
	mov cl,0		; Start at beginning of row.
	mov dx,184FH
	mov bh,7
	int bios
	mov dx,temp
	mov dl,0
	mov ah,2
	mov bh,0
	int bios
	jmp telnoe
	
TEL	ENDP
ENDIF

;*
 
	page +
; This is the SET command.
 
SETCOM	PROC	NEAR
	mov dx,offset settab	; Parse	a keyword from the set table.
	mov bx,offset sethlp
	mov ah,cmkey
	call comnd
	 jmp r
	call bx
	jmp rskp
SETCOM	ENDP
 
 
	page
;	This is	the ESCAPE character SET subcommand.
 
ESCAPE	PROC	NEAR

	call cmgtch		; Get a char.
	test ah,80H		;[uno1]
	jz es2			; Terminator or no?
	and ah,7FH		; Turn off minus bit.
	cmp ah,'?'
	jne es0
esch:	mov dx,offset eschlp
	mov ah,prstr
	int dos
	mov dx,offset crlf
	mov ah,prstr		;[uno1]
	int dos
	mov dx,offset kerm
	mov ah,prstr		;[uno1]
	int dos
	mov bx,cmdptr
	mov al,'$'
	mov [bx],al
	mov dx,offset cmdbuf
	mov ah,prstr		;[uno1]
	int dos
	jmp repars
es0:	mov dx,offset escmes	; Print a message.
	mov ah,prstr
	int dos
	mov ah,conin
	int dos			; Get new escape char.
	mov ah,al
	cmp ah,'?'
	je esch
	cmp ah,cr
	jne es2
es1:	mov ah,prstr
	mov dx,offset ermes3
	int dos
	ret
es2:	cmp ah,37Q		;[uno1] Is it still a control char?
	jg es1			;[uno1] No, tell him to try again
	mov escchr,ah		; Save new value.
	add ah,100Q		;[uno1] Make it printable
	mov eschr,ah		;[uno1] And displayable
	ret
ESCAPE	ENDP
 
 
	page
;	This is	the LOCAL echo SET subcommand.
 
LCAL	PROC	NEAR
	mov dx,offset ontab
	mov bx,offset onhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx			; Save the parsed value.
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp rpbx	 	;[uno1]  Didn't get a confirm.
	pop bx
	mov ecoflg,bl		; Set the local	echo flag.
	ret
LCAL	ENDP
 
	page
;	This is	the VT52 emulation SET subcommand.
 
IF IBMPC
VT52EM	PROC	NEAR
	mov dx,offset ontab
	mov bx,offset onhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r			;  Didn't get a	confirm.
	pop bx
	mov vtflg,bl		; Set the VT52 emulation flag.
	ret
VT52EM	ENDP
ENDIF
 
;	This is	the SET	IBM command.
 
	page
IBMSET	PROC	NEAR
	mov dx,offset ontab
	mov bx,offset onhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp rpbx 	 	;[uno1]  Didn't get a confirm.
	pop bx
	mov ibmflg,bl		; Set the IBM flag.
	ret
IBMSET	ENDP

;	This is	the SET	File-Warning command.
 
	page
FILWAR	PROC	NEAR
	mov dx,offset ontab
	mov bx,offset onhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp rpbx  	 	;[uno1]   Didn't get a confirm.
	pop bx
	mov flwflg,bl		; Set the IBM flag.
	ret
FILWAR	ENDP

	page
; Sets debugging mode on and off.

DEBST	PROC    NEAR
	mov dx,offset ontab
	mov bx,offset onhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp rpbx  	 	;[uno1]  Didn't get a confirm.
	pop bx
	mov debug,bl		; Set the IBM flag.
	ret
DEBST	ENDP

	page
;[uno4]
;  This function sets the server talker mode.
;

SETSRV	PROC	NEAR

	mov dx,offset ontab	;[uno4] Get the command table
	mov bx,offset onhlp	;[uno4] Get the help table
	mov ah,cmkey
	call comnd		;[uno4] Get a value
	 jmp r
	push bx			;[uno4] Save the value
	mov ah,cmcfm		;[uno4] Get a comfirm
	call comnd
	 jmp rpbx		;[uno4] Didn't get a confirm
	pop bx			;[uno4] Get the command value
	mov srvflg,bl		;[uno4] Set the flag
	ret
SETSRV	ENDP

	page
;  This	function sets the baud rate.

BAUDST	PROC	NEAR
	mov dx,offset bdtab
	mov bx,offset bdhlp
	mov ah,cmkey
	call comnd
	 jmp r
	push bx
	mov ah,cmcfm
	call comnd		; Get a confirm.
	 jmp r			; Didn't get one.
	pop bx
IF IBMPC
	mov baud,bx		; Set the IBM flag.
	mov dx,03FBH		; LCR
	in al,dx
	mov bl,al
	or ax,80H
	out dx,al
	mov dx,03F8H
	mov ax,baud
	out dx,al
	inc dx
	mov al,ah
	out dx,al
	mov dx,03FBH
	mov al,bl
	out dx,al
ENDIF
IF Z100
	mov baud,bl		;[uno1] set the baud rate
	mov bx,ds		; Set up pointer to config info
	mov es,bx		;  .  .  .
	mov bx,offset auxcnf	;	 .  .  .
	mov ah,chr_control	; Function is control
	mov al,chr_cfsu		; Subfunction	is set new config
	call bios_auxfunc	; Set the configuration
ENDIF
	ret
BAUDST	ENDP
 
	page	+
;	This is	the STATUS command.
 
STATUS	PROC	NEAR
	call stat0
	 jmp r
	jmp rskp
STATUS	ENDP
 
STAT0	PROC	NEAR
	mov ah,cmcfm
	call comnd		; Get a	confirm.
	 jmp r			;  Didn't get a	confirm.
stat01:	mov dx,offset locst	; Assume local echo on.
	cmp ecoflg,0	 	; Is the local echo flag on?
	jnz stat1		
	mov dx,offset remst	; If not say so.
stat1:	mov ah,prstr		; Print	it.
IF IBMPC
	int dos
	mov dx,offset vtemst	; Get address of the VT52 emulation string.
	cmp vtflg,0		; Is the VT52 emulation	flag on?
	jnz stat2
	mov dx,offset novtst	; If not say so.
stat2:	mov ah,prstr		; Print	it.
	int dos
ENDIF
	mov dx,offset ibmst	; Is IBM flag on?
	cmp ibmflg,0
	jnz stat3
	mov dx,offset noibm	; Say it's not.
stat3:	mov ah,prstr
	int dos
	mov dx,offset deboff	; Assume debug mode is off.
	cmp debug,0
	je stat4
	mov dx,offset debon
stat4:	mov ah,prstr
	int dos
	mov dx,offset flwon	; Assume file-warning on.
	cmp flwflg,0
	jne stat5
	mov dx,offset flwoff
stat5:	mov ah,prstr
	int dos
IF Z100
	mov dx,offset b04st
	cmp baud,B00455
	jz stat9a
	mov dx,offset b05st
	cmp baud,B0050
	jz stat9a
	mov dx,offset b07st
	cmp baud,b0075
	jz stat9a
	mov dx,offset b11st
	cmp baud,B0110
	jz stat9a
	mov dx,offset b13st
	cmp baud,B01345
	jz stat9a
	mov dx,offset b15st
	cmp baud,B0150
	jz stat9a
	mov dx,offset b06st
	cmp baud,B0600
	jne stat9b
stat9a:	jmp stat9
stat9b:	mov dx,offset b20st
	cmp baud,B2000
	jz stat9
	mov dx,offset b19st
	cmp baud,B19200
	jz stat9
	mov dx,offset b38st
	cmp baud,B38400
	jz stat9
ENDIF
	mov dx,offset b48st	; Assume 4800 baud.
	cmp baud,B4800
	jz stat9
	mov dx,offset b12st
	cmp baud,B1200
	jz stat9
	mov dx,offset b18st
	cmp baud,B1800
	jz stat9
	mov dx,offset b24st
	cmp baud,B2400
	jz stat9
	mov dx,offset b96st
	cmp baud,B9600
	jz stat9
	mov dx,offset b03st
stat9:	mov ah,prstr
	int dos
	mov ah,prstr		;[uno1] Tell about the escape char
	mov dx,offset escsta	;[uno1]
	int dos			;[uno1]
	mov dl,escchr		;[uno1] Get the excape character
	add dl,100Q		;[uno1] Make printable
	mov ah,conout		;[uno1] Print it
	int dos			;[uno1]
;	mov dx,offset srvoff	;[uno4] Get the off message
;	cmp srvflg,0		;[uno4] Is it really off?
;	je stat11		;[uno4] Yes, go print this message
;	mov dx,offset srvon	;[uno4] No, get the on message
;stat11:	mov ah,prstr		;[uno4]
;	int dos			;[uno4]
	mov dx,offset cmcrlf	; Get the address of a crlf
	mov ah,prstr		; Print it
	int dos
	jmp rskp
STAT0	ENDP
 

	page	+
;[uno4]
; This is the FINISH command.
;

FINISH	PROC NEAR

	cmp srvflg,1
	je finis1		;[uno4] Yes, go do it
	mov ah,prstr		;[uno4] Tell the user that the mode is wrong
	mov dx,offset erms21	;[uno4]
	int dos			;[uno4]
	jmp r			;[uno4] Error return

finis1:	mov ah,cmcfm		;[uno4] Get a confirm
	call comnd		;[uno4]
	 jmp r			;[uno4] Error return
	call init		;[uno4]
	mov numrtr,0		;[uno4] Set the retry counter to 0
	mov numtry,0		;[uno4] Set the try counter to 0
	call rtpos		;[uno4] Where we want to print the retry count
	mov ax,numrtr		;[uno4]
	call nout		;[uno4]
	jmp fins21		;[uno4]
finis2:	inc numtry		;[uno4] bump the try counter
fins21:	cmp numtry,maxtry	;[uno4] No response from server
	jne finis3		;[uno4] Can still try, so try (DO)
	call erpos		;[uno4] Locate to the error line
	mov ah,prstr		;[uno4] Can not do, so complain
	mov dx,offset erms22	;[uno4]
	int dos			;[uno4]
	jmp r			;[uno4] and die
finis3:	mov BYTE PTR data,'F'	;[uno4] The FINISH generic subcommand
	mov argblk,0		;[uno4] First packet
	mov argbk1,1		;[uno4] the length of an 'F'
	mov ah,'G'		;[uno4] Using the server generic commands
	call spack		;[uno4] send the finish command
	call rpack		;[uno4] try for an ack back
	 jmp finis2		;[uno4] something went wrong, so try again
	cmp ah,'E'		;[uno4] Did we get an error packet?
	jne finis4		;[uno4] No, try something completely different
	call error		;[uno4] report the error
	 jmp r			;[uno4] return in error
finis4:	cmp ah,'N'		;[uno4] a NAK?
	jne finis5		;[uno4] try again
	inc numrtr		;[uno4] Bump the retry counter
	cmp numrtr,5		;[uno4] Retryed enough?
	jl finis2		;[uno4] No, try again
	jmp finis6		;[uno4] Die.
finis5:	cmp ah,'Y'		;[uno4] an ACK?
	jne finis6		;[uno4] No, we are in trouble
	mov ah,prstr		;[uno4] Say that we are done
	mov dx,offset scrst	;[uno4]
	int dos			;[uno4]
	mov ah,prstr		;[uno4]
	mov dx,offset infms3	;[uno4]
	int dos			;[uno4]
	mov ah,prstr		;[uno4]
	mov dx,offset scrrpr	;[uno4] Position the cursor so the prompt
	int dos			;[uno4]  will appear in a reasonable place
	jmp rskp		;[uno4] Yes, just exit
finis6:	jmp r			;[uno4] nothing else to do

FINISH	ENDP
 

	page	+
;[uno4]
;  This is the BYE command.  IT causes the server to logout and also
; exits KERMIT.
;

BYE	PROC NEAR

	cmp srvflg,1		;[uno4] Is the server flag on?
	je bye1			;	No, tell the user that the mode is wrong
	mov ah,prstr
	mov dx,offset erms21
	int dos
	jmp r

bye1:	mov ah,cmcfm		;	Get a confirm
	call comnd
	 jmp r			;	No confirm, so error out
	call logo		;	Do the logout at the server
	 jmp r			;	something went wrong, so don't edit
	mov extflg,1		;	set the exit flag
	mov ah,prstr		;	clear the screen
	mov dx,offset clrscr
	int dos
	jmp rskp		;[uno4] Go cause an exit.

BYE	ENDP


	page	+
;[uno4]
;  THis is the logout command.  It will cause the server to exit and
; logout the joub it was running under.  KERMIT will not exit.
;

LOGOUT	PROC	NEAR

	cmp srvflg,1		;[uno4] Is the server flag set?
	je logot1		;	Yes, go do the command
	mov ah,prstr		;	Tell the user that the mode is worng
	mov dx,offset erms21
	int dos
	jmp r			;	error return

logot1:	call logo		;	Do the logout command
	 jmp r			;	something went wrong, so retunr in error
	jmp rskp		;[uno4]	Done, return

LOGOUT	ENDP



	page
LOGO	PROC NEAR


;[uno4]
;  THis is the LOGOUT command function to the server.  It is shared
; between the actual logout command and the bye command.
;


	call init		;[uno4]
	mov numrtr,0		;[uno4] Set the retry counter to 0
	mov numtry,0		;[uno4] Set the try counter to 0
	call rtpos		;[uno4] Where we want to print the retry count
	mov ax,numrtr		;[uno4]
	call nout		;[uno4]
	jmp logo21		;[uno4]
logo2:	inc numtry		;[uno4] bump the try counter
logo21:	cmp numtry,maxtry	;[uno4] No response from server
	jne logo3		;[uno4] Can still try, so try 
	call erpos		;[uno4] Locate to the error line
	mov ah,prstr		;[uno4] Can not do, so complain
	mov dx,offset erms23	;[uno4]
	int dos			;[uno4]
	jmp r			;[uno4] and die
logo3:	mov BYTE PTR data,'L'	;[uno4] The LOGOUT generic subcommand
	mov argblk,0		;[uno4] First packet
	mov argbk1,1		;[uno4] the length of an 'L'
	mov ah,'G'		;[uno4] Using the server generic commands
	call spack		;[uno4] send the logout command
	call rpack		;[uno4] try for an ack back
	 jmp logo2		;[uno4] something went wrong, so try again
	cmp ah,'E'		;[uno4] Did we get an error packet?
	jne logo4		;[uno4] No, try something completely different
	call error		;[uno4] report the error
	 jmp r			;[uno4] return in error
logo4:	cmp ah,'N'		;[uno4] a NAK?
	jne logo5		;[uno4] try again
	inc numrtr		;[uno4] Bump the retry counter
	cmp numrtr,5		;[uno4] Retryed enough?
	jl logo2		;[uno4] No, try again
	jmp logo6		;[uno4] Die.
logo5:	cmp ah,'Y'		;[uno4] an ACK?
	jne logo6		;[uno4] No, we are in trouble
	mov ah,prstr		;[uno4] Say that we are done
	mov dx,offset scrst	;[uno4]
	int dos			;[uno4]
	mov ah,prstr		;[uno4]
	mov dx,offset infms3	;[uno4]
	int dos			;[uno4]
	mov ah,prstr		;[uno4]
	mov dx,offset scrrpr	;[uno4] Position the cursor so the prompt
	int dos			;[uno4]  will appear in a reasonable place
	jmp rskp		;[uno4] Yes, just exit
logo6:	jmp r			;[uno4] nothing else to do


LOGO	ENDP

 
	page	+
;	Utility	routines
 
; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a	jmp addr.
 
RSKP	PROC	NEAR
	pop bp
	add bp,3
	push bp
	ret
RSKP	ENDP
 
; Jumping here is the same as a	ret.
 
R	PROC	NEAR
	ret
R	ENDP

;[uno1] Jumping here is also the same as a ret but with cleaning
;[uno1] up the stack a bit so you get back where you came from.

RPBX	PROC	NEAR
	pop bx			;[uno1]	clean up the stack
	ret			;	go home
RPBX	ENDP			;[uno1]

 
	page
; This routine prints the number in AX on the screen.
;	(Thanks	to Jeff	Damens)
 
NOUT	PROC	NEAR
	push bx			; Save some stuff.
	push cx
	push dx
	push ax
	mov bh,0		; Don't	print leading zeros.
	and ah,0F0H		; Only want high order nibble.
	mov cl,4
	shr ah,cl
	call pdig		; Print	the digit.
	pop ax			; Restore argument.
	and ah,0FH		; Just the low order nibble.
	call pdig
	mov ah,al
	and ah,0F0H		; Only want high order nibble.
	mov cl,4
	shr ah,cl
	call pdig		; Print	the digit.
	mov ah,al
	and ah,0FH		; Just the low order nibble.
	mov bh,0FFH		; Make sure at least one zero is printed.
	call pdig
	pop dx			; Restore some stuff.
	pop cx
	pop bx
	ret
NOUT	ENDP
 
	page
	; print	the digit in register AH
 
PDIG	PROC	NEAR
	push ax			; Save it.
	cmp ah,0
	jne pdig2
	cmp bh,0
	jne pdig2
	pop ax
	ret
pdig2:	mov bh,0FFH		; Set the print	zero flag.
	cmp ah,10		; Do we	use digits or a-f?
	jl usedig		; Digit.
	add ah,'A'-10		; Compute digit
	jmp havdig		; and proceed.
usedig:	add ah,'0'		; Convert to digit
havdig:	mov dl,ah
	mov ah,conout
	int dos
	pop ax
	ret
PDIG	ENDP
 

	page	+
;	This set of routines provides a	user oriented way of parsing
;	commands.  It is similar to that of the	COMND JSYS in TOPS-20.
 
 
;	This routine prints the	prompt in DE and specifies the reparse
;	address.
 
PROMPT	PROC  NEAR
	pop bx			 ; Get the return address.
	push bx			; Put it on the	stack again.
	mov cmrprs,bx		; Save as addr to go to	on reparse.
	mov bx,0			; Clear	out register.
	add bx,sp		; Get the present stack	pointer.
	mov cmostp,bx		; Save for later restoral.
	mov cmprmp,dx		; Save pointer to the prompt.
	mov bx,offset cmdbuf
	mov cmcptr,bx		; Initialize the command pointer.
	mov cmdptr,bx
	mov ah,0
	mov cmaflg,ah		; Zero the flags.
	mov cmccnt,ah
	mov cmsflg,0FFH
	mov ah,prstr
	mov dx,offset cmcrlf
	int dos
	mov ah,prstr		; Print	the prompt.
	mov dx,cmprmp
	int dos
	ret
PROMPT	ENDP
 
	page
;	This address is	jumped to on reparse.

PARSE	PROC NEAR	
repars:	mov sp,cmostp		; new sp <-- old sp
	mov bx,offset cmdbuf
	mov cmdptr,bx
	mov ah,0FFH
	mov cmsflg,ah
	mov bx,cmrprs		; Get the reparse address.
	call bx			; Go there.
 
;	This address can be jumped to on a parsing error.
 
prserr:	mov sp,cmostp		; Set new sp to	old one.
	mov bx,offset cmdbuf
	mov cmcptr,bx		; Initialize the command pointer.
	mov cmdptr,bx
	mov ah,0
	mov cmaflg,ah		; Zero the flags.
	mov cmccnt,ah
	mov cmsflg,0FFH
	mov ah,prstr
	mov dx,offset cmcrlf
	int dos
	mov ah,prstr		; Print	the prompt.
	mov dx,cmprmp		; Get the prompt.
	int dos
;* Instead return to before the	prompt call.
	mov bx,cmrprs
	call bx
PARSE	ENDP
 
	page
;	This routine parses the	specified function in AH. Any additional
;	information is in DX and BX.
;	Returns	+1 on success
;		+4 on failure (assumes a JMP follows the call)
 
CMND	PROC NEAR
comnd:	mov cmstat,ah		; Save what we are presently parsing.
	call cminbf		; Get chars until an action or a erase char.
	mov ah,cmstat		; Restore 'ah' for upcoming checks.
	cmp ah,cmcfm		; Parse	a confirm?
	jz cmcfrm		; Go get one.
	cmp ah,cmkey		; Parse	a keyword?
	jnz cm1
	jmp cmkeyw		; Try and get one.
cm1:	cmp ah,cmifi		; Parse an input file spec?
	jnz cm2
	jmp cmifil		; Go get one.
cm2:	cmp ah,cmofi		; Output file spec?
	jnz cm3
	jmp cmofil		; Go get one.
cm3:	cmp ah,cmtxt		;[uno4] Get text?
	jne cm4			;[uno4]
	jmp cmtext		;[uno4] Go get a buffer full
cm4:	mov ah,prstr		; Else give error.
	mov dx,offset cmer00	; "?Unrecognized COMND call"
	int dos
	ret

	page
; This routine gets a confirm.

cmcfrm:	call cmgtch		; Get a char.
	cmp ah,0		; Is it negative (a terminator; a space or
				; a tab will not be returned here as they
				; will be seen as leading white space.)
	js cmcfr0
	ret			; If not, return failure.
cmcfr0:	and ah,7FH		; Turn off the minus bit.
	cmp ah,esc		; Is it an escape?
	jne cmcfr2
	mov ah,conout
	mov dl,bell		; Get a	bell.
	int dos
	mov ah,0
	mov cmaflg,ah		; Turn off the action flag.
	mov bx,cmcptr		; Move the pointer to before thee scape.
	dec bx
	mov cmcptr,bx
	mov cmdptr,bx
	dec cmccnt		; Decremrnt the	char count.
	jmp cmcfrm		; Try again.
cmcfr2:	cmp ah,'?'		; Curious?
	jne cmcfr3
	mov ah,prstr		; Print	something useful.
	mov dx,offset cmin00
	int dos
	mov ah,prstr
	mov dx,offset cmcrlf	; Print a crlf.
	int dos
	mov ah,prstr
	mov dx,cmprmp		; Reprint the prompt.
	int dos
	mov bx,cmdptr		; Get the pointer into the buffer.
	mov ah,'$'		; Put a	$ there	for printing.
	mov [bx],ah
	mov bx,cmcptr
	dec bx			; Decrement & save the buffer pointer.
	mov  cmcptr,bx
	mov ah,prstr
	mov dx,offset cmdbuf
	int dos
	mov ah,0		; Turn off the action flag.
	mov cmaflg,ah
	jmp repars		; Reparse everything.
 
cmcfr3:	cmp ah,ff		; Is it a form feed?
	jne cmcfr4
	call cmblnk		; If so	blank the screen.
cmcfr4:	jmp rskp
 
	page
;	This routine parses a keyword from the table pointed
;	to in DX.  The format of the table is as follows:
;
;	addr:	db	n	; Where	n is the # of entries in the table.
;		db	m	; M is the size	of the keyword.
;		db	'string$' ; Where string is the	keyword.
;		dw	ab	; Where	ab is data to be returned.
;
;	The keywords must be in	alphabetical order.


cmkeyw:	mov cmhlp,bx		; Save the help.
	mov cmptab,dx		; Save the beginning of	keyword	table.
	mov bx,dx
	mov ch,[bx]		; Get number of entries in table.
	inc bx
	mov dx,cmdptr		; Save command pointer.
	mov cmsptr,dx		; Save pointer's here.
cmky1:	cmp ch,0		; Any commands left to check?
	jne cmky2
	ret			; Fail if not.
cmky2:	dec ch
	mov cl,0		; Keep track of how many chars read in so far.
	call cmgtch		; Get a	char.
	cmp ah,0		; Do we	have a terminator?
	jns cmky2x 
	jmp cmky4		; Negative number means we do.
cmky2x:	inc bx			; Point	to first letter	of keyword.
	inc cl			; Read in another char.
	mov al,[bx]		      
	cmp ah,'a'		; Less than a?
	jl cmky21		; If so, don't capitalize.
	cmp ah,'z'+1		; More than z?
	jns cmky21
	and ah,137O		; Capitalize the letter.
cmky21:	cmp ah,al
	je cmky3
	jg cmky2y
	jmp cmky41		; Fail if ah preceeds al alphabetically.
cmky2y:	jmp cmky6		; Not this keyword - try the next.
cmky3:	inc bx			; We match here, how 'bout next	char?
	mov al,[bx]
	cmp al,'$'		; End of keyword?
	jne cmky3x
	jmp cmky7		 ; Succeed.
cmky3x:	mov dl,al		; Save al's char here.
	call cmgtch
	inc cl			; Read in another char.
	mov al,dl
	cmp ah,'a'
	jl cmky31
	cmp ah,'z'+1
	jns cmky31
	and ah,137O
cmky31:	cmp ah,9BH		; Escape Recognition (escape w/minus bit on)?
	je cmky3y
	cmp ah,0A0H		; A space?
	je cmky3y
	cmp ah,8DH		; Carriage return?
	je cmky3y
	jmp cmky38
cmky3y:	mov cmkptr,bx		; Save bx here.
	mov cmsiz,cx		; Save size info.
	mov cmchr,ah		; Save char for latter.
	call cmambg		; See if input is ambiguous or not.
	 jmp cmky32		; Succeeded (not ambiguous).
	mov ah,cmchr
	cmp ah,9BH		; Escape?
	je cmky3z
	jmp cmky41		; Fail.
cmky3z:	mov ah,conout		; Else, ring a bell.
	mov dl,bell
	int dos
	mov bx,cmcptr		; Move pointer to before the escape.
	dec bx
	mov cmcptr,bx
	mov cmdptr,bx
	dec cmccnt		; Decrement char count.
	mov bx,cmkptr		; Failed - pretend user	never typed ....
	mov cx,cmsiz		; ... in a char.
	dec cl			; Don't count the escape.
	dec bx
	mov cmaflg,0		; Reset the action flag.
	jmp cmky3		; Keep checking.
cmky32:	mov cx,cmsiz		; Restore info.
	mov bx,cmkptr		; Our place in the keyword table.
	cmp cmchr,0A0H		; Space?
	je cmky35
	cmp cmchr,8DH		; Carriage return?
	je cmky35
	dec cmcptr		; Pointer into buffer of input.
	mov dx,cmcptr
cmky33:	mov ah,[bx]		; Get next char in keyword.
	cmp ah,'$'		; Are we done yet?
	jz cmky34
	mov di,dx
	mov [di],ah
	inc bx
	inc dx
	inc cmccnt
	jmp cmky33
cmky34:	mov ah,' '
	mov di,dx
	mov [di],ah		; Put a blank in the buffer.
	inc dx
	mov cx,cmcptr		; Remember where we were (for printing below).
	mov cmcptr,dx		; Update our pointers.
	mov cmdptr,dx
	mov ah,'$'
	mov di,dx
	mov [di],ah		; Add '$' for printing.
	mov ah,prstr
	mov dx,cx		; Point to beginning of filled in data.
	int dos
	inc bx			; Point to address we'll need.
	mov bx,[bx]
	mov cmaflg,0 		; Turn off action flag.
	jmp rskp

cmky35:	inc bx
	mov ah,[bx]		; Find end of keyword. 
	cmp ah,'$'
	jne cmky35	
	inc bx
	mov bx,[bx]		; Address of next routine to call.
;	mov cmaflg,0		; Zero the action flag.
	jmp rskp

cmky38:	cmp ah,al
	jne cmky6		; Go to	end of keyword and try next.
	jmp cmky3
	   
cmky4:	and ah,7FH		; Turn off minus bit.
	cmp ah,'?'		; Need help?
	je cmky5
	cmp ah,' '		; Just a space - no error.
	je cmky51
	cmp ah,cr
	je cmky51
	cmp ah,tab
	je cmky51 
	cmp ah,esc		; Ignore escape?
	je cmky43
cmky41:	mov ah,prstr
	mov dx,offset cmer03
	int dos
	jmp prserr		; Parse	error -	give up.

cmky43:	mov ah,conout		; Ring a bell.
	mov dl,bell
	int dos
	mov bx,cmcptr
	dec bx
	mov cmcptr,bx
	mov cmdptr,bx
	dec cmccnt		; Don't count the escape.
	mov cmaflg,0		; Reset action flag.
	inc ch			; Account for a previous 'dec'.
	jmp cmky1		; Start over.

cmky5:	mov ah,prstr
	mov dx,cmhlp		; Print	the help text.
	int dos
	mov dx,offset crlf
	int dos
	mov dx,offset kerm
	int dos
	mov bx,cmdptr		; Get pointer into buffer.
	mov al,'$'
	mov [bx],al		; Add dollar sign for printing.
	mov dx,offset cmdbuf
	int dos
	dec cmcptr		; Don't keep it in the buffer.
	dec cmccnt		; Don't conut it.
	mov cmaflg,0		; Turn off the action flag.
	jmp repars

cmky51:	jmp prserr

cmky6:	inc bx			; Find end of keyword.
	mov al,[bx]
	cmp al,'$'
	jne cmky6	      
	inc bx			; Beginning of next command.
	inc bx
	inc bx
	mov dx,cmsptr		; Get old cmdptr.
	mov cmdptr,dx		; Restore.
	mov cmsflg,0FFH
	jmp cmky1		; Keep trying.

cmky7:	call cmgtch		; Get char.
	cmp ah,0
	js cmky71		; Ok if a terminator.
	dec bx
	jmp cmky6		; No match - try next keyword.
cmky71:	inc bx			; Get necessary	data.
	mov bx,[bx]
	cmp ah,9BH		; An escape?
	jne cmky72
	mov ah,prstr
	mov dx,offset prsp	; Print a space.
	int dos
	mov di,cmcptr
	dec di
	mov ah,20H
	mov [di],ah		;	Replace	escape char with space.
	mov cmaflg,0
	mov cmsflg,0FFH		; Pretend they typed a space.
cmky72:	jmp rskp

	page
; See if keyword is unambiguous	or not from what the user has typed in.

cmambg:	cmp ch,0		; Any keywords left to check?
	jne cmamb0
	ret			; If not then not ambiguous.
cmamb0:	inc bx			; Go to end of keyword ...
	mov al,[bx]		; So we can check the next one.
	cmp al,'$'
	jne cmamb0
	add bx,4		; Point to start of next keyword.
	dec cl			; Don't count	escape.
	mov dx,cmsptr		; Buffer with input typed by user.
cmamb1:	mov ah,[bx]		; Keyword char.	
	mov di,dx
	mov al,[di]		; Input char.
	cmp al,'a'		; Do capitalizing.
	jl cmam11
	cmp al,'z'+1
	jns cmam11
	and al,137O
cmam11:	cmp ah,al		; Keyword bigger than input (alphabetically)?
	jle cmamb2		; No - keep checking.
	ret			; Yes - not ambiguous.
cmamb2:	inc bx			; Advance one char.
	inc dx
	dec cl
	jnz cmamb1
	jmp rskp		; Fail - it's ambiguous.

	page
cmifil:	mov bx,dx		; Get the fcb address in bx.
	mov cmfcb,bx		; Save it.
	mov ch,0		; Initialize char count.
	mov ah,0
	mov [bx],ah		; Set the drive to default to current.
	inc bx
	mov cmfcb2,bx
	mov cl,' '
cmifi0:	mov [bx],cl		; Blank the FCB.
	inc bx
	inc ah
	cmp ah,0BH		; Twelve?
	jl cmifi0
cmifi1:	call cmgtch		; Get another char.
	cmp ah,0		; Is it an action character.
	jns cmifi2
	and ah,7FH		; Turn off the action bit.
	cmp ah,'?'		; A question mark?
	jne cmif12
	mov al,0
	mov cmaflg,al		; Blank	the action flag.
	dec cmcptr	 	; Decrement the buffer pointer.
	dec cmccnt		; Decrement count.
;	 jmp cmifi8		 ; Treat like any other	character.
	mov ah,prstr
	mov dx,offset filhlp	; Help message.
	int dos
	mov dx,offset crlf
	int dos
	mov dx,offset kerm
	int dos
	mov bx,cmdptr
	mov al,'$'
	mov [bx],al		; Put in dollar sign for printing.
	mov dx,offset cmdbuf
	int dos
	jmp repars
cmif12:	cmp ah,esc		; An escape?
	jne cmif13
	mov ah,0
	mov cmaflg,ah		; Turn off the action flag.
	mov ah,conout
	mov dl,bell
	int dos			; Ring the bell.
	mov bx,cmcptr		; Move the pointer to before the escape.
	dec bx
	mov cmcptr,bx
	mov cmdptr,bx
	dec cmccnt		; Decrement char count.
	jmp repars
cmif13:	mov ah,ch		; It must be a terminator.
	cmp ah,0		; Test the length of the file name.
	jnz cmf3x
	jmp cmifi9		; If zero complain.
cmf3x:	cmp ah,0DH
	js cmf3y
	jmp cmifi9		; If too long complain.
cmf3y:	jmp rskp		; Otherwise we have succeeded.
cmifi2:	cmp ah,'.'
	jne cmifi3
	inc ch
	mov ah,ch
	cmp ah,1H		; Any chars yet?
      	jnz cmf2x
	jmp cmifi9		 ; No, give error.
cmf2x:	cmp ah,0AH		; Tenth char?
      	js cmf2y
	jmp cmifi9		; Past it, give an error.
cmf2y:	mov dl,9H
	mov dh,0
	mov bx,cmfcb
	add bx,dx		; Point	to file	type field.
	mov cmfcb2,bx
	mov ch,9H		; Say we've gotten nine.
	jmp cmifi1		; Get the next char.
cmifi3:	cmp ah,':'
	jne cmifi4
	inc ch
	cmp ch,2H		; Is it in right place for a drive?
	jne cmifi9		; If not, complain.
	mov bx,cmfcb2
	sub bx,1
	mov ah,[bx]		; Get the drive name.
	sub ah,'@'		; Get the drive	number.
	mov cmfcb2,bx
 	mov bx,cmfcb
	mov [bx],ah		; Put it in the fcb.
	jmp cmifi1
cmifi4:	cmp ah,'*'
	jne cmifi7
	mov ah,ch
	cmp ah,8H		; Is this in the name or type field?
	jz cmifi9		; If its where the dot should be give up.
	jns cmifi5		; Type.
	mov cl,8H		; Eight	chars.
	jmp cmifi6
cmifi5:	mov cl,0CH		; Three	chars.
cmifi6:	mov bx,cmfcb2		; Get a	pointer	into the FCB.
	mov ah,'?'
	mov [bx],ah		; Put a question mark in.
	inc bx
	mov cmfcb2,bx
	inc ch
	mov ah,ch
	cmp ah,cl
	jl cmifi6		; Go fill in another.
	jmp cmifi1		; Get the next char.
cmifi7:	cmp ah,'0'
	jl cmif8x
	cmp ah,'z'+1
	jns cmif8x
	cmp ah,'A'		; Don't capitalize non-alphabetics.
	jl cmifi8
	and ah,137O		; Capitalize.
cmifi8:	mov bx,cmfcb2		; Get the pointer into the FCB.
	mov [bx],ah		; Put the char there.
	inc bx
	mov cmfcb2,bx
	inc ch
	jmp cmifi1

cmif8x:	push es
	mov cx,ds
	mov es,cx		; Scan uses ES register.
	mov di,offset spchar	; Special chars.
	mov cx,20		; Twenty of them.
	mov al,ah		; Char is in al.
	repnz scasb		; Search string for input char.
	cmp cx,0		; Was it there?
	pop es
	jnz cmifi8
 
cmifi9:	mov ah,prstr
	mov dx,offset cmer02
	int dos
	ret
 
	page
cmofil:	jmp cmifil		; For now, the same as CMIFI.



	page
cminbf:	push dx
	push bx
	mov cx,dx		; Save value here too.
	mov ah,cmaflg		; Is the action	char flag set?
	cmp ah,0
	je cminb1
	jmp cminb9		; If so	get no more chars.
cminb1:	inc cmccnt		; Increment the	char count.
	mov ah,conin		; Get a	char.
	int dos
	mov ah,al		; Keep char in 'ah'.
	mov bx,cmcptr		; Get the pointer into the buffer.
	mov [bx],ah		; Put it in the buffer.
	inc bx
	mov cmcptr,bx
	cmp ah,25O		; Is it a ^U?
	jne cminb2
cmnb12:	mov ah,prstr
	mov dx,offset clrlin
	int dos
IF IBMPC
	mov ax,0920H	 	; Write spaces.
	mov bx,7	 	; Clear the line.
	mov cx,80
	int bios
ENDIF
	mov ah,prstr
	mov dx,cmprmp		; Print	the prompt.
	int dos
	mov bx,offset cmdbuf
	mov cmcptr,bx		; Reset	the point to the start.
	mov cmccnt,0		; Zero the count.
	mov dx,cx		; Preserve original value of dx.
	jmp repars		; Go start over.
cminb2:	cmp ah,10O		; Or backspace?
	jz cminb3
	cmp ah,del		; Delete?
	jne cminb4
	mov ah,prstr		; Print	the delete string.
	mov dx,offset delstr
	int dos
cminb3:	mov ah,cmccnt		; Decrement the	char count by two.
	dec ah
	dec ah
	cmp ah,0		; Have we gone too far?
	jns cmnb32		; If not proceed.
	mov ah,conout		; Ring the bell.
	mov dl,bell
	int dos
	jmp cmnb12		; Go reprint prompt and	reparse.
cmnb32:	mov cmccnt,ah		; Save the new char count.
	mov ah,prstr		; Erase	the character.
	mov dx,offset clrspc
	int dos
	mov bx,cmcptr		; Get the pointer into the buffer.
	dec bx			; Back up in the buffer.
	dec bx
	mov cmcptr,bx
	jmp repars		; Go reparse everything.
cminb4:	cmp ah,'?'		; Is it a question mark.
	jz cminb6
	cmp ah,esc		; Is it an escape?
	jz cminb8
	cmp ah,cr		; Is it a carriage return?
	jz cminb5
	cmp ah,lf		; Is it a line feed?
	jz cminb5
	cmp ah,ff		; Is it a formfeed?
	jne cminb7
	call cmblnk
	call locate
cminb5:	mov ah,cmccnt		; Have we parsed any chars yet?
	cmp ah,1
	jnz cminb6
	jmp prserr		; If not, just start over.
cminb6:	mov ah,0FFH		; Set the action flag.
	mov cmaflg,ah
	jmp cminb9
cminb7:	jmp cminb1		; Get another char.

cminb8:	mov ah,prstr		; Don't print the escape char.
	mov dx,offset escspc
	int dos
	jmp cminb6
 
cminb9:	pop bx
	pop dx
	ret
 
	page
cmgtch:	push cx
	push bx
	push dx
cmgtc1:	mov ah,cmaflg
	cmp ah,0		; Is it set.
	jne cmgt10
	call cminbf		; If the action	char flag is not set get more.
cmgt10:	mov bx,cmdptr		; Get a	pointer	into the buffer.
	mov ah,[bx]		; Get the next char.
	inc bx
	mov cmdptr,bx
	cmp ah,' '		; Is it a space?
	jz cmgtc2
	cmp ah,tab		; Or a tab?
	jne cmgtc3
cmgtc2:	mov ah,cmsflg		; Get the space	flag.
	cmp ah,0		; Was the last char a space?
	jne cmgtc1		; Yes, get another char.
	mov ah,0FFH		; Set the space	flag.
	mov cmsflg,ah
	mov ah,' '
	pop dx
	pop bx
	jmp cmgtc5
cmgtc3:	mov al,0
	mov cmsflg,al		; Zero the space flag.
	pop dx
	pop bx
	cmp ah,esc
	jz cmgtc5
	cmp ah,'?'		; Is the user curious?
	jz cmgtc4
	cmp ah,cr
	jz cmgtc4
	cmp ah,lf
	jz cmgtc4
	cmp ah,ff
	je cmgtc4
	pop cx
	ret			; Not an action char, just return.
cmgtc4:	dec cmdptr
cmgtc5:	or ah,80H		; Make the char negative to indicate
	pop cx
	ret			; it is a terminator.

	page
	;[uno4]
	;  This routine returns some text to the buffer that BX 
	; points to.  It also returns the character count in AL.
	;

cmtext:
	push cx			;[uno4] Save registers used
	push bx

	sub cx,cx		;[uno4] Zero counter
cmtxt1:	call cmgtch		;[uno4] Get a character
	cmp ah,0		;	Is is a terminator
	jns cmtxt3		;	No, go put it away
	and ah,7FH		;	Clear the 8 bit
	cmp ah,esc		;	ESC?
	jne cmtxt2		;	No, try another terminator
	mov dl,bell		;	Make some noise
	mov ah,conout		;	since we can't complete what
	int dos			;	we don't know about
	dec cmdptr		;	Eat the ESC
	jmp cmtxt1		;	and do it all over again
cmtxt2:	cmp ah,'?'		;	??
	jne cmtxt4		;	No, go check for another
	inc cmdptr		;	Don't lose this character
cmtxt3:	mov [bx],ah		;	Put the character into the buffer
	inc bx			;	Bump the pointer
	inc cl			;	and the counter
	jmp cmtxt1		;	Do it over again
cmtxt4:	cmp ah,FF		;	Form Feed?
	jne cmtxt5		;	No, we must be finished
	call cmblnk		;	Blank the screen
cmtxt5:	mov al,cl		;	Get the character count
	pop bx			;	Restore registers
	pop cx
	ret			;[uno4] And return.

CMND	ENDP

	page
; This routine blanks the screen.

CMBLNK	PROC	NEAR		; This is stolen from the IBM example.
IF IBMPC
	mov cx,0
	mov dx,184FH
	mov bh,7
	mov ax,600H
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Get the function code
	mov dx,offset clrscr	; Want to clear the screen
	int dos			; Do it
ENDIF
	ret
CMBLNK	ENDP

	page
; Cursor control.

LOCATE	PROC	NEAR
IF IBMPC
	mov dx,0		; Go to top left corner of screen.
	mov bh,0
	mov ah,2
	int bios
ENDIF
IF Z100
	mov ah,prstr		; Function is print string
	mov dx,offset homcur	; Home cursor
	int dos			; do	it
ENDIF
	ret
LOCATE	ENDP

 
MAIN 	ENDS			; End of code section.
	END	START

