$title('GETF  - CP/M 3.0 Input Redirection - August 1982')
	name	getf
;******************************************************************
;
;	get  'Input Redirection Initializer'  version 3.0
;
; 	11/30/82 - Doug Huskey
;******************************************************************
;
;
;	Copyright (c) 1982
;	Digital Research
;	P.O. Box 579
;	Pacific Grove, Ca.
;	93950
;
;
;	generation procedure
;
;	seteof get.plm
;	seteof getscan.dcl
;	seteof getf.asm
;	seteof getscan.plm
;	seteof parse.asm
;	is14
;	asm80 getf.asm debug
;	asm80 mcd80a.asm debug
;	asm80 parse.asm debug
;	plm80 get.plm pagewidth(100) debug optimize
;	link mcd80a.obj,get.obj,parse.obj,getf.obj,plm80.lib to get.mod
;	locate get.mod code(0100H) stacksize(100)
;	era get.mod
;	cpm
;	objcpm get
;	rmac getrsx
;	link getrsx[op]
;	era get.rsx
;	ren get.rsx=getrsx.prl
;	gencom get.com
;	gencom get.com get.rsx 
;	
;
;
;	This module is called as an external routine by the
;	PL/M routines GET and SUBMIT.  It is passed a structure
;	with the following format:
;
;
;		  declare getpb structure
;		    (input$type   byte,
;		     echo$flag     byte,
;		     filtered$flag byte,
;		     program$flag  byte);
;
;	input$type 	= 0     > console input (default)
;		    	= 1     > auxiliary output
;
;	echo		= true  > echo input to real device
;				  (default)
;			= false > don't echo input (output is 
;				  still echoed)
;	filtered 	= true  > convert control characters
;				  to a printable form 
;			          preceeded by an ^ in echo
;				  (default)
;			= false > no character conversions
;	program	 	= false > continue until EOF or 
;				  GET INPUT FROM CONSOLE
;			          command
;			= true  > active only until program
;				  termination
;
	public	getf
	extrn	mon1,fcb,memsiz
;
;
true		equ	0ffffh
false		equ	00000h
;
biosfunctions	equ	true		;intercept BIOS conin & constat 
;
;
;	low memory locations
;
wboot	equ	0000h
wboota	equ	wboot+1
;
;	equates for non graphic characters
;
cr	equ	0dh	; carriage return
lf	equ	0ah	; line feed
;
;	BDOS function equates
;
cinf	equ	1	;read character
coutf	equ	2	;output character
crawf	equ	6	;raw console I/O
creadf	equ	10	;read buffer
cstatf	equ	11	;status
pchrf	equ	5	;print character
pbuff	equ	9	;print buffer
openf	equ	15	;open file
closef	equ	16	;close file
delf	equ	19	;delete file
dreadf	equ	20	;disk read
dmaf	equ	26	;set dma function
curdrv	equ	25
userf	equ	32	;set/get user number
scbf	equ	49	;set/get system control block word
rsxf	equ	60	;RSX function call
initf	equ	128	;GET initialization sub-function no.
killf	equ	129	;GET delete sub-function no.
jkillf	equ	141	;JOURNAL delete sub-function no.
;
;	System Control Block definitions
;
scba	equ	03ah	;offset of scbadr from SCB base
ccpflg2	equ	0b4h	;offset of 2nd ccp flag byte from pg bound
errflg	equ	0aah	;offset of error flag from page boundary
conmode	equ	0cfh	;offset of console mode from page boundary
listcp	equ	0d4h	;offset of ^P flag from page boundary
common	equ	0f9h	;offset of common memory base from pg. bound
wbootfx	equ	068h	;offset of warm boot jmp from page. bound
constfx	equ	06eh	;offset of constat jmp from page. bound
coninfx	equ	074h	;offset of conin jmp from page. bound
conoufx	equ	07ah	;offset of conout jmp from page. bound
listfx	equ	080h	;offset of list jmp from page. bound
realdos	equ	098h	;offset of real BDOS entry from pg. bound
;
;	Restore mode equates    (used with inr a, rz, rm, rpe, ret)
;
norestore	equ	0ffh	;no BIOS interception
biosonly	equ	07fh	;restore BIOS jump table only
stfix	equ	080h	;restore BIOS jump table and
				;restore JMP in RESBDOS for constat
everything	equ	0	;restore BIOS jump table and jmps in
				;RESBDOS (default mode)
;
;	Instructions
;
lxih		equ	21h	;LXI H, instruction
jmpi		equ	0c3h	;JMP instruction
shldi		equ	22h	;SHLD instruction
;
;******************************************************************
;		START OF INITIALIZATION CODE
;******************************************************************

		cseg

getf:
	;get parameters
	mov	h,b
	mov	l,c		;HL = .(parameter block)
	mov	a,m		;input type 0=con:,1=aux:
	cpi	1		;is it aux?
	jz	notimp		;error if so
	inx	h
	mov	a,m		;echo/noecho mode
	sta	echo
	inx	h
	mov	a,m		;cooked/raw mode	
	sta	cooked	
	inx	h
	mov	a,m
	sta	program
	;
	;check if enough memory
	;
	lhld	memsiz
	mov	a,h
	cpi	20h
	jc	nomem
	;
	;close to get those blocks in the directory
	;
	lxi	d,fcb
	mvi	c,closef
	call	mon1
	;
	;check if drive specified
	lxi	h,fcb
	mov	a,m		;drive code
	ora	a		;default?
	jnz	movfcb
	;
	;set to current drive, if  not
	;
	push	h		;save .fcb
	mvi	c,curdrv
	call	mon1
	pop	h		;a=current drive, hl=.fcb
	inr	a
	mov	m,a		;set fcb to force drive select
	;
movfcb:	;copy default fcb up into data area for move to RSX
	;
	lxi	d,subfcb
	lxi	b,32		;length of fcb
	call	ldir		;move it to subfcb
	;
	;initialize other variables to be moved to RSX
	;
	call	getusr		;get current user number
	sta	subusr		;save for redirection file I/O
	call	getscbadr
	shld	scbadr		;System Control Block address
	;
	;get real BDOS address (bypass chain to check for user break)
	;
	mvi	l,realdos
	mov	e,m
	inx	h
	mov	d,m
	xchg
	shld	realbdos+1
	;
	;check for user abort
	;
	xchg
	mvi	l,conmode
	mov	a,m
	ori	1		;set ^C status mode
	mov	m,a
	mvi	c,cstatf
	call	realbdos	;check for user abort
	ora	a
	jnz	error1		;abort if so
	;
	;get address of initialization table in RSX
	;
	mvi	c,rsxf
	lxi	d,journkill
	call	mon1		;terminate any PUT INPUT commands
	mvi	c,rsxf
	lxi	d,rsxinit
	call	mon1		;call GET.RSX initialization routine
	push	h		;save for move at end of setup
	mov	e,m
	inx	h
	mov	d,m		;DE = .RSXKILL flag 
	push	d		;set flag to zero if successfull
	inx	h		;HL = .(real bios status routine)
	push	h
	;
if biosfunctions
	;
	;check if BIOS jump table looks valid (jmp in right places)
	lhld	wboota
	lxi	d,3
	dad	d		;HL = .(jmp constat address)
	mov	a,m
	cpi	jmpi		;should be a jump
	jnz	bioserr		;skip bios redirection if not
	dad	d		;HL = .(jmp conin address)
	mov	a,m
	cpi	jmpi
	jnz	bioserr		;skip bios redirection if not
	;
	;fix up RESBDOS to do BIOS calls to intercepted functions
	;
	lhld	scbadr
	mvi	l,common+1
	mov	a,m		;get high byte of common base
	ora	a		
	jnz	fix0		;high byte = zero if non-banked
	mvi	a,biosonly
	sta	biosmode
	jmp	trap		;skip code that fixes resbdos
	;fix BIOS constat
fix0:	mvi	l,constfx		;hl = .constfx in SCB
	mov	a,m
	cpi	jmpi		;is it a jump instruction?
	jz	fix1		;jump if so
	mvi	a,biosonly	;whoops already changed
	sta	biosmode	;restore jump table only
fix1:	mvi	m,lxih
	;fix BIOS conin
	mvi	l,coninfx	;hl = .coninfx in SCB
	mov	a,m
	cpi	jmpi		;is it a jump instruction?
	lda	biosmode
	jz	fix2		;jump if so
	cpi	biosonly
	jnz	bioserr		;error if conin is LXI but not constat
	xra	a		;zero accumulator to jnz below
fix2:	cpi	biosonly	;was const already an LXI h?
	jnz	fix3		;jmp if not
	mvi	a,stfix	;restore constat jmp but not conin
	sta	biosmode
fix3:	mvi	m,lxih
	;get addresses of RSX const and conin traps
trap:	pop	h
	mov  	c,m		;HL = .(.bios constat trap)
	inx	h
	mov	b,m		;BC = .bios constat trap in RSX
	inx	h
	push	h		;save for CONIN setup
	;
	;patch RSX constat entry into BIOS jump table 
	;save real constat address in RSX exit table
	;
	lhld	wboota
	lxi	d,4
	dad	d		;HL = .(jmp constat address)
	shld	constjmp	;save for RSX restore at end
	mov	e,m
	mov	m,c
	inx	h
	mov	d,m		;DE = constat address
	mov	m,b		;BIOS constat jumps to RSX
	xchg
	shld	biosta		;save real constat address
	;
	;get address of RSX bios conin entry point
	;
	pop	h		;HL = .(RSX BIOS conin trap)
	mov	c,m
	inx	h
	mov	b,m
	;
	;patch RSX conin entry into BIOS jump table 
	;save real conin address in RSX exit table
	;
	xchg
	inx	h		;past jmp instruction
	inx	h		;HL = .(conin address)
	shld	coninjmp
	mov	e,m
	mov	m,c
	inx	h
	mov	d,m		;DE = conin address
	mov	m,b		;BIOS conin jumps to RSX
	xchg
	shld	biosin		;save real conin address
endif
	;
	;move data area to RSX
	;
rsxmov:
	pop	h		;HL = .Kill flag in RSX
	inr	m		;switch from FF to 0
	lxi	h,movstart
	pop	d		;RSX data area address
	lxi	b,movend-movstart
	call	ldir
	mvi	c,crawf
	mvi	e,0fdh		;raw console input
	call	mon1		;prime RSX by reading a char
	jmp	wboot

if biosfunctions
;
;	can't do BIOS redirection
;
bioserr:
	lxi	d,nobios
	mvi	c,pbuff
	call	mon1
	lxi	h,biosmode
	mvi	m,norestore	;no bios redirection 
	pop	h		;throw away bios constat trap adr
	jmp	rsxmov
endif
;
;	auxiliary redirection
;
notimp:
	lxi	d,notdone
error:
	mvi	c,pbuff
	call	mon1	
error1:	mvi	c,closef
	lxi	d,fcb
	call	mon1
	mvi	c,delf
	lxi	d,fcb
	call	mon1
	jmp	wboot
;
;	insufficient memory
;
nomem:	lxi	d,memerr
	jmp	error
	
;
;	get/set user number
;
getusr:	mvi	a,0ffh		;get current user number
setusr:	mov	e,a		;set current user number (in A)
	mvi	c,userf
	jmp	mon1
;
;	get system control block address 
;	(BDOS function #49)
;
;	exit:	hl = system control block address
;
getscbadr:
	mvi	c,scbf
	lxi	d,data49
	jmp	mon1
;
data49:	db	scba,0		;data structure for getscbadd
;
;	copy memory bytes (emulates z80 ldir instruction)
;
ldir:	mov	a,m		;get byte
	stax	d		;store it at destination
	inx	h		;advance pointers
	inx	d
	dcx	b		;decrement byte count
	mov	a,c		;loop if non-zero
	ora	b
	jnz	ldir
	ret
;
;******************************************************************
;		DATA AREA
;******************************************************************

	;
journkill:	db	jkillf
rsxinit:	db	initf
nobios:		db	'WARNING: Cannot redirect from BIOS',cr,lf,'$'
notdone:
	db 'ERROR: Auxiliary device redirection not implemented',cr,lf,'$'
memerr:
	db 'ERROR: Insufficient Memory',cr,lf,'$'
	;	
;******************************************************************
;	Following variables are initialized by GET.COM
;	and moved to the GET RSX - Their order must not be changed
;******************************************************************
	;
	;
	;
movstart:
inittable:			;addresses used by GET.COM for 
scbadr:	dw	0		;address of System Control Block
	;
	if biosfunctions	;GET.RSX initialization
	;
biosta:	dw	0		;set to real BIOS routine
biosin:	dw	0		;set to real BIOS routine
	;
				;restore only if changed when removed.
biosmode:
	db	0		;if non-zero change LXI @jmpadr to JMP
				;when removed.
restorebios:
	;hl = real constat routine
	;de = real conin routine
	db	shldi
constjmp:
	dw	0		;address of const jmp initialized by COM
	xchg
	db	shldi
coninjmp:
	dw	0		;address of conin jmp initialized by COM
	ret
	endif
	;
realbdos:
	jmp	0		;address filled in by COM
	;
echo:	db	1
cooked:	db	0
	;
program:
	db	0		;true if only program input 
subusr:	db	0		;user number for redirection file
subfcb:	db	1		;a:
	db	'SYSIN   '
	db	'SUB'
	db	0,0
submod:	db	0
subrc:	db	0
	ds	16		;map
subcr:	db	0
	;
movend:
;*******************************************************************
	end
EOF

