
;*****************************************************
;*
;*	Character I/0 Routines
;*
;*****************************************************

;===========
conin_entry:	;Function 1:console input
;===========
	call coninit ! call attach		;verify attach
	call conbrk ! call conin		;chk for ctl char pending
	mov bl,dl ! call chkctl			;wait for input, chk for ctl
	cmp al,0 ! je conin_entry
	    call echoc ! jb ciexit		;check nonprint char
		call tabout			;echo character
ciexit:	    mov bl,dl ! ret

;============
conout_entry:	;Function 2:console output - DL = char
;============

	call coninit ! call attach	;verify attach
	jmp tabout			;output char

;============
rconin_entry:	; raw console input
;============

	call rawinit ! call attach
conin:	mov dl,c_nchar[si]
	mov c_nchar[si],0
	cmp dl,0 ! jne ciout
	    call coninf ! mov dl,bl ! ret
ciout:	mov bl,dl ! ret


;=============
rconout_entry:	; raw console output - DL = char
;=============

	call rawinit ! call attach
rconout:jmp conout

;=============
listout_entry:	; write to list device - DL = char
;=============

	mov bx,rlr ! mov dh,p_lst[bx]
	call getccbadr
	push dx ! call lstattach_entry ! pop dx
	sub dh,ncondev ! jmp listf

;=============
constat_entry:        ;check console status
;=============

	call coninit
	mov di,rlr ! cmp di,c_attach[si]
	je cse_cl
	    mov cl,f_dispatch ! call mpmif
	    mov bl,0 ! ret
cse_cl:	call conbrk
	mov bl,al ! ret

;===========
dirio_entry:
;===========
; direct console i/o - read if 0ffh
;	input:	DL = 0ffh if readif (ret=0 on not ready)
;		   = 0feh if status
;		   = 0fdh if read   (hang until ready)
;		   = char if write

	call rawinit ! call attach
	cmp dl,0fdh ! je conin		;DL=0FDh, read
	    jb rconout			;output DL
		call conbrk ! mov bl,al	;get status
		cmp dl,0feh ! jne diocin	;DL=0FEh, return status
		    dec bl ! not bl ! ret
diocin:		cmp bl,0 ! jne conin		;DL=0FFh, if char,conin
		    mov cx,f_dispatch
		    call mpmif
		    mov bl,0 ! ret

;==============
conwrite_entry:	;write line until $ encountered
;==============
;	input:	DX = buffer addr in u_wrkseg

	mov bh,0 ! mov bl,'$'
	;jmps conprint_entry

;==============
conprint_entry:	;write line until delimiter or max
;==============
;	input:	DX = address of buffer in u_wrkseg
;		BH = max characters (0=no max)
;		BL = delimiter character

	push bx ! push dx
	call coninit ! call attach
	pop bx ! pop ax ! sub cx,cx ! and al,07fh
		; AH=max, AL=delimiter, BX->buffer
		; CX = count = 0
cpr1:	cmp ah,cl ! jne cpr2
	cmp ah,0 ! jne cpr_e
cpr2:	    push ds ! mov ds,u_wrkseg
	    mov dl,[bx] ! pop ds
	    and dl,07fh
	    cmp dl,al ! je cpr_e
		push ax ! push cx ! push bx
		call tabout
		pop bx ! pop cx ! pop ax
		inc cl ! inc bx
		jmps cpr1
cpr_e:	ret

;=============
conread_entry:	;read a buffered console line
;=============
; buffer=(max length, current length, buffer)

	push dx ! call coninit
	call attach ! pop bx
read:	push bx				;[SP] = buffer offset
	mov al,c_column[si]
	mov c_strtcol[si],al		;start column = current column
	sub bx,bx			;BX = character count

		;read next character, CX, BX active
readnx:	push bx
readn0:	call conin ! and dl,07fh	;DL = char just read
	pop bx

		;	Carriage Return
	cmp dl,cr ! jnz notcr
eofre:	    jmp readen
notcr:
		;	Line Feed
	cmp dl,lf ! jz eofre

		; check for Ctrl C,Ctrl D and Ctrl S
		; only if first character

	or bl,bl ! jnz tryh
	    push bx
	    mov bl,dl ! call chkctl
	    pop bx
	    cmp al,1 ! je tryh
		pop dx ! jmp conread_entry

tryh:		;	Backspace
	cmp dl,ctlh ! jnz noth
	    or bl,bl ! jz readnx			;if not 1st char
		dec bl ! mov al,c_column[si]		;decrement char count
		mov di,rlr ! mov p_scratch[di],al	;temporary hold
		or c_flag[si],cf_compc ! jmp linelen
noth:
		;	Rubout

	cmp dl,rubout ! jnz notrub
	    or bl,bl ! jz readnxx			;only if not 1st char
	        pop di ! push di
		push ds ! mov ds,u_wrkseg
		mov dl,1[di+bx] ! pop ds		;make char=last char
		dec bx					;dec char count
		jmp rdech1				;echo, read next
readnxx:    jmp readnx
notrub:
		;	Control E

	cmp dl,ctle ! jnz note
	    push bx
	    call pcr ! mov dl,lf ! call conoutf
	    mov c_column[si],0
	    mov c_strtcol[si],0
	    jmp readn0
note:
		;	Control P
	cmp dl,ctlp ! jnz notp
	    call control_p
	    jmps readnxx
notp:
		;	Control X
	cmp dl,ctlx ! jnz notx
backx:	    mov al,c_strtcol[si]
	    cmp al,c_column[si] ! jb backxxx
		sub bx,bx ! jmps readnxx
backxxx:    call pbacksp ! call pspace
	    call pbacksp
	    dec c_column[si] 
	    jmps backx
notx:
		;	Control U
	cmp dl,ctlu ! jnz notu
	    call crlfp
	    pop bx ! jmp read
notu:
		;	CONTROL R - redraw line
	cmp dl,ctlr ! jnz notr
linelen:    push bx ! call crlfp
			;print buffer on screen
	    pop cx ! sub bx,bx
rep0:	    or cl,cl ! jz rep1
		pop di ! push di
		push ds ! mov ds,u_wrkseg
		inc bx ! dec cl
		mov dl,1[di+bx] ! pop ds	;DL = nxt char
		mov ch,bl ! push cx
		call ctlout
		pop cx ! mov bh,0 ! mov bl,ch
	        jmps rep0
rep1:	    test c_flag[si],cf_compc
	    push bx ! jz l_22
		and c_flag[si],not cf_compc
backsp:		mov di,rlr ! mov al,p_scratch[di]
		sub al,c_column[si]
		or al,al ! jz l_22
		    call pbacksp ! call pspace
		    call pbacksp
		    mov di,rlr ! dec byte ptr p_scratch[di]
		    jmps backsp
l_22:	    jmp readn0
notr:
		;	All other characters
rdecho:	    inc bx
	    pop di ! push di
	    push ds ! mov ds,u_wrkseg
	    mov 1[di+bx],dl ! pop ds
rdech1:	    push bx ! call ctlout ! pop bx
	    pop di ! push di
	    push ds ! mov ds,u_wrkseg
	    cmp bl,[di] ! pop ds ! jae readen
		push bx ! jmps l_22
		;	End of Console String
readen:	pop di
	push ds ! mov ds,u_wrkseg
	mov 1[di],bl ! pop ds
	call pcr
	mov c_column[si],0
	ret

rawinit:
;-------
	call getconnum
	or p_flag[bx],pf_raw
	jmps getccbadr

coninit:
;-------
	call getconnum
	and p_flag[bx],not pf_raw
	jmps getccbadr

getconnum:	;get console number
;---------
;	output:	DH = console #
;		DL = character (unchanged)
;		BX = PD address

	mov bx,rlr
	mov dh,p_cns[bx]
	ret

attach:		;attach to default console
;------
;	output:	DH = console #
;		DL = character (unchanged)
;		SI = CCB address

	cmp c_attach[si],bx ! je attret
	    push dx ! push si
	    call conattach_entry
	    mov bx,rlr
	    test p_flag[bx],pf_ctld ! jz noattmsg
		and p_flag[bx],not pf_ctld
		mov dx,offset attachmsg
		call prcsmsg
		mov dx,rlr ! add dx,p_name
		call prname
		pop si ! pop dx ! call crlf
		mov bx,rlr ! ret
noattmsg:   pop si ! pop dx
attret:	ret

getccbadr:
;---------
; get CCB for calling proc's default console
;	input:	DH = console number
;		DL = character
;	output:	SI = address of ccb
;		BX = PD address
;		DX unchanged

	mov bx,rlr
	sub ax,ax ! mov al,dh
	shl ax,1 ! shl ax,1
	mov si,ccb ! add si,ax
	add si,ax ! add si,ax		;ccb+12(ccbnum)
	ret

echoc:
;-----
; check if character is graphic
;	input:	DL = character
;		DH = console #
;		SI = CCB address
;	output: carry set if not graphic
;		DL,DH,SI pass through

	cmp dl,cr ! je ret0
	cmp dl,lf ! je ret0
	cmp dl,tab ! je ret0
	cmp dl,ctlh ! je ret0
	cmp dl,' '
ret0:	ret

conbrk:
;------
; read next character, check for break
;	input:	DH = console #
;		DL = current char
;		SI -> CCB
;	output:	DX,SI unchanged
;		AL = 0 if no character
;		   = 1 if character

		; see if char already available
	cmp c_nchar[si],0 ! jne conb_y
		;char not ready, check external break
	    call constf
	    and bl,1 ! jz conb_no
			;character ready, read it
		call coninf
		mov di,rlr ! mov ax,p_flag[di]
		test p_flag[di],pf_raw ! jnz conb0
		    call chkctl
		    cmp al,0 ! je conb_no
conb0:		mov c_nchar[si],bl ! jmps conb_y
conb_no:    mov al,0 ! ret
conb_y:	mov al,1 ! ret

chkctl:
;------
;	input:	bl=char to check
;	return:	al=0 if ctr char found
;		al=1 if char is not ctrl c,d,s
;		dx,si preserved
;		bl preserved if al=1

	mov al,1
chkd:	cmp bl,ctld ! jne chks
	    push dx ! push si
	    mov bx,rlr
	    or p_flag[bx],pf_ctld
	    call condetach_entry
	    pop si ! pop dx
	    jmp chk0
chks:	cmp bl,ctls ! jne chkc
control_s:  call coninf
	    cmp bl,ctlc ! je chkc
		cmp bl,ctlq ! je chk0
		    push dx ! mov dl,bell
		    call conoutf ! pop dx
		    jmps control_s
chkc:	cmp bl,ctlc ! jne chk1
		;print Abort string
chkc1:	    push dx ! push si
	    call crlf					; CR,LF
	    mov bx,rlr
	    lea dx,p_name[bx]
	    call prname					; Process Name
	    mov dx,offset abortmsg
	    call prcsmsg				; Abort String
	    pop si ! pop dx
		;get answer from user
	    call coninf ! and bl,05fh
	    cmp bl,' ' ! jb ctlc_r
		push dx ! push bx
		mov dl,bl ! call conoutf
		pop bx ! pop dx
	 	cmp bl,'Y' ! jne ctlc_r
		    mov bx,rlr ! or p_flag[bx],pf_ctlc
		    push dx ! mov cx,f_terminate ! sub dx,dx
		    push si ! call mpmif ! pop si ! pop dx
ctlc_r:	    cmp bl,ctlc ! je chkc1
		call crlf
chk0:	mov al,0
chk1:	ret

control_p:
;---------

	push bx ! push dx ! push si
	mov bx,rlr
	test c_flag[si],cf_listcp
	jz mimic

		; turn off control p
	    mov dl,c_mimic[si]
	    call unmimic_entry ! jcxz mimout
		pop si ! jmps mimpret

		; turn on control p
mimic:	mov dh,p_cns[bx]
	mov dl,p_lst[bx]
	call mimic_entry
	jcxz mimout

		; print 'Printer Busy'
	    mov dx,offset ptrmsg
	    call prcsmsg
	    pop si ! jmps mimpret

		; toggle listcp for current console
mimout:	pop si ! xor c_flag[si],cf_listcp
mimpret:pop dx ! pop bx ! ret

prcsmsg:
;-------
; print string in Code Segment
;	input:	DX->null terminated string in CS

	sub bx,bx ! mov ax,cs
prstr:	push u_wrkseg
	mov u_wrkseg,ax
	call conprint_entry
	pop u_wrkseg ! ret

prname:
;------
; print name
;	input:	DX->8 char name in DS

	mov bh,8 ! mov bl,' '
	mov ax,ds ! jmps prstr

conout:
;------
; compute character position/write console
;	input:	DL = character
;		DH = console #
;		SI = ccb address
;	output:	DL = character
;		DH = console #
;		SI = ccb address

		;check if only calculating column position
	test c_flag[si],cf_compc ! jnz compout
		;write the character, then compute column.
	    call conbrk ! call attach
	    call conoutf

		; check if mimic device
	    cmp c_mimic[si],0ffh ! je compout
		push dx ! push si
		mov dh,c_mimic[si]
		call getccbadr
		call stdout
		pop si ! pop dx

		;compute column position
compout:
	mov al,c_column[si]
	cmp dl,rubout ! je ccret
	    inc al
	    cmp dl,' ' ! jae ccret
		dec al
		or al,al ! jz ccret
		    cmp dl,ctlh ! jnz notbs
			dec al ! jmps ccret
notbs:		    cmp dl,cr ! jne ccret
			mov al,0
ccret:	mov c_column[si],al
	ret

stdout:
;------
	cmp dh,ncondev ! jl xcout
	    push dx ! sub dh,ncondev
	    cmp dh,nlstdev ! jl xlout
		ret
xlout:	    call listf ! pop dx ! ret
xcout:	jmp conoutf

ctlout:
;------
; send CTRL character with possible preceding up-arrow
;	input:	DL = character
;		DH = console #
;		SI = ccb address
;	output:	DL,DH = character,console
;		SI = ccb address

	call echoc ! jae tabout
	    push dx ! mov dl,ctl ! call conout
	    pop dx ! or dl,40h
	    ; jmp tabout

tabout:
;------
; expand tabs to console
;	input:	DL = character
;		DH = console
;		SI = ccb address
;	output:	DL,DH = char,console
;		SI = ccb address

	cmp dl,tab ! jne conout
	    mov dl,' '
tab0:	    call conout
	    mov al,c_column[si]
	    and al,111b ! jnz tab0
		mov dl,tab
ret2:		ret

pspace:
;------
; print space

	mov dl,' ' ! jmps conoutf

pbacksp:
;-------
; print backspace

	mov dl,ctlh ! jmps conoutf

pcr:
;---
; print CR

	mov dl,cr ! jmps conoutf

crlf:
;----
	push dx ! mov dl,cr ! call conout
	mov dl,lf ! call conout ! pop dx
	ret
crlfp:
;-----
; print #, cr, lf for ctlx, ctlu, ctlr functions
; then print ' ' until we are at strtcol (starting column)
;	input:	DH = console
;		SI = ccb address
;	output: DH = console
;		SI = ccb address

	mov dl,'#' ! call conout
	call crlf
	mov dl,' '
crlfp0:	mov al,c_column[si]
	cmp al,c_strtcol[si] ! jae crlfp1
	    call conout ! jmps crlfp0
crlfp1:	ret

;
;	XIOS CHARACTER I/O INTERFACE
;
;	input:	DH = console #
;		DL = character
;		SI = ccb address
;	output:	DH = console #
;		DL = character
;		SI = ccb address
;		AX = BX = return

listf:	mov ax,io_list ! jmps xiolst
conoutf:mov ax,io_conout
xiolst:	push dx ! mov cl,dl
	mov dl,dh ! mov dh,0
	call xiosc
	pop dx ! ret

constf:	mov ax,io_const ! jmps xio1
coninf:	mov ax,io_conin
xio1:	mov cl,dh
xiosc:	push si ! push dx
	mov ch,0 ! call xiosif
	pop dx ! pop si ! ret

;
;	String Constants
;

ptrmsg		db	cr,lf,'Printer Busy',cr,lf,0
abortmsg	db	': Abort (Y/N)? ',0
attachmsg	db	cr,lf,'Attach: ',0
