512 lines
10 KiB
Plaintext
512 lines
10 KiB
Plaintext
; termio.z - subroutines for doing the terminal i/o part of qterm
|
|
|
|
.incl "c:termcap"
|
|
.incl "c:vars"
|
|
|
|
.macro table byte,addr
|
|
dw addr
|
|
db byte
|
|
.endm
|
|
|
|
.extern procch
|
|
procch: call kbdcc ; get a char if it's waiting
|
|
or a
|
|
jr z,lstmod ; skip if no character
|
|
cp 'x' & 0x1f ; ctl x?
|
|
jp z,canscr ; quit if so
|
|
ld e,a ; save char in e
|
|
ld a,(escval) ; get the escape value
|
|
ld hl,pccs
|
|
inc (hl)
|
|
dec (hl) ; what state?
|
|
jr z,pccs0 ; state zero - look for escape
|
|
dec (hl) ; reset to 0
|
|
cp e ; escape twice?
|
|
jr z,pccop ; yes - send one to modem
|
|
ld a,e ; get char back
|
|
cp ',' ; was it a ','?
|
|
call z,hangup ; hang up if so
|
|
cp '.' ; or a '.'
|
|
call z,break ; do a break
|
|
jr lstmod
|
|
|
|
; This is here for branch length reasons
|
|
|
|
.extern modop
|
|
modop: ; send a character to the modem, respecting
|
|
; half duplex etc.
|
|
push af
|
|
call modopc ; send it to the modem first
|
|
pop hl
|
|
ld a,(wflg) ; window mode?
|
|
or a
|
|
ld a,h ; get character back
|
|
jr z,nowin
|
|
push hl
|
|
call winsnd ; go give it to window input code
|
|
pop af ; char back
|
|
cp '\r'
|
|
ret nz ; returns get special processing
|
|
ld a,(eflg) ; echo mode?
|
|
or a
|
|
ret z ; return if not
|
|
ld a,'\n' ; throw a linefeed into the system
|
|
jr modop
|
|
nowin: ld a,(hflg) ; half duplex?
|
|
or a
|
|
ret z
|
|
ld a,h ; get character again
|
|
cp '\r'
|
|
jr nz,ipchar ; pass non-return chars straight in
|
|
ld a,(eflg) ; echo mode too?
|
|
or a
|
|
ld a,h ; get the '\r' back
|
|
jr z,ipchar ; no echo mode, don't expand it
|
|
call ipchar ; go send return to receive code
|
|
ld a,'\n'
|
|
jr ipmchr ; throw a newline into system as well
|
|
|
|
pccs0: cp e ; did we see an escape?
|
|
jr z,setesc ; yes, set the flag
|
|
ld a,e
|
|
pccop: call modop ; send char to modem
|
|
db 0x3e ; ld a,xx opcode
|
|
setesc: inc (hl)
|
|
|
|
.extern lstmod
|
|
lstmod:
|
|
call wrtscn ; keep the printer going and check if a
|
|
; character is waiting at the modem port.
|
|
ret c ; return if nothing arrived
|
|
|
|
ld hl,ecval ; echo check needed?
|
|
dec (hl)
|
|
inc (hl)
|
|
jr z,noec ; jump if not
|
|
cp (hl) ; did we match?
|
|
jr nz,noec ; no - leave value in place
|
|
ld (hl),1 ; reset to say we got it
|
|
noec: ld hl,bmask
|
|
and (hl) ; mask if 7 bit mode
|
|
scf
|
|
ret z ; return on nulls as well
|
|
ld hl,cscqfl
|
|
inc (hl)
|
|
dec (hl) ; ^S ^Q spotting enabled?
|
|
jr z,nocscq
|
|
bit 0,(hl)
|
|
jr nz,nocs ; waiting for a ^Q?
|
|
cp 's' & 0x1f ; ^S ?
|
|
jr nz,nocscq ; nope, check status now
|
|
set 0,(hl) ; flag that a ^S arrived
|
|
scf
|
|
ret
|
|
nocs: cp 'q' & 0x1f ; was it a ^Q
|
|
jr z,wascq
|
|
cp 's' & 0x1f ; also let a second ^S toggle
|
|
jr nz,nocscq ; not yet - pass this character
|
|
wascq: res 0,(hl) ; clear the flag
|
|
scf
|
|
ret
|
|
nocscq: ld hl,eflg
|
|
inc (hl)
|
|
dec (hl) ; echo mode?
|
|
zipch: jr z,ipchar ; no, hand straight to input code
|
|
cp '\r' ; return?
|
|
jr nz,ipmchr ; no, echo and hand to input code
|
|
call ipmchr ; otherwise process,
|
|
ld a,'\n' ; and send a newline into the system as well
|
|
|
|
ipmchr: push af
|
|
call modopc ; send character to modem to echo it
|
|
pop af
|
|
|
|
.extern ipchar ; needed for sendcs in chat
|
|
ipchar: ld c,a ; save char in c
|
|
ld a,(jflg)
|
|
or a ; junking control characters?
|
|
ld a,c
|
|
call nz,limitb ; if so it gets tested
|
|
ret c ; and thrown if bad
|
|
push af ; save the character
|
|
call opchar
|
|
pop af
|
|
call oplst ; output to printer
|
|
or a ; clear the carry
|
|
ld hl,cflg
|
|
bit 0,(hl) ; catch mode enabled
|
|
ret z ; no - return
|
|
ld hl,(cptr)
|
|
ld (hl),a ; save char away
|
|
inc hl
|
|
ld (cptr),hl ; update pointer
|
|
ld de,(endcbf)
|
|
or a
|
|
sbc hl,de ; buffer full?
|
|
scf
|
|
ccf ; clear carry w/o affecting zero
|
|
ret nz ; no - keep going
|
|
push af
|
|
call flushc ; go flush data in catch buffer
|
|
call ctlq
|
|
pop af
|
|
ret
|
|
|
|
.extern savrng
|
|
savrng: ; get a char and save in ring buffer
|
|
call modist ; char available?
|
|
ret z ; no.
|
|
call modin ; get it
|
|
ld de,(ringpw) ; pick up indices
|
|
ld hl,(ringpr)
|
|
inc de ; move write index
|
|
res 2,d
|
|
or a
|
|
sbc hl,de ; buffer full?
|
|
ret z ; return if so
|
|
ld (ringpw),de ; save revised index
|
|
ld hl,ring
|
|
add hl,de
|
|
ld (hl),a
|
|
ret
|
|
|
|
wrtscn: call wrtlst ; keep printer output rolling
|
|
call savrng ; get any incoming characters
|
|
ld de,(ringpr)
|
|
ld hl,(ringpw)
|
|
xor a
|
|
sbc hl,de ; anything in the ring?
|
|
scf
|
|
ret z ; nope
|
|
inc de
|
|
res 2,d
|
|
ld (ringpr),de ; save new index
|
|
ld hl,ring
|
|
add hl,de ; index into buffer
|
|
ld a,(hl) ; get the char
|
|
ret ; and return it
|
|
|
|
.extern oplst ; put a character in the list ring buffer
|
|
oplst:
|
|
ld hl,oflg ; are we saving?
|
|
bit 0,(hl)
|
|
ret z ; return if not
|
|
push bc ; save bc
|
|
ld hl,(lstpr)
|
|
ld de,(lstpw) ; get the list ring buffer indices
|
|
inc de ; move the write pointer
|
|
res 2,d ; wrap if it hits 1K
|
|
or a
|
|
sbc hl,de ; check for buffer full
|
|
jr nz,notful
|
|
push af ; save the character
|
|
call ctls ; send an xoff and wait for things to cool
|
|
mtloop: call wrtlst ; write a character if we can
|
|
jr nc,mtloop ; keep writing if we're not done
|
|
call ctlq ; OK - you can wake up again
|
|
pop af ; restore char again
|
|
notful: ld hl,(lstpw)
|
|
inc hl
|
|
res 2,h
|
|
ld (lstpw),hl ; save the revised write pointer
|
|
ld de,lstbuf ; address the list buffer
|
|
add hl,de
|
|
ld (hl),a ; and save the character
|
|
pop bc ; get bc back.
|
|
ret
|
|
|
|
wrtlst: ld de,(lstpr) ; see if we can send a character to the lst
|
|
ld hl,(lstpw) ; get the ring buffer indices
|
|
or a
|
|
sbc hl,de ; anything in the buffer
|
|
scf ; set carry to say we're done
|
|
ret z ; nope - nothing to do
|
|
push de
|
|
ld a,0x2d
|
|
call cbios ; call to list status
|
|
pop de ; get read pointer back
|
|
or a
|
|
ret z ; can't write - return now
|
|
ld hl,lstbuf
|
|
add hl,de ; index into buffer
|
|
inc de
|
|
res 2,d ; wrap if over 1K
|
|
ld (lstpr),de ; save new index
|
|
ld c,(hl)
|
|
|
|
.extern lstout
|
|
lstout: ld a,0x0f
|
|
call cbios
|
|
or a ; clear the carry
|
|
ret
|
|
|
|
.extern ctlq
|
|
ctlq:
|
|
ld a,(lxoff) ; get local xon / xoff status
|
|
or a
|
|
ret z ; send nothing if xoff sent from keyboard
|
|
ld a,(cqchr)
|
|
|
|
.extern modopc
|
|
modopc: push af ; save character on stack
|
|
modopl: call modost ; check if we can send
|
|
jr z,modopl ; can't send - loop back
|
|
pop af ; char back to a
|
|
jp modout ; and away it goes
|
|
|
|
.extern limitb
|
|
limitb: ; like limitc, but includes backspace
|
|
cp '\b'
|
|
ret z
|
|
|
|
.extern limitc
|
|
limitc:
|
|
cp 0x7f ; del or greater
|
|
ccf
|
|
ret c ; are invalid
|
|
|
|
.extern iswa
|
|
iswa:
|
|
cp ' ' ; space to '~'
|
|
ret nc ; are valid
|
|
cp '\r'
|
|
ret z ; return is valid
|
|
cp '\n'
|
|
ret z ; newline also
|
|
cp '\t'
|
|
ret z ; and tab
|
|
scf ; rest are bad
|
|
ret
|
|
|
|
.var #where 0
|
|
.var #bot 1
|
|
.var #top 2
|
|
.var #col 6
|
|
.var #row 7
|
|
.var #lff 8
|
|
|
|
nocndo: call ilprt ; and finish the message
|
|
db '\r\nW ignored - insufficient terminal capabilities\r\n\0'
|
|
ret
|
|
|
|
wend: ld hl,23 << 8
|
|
jp moveto
|
|
|
|
.extern witog
|
|
witog: ld a,(tcbits) ; check what terminal abilities we have
|
|
cpl
|
|
and b_delln | b_insln
|
|
ld (wtflag),a ; save window type value
|
|
jr z,cando ; got insert and delete - away we go
|
|
ld a,(tcbits)
|
|
and b_cleol ; alternatively check for clear to end-of-line
|
|
jr z,nocndo ; missing it as well - can't do this
|
|
|
|
cando: ld hl,wflg
|
|
call togflg ; toggle the flag first of all
|
|
jr z,wend ; disabled - so return & do nothing
|
|
dec (hl) ; temporarily turn mode back off so prompt
|
|
push hl ; works right
|
|
call prompt
|
|
db 'Window size (b / s)? \0'
|
|
pop hl
|
|
inc (hl) ; turn flag back on
|
|
ld hl,ipbuf
|
|
call byp
|
|
or 0x20
|
|
xor 's' ; did they say 's'?
|
|
|
|
; we could probably optimise this even more, only two numbers actually change
|
|
|
|
ld hl,sdat ; get small window data
|
|
jr z,gotdat ; jump if so
|
|
ld hl,bdat ; otherwise large window data
|
|
gotdat: ld de,wrdat
|
|
ld bc,6
|
|
ldir ; go install it
|
|
ld h,d
|
|
ld l,e
|
|
inc de
|
|
ld c,5
|
|
ld (hl),b ; clear the rest of the information
|
|
ldir
|
|
ld a,(wtflag)
|
|
or a ; what sort of windowing
|
|
jr nz,setrol ; rolling w/ clear to eol
|
|
ld hl,(rbot) ; normal - get bottom row
|
|
ld a,(sbot) ; and the other
|
|
jr wsetsc ; and install them
|
|
setrol: ld hl,(rtop) ; get top row
|
|
ld a,(stop) ; and the other
|
|
wsetsc: ld (srow),a ; save send window current row
|
|
ld a,l
|
|
ld (rrow),a ; and receive window
|
|
ld (where),a ; and set where so we'll do a moveto
|
|
call clear
|
|
ld hl,(rtop - 1) ; get top of receive window
|
|
dec h ; - 1 to move up a line
|
|
ld l,0 ; and the first positon
|
|
call moveto ; go there
|
|
call dim ; dim mode
|
|
ld bc,[80 << 8] + '-'
|
|
dashes: push bc
|
|
call scrout ; spit out 80 dashes
|
|
pop bc
|
|
djnz dashes
|
|
jp bright ; set bright mode and we're done
|
|
|
|
istab: ld c,' '
|
|
call opwc
|
|
ld a,(iy + #col)
|
|
and 7
|
|
jr nz,istab
|
|
ret
|
|
|
|
trybs: cp '\b'
|
|
jr nz,trytab
|
|
ld a,(iy + #col)
|
|
or a
|
|
ret z
|
|
dec (iy + #col)
|
|
call opbs
|
|
ld c,' '
|
|
call scrout
|
|
opbs: ld c,'\b'
|
|
jp scrout
|
|
|
|
trytab: cp '\t'
|
|
jr z,istab
|
|
|
|
nobs: cp '~' + 1
|
|
ret nc
|
|
cp ' '
|
|
ret c
|
|
opwc: push hl
|
|
call scrout
|
|
pop hl
|
|
ld (iy + #lff),0
|
|
inc (iy + #col)
|
|
ld a,(iy + #col)
|
|
xor 80
|
|
jr z,scrl
|
|
ret
|
|
|
|
.extern winrec
|
|
winrec: ld iy,wrdat
|
|
jr winpc
|
|
|
|
winsnd: ld iy,wsdat
|
|
ld c,a
|
|
|
|
winpc: ld hl,where
|
|
ld a,(iy + #where)
|
|
cp (hl)
|
|
jr z,posok
|
|
ld (hl),a
|
|
push hl
|
|
push bc
|
|
ld l,(iy + #col)
|
|
ld h,(iy + #row)
|
|
call moveto
|
|
pop bc
|
|
pop hl
|
|
posok: ld a,c
|
|
cp '\n'
|
|
jr z,scrl
|
|
cp '\r'
|
|
jr nz,trybs
|
|
scrl: xor a
|
|
cp (iy + #lff)
|
|
ret nz
|
|
ld (iy + #col),a
|
|
ld (hl),h
|
|
ld (iy + #lff),h
|
|
ld a,(wtflag)
|
|
or a
|
|
jr nz,roll
|
|
ld a,(iy + #top)
|
|
ld h,(iy + #bot)
|
|
ld l,22
|
|
|
|
; rollit - scroll a region on the screen - this is made external so the VT100
|
|
; code can get at it
|
|
|
|
.extern rollit
|
|
rollit: or a
|
|
push hl
|
|
jr nz,dell
|
|
ld hl,23 << 8
|
|
call moveto
|
|
ld c,'\n'
|
|
call scrout
|
|
jr dontop
|
|
dell: ld l,0
|
|
ld h,a
|
|
call moveto
|
|
call dellin
|
|
dontop: pop hl
|
|
ld a,h
|
|
cp l
|
|
ret z
|
|
ld l,0
|
|
call moveto
|
|
jp inslin
|
|
|
|
roll: ld a,(iy + #row)
|
|
call incrow
|
|
ld (iy + #row),a
|
|
call incrow
|
|
ld h,a
|
|
ld l,0
|
|
call moveto
|
|
jp cleol
|
|
|
|
incrow: cp (iy + #bot)
|
|
jr z,reload
|
|
inc a
|
|
ret
|
|
reload: ld a,(iy + #top)
|
|
ret
|
|
|
|
.dseg
|
|
.extern pccs
|
|
pccs: db 0
|
|
ringpr: dw 0
|
|
ringpw: dw 0
|
|
lstpr: dw 0
|
|
lstpw: dw 0
|
|
|
|
.useg
|
|
ring: ds 1024
|
|
lstbuf: ds 1024
|
|
|
|
wrdat:
|
|
rwhere: ds 1
|
|
rbot: ds 1
|
|
rtop: ds 1
|
|
|
|
wsdat:
|
|
swhere: ds 1
|
|
sbot: ds 1
|
|
stop: ds 1
|
|
|
|
rcol: ds 1
|
|
rrow: ds 1
|
|
rlff: ds 1
|
|
|
|
scol: ds 1
|
|
srow: ds 1
|
|
slff: ds 1
|
|
|
|
.extern where
|
|
where: ds 1
|
|
wtflag: ds 1
|
|
|
|
.dseg
|
|
|
|
sdat: db 0,22,12
|
|
db 1,10,0
|
|
|
|
bdat: db 0,22,5
|
|
db 1,3,0
|
|
|