;
;			UKM7
;This program was originally written in 1977 by Ward Christensen.
;Ward's comments were removed, Terminal File and Batch Mode were
;added in 1980 by Mark Zeiger and James Mills. The original CRC
;checks were added by Paul Hansknecht in June 1981.
;Improved terminal file facilities, menus and a general tidy
;up of a very untidy program, removal of all modem dependent
;features, many bugs and adaptation for the UK CP/M Users
;Group Library by David Back. 4 May 1983.
;Version 1.5 includes many additional facilities, including a
;printer buffer, active toggling of terminal and secondary
;options, faster CRC's etc. David Back. 21 February 1984
;
;The file exchange protocols are compatible with the MODEMX
;series of programs in the US CP/M UG Library.
;UKM7 is compatible with CP/M 1.4 and CP/M 2.2.
;
FALSE	EQU	0
TRUE	EQU	0FFH

	ORG 100H
;********* SYSTEM DEPENDENT OVERLAY **************
;**** This is a general purpose overlay applicable to many systems ****
	JMP	300H	;absolute start of program

MODCTLP	EQU	0ECH	;MODEM CONTROL PORT
MODDATP	EQU	0EDH	;MODEM DATA PORT FOR SEND
MODDRCV	EQU	0EDH	;MODEM DATA PORT FOR RECEIVE
MSNDB	EQU	1	;MODEM SEND BIT (XMIT BUFF EMPTY)
MSNDR	EQU	1	;MODEM SEND READY
MRCVB	EQU	2	;MODEM RECEIVE BIT (DAV)
MRCVR	EQU	2	;MODEM RECEIVE READY
BAUD	EQU	2	;enter 1 for 1X, or 2 for 16X, or 3 for 64X
;It is important not to alter the addresses of labels below
OLID:		DB 1		;overlay identifier
TWIDTH:		DB 70		;max. terminal columns
FASTCLK:	DB  TRUE	;4 MHz or greater processor speed
BAKUPBYTE:	DB  TRUE	;true=make .BAK file
XPRFLG:		DB  TRUE	;true=menu initially off
SAVCCP:		DB  TRUE	;true=do not overwrite CCP
SAVEFLG:	DB TRUE		;true=terminal filesave initially on
ECHOFLG:	DB FALSE	;true=terminal echo initially on
INITFLG:	DB FALSE	;true=modem port already initialised
ANSBAK:		DB TRUE		;true=answerback on ^E
INMODCTLP:	IN	MODCTLP	;get port status
		RET
		DB	0	;space for memory mapped I/O's
OUTCTLP:	OUT	MODCTLP	;control
		RET
		DB	0
OUTMODDATP:	OUT	MODDATP	;send data
		RET
		DB	0
ANISND:		ANI	MSNDB	;bit to test for send ready
		RET
CPISND:		CPI	MSNDR	;value of send bit when ready
		RET
INMODDATP:	IN	MODDRCV	;get data
		RET
		DB	0
ANIRCV:		ANI	MRCVB	;bit to test for receive ready
		RET
CPIRCV:		CPI	MRCVR	;value of receive bit when ready
		RET
LOGMSSG:	DB 'David;Back;Shepperton Middx',CR,LF,0
	ORG 150H	;do not alter this org
;The routine below should work in most systems which use an 8251 USART
;Modem port must be initialised for 8 data bits and no parity
INITMOD:LXI	D,CPMS	;finish signon message
	MVI	C,9
	CALL	BDOS
	LDA	INMODCTLP+1
	CALL	HEXPRT
	LXI	D,DPMS
	MVI	C,9
	CALL	BDOS
	LDA	OUTMODDATP+1
	CALL	HEXPRT
	LXI	D,HMS
	MVI	C,9
	CALL	BDOS
	LDA	INITFLG
	ORA	A	;return if already initialsed
	RNZ
	MVI	A,0EH
	CALL	OUTCTLP	;force command instruction
	PUSH	PSW
	POP	PSW
	MVI	A,40H
	CALL	OUTCTLP	;internal reset
	PUSH	PSW
	POP	PSW
	MVI	A,6CH OR (BAUD AND 3)
	CALL	OUTCTLP	;8 bits no parity
	PUSH	PSW
	POP	PSW
	MVI	A,37H	;modem connected
	CALL	OUTCTLP
	CALL	INMODDATP
	CALL	INMODDATP ;clear buffers
	RET
;necessary because location of HEXO is not fixed
HEXPRT:	PUSH	PSW
	RAR
	RAR
	RAR
	RAR
	CALL	NIB
	POP	PSW
NIB:	ANI	0FH
	CPI	10
	JC	NU
	ADI	7
NU:	ADI	'0'
	MOV	E,A
	MVI	C,2
	CALL	BDOS
	RET
CPMS:	DB 'Control port=0$'
DPMS:	DB 'H  Data port=0$'
HMS:	DB 'H',CR,LF,'$'
;********** END OF OVERLAY AREA ************

DBUFSIZ	EQU	2	;S & R BUFFER SIZE IN KBYTES
			;2K is the normally accepted optimum
RING	EQU	8	;print ring buffer size, K bytes
ERRLIM	EQU 10		;NUMBER OF TIMES TO RETRY
			;SEND/RECEIVE ERRORS BEFORE QUIT
COMPUT EQU 'C'-40H	; ^C = Computer mode
DMENU EQU 'D'-40H	; ^D = display terminal menu
EXITCHR	EQU 'E'-40H	; ^E = exit terminal mode
TRANCHR	EQU 'T'-40H	; ^T = TRANSFER FILE
SAVECHR	EQU 'Y'-40H	; ^Y = memory save toggle
PRNCHR	EQU 'P'-40H	; ^P = printer toggle
EXTCHR	EQU '^'-40H	;SEND NEXT CHAR LITERALLY
SAVON	EQU 12H		;^R Terminal filesave on
SAVOFF	EQU 14H		;^T Terminal filesave off
;
;PROGRAM FOLLOWING IS NOT SYSTEM DEPENDENT,
;PLEASE DO NOT INTRODUCE ANY SYSTEM DEPENDENT FEATURES BELOW
;
XOFF	EQU 'S'-40H	; ^S = XOFF CHARACTER
XON	EQU 'Q'-40H	; ^Q = XON CHARACTER
CAN	EQU 'X'-40H	; ^X = CANCEL SEND/RECEIVE
EOFCHAR	EQU 'Z'-40H	; ^Z = END OF FILE
ENQ	EQU 5		; ^E Auto ID
SOH	EQU 1		; START OF HEADER
EOT	EQU 4		; END OF TEXT
ACK	EQU 6		; ACKNOWLEDGE
NAK	EQU 15H		; NOT ACKNOWLEDGE
CRC	EQU 'C'		;USED TO RQST CRC INSTEAD OF CKSUM
BDNMCH	EQU 75H		; BAD NAME MATCH
LF	EQU 10		; LINEFEED
CR	EQU 13		; CARRIAGE RETURN
BELL	EQU 7		; BELL CHARACTER
WRCON	EQU 2
LIST	EQU 5		;printer o/p
PRINT	EQU 9		;string o/p to console
OPEN	EQU 15
CLOSE	EQU 16
SRCHF	EQU 17
SRCHN	EQU 18
ERASE	EQU 19
READ	EQU 20
WRITE	EQU 21
MAKE	EQU 22
REN	EQU 23
STDMA	EQU 26
FILSIZ	EQU 35
BDOS	EQU 5
FCB	EQU 5CH
FCBEXT	EQU FCB+12
FCBRNO	EQU FCB+32

	ORG 300H	;do not alter this org
	LXI	H,0
	DAD	SP	;GET CP/M'S STACK
	SHLD	STAK	;SAVE IT
	LXI	SP,STAK ;LOCAL STACK
	CALL	INITADR	;INITIALIZE BIOS ADDRESSES
	CALL	INITCRC	;initialise crc table
	CALL	ILPRT
	DB 'UK MODEM7 D.R. Back Version 1.5',CR,LF,0
	CALL	INITMOD	;INITIALISE MODEM PORTS
	LXI	H,80H
	LXI	D,CMDBUF+1
	MVI	B,80H
	CALL	MOVE	;default buffer to cmdbuf
	MVI	A,TRUE
	STA	NFILFLG
	CALL	PROCOPT	;PROCESS CONTROL OPTIONS
RESTART:LDA	OPTION	;GET MAIN OPTION
	CPI	' '	;NO OPTION SPEC'D?
	JZ	MENU
	CPI	'M'	;MENU
	JZ	MENU2
	CALL	MOVEFCB	;MOVE 2ND HALF FCB TO FIRST HALF
	CALL	INMODDATP ;GOBBLE UP GARBAGE..
	CALL	INMODDATP ;..CHARACTERS ON LINE
	LDA	OPTION	;PROCESS MAIN OPTION
	CPI	'T'	;TERMINAL MODE?
	JZ	DSKSAVE
	CPI	'S'	;SEND A FILE?
	JZ	SENDFIL
	CPI	'R'	;RECEIVE A FILE?
	JZ	RCVFIL
MENU:	LXI	SP,STAK	;RESTORE STACK
	LXI	H,RESTSN  ;RESTORE SECTOR NUMBERS..
	LXI	D,SECNOB ;..FOR NEW FILE TRANSFER.
	MVI	B,SECNOE-SECNOB
	CALL	MOVE
	LXI	H,RESTROPT ;RESTORE OPTION TABLE
	LXI	D,OPTBL
	MVI	B,OPTBE-OPTBL
	CALL	MOVE
	LDA	LSTFLG
	STA	LSTRET	;save print toggle
	MVI	A,0
	STA	LSTFLG	;printer off
	STA	MFFLG1	;RESET MFACCESS ROUTINE..
	CMA		;..AND MULTI TRANS IN CASE..
	STA	FSTFLG	;..OF ABORT.
MENU1:	LDA	XPRFLG	;TEST IF MENU SHOULD BE SHOWN
	ORA	A
	JNZ	XPRT
MENU2:	CALL	ILPRT
	DB CR,LF
	DB 'SYNTAX: primaryoption[secondaryoptions] [d:][filename] [ afn]'
	DB CR,LF,CR,LF
	DB '            PRIMARY OPTIONS:',CR,LF
	DB ' S     Send binary files, afn list',CR,LF
	DB ' R     Receive binary files, drive:',CR,LF
	DB ' T     Terminal mode. Terminal filename optional',CR,LF
	DB ' DEL   Delete Terminal file',CR,LF
	DB ' DIR   Directory list, afn optional',CR,LF
	DB ' CPM   Exit to CP/M.',CR,LF
	DB ' X     Expert, toggle menus on/off',CR,LF
	DB ' M     Menu display',CR,LF,CR,LF
	DB '            SECONDARY OPTIONS: (for primary options S and R)'
	DB CR,LF
	DB ' N     Non batch mode, send or receive file'
	DB CR,LF
	DB ' Q     Quiet mode, remote system Send/Receive',CR,LF
	DB 'S,R,V  Monitor data Sent, Received or View file',CR,LF
	DB ' T     Go to Terminal mode after file transfers',CR,LF,0
XPRT:	CALL	ILPRT
	DB CR,LF,0
	MVI	C,25	;CURRENT DISK FUNCTION
	CALL	BDOS
	ADI	41H	;MAKE ASCII
	CALL	CTYPE
	CALL	ILPRT
	DB ' ==>>',0
	LXI	D,CMDBUF ;ENTER COMMAND
	CALL	INBUFF
	CALL	CRLF
	LXI	D,CMDBUF+2 ;POINT TO COMMAND
	CALL	ILCOMP
	DB 'CPM',0
	JNC	EXIT
	CALL	ILCOMP
	DB 'DIR',0
	JNC	DIR
	CALL	ILCOMP
	DB 'DEL',0
	JNC	NEWFILE
	LXI	D,CMDBUF
	LXI	H,FCB
	CALL	CPMLINE	;LOAD FCB
	CALL	PROCOPT
	JMP	RESTART

DIR:	CALL	DIRLST
	JMP	XPRT

EXIT:	LDA	NFILFLG
	CPI	TRUE
	CNZ	TFILWR	;write and close terminal file
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
	LHLD	STAK
	SPHL
	LDA	SAVCCP
	ORA	A
	JZ	0	;WARM BOOT
	RET		;to CCP

NEWFILE:LDA	NFILFLG
	CPI	TRUE
	JZ	MENU1	;IF NO FILE, DON'T ERASE
	LXI	D,FCB3
	MVI	C,ERASE
	CALL	BDOSRT
	MVI	A,TRUE	;DO NOT ALLOW TERMINAL..
	STA	NFILFLG	;..SAVE SINCE NO FILE..
	JMP	MENU1
;======================================
;TERMINAL ROUTINE ALLOWING MEMORY SAVE
DSKSAVE:LDA	FCB+1	;FIRST CHAR OF FILENAME
	CPI	' '	;FILE SPEC'D
	LHLD	HLSAVE
	JZ	TERM1
	LDA	NFILFLG
	CPI	TRUE
	CNZ	TFILWR	;write & close existing file
	CALL	TFLERAS
	CALL	MOVE2	;move FCB to FCB3
	LXI	D,FCB3
	MVI	C,MAKE
	CALL	BDOS
	INR	A
	JNZ	TERM0
	CALL	ILPRT
	DB 'Can''t make file',CR,LF,0
	JMP	TERM1
TERM0:	LXI	H,BOTTRAM
	SHLD	HLSAVE
	MVI	A,FALSE
	STA	NFILFLG
	STA	CTRLR	;cancel any previous ^R
TERM1:	LDA	LSTRET
	STA	LSTFLG	;restore printer toggle
	LDA	XPRFLG
	ORA	A
	JNZ	TERM3
TERM2:	LDA	NFILFLG
	CPI	TRUE
	JZ	NOTFIL
	PUSH	H
	LXI	H,FCB3
	LXI	D,TFILE
	MOV	A,M
	ORA	A
	JNZ	PUTDRV
	MVI	A,' '
	STAX	D
	INX	D
	JMP	NAME1
PUTDRV:	ADI	40H
	STAX	D
	INX	D
	MVI	A,':'
NAME1:	STAX	D
	INX	D
	INX	H
	MVI	B,8
	CALL	MOVE
	INX	D
	MVI	B,3
	CALL	MOVE
	POP	H
	CALL	ILPRT
	DB CR,LF,' ^Y    Terminal file '
TFILE:	DB '               toggle save on/off  '':'' =on',0
NOTFIL:	CALL	ILPRT
	DB CR,LF
	DB ' ^P    Printer, toggle on/off',CR,LF
	DB ' ^T    Transfer (Send) ASCII file without checks',CR,LF
	DB ' ^X    Abort transfer initiated above',CR,LF
	DB ' ^C    Computer mode, toggle echo on/off',CR,LF
	DB ' ^^    Send following character literally',CR,LF
	DB ' ^E    Exit to command menu',CR,LF
	DB ' ^D    Display terminal menu',CR,LF,0
TERM3:	LDA	NFILFLG
	ORA	A
	JNZ	TERM
	LDA	SAVEFLG
	ORA	A
	JZ	TERM
	MVI	A,':'	;indicate filesave is on
	CALL	TYPE	;dont print or inc col count
TERM:	CALL	STAT	;o/p to print & check keypress
	JZ	TERML	;NO, CHECK LINE
	CALL	KEYIN	;GET CHAR FROM KBD
	MOV	B,A
	LDA	EXACFL
	ORA	A
	MVI	A,FALSE
	STA	EXACFL
	MOV	A,B
	JNZ	NOTOG
	CPI	EXITCHR	;^E?
	JZ	MENU	;YES, RETURN TO MENU
	CPI	COMPUT	;^C Computer mode with echo
	JNZ	NOECH
	LDA	ECHOFLG
	CMA
	STA	ECHOFLG
	JMP	TERML
NOECH:	CPI	DMENU	;^D display terminal menu
	JZ	TERM2
	CPI	EXTCHR	;literal
	JZ	EXTFLG
	CPI	TRANCHR	;TEST FOR TRANSFER REQUEST (^T)
	CZ	TRANSFER ;SEND-A-FILE
	JZ	TERM3	;LOOP
	CPI	PRNCHR
	JNZ	NOTLST
	LDA	LSTFLG
	CMA
	STA	LSTFLG
	JMP	TERML
NOTLST:	CPI	SAVECHR
	JNZ	NOTOG
	LDA	NFILFLG	;DO NOT ALLOW SAVE IF..
	CPI	TRUE	;..THIS FLAG IS SET.
	JZ	TERML
	LDA	SAVEFLG
	CMA
	STA	SAVEFLG
	JMP	TERM3
EXTFLG:	MVI	A,TRUE
	STA	EXACFL
	JMP	TERML
NOTOG:	MOV	B,A
	LDA	ECHOFLG
	ORA	A
	MOV	A,B
	JZ	TSEND
	CPI	LF
	JZ	TERML	;ignore LF
	CALL	OUTMODDATP
	CALL	CTYPE	;local echo
	PUSH	PSW
	CALL	MSAVE	;local save in terminal file
	POP	PSW
	CPI	CR
	JNZ	TERML
	MVI	A,LF
	CALL	CHRSND	;send to remote
	CALL	CTYPE	;append LF
	CALL	MSAVE
	JMP	TERML
TSEND:	CALL	OUTMODDATP
TERML:	CALL	INMODCTLP
	CALL	ANIRCV
	CALL	CPIRCV
	JNZ	TERM
	CALL	INMODDATP
	ANI	7FH	;strip parity
	JZ	TERM	;ignore null
	CPI	ENQ	;auto logon
	JNZ	NOLOG
	LDA	ANSBAK
	ORA	A
	JZ	TERM
	LXI	D,LOGMSSG
NXCHAR:	LDAX	D
	INX	D
	ORA	A
	JZ	TERM
	CALL	CHRSND	;send to remote
	MOV	B,A
	LDA	ECHOFLG
	ORA	A
	MOV	A,B
	JNZ	CHRSAV
	PUSH	D
	MVI	D,0	;init count
	CALL	INMODEM	;wait 100ms for echo
	DCR	D
	POP	D
	JNZ	NXCHAR
CHRSAV:	CALL	CTYPE
	CALL	MSAVE
	JMP	NXCHAR
NOLOG:	CPI	SAVON	;auto filesave on
	JNZ	TRYT
	LDA	SAVEFLG
	ORA	A
	JNZ	TERM	;save already on
	MVI	A,TRUE
	STA	SAVEFLG	;turn on save
	STA	CTRLR	;remember
	JMP	TERM3
TRYT:	CPI	SAVOFF	;auto save off
	JNZ	ONWRD
	LDA	CTRLR
	ORA	A
	JZ	TERM	;turn save off only
	MVI	A,FALSE	;if it was turned on
	STA	SAVEFLG	;by ^R from remote
	STA	CTRLR
	JMP	TERM
ONWRD:	MOV	B,A
	LDA	ECHOFLG
	ORA	A
	MOV	A,B
	JZ	TERM5
	CPI	LF
	JZ	TERM	;ignore LF
	CALL	OUTMODDATP	;echo to distant terminal
	CPI	CR
	JNZ	TERM5
	CALL	CTYPE
	CALL	MSAVE	;save in terminal file
	MVI	A,LF
	CALL	CHRSND	;send LF
TERM5:	CALL	CTYPE
	CALL	MSAVE	;save in terminal file
	JMP	TERM
CTRLR:	DB FALSE
LASTB1:	DB 0
LASTB2:	DB 0
;=========================================
;SEND A CP/M FILE
SENDFIL:LDA	BATCHFLG ;CHECK IF MULTIPLE FILE..
	ORA	A	;..MODE IS SET.
	JZ	SENDC1
	MVI	A,TRUE	;INDICATE BATCH SEND
	STA	SENDFLG
	LDA	FSTFLG	;IF FIRST TIME THRU..
	ORA	A	;..SCAN THE COMMAND LINE..
	CNZ	TNMBUF	;..FOR MULTIPLE NAMES.
	CALL	SENDFN	;SENDS FILE NAME TO RECEIVER
	JNC	SENDC2	;CARRY SET MEANS NO MORE FILES.
	MVI	A,0	;STOP BATCH..
	STA	BATCHFLG ;..MODE OPTION.
	MVI	A,EOT	;FINAL XFER END
	CALL	SEND
	JMP	DONE
SENDC1:	LDA	FCB+1
	CPI	' '
	JZ	BLKFILE
	CALL	AMBGTS	;test for ambiguous filename
SENDC2:	CALL	CNREC	;GET NUMBER OF RECORDS
	CALL	OPENFIL
	MVI	E,80
	CALL	WAITNAK	;if a 'C' is received instead of NAK
SENDLP:	CALL	RDSECT	;then CRC mode is enabled
	JC	SENDEOF
	CALL	INCRSNO
	XRA	A
	STA	ERRCT
SENDRPT:CALL	SENDHDR
	CALL	SENDSEC
	LDA	CRCFLG
	ORA	A
	CZ	SENDCRC
	CNZ	SENDCKS
	CALL	GETACK
	JC	SENDRPT
	JMP	SENDLP
SENDEOF:MVI	A,EOT
	CALL	SEND
	CALL	GETACK
	JC	SENDEOF
	JMP	DONE
;===============================
;RECEIVE A FILE
RCVFIL:	XRA	A	;default to CRC mode
	STA	CRCFLG
RCV1FIL:LDA	BATCHFLG ;CHECK IF MULT..
	ORA	A	;..FILE MODE.
	JZ	RCVC1
	MVI	A,FALSE	;FLAG WHERE TO RETURN..
	STA	SENDFLG	;..FOR NEXT FILE TRANS.
	CALL	GETFN	;GET THE FILE NAME.
	JNC	RCVC2	;CARRY SET MEANS NO MORE FILES.
	MVI	A,0	;STOP BATCH..
	STA	BATCHFLG ;..MODE OPTION.
	JMP	DONE
RCVC1:	LDA	FCB+1	;MAKE SURE FILE IS NAMED
	CPI	' '
	JZ	BLKFILE
	JMP	RCVC3
RCVC2:	CALL	CKCPM2
	CALL	CKBAKUP
RCVC3:	CALL	ERASFIL
	CALL	MAKEFIL
	LDA	QFLG
	ORA	A
	JZ	RCVFST
RCVC4:	CALL	ILPRT	;first comment
	DB 'File open, ready to receive',CR,LF,0
RCVFST:	LDA	CRCFLG
	ORA	A
	MVI	A,NAK
	JNZ	RCV2FIL
	MVI	A,CRC	;indicate to Tx that CRC is wanted
RCV2FIL:CALL	SEND	;by sending a 'C' instead of NAK
	LDA	QFLG
	ORA	A
	JZ	RCVLP
	LDA	CRCFLG
	ORA	A
	JNZ	RCVNAKM		;if in CRC mode
	CALL	ILPRT		;then say so
	DB	'CRC in effect',cr,lf,0
	JMP	RCVLP
RCVNAKM:CALL	ILPRT		;else say checksum mode
	DB	'Checksum in effect',cr,lf,0
RCVLP:	CALL	RCVSECT
	JC	RCVEOT
	CALL	WRSECT	;sends CAN if error
	CALL	INCRSNO
	CALL	SENDACK
	JMP	RCVLP
RCVEOT:	CALL	WRBLOCK	;sends CAN if error
	CALL	SENDACK
	CALL	CLOSFIL
	JMP	DONE
;===================================
BLKFILE:CALL	ILPRT	;fatal error
	DB CR,LF,'No file specified',CR,LF,BELL,0
	JMP	MENU
;===============================
DONE:	LDA	BATCHFLG
	ORA	A
	JZ	DONETB
	LDA	QFLG
	ORA	A
	JZ	NMSTRNS
	LXI	H,FCB+1	;PUT FILE NAME IN..
	LXI	D,FTRNMSG ;..SPACES IN MESSAGE..
	MVI	B,8	;..BELOW.
	CALL	MOVE
	INX	D	;PUT FILE TYPE AFTER..
	MVI	B,3	;..SKIPPING ONE SPACE..
	CALL	MOVE	;..BELOW.	
	CALL	ILPRT	;final comment
	DB CR,LF
FTRNMSG:DB '              transferred',CR,LF,CR,LF,0	;13 SPACES
NMSTRNS:LDA	FCB	;SAVE DRIVE NO.
	STA	DISKNO
	LXI	H,FCB	;BLANK OUT FILE CONTROL BLOCKS
	CALL	INITFCBS
	LDA	DISKNO	;PUT DRIVE NUMBER BACK
	STA	FCB
	LXI	H,RESTSN ;RESTORE SECTOR NUMBERS..
	LXI	D,SECNOB ;..FOR NEW FILE TRANSFER.
	MVI	B,SECNOE-SECNOB ;ROUTINE ALSO DONE IN MENU.
	CALL	MOVE
	LDA	SENDFLG	;GOES TO EITHER SEND OR..
	ORA	A	;..RECEIVE FILE, DEPENDING..
	JNZ	SENDFIL	;..UPON WHICH ROUTINE SET..
	JMP	RCV1FIL	;..THE FLAG IN MULTI-FILE MODE.

DONETB:	MVI	A,TRUE	;INDICATE NO FILES BEING..
	STA	FSTFLG	;RESET MULTIFILE TRANS
	LDA	QFLG
	ORA	A
	JZ	DONETA
	CALL	ILPRT	;final comment
	DB CR,LF,'All transfers completed'
	DB CR,LF,BELL,0
DONETA:	LXI	SP,STAK	;restore stack
	MVI	A,CRC
	STA	CRCFLG	;turn off CRC option
	MVI	A,0FFH
	STA	FIRSTME	;set first-time flag
	LDA	TERMFLG	;SEE IF RETURN TO..
	ORA	A	;..TERMINAL MODE..
	JNZ	MENU	;..AFTER X'FER.
	CALL	CRLF
	MVI	A,'T'
	STA	OPTION
	MVI	A,' '
	STA	FCB+1	;too late to specify filename
	CALL	INMODDATP
	CALL	INMODDATP;clear usart
	JMP	DSKSAVE
;============================= SUBROUTINES ===============
MSAVE:	PUSH	PSW
	LDA	NFILFLG
	CPI	TRUE
	JZ	NOSAVE	;CANT SAVE IF NO FILE
	LDA	SAVEFLG
	CPI	FALSE
	JZ	NOSAVE
	POP	PSW
	CPI	EOFCHAR	;dont save EOF's in file
	RZ		;CP/M doesn't like them
	LHLD	HLSAVE
	MOV	M,A
	INX	H
	SHLD	HLSAVE	;MENU COMMAND DESTROYS HL-REG..
	CPI	LF
	JNZ	NOCOLON	;TYPE ":" AFTER EACH LINE FEED..
	MVI	A,':'	;..WHEN MEMORY SAVE ACTIVE.
	CALL	TYPE	;dont increment col count
NOCOLON:LDA	SAVCCP
	ORA	A
	JZ	SUB1
	LDA	7
	SBI	8	;..PAGE BELOW CCP ..
	JMP	SUB1A
SUB1:	LDA	7
SUB1A:	DCR	A	;..OR BDOS HAS BEEN..
	CMP	H	;..REACHED AND DISKSAVE IS NEEDED.
	CZ	INTDSKSV
	RET
NOSAVE:	POP	PSW
	RET
;==================================
PROCOPT:LXI	D,FCB+1
	LDAX	D
	STA	OPTION	;primary option
OPTLP:	INX	D
	LDAX	D
	CPI	' '
	JZ	CKPRI
	LXI	H,OPTBL
	MVI	B,OPTBE-OPTBL
OPTCK:	CMP	M
	JNZ	OPTNO
	MVI	M,0	;INSERT SECONDARY OPTION
	JMP	OPTLP
OPTNO:	INX	H
	DCR	B
	JNZ	OPTCK
	JMP	BDOPT
CKPRI:	LDA	FCB+1	;CHECK ON THE PRIMARY OPTION
	CPI	'X'
	JZ	EXPRT
	CPI	' '
	RZ
	CPI	'M'
	RZ
	CPI	'T'
	RZ
	CPI	'S'
	JZ	CKFILE
	CPI	'R'
	JNZ	BDOPT
	LDA	BATCHFLG ;IF MULT FILE MODE, THEN..
	ORA	A	 ;..RECV OPT MUST NOT BE NAMED
	JZ	CKFILE
	LDA	FCB+17
	CPI	' '
	RZ
BDOPT:	CALL	ILPRT	;fatal error
	DB '++Bad Syntax++',CR,LF,0
	JMP	MENU
EXPRT:	LDA	XPRFLG
	CMA
	STA	XPRFLG
	JMP	MENU
CKFILE:	LDA	FCB+17	;IF OPTION THAT NEEDS FILE NAME,..
	CPI	' '	;..THEN CHECK TO SEE IF NAME..
	RNZ		;..EXISTS.
	JMP	BDOPT
;==================================
TFILWR:	LHLD	HLSAVE
	CALL	NUMRECS	;DISK WRITE ROUTINE AS USED IN..
	CALL	WRTDSK	;..IN THE INTDSKSV ROUTINE.
	LXI	D,FCB3
	MVI	C,CLOSE
	CALL	BDOS
	MVI	A,TRUE
	STA	NFILFLG
	RET
;================================
INTDSKSV:
	MVI	A,XOFF	;SEND A CTRL-S TO STOP..
	CALL	OUTMODDATP ;..REMOTE COMPUTER OUTPUT.
	MVI	D,0	;D IS THE BUFFER COUNT
	CALL	INMODEM	;GET LAST BYTES SENT..
	STA	LASTB1 ;..AFTER CTRL-S.
	CALL	INMODEM	;ADD MORE CALLS TO INMODEM..
	STA	LASTB2 ;..AND STA LASTBYT# IF YOU ARE..
			;..LOSING BYTES WHEN MEMORY IS FULL.
	PUSH	D
	CALL	NUM1REC
	CALL	WRTDSK	;WRITE THE RECORDS
	POP	D
	LXI	H,BOTTRAM
	INR	D
	DCR	D	;TEST BUFFER COUNT FOR ZERO
	JZ	CTRLQ
	LDA	LASTB1 ;GET THE LAST BYTES THAT WERE..
	MOV	M,A	;..SAVED AND PUT THEM IN..
	INX	H	;..BOTTRAM.
	CALL	CTYPE
	DCR	D
	JZ	CTRLQ
	LDA	LASTB2
	MOV	M,A
	INX	H
	CALL	CTYPE
CTRLQ:	SHLD	HLSAVE
	MVI	A,XON	;SEND START CHARACTER..
	CALL	OUTMODDATP ;..TO REMOTE COMPUTER.
	RET
;======================================
;SUBROUTINE LOOPS UNTIL THE MODEM RECEIVES A CHARACTER OR 100ms
;RETURNS BYTE COUNT IN D OR ZERO FOR TIMEOUT
;if ^S is received it waits until ^Q is received
INMODEM:LDA	FASTCLK
	ORA	A
	LXI	B,1250
	JZ	CHKMOD
	LXI	B,2500
CHKMOD:	CALL	INMODCTLP
	CALL	ANIRCV
	CALL	CPIRCV
	JZ	GETBYTE
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	CHKMOD
	RET
GETBYTE:CALL	INMODDATP
	ANI	7FH	;clear parity
	CPI	XOFF
	JNZ	TWAIT4
	PUSH	H
	CALL	ILPRT
	DB CR,LF,'XOFF received, type ^Q to force continuation',CR,LF,0
TWAIT1:	CALL	INMODCTLP
	CALL	ANIRCV
	CALL	CPIRCV
	JZ	TWAIT2
	CALL	STAT	;local key?
	JZ	TWAIT1
	CALL	KEYIN	;get char
	CPI	XON
	JZ	TWAIT3
	JMP	TWAIT1
TWAIT2:	CALL	INMODDATP
	ANI	7FH
	CPI	XON	;remote XON?
	JNZ	TWAIT1
	CALL	ILPRT
	DB 'XON received',CR,LF,0
TWAIT3:	POP	H
	JMP	INMODEM
TWAIT4:	INR	D
	RET
;================================
NUMRECS:MVI	M,EOFCHAR
	INX	H
	LXI	D,127
	DAD	D
NUM1REC:LXI	D,-(BOTTRAM)
	DAD	D
	MOV	A,L	;DIVIDE HL BY 128..
	ORA	A
	RAL		;..TO GET THE..
	MOV	L,H	;..NUMBER OF SECTORS
	MVI	H,0
	PUSH	PSW
	DAD	H
	POP	PSW
	MVI	A,0
	ADC	L
	MOV	L,A	;RETNS WITH NUMBER OF..
	RET		;..128 BYTE RECORDS IN HL.
;======================================
WRTDSK:	LXI	D,BOTTRAM
NEXTWRT:MVI	C,STDMA
	CALL	BDOSRT
	PUSH	D
	LXI	D,FCB3
	MVI	C,WRITE
	CALL	BDOSRT
	POP	D
	INR	A
	JZ	WRTERR
	XCHG
	PUSH	D
	LXI	D,128
	DAD	D
	POP	D
	XCHG
	DCX	H
	MOV	A,H
	ORA	L
	JNZ	NEXTWRT
	CALL	RSDMA	;for CP/M 1.4
	RET
WRTERR:	CALL	ILPRT
	DB 'Terminal file write error',CR,LF,0
	RET
;==========================
BDOSRT:	PUSH	B
	PUSH	D
	PUSH	H
	CALL	BDOS
	POP	H
	POP	D
	POP	B
	RET
;============================
MOVE2:	LXI	H,FCB3
	CALL	INITFCBS
	LXI	H,FCB
	LXI	D,FCB3
	MVI	B,12
	CALL	MOVE
	RET
;=============================
;FILE TRANSFER ROUTINE - CALLED WITH 
;CONTROL-T FROM TERMINAL ROUTINE.
;TRANSFER MAY BE CANCELLED WHILE SENDING BY USING CONTROL-X.
TRANSFER:
	SHLD	HLSAVE
	PUSH	D
	PUSH	B
	PUSH	PSW
	LXI	H,FCB4
	CALL	INITFCBS ;INITIALIZES FCBS POINTED..
	LXI	H,FCB+16 ;..TO BY HL REG.
	CALL	INITFCBS
GET:	CALL	ILPRT
	DB CR,LF,'Enter file name to be transferred -  C/R TO QUIT: ',0
	LXI	D,CMDBUF
	CALL	INBUFF
	CALL	CRLF
	LDA	CMDBUF+2 ;WAS FILE ENTERED
	CPI	20H
	JZ	TRANCAN
	LXI	D,CMDBUF
	LXI	H,FCB4
	CALL	CPMLINE
	LXI	D,FCB4
	MVI	C,OPEN
	CALL	BDOS
	CPI	0FFH	;RETURN WITH 0FFH MEANS
	JNZ	CONTIN	;FILE DOES NOT EXIST
	CALL	ILPRT
	DB '++File does not exist++',CR,LF,0
TRANS2L:CALL ILPRT
	DB 'Type "^X" to cancel transfer',CR,LF
	DB 'Type "A" to re-enter name: ',BELL,0
	CALL	KEYIN
	CALL	UCASE
	CALL	CTYPE	;ECHO RESPONSE
	CALL	CRLF
	CPI	'A'
	JZ	GET
	CPI	CAN
	JZ	TRANCAN
	JMP	TRANS2L
CONTIN:	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
	LDA	ECHOFLG	;computer mode ?
	ORA	A
	JZ	READMR
	MVI	A,SAVON	;activate remote save
	CALL	CHRSND	;computer mode only
READMR:	LXI	D,FCB4
	MVI	C,READ
	CALL	BDOS
	ORA	A
	JNZ	RETNS
	CALL	SEND80C
	CPI	EOFCHAR	;END OF FILE
	JZ	RETNS
	CPI	CAN	;CANCELLATION?
	JZ	TRANC1
	JMP	READMR
RETNS:	LDA	ECHOFLG
	ORA	A
	JZ	RETN1
	MVI	A,SAVOFF
	CALL	CHRSND	;deactivate remote save
RETN1:	CALL	ILPRT
	DB CR,LF,'++File transfer completed++',CR,LF,BELL,0
	JMP	RETURN
TRANC1:	LDA	ECHOFLG
	ORA	A
	JZ	TRANCAN
	MVI	A,SAVOFF
	CALL	CHRSND	;deactivate remote save
TRANCAN:CALL	ILPRT
	DB CR,LF,'++ Transfer cancelled ++',CR,LF,BELL,0
RETURN:	POP	PSW
	POP	B
	POP	D
	LHLD	HLSAVE
	RET
;=============================
INITFCBS:		;ENTRY AT +2 WILL LEAVE..
	MVI	M,0	;..DRIVE NO. INTACT.
	INX	H	;WILL INITIALIZE AN FCB..
	MVI	B,11	;..POINTED TO BY HL-REG. FILLS 1ST POS
LOOP10:	MVI	M,' '	;..WITH 0, NEXT 11 WITH..
	INX	H	;..WITH BLANKS, AND LAST..
	DCR	B	;..21 WITH NULLS.
	JNZ	LOOP10
	MVI	B,21
LOOP11:	MVI	M,0
	INX	H
	DCR	B
	JNZ	LOOP11
	RET
;===========================
CHRSND:	PUSH	PSW
REDY:	CALL	INMODCTLP
	CALL	ANISND
	CALL	CPISND
	JNZ	REDY
	POP	PSW
	CALL	OUTMODDATP
	RET
;===============================
;used by ^T transfer
SEND80C:MVI	B,80H
	LXI	H,80H
SEND81:	MOV	A,M	;get next char
	ANI	7FH	;remove top bit
	CPI	EOFCHAR	;end of file?
	RZ
	CALL	FILTER	;ignore non printing ASCII
	JC	SEND85
	MOV	C,A
	LDA	ECHOFLG
	ORA	A
	MOV	A,C
	JNZ	SEND83
	CPI	LF	;ignore lf's in terminal mode
	JZ	SEND85
	MOV	A,C
	CALL	CHRSND	;send to remote
	CPI	CR
	JZ	SEND82
	PUSH	B
	MVI	D,0
	CALL	INMODEM	;wait 100ms for echo
	POP	B
	JZ	SEND85	;zero indicates no echo
	JMP	SEND84
SEND83:	CALL	CHRSND
	PUSH	PSW
	PUSH	B
	LXI	B,1	;zero delay
	CALL	CHKMOD	;check for XOFF from remote
	POP	B
	POP	PSW
SEND84:	CALL	CTYPE	;local console
	PUSH	B
	PUSH	H
	CALL	MSAVE	;save to memory
	POP	H
	POP	B
	JMP	SEND85
SEND82:	PUSH	B
	MVI	D,0
	CALL	INMODEM	;wait 100ms for echo
	POP	B
	JZ	SEND85	;loop until timeout
	PUSH	B
	CALL	CTYPE
	PUSH	PSW	;save inmodem flag
	PUSH	H
	CALL	MSAVE
	POP	H
	POP	PSW
	POP	B
	JMP	SEND82
SEND85:	CALL	STAT	;TEST TO SEE IF
	ORA	A	;CANCELLATION REQUESTED
	JZ	SKIP12
	CALL	KEYIN
	CPI	CAN	;cancel?
	RZ
	CPI	SAVECHR	;memory save toggle
	JNZ	SEND86
	LDA	NFILFLG
	CPI	TRUE	;cant save if no file
	JZ	SEND86
	LDA	SAVEFLG
	CMA
	STA	SAVEFLG
SEND86:	CPI	PRNCHR
	JNZ	SKIP12
	LDA	LSTFLG
	CMA
	STA	LSTFLG	;print toggle
SKIP12:	INX	H
	DCR	B
	JNZ	SEND81
	RET
;=================================-
;send filename
SENDFN:	LDA	QFLG
	ORA	A
	JZ	SWNAK
	CALL	ILPRT	;first comment
	DB 'Awaiting name NAK',CR,LF,0
SWNAK:	MVI	E,80	;80 second timeout
	CALL	WAITNLP
	MVI	A,ACK	;GOT NAK, SEND ACK
	CALL	SEND
	LXI	H,FILECT
	DCR	M
	JM	NOMRNM
	LHLD	NBSAVE	;GET FILE NAME..
	LXI	D,FCB	;..IN FCB
	MVI	B,12
	CALL	MOVE
	SHLD	NBSAVE
	CALL	SENDNM	;SEND IT
	ORA	A	;CLEAR CARRY
	RET
NOMRNM:	MVI	A,EOT
	CALL	SEND
	STC
	RET
;======================================
SENDNM:	PUSH	H
SEND1NM:MVI	D,11	;COUNT CHARS IN NAME
	MVI	C,0	;INIT CHECKSUM
	LXI	H,FCB+1	;ADDRESS NAME
NAMLPS:	MOV	A,M	;SEND NAME
	ANI	7FH	;STRIP HIGH ORDER BIT SO CP/M 2..
	CALL	SEND	;..WON'T SEND R/O FILE DESIGNATION.
	LDA	SSEEFLG
	ORA	A
	JZ	ACKLP	;already typed by SEND
	LDA	QFLG	;SHOW NAME IF..
	ORA	A	;..QFLG NOT SET.
	MOV	A,M
	CNZ	TYPE	;first comment
ACKLP:	PUSH	B	;SAVE CKSUM
	MVI	B,1	;WAIT FOR RECEIVER..
	CALL	RECV	;..TO ACKNOWLEDGE..
	POP	B	;..GETTING LETTER.
	JC	SCKSER
	CPI	ACK
	JNZ	ACKLP
	INX	H	;NEXT CHAR
	DCR	D
	JNZ	NAMLPS
	MVI	A,EOFCHAR ;TELL RECEIVER END OF NAME
	CALL	SEND
	LDA	QFLG
	ORA	A
	CNZ	CRLF	;first comment
	MOV	D,C	;SAVE CHECKSUM
	MVI	B,1
	CALL	RECV	;GET CHECKSUM..
	CMP	D	;..FROM RECEIVER.
	JZ	NAMEOK
SCKSER:	MVI	A,BDNMCH ;BAD NAME-TELL RECEIVER
	CALL	SEND
	LDA	QFLG
	ORA	A
	JZ	SKCSER1
	CALL	ILPRT	;error message
	DB 'Checksum error',CR,LF,0
SKCSER1:MVI	E,80	;DO HANDSHAKING OVER
	CALL	WAITNLP	;DON'T PRINT "AWAITING NAK" MSG
	MVI	A,ACK
	CALL	SEND
	JMP	SEND1NM
NAMEOK:	MVI	A,ACK	;GOOD NAME-TELL RECEIVER
	CALL	SEND
	POP	H
	RET	
;============================
;get filename
GETFN:	LXI	H,FCB
	CALL	INITFCBS+2 ;DOES NOT INITIALIZE DRIVE
	LDA	QFLG
	ORA	A
	JZ	GNAMELP
	CALL	ILPRT	;first comment
	DB 'Awaiting file name',CR,LF,0
GNAMELP:CALL	HSNAK
	JC	GNAMELP
	CALL	GETNM	;GET THE NAME
	CPI	EOT	;IF EOT, THEN NO MORE FILES
	JZ	NOMRNG
	ORA	A	;CLEAR CARRY
	RET
NOMRNG:	STC
	RET
;================================
GETNM:	PUSH	H
GETNM1:	MVI	C,0	;INIT CHECKSUM
	LXI	H,FCB+1
NAMELPG:MVI	B,5
	CALL	RECV	;GET CHAR
	JNC	GETNM3
	LDA	QFLG
	ORA	A
	JZ	GETNM2
	CALL	ILPRT	;error message
	DB 'Time out receiving filename',CR,LF,0
GETNM2:	JMP	GCKSER
GETNM3:	CPI	EOT	;IF EOT, THEN NO MORE FILES
	JZ	GNRET
	CPI	EOFCHAR	;GOT END OF NAME
	JZ	ENDNAME
	MOV	M,A	;PUT NAME IN FCB
	LDA	RSEEFLG
	ORA	A
	JZ	GETNM4	;already typed by RECV
	LDA	QFLG	;TYPE IT IF NO QFLG
	ORA	A
	MOV	A,M
	CNZ	CTYPE	;first comment
GETNM4:	PUSH	B	;SAVE CKSUM
	MVI	A,ACK	;ACK GETTING LETTER
	CALL	SEND
	POP	B
	INX	H	;GET NEXT CHAR
	MOV	A,L	;DON'T LET NOISE...
	CPI	7FH	;..CAUSE OVERFLOW..
	JZ	GCKSER	;..INTO PROGRAM AREA.
	JMP	NAMELPG
ENDNAME:LDA	QFLG
	ORA	A
	CNZ	CRLF	;first comment
	MOV	A,C	;SEND CHECKSUM
	CALL	SEND
	MVI	B,1
	CALL	RECV	;CHECKSUM GOOD?
	CPI	ACK	;YES IF ACK SENT..
	JZ	GNRET	;..ELSE DO OVER.
GCKSER:	LXI	H,FCB	;CLEAR FCB (EXCEPT DRIVE)..
	CALL	INITFCBS+2 ;..SINCE IT MIGHT BE DAMAGED..
	LDA	QFLG	;..BY TOO MANY CHARS.
	ORA	A
	JZ	GCK1SER
	CALL	ILPRT	;error message
	DB 'Checksum error',CR,LF,0
GCK1SER:CALL	HSNAK	;DO HANDSHAKING OVER
	JC	GCK1SER
	JMP	GETNM1
GNRET:	POP	H
	RET
;==============================
HSNAK:	MVI	A,NAK	;SEND NAK UNTIL..
	CALL	SEND	;..RECEIVING ACK.
	CALL	CKABORT	;DON'T GET HUNG UP HERE
	MVI	B,2	;WAIT 2 SECONDS..
	CALL	RECV	;..IN RECEIVE.
	CPI	ACK	;IF ACK,RETURN WITH..
	RZ		;..CARRY CLEAR.
	STC
	RET
;============================
TNMBUF:	MVI	A,FALSE	;CALL FROM SENDFIL ONLY ONCE.
	STA	FSTFLG
	STA	FILECT
	CALL	SCAN
	LXI	H,NAMEBUF
	SHLD	NBSAVE	;SAVE ADDR OF 1ST NAME
TNLP1:	CALL	TRTOBUF
	LXI	H,FCB
	LXI	D,FCBBUF
	CALL	CPMLINE	;PARSE NAME TO CP/M FORMAT
TNLP2:	CALL	MFNAME	;SEARCH FOR NAMES (* FORMAT)
	JC	NEXTNM
	LDA	FCB+10	;IF CP/M 2 $SYS FILE..
	ANI	80H	;..DON'T SEND
	JNZ	TNLP2
	LHLD	NBSAVE	;GET NAME
	LXI	D,FCB	;MOVE IT TO FCB
	XCHG
	MVI	B,12
	CALL	MOVE
	XCHG
	SHLD	NBSAVE	;ADDR OF NEXT NAME
	LXI	H,FILECT	;COUNT FILES FOUND
	INR	M
	JMP	TNLP2
;
NEXTNM:	LXI	H,NAMECT ;COUNT NAMES FOUND
	DCR	M
	JNZ	TNLP1
	LXI	H,NAMEBUF ;SAVE START OF BUFFER
	SHLD	NBSAVE
	LDA	FILECT
	ORA	A
	JZ	NOBFILE
	CPI	65	;NO MORE THAN 64 TRANSFERS
	RC
	MVI	A,64	;ONLY X'FER FIRST 64
	STA	FILECT
	RET
NOBFILE:CALL	ILPRT	;fatal error
	DB 'No file',CR,LF,0
	JMP	MENU
;==============================================-
;SCANS CMDBUF COUNTING NAMES AND PUTTING DELIMITER (SPACE)
;AFTER LAST NAME
SCAN:	PUSH	H
	LXI	H,NAMECT
	MVI	M,0
	LXI	H,CMDBUF+1 ;FIND END OF CMD LINE..
	MOV	C,M	;..AND PUT SPACE THERE.
	MVI	B,0
	LXI	H,CMDBUF+2
	DAD	B
	MVI	M,20H
	LXI	H,CMDBUF+1
	MOV	B,M
	INR	B
	INR	B
	CALL	EAT	;eat spaces
	JZ	DNSCAN
SCAN1LP:INX	H
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JNZ	SCAN1LP
	CALL	EAT
	JZ	DNSCAN
	SHLD	BGNMS	;SAVE START OF NAMES IN CMDBUF
	INR	B
	DCX	H
SCAN3LP:INX	H
	DCR	B
	JZ	DNSCAN
	MOV	A,M
	CPI	20H
	JNZ	SCAN3LP
	LDA	NAMECT	;COUNTS NAMES
	INR	A
	STA	NAMECT
	CALL	EAT
	JZ	DNSCAN
	JMP	SCAN3LP
;
DNSCAN:	MVI	M,20H	;SPACE AFTER LAST CHAR
	POP	H
	RET
;==================================
;Space eater
EAT:	INX	H
	DCR	B
	RZ
	MOV	A,M
	CPI	' '
	JZ	EAT
	RET
;==========================================
;PLACES NEXT NAME IN BUFFER SO CPMLINE MAY PARSE IT
TRTOBUF:LHLD	BGNMS
	MVI	B,0
	LXI	D,FCBBUF+2
TBLP:	MOV	A,M
	CPI	20H
	JZ	TRBFEND
	STAX	D
	INX	H
	INX	D
	INR	B	;COUNT CHARS IN NAME
	JMP	TBLP
;
TRBFEND:INX	H
	MOV	A,M	;EAT EXTRA SPACES
	CPI	20H
	JZ	TRBFEND
	SHLD	BGNMS
	LXI	H,FCBBUF+1 ;PUT # CHARS BEFORE NAME
	MOV	M,B
	RET
;====================================
;IN CP/M V.2, IF FILE IS R/O OR SYS, IT IS CHANGED TO 'BAK'.
CKCPM2:	MVI	C,12
	CALL	BDOS
	ORA	A	;RETURN 0 MEANS CP/M 1
	RZ
	MVI	C,STDMA
	LXI	D,80H
	CALL	BDOS
	MVI	C,SRCHF	;SEARCH FOR FILE
	LXI	D,FCB
	CALL	BDOS
	CPI	0FFH
	RZ
	ADD	A
	ADD	A	;MULT A-REG BY..
	ADD	A
	ADD	A	;..32 TO FIND..
	ADD	A	;..NAME IN DMA.
	LXI	H,80H
	ADD	L
	MOV	L,A	;HL POINTS TO DIR NAME
	LXI	D,9
	DAD	D	;POINT TO R/O ATTRIB BYTE
	MOV	A,M
	ANI	80H	;TEST MSB
	JNZ	MKCHG	;IF SET, MAKE CHANGE
	INX	H	;CHECK SYSTEM ATTRIB BYTE
	MOV	A,M
	ANI	80H
	RZ		;NOT $SYS OR $R/O
	DCX	H
MKCHG:	LXI	D,-8
	DAD	D	;POINT HL TO FILENAME + 1
	LXI	D,FCB+1	;MOVE DIR NAME TO FCB..
	MVI	B,11	;..WITHOUT CHANGING DRIVE.
	CALL	MOVE
	LXI	H,FCB+9	;R/O ATTRIB
	MOV	A,M
	ANI	7FH	;STRIP R/O ATTRIB
	MOV	M,A
	INX	H	;SYS ATTRIB
	MOV	A,M
	ANI	7FH
	MOV	M,A
	LXI	D,FCB
	MVI	C,30	;SET NEW ATTRIBS IN DIR
	CALL	BDOS

;MAY BE CALLED BY CKBAKUP BELOW. ITS RETURN DONE HERE
PLANCHG:LXI	H,FCB	;CHANGE NAME TO TYPE "BAK"
	LXI	D,6CH
	MVI	B,9	;MOVE DRIVE AND NAME (NOT TYPE)
	CALL	MOVE
	LXI	H,75H	;START OF TYPE IN FCB2
	MVI	M,'B'
	INX	H
	MVI	M,'A'
	INX	H
	MVI	M,'K'
	LXI	D,6CH
	MVI	C,ERASE	;ERASE ANY PREV BACKUPS
	CALL	BDOS
	LXI	H,6CH	;FCB2 DR FIELD SHOULD..
	MVI	M,0	;..0 FOR RENAME.
	LXI	D,FCB
	MVI	C,REN
	CALL	BDOS
	RET

CKBAKUP:LDA	BAKUPBYTE
	ORA	A
	RZ
	MVI	C,SRCHF
	LXI	D,FCB
	CALL	BDOS
	INR	A
	RZ	;FILE NOT FOUND
	JMP	PLANCHG	;IN "CKCPM2" - RET DONE THERE
;====================================
;receive a sector
RCVSECT:XRA	A
	STA	ERRCT
RCVRPT:	CALL	VORQ
	JZ	RCVSQ
	CALL	CRLF	;clear col count
	CALL	ILPRT	;comment message
	DB 'Awaiting # ',0
	PUSH	H	;SAVE IT
	LHLD	SECNO	;GET SECTOR NUMBER
	INX	H	;BUMP IT
	CALL	DECOUT	;PRINT SECTOR NUMBER IN DECIMAL
	CALL	ILPRT
	DB	' (', 0
	CALL	DHXOUT	;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	POP	H	;RESTORE IT
;	If CRC is in effect, there is only a 7 second wait
;	for the first SOH.  If the SOH is not received within
;	this time, then a NAK is sent which tells the sender
;	to use checksum checking instead of CRC.  This allows
;	automatic compatability with versions of MODEM that
;	do not implement Cyclic Redundancy Checking(CRC).
RCVSQ:	LDA	FIRSTME	;first SOH...
	ORA	A	;...been received?
	JZ	RCVSQ2	;yes, go get next SOH
	XRA	A	;turn off...
	STA	FIRSTME	;...first soh recvd switch
	LDA	CRCFLG	;CRC in...
	ORA	A	;...effect?
	JNZ	RCVSQ2	;no, do long wait for first SOH
	MVI	B,7	;wait for upto 7 seconds
	CALL	RECV	;get a character from modem
	JNC	RCVSQ3	;got a char, go see if SOH
	LDA	QFLG
	ORA	A
	JZ	CRCM
	CALL	ILPRT	;first comment
	DB CR,LF,'++Switching to CHECKSUM MODE++',CR,LF,0
CRCM:	MVI	A,'C'	;turn off...
	STA	CRCFLG	;...CRC mode.
	MVI	A,NAK	;send NAK to tell sender checksum
	CALL	SEND	;...is in effect & to start sending.
	JMP	RCVSECT	;go start receiving sector
;
RCVSQ2:	MVI	B,7	;10 IN ORIG PROG
	CALL	RECV
	JC	RCVSTOT
RCVSQ3:	CPI	SOH
	JZ	RCVSOH
	ORA	A	;IGNORE NULLS
	JZ	RCVSQ
	CPI	EOT
	STC
	RZ
	MOV	B,A
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
	MOV	A,B
	CALL	CRLF
	CALL	HEXO
	CALL	ILPRT	;error message
	DB 'H recv''d, not SOH',CR,LF,0
RCVSERR: MVI	B,1
	CALL	RECV
	JNC	RCVSERR
	MVI	A,NAK
	CALL	SEND
	LDA	ERRCT
	INR	A
	STA	ERRCT
	CPI	ERRLIM
	JC	RCVRPT
	LDA	QFLG
	ORA	A
	JZ	RCVSABT
	CALL	CKQUIT
	JZ	RCVSECT
RCVSABT:CALL	CLOSFIL
	CALL	ERXIT	;fatal error
	DB CR,LF,'++Unable to receive block - Aborting++$'
RCVSTOT:LDA	QFLG
	ORA	A
	JZ	RCVSERR
	CALL	ILPRT	;error message
	DB CR,LF,'++  Timeout ++ ',0
RCVPRN:	LDA	ERRCT
	CALL	HEXO
	CALL	CRLF
	JMP	RCVSERR
RCVSOH:	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	MOV	D,A
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CMA
	CMP	D
	JZ	RCVDATA
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
	CALL	ILPRT	;error message
	DB CR,LF,'++  Bad sector # in Hdr',CR,LF,0
	JMP	RCVSERR
RCVDATA:MOV	A,D
	STA	RCVSNO
	MVI	A,1
	STA	DATAFLG
	MVI	C,0	;clear checksum
	CALL	CLRCRC	;clear crc counter
	LXI	H,80H
RCVCHR:	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	MOV	M,A
	INR	L
	JNZ	RCVCHR
	XRA	A
	STA	DATAFLG
	LDA	CRCFLG
	ORA	A
	JZ	RCVCRC
	MOV	D,C
	MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	CMP	D
	JNZ	RCVCERR
CHKSNUM:LDA	RCVSNO
	MOV	B,A
	LDA	SECNO
	CMP	B
	JZ	RECVACK
	INR	A
	CMP	B
	JNZ	ABORT
	RET
RCVCRC:	MVI	E,2	;nr of crc bytes
RCV2CRC:MVI	B,1
	CALL	RECV
	JC	RCVSTOT
	DCR	E
	JNZ	RCV2CRC
	CALL	CHKCRC
	ORA	A
	JZ	CHKSNUM
	LDA	QFLG
	ORA	A
	JZ	RCVSERR
	CALL	ILPRT	;error message
	DB CR,LF,'++CRC error++',0
	JMP	RCVPRN
RCVCERR:LDA	QFLG
	ORA	A
	JZ	RCVSERR
	CALL	ILPRT	;error message
	DB '++Cksum error++ ',0
	JMP	RCVPRN
RECVACK:CALL	SENDACK
	JMP	RCVSECT
;===============================
SENDACK:MVI	A,ACK
	CALL	SEND
	RET
;===========================
;send header
SENDHDR:CALL	VORQ
	JZ	SENDHNM
	CALL	CRLF	;clear col count
	CALL	ILPRT	;comment message
	DB 'Send # ',0
	PUSH	H
	LHLD	SECNO	;GET SECTOR NUMBER
	CALL	DECOUT	;PRINT IT IN DECIMAL
	CALL	ILPRT
	DB	'  (',0
	CALL	DHXOUT	;16 BIT HEX CONVERSION & OUTPUT
	CALL	ILPRT
	DB	'H)',0
	POP	H
SENDHNM:MVI	A,SOH
	CALL	SEND
	LDA	SECNO
	CALL	SEND
	LDA	SECNO
	CMA
	CALL	SEND
	RET
;========================
SENDSEC:MVI	A,1
	STA	DATAFLG
	MVI	C,0
	CALL	CLRCRC
	LXI	H,80H
SENDC:	MOV	A,M
	CALL	SEND
	INR	L
	JNZ	SENDC
	XRA	A
	STA	DATAFLG
	RET
;===============================
SENDCKS:MOV	A,C
	CALL	SEND
	RET
;==============================
SENDCRC:PUSH	H
	LHLD	CRCVAL
	MOV	A,H
	CALL	SEND
	MOV	A,L
	CALL	SEND
	POP	H
	XRA	A
	RET
;===============================
GETACK:	MVI	B,7	;10 IN ORIG PROG
	CALL	RECVDG
	JC	GETATOT
	CPI	ACK
	RZ
	MOV	B,A
	LDA	QFLG
	ORA	A
	JZ	ACKERR
	MOV	A,B
	CALL	CRLF
	CALL	HEXO
	CALL	ILPRT	;error message
	DB 'H Recv''d, not ACK',CR,LF,0
ACKERR:	LDA	ERRCT
	INR	A
	STA	ERRCT
	CPI	ERRLIM
	RC
	LDA	QFLG
	ORA	A
	JZ	CSABORT
	CALL	CKQUIT
	STC
	RZ
CSABORT:CALL	ERXIT	;fatal error
	DB CR,LF,'Can''t send sector -- Aborting$'
GETATOT:LDA	QFLG
	ORA	A
	JZ	ACKERR
	CALL	ILPRT	;error message
	DB CR,LF,'Timeout on ACK',CR,LF,0
	JMP	ACKERR
;================================
CKABORT:LDA	QFLG
	ORA	A
	RZ	
	CALL	STAT
	RZ
	CALL	KEYIN
	CPI	CAN
	JZ	ABORT	;local abort
	RET
ERXIT:	POP	D	;print message and abort
	MVI	C,PRINT
	CALL	BDOS	;does not update col count
	CALL	CRLF	;reset col count
ABORT:	LXI	SP,STAK
ABORTL:	MVI	B,1
	CALL	RECV	;wait until sender finishes
	JNC	ABORTL
	MVI	A,CAN
	CALL	SEND
ABORTW:	MVI	B,1
	CALL	RECV	;wait until sender finishes
	JNC	ABORTW
	MVI	A,' '	;send a space to clear out ^X
	CALL	SEND
	CALL	ILPRT
	DB CR,LF,'Routine cancelled',CR,LF,BELL,0
	LXI	H,RESTROPT
	LXI	D,OPTBL
	MVI	B,OPTBE-OPTBL-2
	CALL	MOVE	;clear options except T
	XRA	A
	STA	BATCHFLG;clear N option
	JMP	DONETA
;===================================
INCRSNO:PUSH	H
	LHLD	SECNO	;GET SECTOR NUMBER
	INX	H	;BUMP IT
	SHLD	SECNO	;STORE IT
	POP	H
	RET
;===============================
AMBGTS:	LXI	H,FCB+1
	MVI	C,11
AMBIG:	MOV	A,M
	INX	H
	CPI	'?'	;test for ambiguous name
	JNZ	NOTAMB
	CALL	ILPRT	;fatal error
	DB 'Ambiguous filename not allowed',CR,LF,0
	JMP	MENU
NOTAMB:	DCR	C
	JNZ	AMBIG
	RET
;=============================
ERASFIL:LDA	BATCHFLG ;DON'T ASK FOR ERASE..
	ORA	A	;..IN MULTI-FILE MODE,..
	JNZ	NOASK
	LDA	QFLG
	ORA	A
	JZ	NOASK	;dont hang up in Q mode
TFLERAS:CALL	AMBGTS	;ambiguous name ?
	LXI	D,FCB
	MVI	C,SRCHF	;see if file exists already
	CALL	BDOS
	INR	A
	RZ
	CALL	ILPRT
	DB 'File exists -- Type ''Y'' to erase: ',BELL,0
	CALL	KEYIN
	PUSH	PSW
	CALL	CTYPE
	POP	PSW
	CALL	UCASE
	CPI	'Y'
	CALL	CRLF
	JNZ	MENU
NOASK:	LXI	D,FCB
	MVI	C,ERASE
	CALL	BDOS
	RET
;===========================
MAKEFIL:LXI	D,FCB
	MVI	C,MAKE
	CALL	BDOS
	INR	A
	RNZ
	CALL	ERXIT	;fatal error
	DB 'Error - Can''t make file',CR,LF
	DB 'Directory must be full$'
;==================================
CNREC:	MVI	C,12
	CALL	BDOS
	ORA	A	;0 means CP/M 1
	JZ	CNREC14
	MVI	C,FILSIZ ;COMPUTE FILE SIZE FUNCTION IN CP/M 2.x
	LXI	D,FCB	;POINT TO FILE CONTROL BLOCK
	CALL	BDOS
	LHLD	FCB+33	;GET RECORD COUNT
	SHLD	RCNT	;STORE IT
	LXI	H,0	;ZERO HL
	SHLD	FCB+33	;RESET RANDOM RECORD IN FCB
	RET
CNREC14:MVI	A,'?'	;MATCH ALL EXTENTS
	STA	FCBEXT
	MVI	A,0FFH
	STA	MAXEXT	;INIT MAX EXT NO.
	MVI	C,SRCHF	;GET 'SEARCH FIRST' FNC
	LXI	D,FCB
	CALL	BDOS	;READ FIRST
	INR	A	;WERE THERE ANY?
	JNZ	SOME	;GOT SOME
	CALL	ERXIT	;fatal error
	DB '++File not found++$'
;POINT TO DIRECTORY ENTRY
SOME:	DCR	A	;UNDO PREV 'INR A'
	ANI	3	;MAKE MODULUS 4
	ADD	A	;MULTIPLY...
	ADD	A	;..BY 32 BECAUSE
	ADD	A	;..EACH DIRECTORY
	ADD	A	;..ENTRY IS 32
	ADD	A	;..BYTES LONG
	LXI	H,80H ;POINT TO BUFFER
	ADD	L	;POINT TO ENTRY
	ADI	15	;OFFSET TO RECORD COUNT
	MOV	L,A	;HL NOW POINTS TO REC COUNT
	MOV	B,M	;GET RECORD COUNT
	DCX	H
	DCX	H	;BACK DOWN TO EXTENT NUMBER
	DCX	H
	LDA	MAXEXT	;COMPARE WITH CURRENT MAX.
	ORA	A	;IF NO MAX YET
	JM	BIGGER	;THEN SAVE RECORD COUNT ANYWAY
	CMP	M
	JNC	MOREDIR
BIGGER:	MOV	A,B	;SAVE NEW RECORD COUNT
	STA	RCNT
	MOV	A,M	;SAVE NEW MAX. EXTENT NO.
	STA	MAXEXT
MOREDIR:MVI	C,SRCHN	;SEARCH NEXT
	LXI	D,FCB
	CALL	BDOS	;READ DIR ENTRY
	INR	A	;CHECK FOR END (0FFH)
	JNZ	SOME	;NOT END OF DIR...PROCESS EXTENT
	LDA	MAXEXT	;HIT END...GET HIGHEST EXTENT NO. SEEN
	MOV	L,A	;WHICH GIVES EXTENT COUNT -1
	MVI	H,0
	MOV	D,H
	LDA	RCNT	;GET RECORD COUNT OF MAX EXTENT SEEN
	MOV	E,A	;SAVE IT IN DE
	DAD	H
	DAD	H	;MULTIPLY # OF EXTENTS -1
	DAD	H	; TIMES 128
	DAD	H
	DAD	H
	DAD	H
	DAD	H
	DAD	D	;ADD IN SIZE OF LAST EXTENT
	SHLD	RCNT	;SAVE TOTAL RECORD COUNT
	RET
;==================================
OPENFIL:XRA	A
	STA	FCBEXT
	LXI	D,FCB
	MVI	C,OPEN
	CALL	BDOS
	INR	A
	JNZ	OPENOK
	CALL	ERXIT	;fatal error
	DB 'Can''t open file$'
OPENOK:	CALL	VORQ
	RZ
	CALL	ILPRT	;comment message
	DB 'File open, size: ',0
	LHLD	RCNT	;GET RECORD COUNT
	CALL	DECOUT	;PRINT NUMBER OF SECTORS IN DECIMAL
	CALL	ILPRT	;PRINT
	DB	' (',0
	CALL	DHXOUT
	CALL	ILPRT
	DB	'H) sectors',CR,LF,0
	RET
;=============================
CLOSFIL:LXI	D,FCB
	MVI	C,CLOSE
	CALL	BDOS
	INR	A
	RNZ
	CALL	ERXIT	;fatal error
	DB 'Can''t close file$'
;================================
RDSECT:	LDA	SECINBF
	DCR	A
	STA	SECINBF
	JM	RDBLOCK
	LHLD	SECPTR
	LXI	D,80H
	CALL	MOVE128
	SHLD	SECPTR
	RET
RDBLOCK:LDA	EOFLG
	CPI	1
	STC
	RZ
	MVI	C,0
	LXI	D,DBUF
RDSECLP:PUSH	B
	PUSH	D
	MVI	C,STDMA
	CALL	BDOS
	LXI	D,FCB
	MVI	C,READ
	CALL	BDOS
	POP	D
	POP	B
	ORA	A
	JNZ	REOF
	LXI	H,80H
	DAD	D
	XCHG
	INR	C
	MOV	A,C
	CPI	DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
	JZ	RDBFULL
	JMP	RDSECLP
REOF:	MVI	A,1
	STA	EOFLG
	MOV	A,C
RDBFULL:STA	SECINBF
	LXI	H,DBUF
	SHLD	SECPTR
	LXI	D,80H
	MVI	C,STDMA
	CALL	BDOS
	JMP	RDSECT
;==================================
WRSECT:	LHLD	SECPTR
	XCHG
	LXI	H,80H
	CALL	MOVE128
	XCHG
	SHLD	SECPTR
	LDA	SECINBF
	INR	A
	STA	SECINBF
	CPI	DBUFSIZ*8 ;BUFFER SIZE IN 128 BYTE SECTORS
	RNZ
WRBLOCK:LDA	SECINBF
	ORA	A
	RZ
	MOV	C,A
	LXI	D,DBUF
DKWRLP:	PUSH	H
	PUSH	D
	PUSH	B
	MVI	C,STDMA
	CALL	BDOS
	LXI	D,FCB
	MVI	C,WRITE
	CALL	BDOS
	POP	B
	POP	D
	POP	H
	ORA	A
	JNZ	WRERR
	LXI	H,80H
	DAD	D
	XCHG
	DCR	C
	JNZ	DKWRLP
	XRA	A
	STA	SECINBF
	LXI	H,DBUF
	SHLD	SECPTR
RSDMA:	LXI	D,80H	;required by CP/M 1.4
	MVI	C,STDMA
	CALL	BDOS
	RET
WRERR:	CALL	RSDMA
	MVI	A,CAN
	CALL	SEND
	CALL	ERXIT	;fatal error
	DB 'Error writing file$'
;===========================================
;RECV: Receive a character
;Timeout time is in B, in seconds. Entry via 'RECVDG' deletes garbage
;characters on the line. For example, having just sent a sector, calling
;RECVDG will delete any line noise induced characters LONG before the
;ACK/NAK would be received.
RECVDG:	CALL	INMODDATP
	CALL	INMODDATP
RECV:	PUSH	D
	LDA	FASTCLK
	ORA	A
	JZ	MSEC
	MOV	A,B
	ADD	A
	MOV	B,A
MSEC:	LXI	D,15000	;60% OF ORIG 50000
	CALL	CKABORT
MWTI:	CALL	STAT	;check keyboard
	ORA	A
	JZ	MWTJ
	CALL	KEYIN	;get char
	CALL	UCASE
	CALL	FLGTGL	;toggle appropriate flag
MWTJ:	CALL	INMODCTLP
	CALL	ANIRCV
	CALL	CPIRCV	;wait for modem char
	JZ	MCHAR
	DCR	E
	JNZ	MWTI
	DCR	D
	JNZ	MWTI
	DCR	B
	JNZ	MSEC
	POP	D
	STC
	RET
MCHAR:	CALL	INMODDATP
	POP	D
	PUSH	PSW
	CALL	UPDCRC	;calc crc
	ADD	C	
	MOV	C,A
	LDA	RSEEFLG
	ORA	A
	JZ	MONIN
	LDA	VSEEFLG
	ORA	A
	JNZ	NOMONIN
	LDA	DATAFLG
	ORA	A
	JZ	NOMONIN
MONIN:	POP	PSW
	PUSH	PSW
	CALL	SHOW
NOMONIN:POP	PSW
	ORA	A
	RET
;==============================
;set/reset secondary options
FLGTGL:	PUSH	B
	PUSH	D
	PUSH	H
	LXI	H,OPTBL	;flag
	LXI	D,RESTROPT
	MVI	C,5	;do Q,R,S,V,T but NOT N
	MOV	B,A
DOCMP:	LDAX	D	;get reference
	CMP	B
	JNZ	DOCMP1
	MOV	A,B
	CMP	M	;current setting
	MOV	M,A	;clear flag
	JNZ	DOCMP1
	XRA	A
	MOV	M,A	;set flag
DOCMP1:	INX	D
	INX	H
	DCR	C
	JNZ	DOCMP
	POP	H
	POP	D
	POP	B
	RET
;=================================
SEND:	PUSH	PSW
	LDA	SSEEFLG
	ORA	A
	JZ	MONOUT
	LDA	VSEEFLG
	ORA	A
	JNZ	NOMONOT
	LDA	DATAFLG
	ORA	A
	JZ	NOMONOT
MONOUT:	POP	PSW
	PUSH	PSW
	CALL	SHOW
NOMONOT:POP	PSW
	PUSH	PSW
	CALL	UPDCRC	;calc crc
	ADD	C
	MOV	C,A
	POP	PSW
	CALL	CHRSND	;send to remote
	CALL	STAT	;check for keypress
	ORA	A
	RZ
	CALL	KEYIN	;get char
	CALL	UCASE
	CALL	FLGTGL	;toggle appropriate flag
	RET
;==================================
WAITNAK:LDA	QFLG
	ORA	A
	JZ	WAITNLP
	CALL	ILPRT	;first comment
	DB 'Awaiting initial NAK',CR,LF,0
WAITNLP:CALL	CKABORT
	MVI	B,1
	CALL	RECV
	CPI	NAK
	RZ
	CPI	CRC	;crc request?
	JZ	WAITCRC	;yes, go set crc flag
	DCR	E
	JZ	ABORT
	JMP	WAITNLP
WAITCRC:XRA	A
	STA	CRCFLG
	LDA	QFLG
	ORA	A
	RZ
	CALL	ILPRT	;first comment
	DB 'CRC request received',CR,LF,0
	RET
;===============================
;return zero = no message display
;use ahead of comment messages except first and final
VORQ:	LDA	VSEEFLG
	ORA	A
	RZ
	LDA	QFLG
	ORA	A
	RET
;==================================
INITADR:LHLD	1
	LXI	D,3
	DAD	D
	SHLD	VSTAT+1
	DAD	D
	SHLD	VKEYIN+1
	DAD	D
	SHLD	VTYPE+1
	LXI	D,33
	DAD	D
	SHLD	LISTST+1
	RET
;=================================
MOVEFCB:LXI	H,FCB+16
	LXI	D,FCB
	MVI	B,16
	CALL	MOVE
	XRA	A
	STA	FCBRNO
	STA	FCBEXT
	RET
;=========================
CMPDEHL:MOV	A,E
	CMP	L
	RNZ
	MOV	A,D
	CMP	H
	RET
;=============================
;carry set for non printing ASCII chars + VT & FF
FILTER:	CPI	8	;BS
	RC		;Byte is less than 08H
	CPI	LF+1	;
	CMC		;invert carry flag
	RNC		;get rid of VT & HT, invert BS & LF carry flag
	CPI	CR	;
	RC		;Byte is less than 0D
	RZ		;byte = LF,CR or BS, no carry
	CPI	' '	;CPI space
	RC		;Byte is between 0E & 0F, reject
	CPI	7FH	;Del char
	CMC		;printable chars to no carry, DEL to carry
	RET
;==============================
;put C into print buffer, if buffer full byte is lost
LISTOUT:MOV	A,C
	ANI	7FH	;remove top bit
	CALL	FILTER	;ignore non printing chars
	RC
LSTBUF:	LHLD	BUFEND
	XCHG
	LHLD	BUFRIN
	INX	H
	CALL	CMPDEHL
	JNZ	LBUFF1	;test for end of buffer
	LHLD	BUFBEG	;reset to start
LBUFF1:	XCHG
	LHLD	BUFROUT
	CALL	CMPDEHL
	RZ		;buffer full
	XCHG
	SHLD	BUFRIN
	MOV	M,C	;save byte in buffer
	RET
;==========================
;Check printer status, if busy return, else print one char
LISTST:	CALL	$-$
	ORA	A
	RZ		;see if printer is busy
	LHLD	BUFRIN
	XCHG
	LHLD	BUFROUT
	CALL	CMPDEHL
	RZ		;return if buffer empty
	INX	H
	PUSH	H
	LHLD	BUFEND
	XCHG
	POP	H
	CALL	CMPDEHL
	JNZ	PRBUF2
	LHLD	BUFBEG	;reset to start
PRBUF2:	SHLD	BUFROUT
	MOV	E,M
	MVI	C,LIST	;CP/M print function
	CALL	BDOS
	RET
;=============================
CONO:	MOV	C,A
	CPI	9
	JNZ	CONSOP
TAB:	MVI	A,' '
	CALL	CONSOP	;expand tabs
	LDA	COLCNT
	ANI	7
	JNZ	TAB
	RET
CONSOP:	MOV	C,A
	LDA	LSTFLG
	ORA	A
	CNZ	LISTOUT	;no tabs left by now
	MOV	A,C
	CALL	TYPE
	MOV	C,A
	LXI	H,COLCNT
	CPI	7FH
	RZ
	INR	M
	CPI	' '
	RNC
	DCR	M
	MOV	A,M
	ORA	A
	RZ
	MOV	A,C
	CPI	8
	JNZ	TRYCR
	DCR	M
	RET
TRYCR:	CPI	CR
	RNZ
	MVI	M,0
	RET
;=============================
SHOW:	CPI	LF
	JZ	CTYPE
	CPI	CR
	JZ	CTYPE
	PUSH	PSW
	PUSH	H
	LXI	H,TWIDTH
	LDA	COLCNT	;check terminal width
	CMP	M
	CNC	CRLF	;force CR,LF
	POP	H
	POP	PSW
	CPI	9
	JZ	CTYPE
	CPI	' '
	JC	SHOWHEX
	CPI	7FH
	JC	CTYPE
SHOWHEX:PUSH	PSW
	MVI	A,'('
	CALL	CTYPE
	POP	PSW
	CALL	HEXO
	MVI	A,')'
CTYPE:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	ANI	7FH	;ensure parity bits are suppressed
	CALL	CONO	;type with tabs expanded
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;=============================
CRLF:	PUSH	PSW
	MVI	A,CR
	CALL	CTYPE
	MVI	A,LF
	CALL	CTYPE
	POP	PSW
	RET
;==========================
TYPE:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	ANI	7FH	;ensure parity bits are suppressed
	MOV	C,A
VTYPE:	CALL	$-$
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;=========================
STAT:	PUSH	B
	PUSH	D
	PUSH	H
	CALL	LISTST	;o/p next char to printer
VSTAT:	CALL	$-$	;get keyboard status
	POP	H
	POP	D
	POP	B
	ORA	A
	RET
;===============================
KEYIN:	PUSH	B
	PUSH	D
	PUSH	H
VKEYIN:	CALL	$-$
	POP	H
	POP	D
	POP	B
	RET
;===========================
UCASE:	CPI	61H	;CHANGES LOWER CASE CHARACTER..
	RC		;..IN A-REG TO UPPER CASE.
	CPI	7BH
	RNC
	ANI	5FH
	RET
;============================
DECOUT:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	LXI	B,-10
	LXI	D,-1
DECOU2:	DAD	B
	INX	D
	JC	DECOU2
	LXI	B,10
	DAD	B
	XCHG
	MOV	A,H
	ORA	L
	CNZ	DECOUT
	MOV	A,E
	ADI	'0'
	CALL	CTYPE
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;======================================
; - double precision hex output routine.
DHXOUT:	PUSH	H
	PUSH	PSW
	MOV	A,H	;GET MS BYTE
	ORA	A
	CNZ	HEXO	;suppress high order if zero
	MOV	A,L	;GET LS BYTE
	CALL	HEXO	;OUTPUT LOW ORDER BYTE
	POP	PSW
	POP	H
	RET
;===============================
HEXO:	PUSH	PSW
	RAR
	RAR
	RAR
	RAR
	CALL	NIBBL
	POP	PSW
NIBBL:	ANI	0FH
	CPI	10
	JC	ISNUM
	ADI	7
ISNUM:	ADI	'0'
	JMP	CTYPE
;=====================================
;RETNS W/ ZERO SET IF RETRY ASKED. IF MULTI-FILE MODE, THEN
;NO QUESTIONS ASKED, JUST QUIT
CKQUIT:	LDA	BATCHFLG
	ORA	A
	JZ	CKQTASK	;ASK FOR RETRY
	INR	A	;RESET ZERO FLG
	RET
CKQTASK:XRA	A
	STA	ERRCT
	CALL	ILPRT
	DB 'Multiple errors encountered.',CR,LF
	DB 'Type Q to quit, R to retry:  ',BELL,0
	CALL	KEYIN
	PUSH	PSW
	CALL	CTYPE
	CALL	CRLF
	POP	PSW
	CALL	UCASE
	CPI	'R'
	RZ
	CPI	'Q'
	JNZ	CKQUIT
	ORA	A
	RET
;==============================
ILPRT:	XTHL
ILPLP:	MOV	A,M
	ORA	A
	JZ	ILPRET
	CALL	TYPE
	INX	H
	JMP	ILPLP
ILPRET:	XTHL
	RET
;=========================
MOVE128:MVI	B,128
MOVE:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE
	RET
;==================================
;Cyclic Redundancy Check Subroutines.
;The generator is X^16 + X^12 + X^5 +1 as
;recommended by CCITT
;Generate table for fast CRC calculation
INITCRC:LXI	H,CRCTBL
	MVI	C,0
GLOOP:	XCHG
	LXI	H,0
	MOV	A,C
	PUSH	B
	MVI	B,8
	XRA	H
	MOV	H,A
LLOOP:	DAD	H
	JNC	LSKIP
	MVI	A,10H
	XRA	H
	MOV	H,A
	MVI	A,21H
	XRA	L
	MOV	L,A
LSKIP:	DCR	B
	JNZ	LLOOP
	POP	B
	XCHG
	MOV	M,D
	INR	H
	MOV	M,E
	DCR	H
	INX	H
	INR	C
	JNZ	GLOOP
	RET
;=================================
;Reset CRC Accumulator for a new message.
CLRCRC:	PUSH	H
	LXI	H,0
	SHLD	CRCVAL
	POP	H
	RET
;====================================
;Update CRC Accumulator using byte in (A).
UPDCRC:	PUSH	PSW
	PUSH	B
	PUSH	D
	PUSH	H
	LHLD	CRCVAL
	XCHG
	MVI	B,0
	XRA	D
	MOV	C,A
	LXI	H,CRCTBL
	DAD	B
	MOV	A,M
	XRA	E
	MOV	D,A
	INR	H
	MOV	E,M
	XCHG
	SHLD	CRCVAL
	POP	H
	POP	D
	POP	B
	POP	PSW
	RET
;==================================
; Check CRC bytes of received message.
CHKCRC:	PUSH	H
	LHLD	CRCVAL
	MOV	A,H
	ORA	L
	POP	H
	RZ
	MVI	A,0FFH
	RET
;
CRCVAL:	DW	0
;======================================
;INBUFF    - DUPLICATES READ BUFFER ROUTINE
;SAME AS CP/M FUNCTION 10, BUT DOES
;NOT USE CTRL-C (REASON FOR ROUTINE).
;DOES ALLOW CONTROLS U, R, E, AND H (BACKSPACE).
INBUFF:	PUSH PSW
	PUSH H
	PUSH B
	PUSH D		;DE REGISTERS MUST BE PUSHED LAST
ISTART:	CALL ICLEAR	;CLEAR THE BUFFER AREA
	POP D		;GET ADDRESS OF BUFFER ON RETRIES
	PUSH D		;RESTORE STACK
	XRA A
	INX D		;ADDRESS COUNT FIELD
	STAX D		;INITIALIZE WITH A ZERO IN COUNT BYTE
	INX D
	XCHG		;ADDRESS FIRST BUFFER BYTE WITH HL
INBUFA:	CALL CONIN
	CPI 0DH		;IS IT A RETURN?
	JZ INBUFR	;IF SO, THEN RETURN
	CPI 7FH		;IS IT A DELETE?
	JZ DELETE
	CPI 8		;CTRL-H WILL BACKSPACE..
	JZ DELETE	;..OVER DELETED CHAR.
	CPI 'U'-40H	;IS IT A CTRL-U
	JZ INBUFO	;OUTPUT # CR LF AND START OVER
	CPI 'R'-40H	;CTRL-R RETYPES LINE
	JZ RETYPE
	CPI 'E'-40H
	JZ PCRLF
	CPI 20H		;NO CONTROL CHARACTERS OTHER..
	JC INBUFA	;..THAN ABOVE ALLOWED.
	MOV B,A		;SAVE INPUTTED CHARACTER
	XCHG		;SAVE HL IN DE
	POP H		;GET ADDRESS OF BUFFER IN HL
	PUSH H		;RESTORE STACK
	INX H		;ADDRESS COUNT BYTE
	INR M		;INCREASE COUNT BYTE
	DCX H		;ADDRESS MAXIMUM
	MOV A,M		;PUT MAXIMUM IN A
	INX H		;ADDRESS COUNT
	CMP M		;COMPARE COUNT TO MAXIMUM
	JC ALERT	;IF MAXIMUM, RING BELL AND WAIT FOR CR
	XCHG		;RESTORE BUFFER POINTER TO HL
	MOV M,B		;PUT INPUTTED CHARACTER IN BUFFER
	MOV A,B		;OUTPUT IT
	CALL TYPE
	INX H		;BUMP POINTER
	JMP INBUFA	;GET NEXT CHARACTER

DELETE:	XCHG		;SAVE BUFFER POINTER IN DE
	POP H		;ADDRESS BEGINNING OF BUFFER
	PUSH H		;RESTORE STACK
	INX H		;ADDRESS COUNT FIELD
	MOV B,A		;SAVE DELETE CHAR - 7FH OR 08H
	MOV A,M
	SUI 1		;DECREASE COUNT
	MOV M,A
	JC NODEL	;DON'T DELETE PAST BEGINING OF BUFFER.
	XCHG		;RESTORE BUFFER POINTER TO HL
	DCX H		;POINT TO LAST BYTE INPUTTED
	MOV A,B		;GET BACK EITHER 7FH OR 08H
	MOV B,M		;GET CHARACTER BEING DELETED
	MVI M,20H	;RESTORE BLANK
	CPI 8
	JZ BKSPC
	CPI 7FH
	JZ BKSPC0
	JMP INBUFA	;GET NEXT CHARACTER
NODEL:	INR M		;DON'T LEAVE COUNT NEGATIVE
	XCHG		;RESTORE POINTER TO HL
	JMP INBUFA
BKSPC0:	MVI A,08H
BKSPC:	CALL TYPE	;TRUE ERASE IF 08H
	MVI A,20H
	CALL TYPE
	MVI A,8
	CALL TYPE
	JMP INBUFA

INBUFO:	MVI A,'#'
	CALL TYPE
	CALL CRLF
	JMP ISTART

RETYPE:	POP D
	PUSH D
	INX D		;POINT TO CURRENT NUMBER..
	LDAX D		;..OF CHARACTERS.
	MOV B,A
	MVI A,'#'
	CALL TYPE
	CALL CRLF
	MOV A,B		;TEST IF ZERO INPUT
	ORA A
	JZ INBUFA
CTLRLP:	INX D
	LDAX D
	CALL TYPE
	DCR B
	JNZ CTLRLP
	JMP INBUFA
	
ALERT:	MVI A,7
	CALL TYPE
	DCR M
	XCHG
	JMP INBUFA

PCRLF:	CALL CRLF
	JMP INBUFA

INBUFR:	CALL CRLF
	POP D
	POP B
	POP H
	POP PSW
	RET

ICLEAR:	POP D		;ACCOUNTS FOR CALL
	POP H		;ADDRESS BUFFER IN HL
	PUSH H		;RESTORE..
	PUSH D		;..STACK
	MOV B,M		;SAVE MAXIMUM IN B
	INX H		;POINT TO FIRST..
	INX H		;..BUFFER BYTE.
	MVI A,20H
CLEARL:	MOV M,A
	INX H
	DCR B
	JNZ CLEARL
	RET

CONIN:	PUSH H
	PUSH D
	PUSH B
CONINLP:CALL STAT
	JZ CONINLP
	CALL KEYIN
	CALL UCASE
	POP B
	POP D
	POP H
	RET
;==========================================
;LOADS A COMMAND LINE ADDRESSED BY DE REGISTERS (MAX # CHARACTERS IN LINE
;IN DE, NUMBER OF CHARS IN LINE IN DE+1, LINE STARTS IN DE+2) INTO FCB
;ADDRESSED BY HL REGISTERS. THE FCB SHOULD BE AT LEAST 33 BYTES IN LENGTH.
;THE COMMAND LINE BUFFER MUST HAVE A MAXIMUM LENGTH OF AT LEAST ONE MORE
;THAN THE GREATEST NUMBER OF CHARACTERS THAT WILL BE NEEDED.

CPMLINE:PUSH PSW
	PUSH B
	PUSH D
	PUSH H
	CALL INIT	;FILLS FCBS WITH BLANKS AND NULLS
	XCHG		;GET START OF COMMAND LINE IN HL.
	INX H		;ADDRESS # BYTES IN CMD LINE.
	MOV E,M		;LOAD DE PAIR WITH # BYTES.
	MVI D,0
	INX H
	DAD D		;POINT TO BYTE AFTER LAST CHAR..
	MVI M,0DH	;..IN CMD LINE AND STORE DELIMITER.
	POP H		;RESTORE HL AND DE.
	POP D
	PUSH D
	PUSH H
	INX D		;ADDRESS START OF COMMAND.
	INX D
	CALL CDRIVE
	MVI C,8		;TRANSFER FIRST FILENAME TO FCB.
	CALL TRANS
	CPI 0DH
	JZ CDONE
	CPI 20H		;IF SPACE, THEN START OF..
	JZ NAME2	;..SECOND FILENAME.
	POP H		;FILETYPE MUST BE AFTER..
	PUSH H		;..EIGHTH BYTE OF NAME.
	LXI B,9
	DAD B
	MVI C,3		;TRANSFER TYPE OF FIRST FILE
	CALL TRANS
	CPI 0DH
	JZ CDONE
NAME2:	LDAX D		;EAT MULTIPLE SPACES..
	CPI 20H		;..BETWEEN NAMES.
	JNZ NAME2C
	INX D
	JMP NAME2
	LDAX D
	CPI 0DH		;TEST IF FIRST NAME..
	JZ CDONE	;..ONLY AND THEN SPACE.
NAME2C:	POP H		;SECOND NAME STARTS IN 16TH BYTE.
	PUSH H		;POINT HL TO THIS BYTE.
	LXI B,16
	DAD B
	CALL CDRIVE
	MVI C,8
	CALL TRANS
	CPI 0DH
	JZ CDONE
	POP H		;SECOND TYPE STARTS IN 25TH BYTE.
	PUSH H
	LXI B,25
	DAD B
	MVI C,3
	CALL TRANS
CDONE:	POP H
	PUSH H
	INX H		;POINT TO FIRST CHAR OF FIRST NAME IN FCB.
	CALL CSCAN	;CHECK FOR * (AMBIGUOUS NAMES).
	POP H
	PUSH H
	LXI B,17	;POINT TO FIRST CHAR OF SECOND NAME IN FCB.
	DAD B
	CALL CSCAN
	POP H
	POP D
	POP B
	POP PSW
	RET

INIT:	PUSH H		;INITIALIZES FCB WITH 1 NULL (FOR FIRST DRIVE),..
	PUSH B		;..11 BLANKS, 4 NULLS, 1 NULL (FOR 2ND DRIVE),..
	MVI M,0		;..11 BLANKS, AND 4 NULLS.
	INX H
	MVI B,11
	MVI A,20H
	CALL INITFILL
	MVI B,5
	MVI A,0
	CALL INITFILL
	MVI B,11
	MVI A,20H
	CALL INITFILL
	MVI B,4
	MVI A,0
	CALL INITFILL
	POP B
	POP H
	RET

INITFILL:
	MOV M,A
	INX H
	DCR B
	JNZ INITFILL
	RET

CDRIVE:	INX D		;CHECK 2ND BYTE OF FILENAME. IF IT..
	LDAX D		;..IS A ":", THEN DRIVE WAS SPECIFIED.
	DCX D
	CPI ':'
	JNZ DEFDR	;ELSE ZERO FOR DEFAULT DRIVE ('INIT' PUT ZERO)
	LDAX D
	ANI 5FH
	SUI 40H		;CALCULATE DRIVE (A=1, B=2,...)..
	MOV M,A		;..AND PLACE IT IN FCB.
	INX D		;ADDRESS FIRST BYTE OF..
	INX D		;..IN CMD LINE,..
DEFDR:	INX H		;..AND NAME FIELD IN FCB.
	RET

TRANS:	LDAX D		;TRANSFER FROM CMD LINE TO FCB..
	INX D		;..UP TO NUMBER OF CHARS SPECIFIED..
	CPI 0DH		;..BY C-REG. KEEP SCANNING FIELD..
	RZ		;..WITHOUT TRANSFER UNTIL A DELIMITING..
	CPI '.'		;..FIELD CHAR SUCH AS '.', BLANK, OR..
	RZ		;..C/R (FOR END OF CMD LINE).
	CPI 20H
	RZ
	DCR C
	JM TRANS	;ONCE C-REG IS LESS THAN ZERO, KEEP READING..
	MOV M,A		;..CMD LINE BUT DO NOT TRANSFER TO FCB.
	INX H
	JMP TRANS

CSCAN:	MVI B,8		;SCAN FILE NAME ADDRESSED BY HL.
TSTNAM:	MOV A,M
	CPI '*'		;IF '*' FOUND, FILL IN REST OF FIELD..
	JZ FILL1	;..WITH '?' FOR AMBIGUOUS NAME.
	INX H
	DCR B
	JNZ TSTNAM
	JMP TSTTYP
FILL1:	CALL FILL

TSTTYP:	MVI B,3		;SCAN AND FILL TYPE FIELD FOR NAME..
TSTLTYP:MOV A,M		;..SPECIFIED ABOVE.
	CPI '*'
	JZ FILL2
	INX H
	DCR B
	RZ
	JMP TSTLTYP
FILL2:	CALL FILL
	RET

FILL:	MVI M,'?'	;ROUTINE TRANSFERS '?'.
	INX H
	DCR B
	JNZ FILL
	RET
;======================================
;IN-LINE COMPARE. COMPARES STRING ADDRESSED BY DE-REG TO STRING
;AFTER CALL (ENDS WITH ZERO). RETURN WITH CARRY SET MEANS STRINGS
;NOT THE SAME. ALL REGISTERS EXCEPT A-REG ARE UNAFFECTED.
ILCOMP:	XTHL		;POINT HL TO 1ST CHAR.
	PUSH D
ILCMPL:	MOV A,M		;HL POINTS TO IN-LINE STRING.
	ORA A		;END OF STRING IF ZERO.
	JZ SAME
	LDAX D
	CMP M
	JNZ NOTSAME
	INX H
	INX D
	JMP ILCMPL
NOTSAME:MVI A,0		;IF NOT SAME, FINISH THRU..
NSLP:	INX H		;..STRING SO RETURN WILL..
	CMP M		;..GO TO INSTRUCTION AFTER..
	JNZ NSLP	;..STRING AND NOT REMAINDER OF STRING.
	STC
SAME:	POP D
	INX H		;AVOIDS A NOP INSTRUCTION..
	XTHL		;..WHEN RETURNING.
	RET
;==================================
;MULTI-FILE ACCESS SUBROUTINE.  ALLOWS PROCESSING
;OF MULTIPLE FILES (E.G. *.ASM) FROM DISK.  THIS
;ROUTINE BUILDS THE PROPER NAME IN THE FCB EACH
;TIME IT IS CALLED.
;THE FCB WILL BE SET UP WITH THE NEXT NAME, READY TO
;DO NORMAL PROCESSING (OPEN, READ, ETC.) WHEN ROUTINE IS CALLED.
;CARRY IS SET IF NO MORE NAMES CAN BE FOUND
MFNAME:	PUSH B
	PUSH D
	PUSH H
	MVI C,STDMA
	LXI D,80H
	CALL BDOS
	POP H
	POP D
	POP B
	XRA A
	STA FCBEXT
	LDA MFFLG1
	ORA A
	JNZ MFN01
	MVI A,1
	STA MFFLG1
	LXI H,FCB
	LXI D,MFREQ
	LXI B,12
	CALL MOVER
	LDA FCB
	STA MFCUR ;SAVE DISK IN CURR FCB
	LXI H,MFREQ
	LXI D,FCB
	LXI B,12
	CALL MOVER
	PUSH B
	PUSH D
	PUSH H
	MVI C,SRCHF
	LXI D,FCB
	CALL BDOS
	POP H
	POP D
	POP B
	JMP MFN02
MFN01:	LXI H,MFCUR
	LXI D,FCB
	LXI B,12
	CALL MOVER
	PUSH B
	PUSH D
	PUSH H
	MVI C,SRCHF
	LXI D,FCB
	CALL BDOS
	POP H
	POP D
	POP B
	LXI H,MFREQ
	LXI D,FCB
	LXI B,12
	CALL MOVER
	PUSH B
	PUSH D
	PUSH H
	MVI C,SRCHN
	LXI D,FCB
	CALL BDOS
	POP H
	POP D
	POP B
MFN02:	INR A
	STC
	JNZ MFFIX1
	STA MFFLG1
	RET
MFFIX1:	DCR A
	ANI 3
	ADD A
	ADD A
	ADD A
	ADD A
	ADD A
	ADI 81H
	MOV L,A
	MVI H,0
	PUSH H ;SAVE NAME POINTER
	LXI D,MFCUR+1
	LXI B,11
	CALL MOVER
	POP H
	LXI D,FCB+1
	LXI B,11
	CALL MOVER
	XRA A
	STA FCBEXT
	STA FCBRNO
	RET
;
;MULTI-FILE ACCESS WORK AREA
;
MFFLG1:	DB	0	;1ST TIME SW
MFREQ:	DS	12	;REQ NAME
MFCUR:	DS	12	;CURR NAME
;=====================================
;MOVE SUBROUTINE
MOVER:	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCX	B
	MOV	A,B
	ORA	C
	JNZ	MOVER
	RET
;================================
DIRLST:	LXI D,CMDBUF	;PUT COMMAND LINE IN FCB
	LXI H,5CH
	CALL CPMLINE
	LXI H,SRCHFCB
	CALL INITFCBS
	LDA 6CH		;GET DRIVE #
	STA SRCHFCB
	LDA 6DH
	CPI 20H		;IF BLANK GET ALL NAMES
	PUSH PSW
	CZ QSTMARK
	POP PSW
	CNZ MOVENAME	;ELSE MOVE NAME INTO FCB
	CALL DRIVE
	LXI D,80H
	MVI C,STDMA
	CALL BDOS
	XRA A
	STA DNAMECT	;CR AFTER 4 NAMES
	LXI D,SRCHFCB
	MVI C,SRCHF	;DO FIRST SEARCH
	CALL BDOS
	CPI 0FFH
	JZ NOFILE
DIRLP:	CALL GETADD
	LXI D,15	;OFFSET FOR RECORD COUNT
	DAD D
	MOV A,M
	ORA A
	JZ NEXTSR	;NO LIST IF FILE IS ZERO LENGTH
	LXI D,-5
	DAD D		;POINT TO $SYS ATTRIB BYTE
	MOV A,M
	ANI 80H
	JNZ NEXTSR	;NO LIST IF $SYS FILE
	LXI D,-10
	DAD D		;POINT TO BEGINNING OF NAME
	INX H		;POINT TO FIRST LETTER
	LXI D,PRNTNAME
	MVI B,8
	CALL MOVE
	INX D
	MVI B,3
	CALL MOVE
	CALL ILPRT
PRNTNAME:
	DB '            ',' : ',0   ;12 SPACES
	LDA DNAMECT
	INR A
	STA DNAMECT
	ANI 03H
	ORA A
	CZ CRLF
NEXTSR:	LXI D,SRCHFCB
	MVI C,SRCHN	;DO NEXT SEARCH
	CALL BDOS
	CPI 0FFH
	JZ DIRDONE
	JMP DIRLP
NOFILE:	CALL ILPRT
	DB 'NOT FOUND',0
DIRDONE:CALL CRLF
	RET

QSTMARK:MVI A,'?'	;IF BLANK IN FCB, PUT IN 11 ?'s
	MVI B,11
	LXI H,SRCHFCB+1
QSTLP:	MOV M,A
	INX H
	DCR B
	JNZ QSTLP
	RET

MOVENAME:
	LXI H,6DH
	LXI D,SRCHFCB+1
	MVI B,11
	CALL MOVE		;MOVE IN CP/M PROGRAM
	RET

GETADD:	ANI 03H			;GET MOD4 FOR CP/M 1.4
	ADD A
	ADD A
	ADD A			;ADD 32
	ADD A
	ADD A
	MOV E,A
	MVI D,0
	LXI H,80H		;ADD DMA OFFSET
	DAD D
	RET

DRIVE:	LDA SRCHFCB		;IF NO DRIVE, CAL
	ORA A			;LOGGED IN DRIVE
	JZ CALCDR
	ADI 40H
	JMP PRNTHD
CALCDR:	MVI C,25
	CALL BDOS
	ADI 41H
PRNTHD:	STA DRNAME
	CALL ILPRT
	DB CR,LF,'DRIVE '
DRNAME:	DB ' ',CR,LF,0
	RET

SRCHFCB:DS 33
DNAMECT:DS 1
;================================
NFILFLG:DB FALSE	;Terminal file open flag

OPTION:	DB 0	;primary option
OPTBL	EQU $
QFLG:	DB 'Q'	;secondary option flags
RSEEFLG:DB 'R'
SSEEFLG:DB 'S'
VSEEFLG:DB 'V'
TERMFLG:DB 'T'
BATCHFLG:DB 'N'	;0=Non-batch
OPTBE	EQU $

RESTROPT:	;MUST BE IN SAME ORDER AS TABLE ABOVE
	DB 'Q','R','S','V','T','N'
CRCFLG:	DB 'C'	;use CRC instead of cksum

RESTSN:	DB 0,0,0,0,0
	DW DBUF
	DB 0,0,0,0,0,0,0

SECNOB	EQU $
RCVSNO:		DB 0
SECNO:		DW 0	;sector no.
ERRCT:		DB 0
EOFLG:		DB 0	;end of file flag
SECPTR:		DW DBUF
SECINBF:	DB 0
MAXEXT:		DB 0
RCNT:		DW 0	;no. of records to send
DATAFLG:	DB 0
EXACFL:		DB 0	;literalise next char flag
COLCNT:		DB 0	;column counter
SECNOE	EQU $

FSTFLG:	DB	TRUE	;multiple file transmit flag
FIRSTME:DB	0FFH	;first SOH received switch(it is zero after 1st SOH)
LSTFLG:	DB	FALSE	;true=print echo on
LSTRET:	DB	FALSE	;print toggle save
BUFBEG:	DW	PRTBUF	;start of prtbuf
BUFRIN:	DW	PRTBUF	;i/p pointer
BUFROUT:DW	PRTBUF	;o/p pointer
BUFEND:	DW	PRTBUF+(RING*1024)	;end of prtbuf
CMDBUF:	DB	80H,0
	DS	80H
HLSAVE:	DS	2		;memory pointer, terminal mode
DISKNO:	DS	1
SENDFLG:DS	1
NBSAVE:	DS	2
BGNMS:	DS	2
FILECT:	DS	1
NAMECT:	DS	1

	DS	64
STAK:	DS	2
FCB3:	DS	33		;terminal file fcb
FCB4:	DS	33		;file transfer fcb
FCBBUF:	DS	15
DBUF:	DS	DBUFSIZ*1024	;FILE BUFFER FOR SEND & RECIEVE MODES
NAMEBUF:DS	64*12		;BUFFER FOR FILE NAMES IN BATCH MODE.
	ORG $ + 100H AND 0FF00H	;must be on page boundary
CRCTBL:	DS	512		;crc lookup table
PRTBUF:	DS	RING*1024	;print buffer
BOTTRAM:DS	1		;MEMORY BUFFER FOR TERMINAL FILE
		END	100H
