; Kermit system dependent module for ACT Apricot

; Added global entry point vtstat for use by Status in mssset.
; Added register save/restore in getbaud procedure.
; Also trimmed off trailing commas in publics. Joe R. Doupnik 12 March 1986

        public  serini, serrst, clrbuf, outchr, coms, vts, vtstat, dodel
        public  ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl
        public  dodisk, getbaud, beep
        public  count, xofsnt, puthlp, putmod, clrmod, poscur
        public  sendbr, term, machnam, setktab, setkhlp, showkey
        include mssdef.h

false   equ     0
true    equ     1
instat  equ     6
rddev   equ     3FH
open    equ     3DH
control equ     0FCH                    ; System Control Device

; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
;           or port2)
; port1, port2 - portinfo structures for the corresponding ports

; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.

modfrm  struc                           ; Format of mode line
        db      'Esc chr: '
m_echr  db      2 dup (?)
        db      ', Speed: '
m_baud  db      4 dup (?)
        db      ', Parity: '
m_par   db      4 dup (?)
        db      ', Echo: '
m_echo  db      3 dup (?)
        db      ', Log: '
m_log   db      3 dup (?)
        db      ', Type '
m_hlp   db      2 dup (?)
        db      '? for Help$'
modfrm  ends

datas   segment public  'datas'
        extrn   drives:byte,  flags:byte, trans:byte
        extrn   portval:word, port1:byte, port2:byte

;
machnam db      'ACT Apricot$'
erms20  db      cr,lf,'?Warning: System has no disk drives$'
erms40  db      cr,lf,'?Warning: Unrecognized baud rate$'
erms41  db      cr,lf,'?Warning: Cannot open com port$'
erms50  db      cr,lf,'Error reading from device$'
badbd   db      cr,lf,'Unimplemented baud rate$'
noimp   db      cr,lf,'Command not implemented.$'
shkmsg  db      'Not implemented.'
shkmln  equ     $-shkmsg
setktab db      0
setkhlp db      0
crlf    db      cr,lf,'$'
delstr  db      BS,BS,' ',BS,'$'        ; Delete string.
clrlin  db      cr,esc,'K$'             ; Clear line.
clreol  db      esc,'K$'                ; Clear line.
clrscr  db      esc,'H',esc,'J$'        ; Home and clear screen.
; Use high/low intensity rather than inverse video.
; It is kinder on the eyes....
invseq  db      esc,'($'                ; High intensity mode.
nrmseq  db      esc,')$'                ; Low intensity mode.
on25    db      esc,'j',esc,';$'        ; Save cursor posn, move to line 25
off25   db      esc,'k$'                ; Restore cursor to saved position
offmscr db      esc,'/',0,esc,'s$'      ; Turn off lights, clear, clock on
onmscr  db      esc,'U',esc,'W'         ; Direct output to microscreen
        db      esc,'c',esc,'B'         ; Disable scrolling, cursor down
        db      'Break Close  Status  '
        db      'Push   Help   Log'
        db      esc,'V'                 ; Revert to normal screen
        db      esc,'/',3FH             ; Turn on all keypad lights
        db      '$'
xofsnt  db      0                       ; Say if we sent an XOFF.
count   dw      0                       ; Number of chars in int buffer.
portin  db      0                       ; Port initialization flag
inited  db      0                       ; Terminal handler init flag
tmp     db      ?,'$'
temp    dw      0
temp1   dw      ?                       ; Temporary storage.
temp2   dw      ?                       ; Temporary storage.

; This character string is used to program various keys to return
; the correct ASCII characters.

kbdesc  db      esc,'43',44,'['-100O    ; Program CTRL-[ key
        db      esc,'43',45,']'-100O    ; Program CTRL-] key
        db      '$'

;  This table is indexed by the baud rate definitions given in msdefs.h.
;  Unsupported baud rates should contain FF.
bddat   label   word
        dw      0FFH                    ;    45.5  Unsupported
        dw      1                       ;    50
        dw      2                       ;    75
        dw      3                       ;   110
        dw      4                       ;   134.5
        dw      5                       ;   150
        dw      6                       ;   300
        dw      7                       ;   600
        dw      8                       ;  1200
        dw      9                       ;  1800
        dw      0FFH                    ;  2000    Unsupported
        dw      10                      ;  2400
        dw      12                      ;  4800    (Have to skip 3600)
        dw      14                      ;  9600    (Have to skip 7200)
        dw      15                      ; 19200
        dw      0FFH                    ; 38400    Unsupported

ourarg  termarg <>
modbuf  modfrm  <>                      ; Mode line buffer

; Some static data for the mode line.
unkbaud db      'Unk '
baudn   db      '45.5'
        db      '  50'
        db      '  75'
        db      ' 110'
        db      ' 135'
        db      ' 150'
        db      ' 300'
        db      ' 600'
        db      '1200'
        db      '1800'
        db      '2000'
        db      '2400'
        db      '4800'
        db      '9600'
        db      ' 19K'
        db      ' 38K'

parnams db      'Even'
        db      'Mark'
        db      'None'
        db      'Odd '
        db      'Spc '
offmsg  db      'Off'
onmsg   db      'On '
lclmsg  db      'Lcl'
remmsg  db      'Rem'
keyoff  dw      0
keyseg  dw      0
;
datas   ends

keybd   segment page    public
; This keytable needs to aligned on a page boundary, else
; the whole machine fall apart.
;
keytab  dw      0400H dup (?)
;
m1      db      2,0,defesc,'B'          ; break
m2      db      2,0,defesc,'C'          ; close
m3      db      2,0,defesc,'S'          ; status
m4      db      2,0,defesc,'P'          ; push
m5      db      2,0,defesc,'?'          ; help
m6      db      2,0,defesc,'R'          ; resume logging
;
mktab   dw      m1,m2,m3,m4,m5,m6
;
keybd   ends

code    segment public
        extrn   comnd:near, dopar:near, prserr:near, atoi:near, prompt:near
        assume  cs:code,ds:datas

; Produce a short beep.  The PC DOS bell is long enough to cause a loss
; of data at the port.  Returns normally.

BEEP    PROC    NEAR
        mov     dl,bell
        mov     ah,dconio
        int     dos
        ret
BEEP    ENDP

; Clear to the end of the current line.  Returns normally.

CLEARL  PROC    NEAR
        mov     dx,offset clreol
        jmp     tmsg                    ; Send terminal message
CLEARL  ENDP

; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer.  This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.

CLRBUF  PROC    NEAR
        mov     bx,34H                  ; Serial Device Driver
        mov     cx,2                    ; Read serial port
clrbf1: int     control                 ; Call System Control Device
        cmp     ax,-1                   ; Read anything ?
        jne     clrbf1                  ; Yes, try again
        ret
CLRBUF  ENDP

; clear the mode line written by putmod.  Returns normally.

CLRMOD  PROC    NEAR
        mov     dx,offset on25          ; Move to line 25
        call    tmsg
        call    clearl                  ; Clear to end of line.
        mov     dx,offset off25         ; Restore cursor position
        call    tmsg
        ret
CLRMOD  ENDP

; This routine blanks the screen.  Returns normally.

CMBLNK  PROC    NEAR
        mov     dx,offset clrscr
        jmp     tmsg                    ; Send terminal message.
CMBLNK  ENDP

; Set the current port.

COMS    PROC    NEAR
        jmp     notimp
COMS    ENDP

; Make a copy of the keyboard table so that we can redefine some keys
; when we go into CONNECT state.

CPYKTAB PROC    NEAR
        push    ds
        mov     ax,0
        mov     es,ax                   ; ES -> lowest page in memory
        mov     ax,es:[0712H]
        mov     keyoff,ax               ; Save offset to keytable
        mov     si,ax                   ; For the copy
        mov     ax,es:[0714H]
        mov     keyseg,ax               ; Save segment of keytable
;
        mov     ds,ax                   ; DS:SI -> system keyboard table
        mov     ax,keybd
        mov     es,ax
        mov     di,0                    ; ES:DI -> our keyboard table
;
        mov     cx,0400H                ; Length of table
        cld
        rep     movsb                   ; Copy table
;
        mov     ax,keybd
        mov     ds,ax                   ; Point to our keyboard segment
;
        mov     si,offset mktab
        mov     di,offset keytab+16     ; First microscreen key def
        mov     cx,12
        cld
        rep     movsb                   ; copy pointers
        pop     ds                      ; restore DS
        ret
CPYKTAB ENDP

; Move the cursor to the left margin, then clear to end of line.
; Returns normally.

CTLU    PROC    NEAR
        mov     dx,offset clrlin
        jmp     tmsg
CTLU    ENDP

; Set the baud rate for the current port, based on the value
; in the portinfo structure.  Returns normally.

DOBAUD  PROC    NEAR
        mov     bp,portval
        mov     temp1,ax                ; Save new rate, don't zap old rate yet
        mov     ax,ds:[bp].baud         ; Check if new rate is valid.
        mov     tmp,2
        mul     tmp                     ; Get index into baud table.
        mov     bx,offset bddat         ; Start of table.
        add     bx,ax
        mov     ax,[bx]                 ; The data to output to the port
        cmp     ax,0FFH                 ; Unimplemented baud rate.
        jne     dobd0
        mov     ax,temp1                ; Get back original value.
        mov     ds:[bp].baud,ax         ; Leave rate as is.
        mov     dx,offset badbd         ; Give an error message.
        call    tmsg
        ret
;
dobd0:  mov     dx,ax
        mov     bx,34H                  ; Serial Device Driver
        mov     cx,4                    ; Set transmit baud rate
        int     control
        mov     cx,5                    ; Set receive baud rate
        int     control
        mov     dx,1                    ; Turn on XON/XOFF just in case...
        mov     cx,10                   ; Transmit XON/XOFF
        int     control
        mov     cx,11                   ; Receive XON/XOFF
        int     control
        mov     cx,3                    ; Install changes, zap line, etc...
        int     control
        mov     inited,0                ; Need to re-init on CONNECT
        ret
DOBAUD  ENDP

; Delete a character from the terminal.  This works by printing
; backspaces and spaces.  Returns normally.

DODEL   PROC    NEAR
        mov     dx,offset delstr        ; Erase weird character.
        jmp     tmsg
DODEL   ENDP

; This is called by Kermit initialization.  It checks the
; number of disks on the system, sets the drives variable
; appropriately.  Returns normally.

DODISK  PROC    NEAR
        mov     ah,gcurdsk              ; Current disk value to AL.
        int     dos
        mov     dl,al                   ; Put current disk in DL.
        mov     ah,seldsk               ; Select current disk.
        int     dos                     ; Get number of drives in AL.
        mov     drives,al
        ret
DODISK  ENDP

; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port.  Returns normally.
; This is used during initialization.

GETBAUD PROC    NEAR
        push    ax                      ; save some regs [jrd]
        push    bx
        push    cx                      ; [jrd]
        push    dx                      ; [jrd]
        push    bp                      ; [jrd]
        mov     bx,34H                  ; Serial Device Driver
        mov     cx,4                    ; Transmit baud rate
        mov     dx,-1                   ; Fetch data
        int     control                 ; Go speak to Control Device Driver
        mov     bx,offset bddat         ; -> baud rate table
        mov     cl,0                    ; Keep track of index
getb0:  cmp     ax,[bx]
        je      getb1
        inc     cl
        cmp     cl,baudsiz              ; At the end of the list
        jge     getb2
        add     bx,2
        jmp     getb0
getb1:  mov     ch,0
        mov     bp,portval
        mov     ds:[bp].baud,cx         ; Save rate index in port structure
;;;[jrd]        ret
        jmp     getb3                   ; [jrd]
getb2:  mov     dx,offset erms40
        call    tmsg
getb3:  pop     bp                      ; restore regs [jrd]
        pop     dx                      ; [jrd]
        pop     cx                      ; [jrd]
        pop     bx                      ; [jrd]
        pop     ax                      ; [jrd]
        ret
GETBAUD ENDP

; Initialize local variables and communications port.

LCLINI  PROC    NEAR
        mov     flags.vtflg,0           ; Don't do terminal emulation.
        mov     bx,34H                  ; Control Device Driver
        mov     cx,0                    ; Initialise driver
        mov     dx,0
        int     control
        mov     cx,6                    ; Set transmit bits per character
        mov     dx,8                    ; to 8-bit bytes
        int     control
        mov     cx,8                    ; Set receive bits per character
        mov     dx,7                    ; to 8-bit bytes
        int     control
        mov     cx,8                    ; Set number of stop bits
        mov     dx,1                    ; to 1 stop bit
        int     control
        mov     cx,9                    ; Set parity type
        mov     dx,0                    ; Parity handled by DOPAR.
        int     control
        mov     cx,10                   ; Transmit XON/XOFF
        mov     dx,1                    ; Enabled
        int     control
        mov     cx,11                   ; Receive XON/XOFF
        mov     dx,1                    ; Enabled
        int     control
        mov     cx,3                    ; Install changes
        int     control
        mov     dx,offset kbdesc
        call    tmsg                    ; Re-program keyboard
        call    cpyktab                 ; Make a copy of the keyboard table.
        ret
LCLINI  ENDP

; Homes the cursor.  Returns normally.

LOCATE  PROC    NEAR
        mov     dx,0000H                ; Go to top left corner of screen.
        jmp     poscur
LOCATE  ENDP

; Display mode line.

MODLIN  PROC    NEAR
        mov     al,ourarg.escc
        mov     modbuf.m_echr,' '
        mov     modbuf.m_hlp,' '
        cmp     al,32                   ; ESC char printable ?
        jnb     modl1                   ; Yes, keep going
        add     al,40H                  ; Convert to printable
        mov     modbuf.m_echr,'^'       ; Note control char
        mov     modbuf.m_hlp,'^'
modl1:  mov     modbuf.m_echr+1,al      ; Fill in character
        mov     modbuf.m_hlp+1,al
;
        mov     al,ourarg.baudb         ; Get baud rate
        mov     si,offset unkbaud       ; Just in case it falls out of range
        cmp     al,baudsiz              ; Too big ?
        jnb     modl2                   ; Yes, use default
        mov     cl,2                    ; Each entry is 4 bytes
        shl     al,cl
        mov     ah,0
        add     ax,offset baudn         ; ax -> baud rate string
        mov     si,ax
modl2:  mov     cx,size m_baud          ; length of baud space
        mov     di,offset modbuf.m_baud
        rep     movsb                   ; Copy over baud rate
;
        mov     al,ourarg.parity        ; Get parity code
        mov     cl,2                    ; Each entry is 4 bytes long
        shl     al,cl
        mov     ah,0
        add     ax,offset parnams       ; ax -> parity setting
        mov     si,ax
        mov     cx,4
        mov     di,offset modbuf.m_par
        rep     movsb                   ; Copy over parity setting string
;
        mov     si,offset remmsg        ; Assume remote echoing
        test    ourarg.flgs,lclecho
        jz      modl3
        mov     si,offset lclmsg        ; Doing local echo
modl3:  mov     cx,3
        mov     di,offset modbuf.m_echo
        rep     movsb
;
        mov     si,offset offmsg        ; Assume not logging
        test    ourarg.flgs,capt
        jz      modl4
        mov     si,offset onmsg         ; Logging input
modl4:  mov     cx,3
        mov     di,offset modbuf.m_log
        rep     movsb
;
        mov     dx,offset modbuf
        call    putmod                  ; Print mode line
        ret
MODLIN  ENDP

; Clear microscreen, redisplay time and revert to system keyboard table.

MSCROFF PROC    NEAR
        mov     ax,0000H
        mov     es,ax                   ; Point to Segment zero
        mov     al,es:[401H]            ; Get machine type
        cmp     al,0
        jnz     mscof1                  ; Not our type
        mov     dx,offset offmscr       ; Send setup string
        call    tmsg
;
        mov     ax,keyoff
        mov     es:[0712H],ax           ; Point system to its own keytable
        mov     ax,keyseg
        mov     es:[0714H],ax
mscof1: ret
MSCROFF ENDP

; Test for machine type.  If Apricot PC or XI then setup microscreen and
; touch keypad for connect functions.

MSCRON  PROC    NEAR
        push    ds
        mov     ax,0000H
        mov     es,ax                   ; Point to Segment zero
        mov     al,es:[401H]            ; Get machine type
        cmp     al,0
        jnz     mscon3                  ; Not our type
        mov     dx,offset onmscr        ; Send setup string
        call    tmsg
;
        mov     ax,0
        mov     es:[0712H],ax           ; Point system to our keytable
        mov     ax,keybd
        mov     es:[0714H],ax
        mov     dl,ourarg.escc          ; Store our ESC char in table.
        mov     dh,'R'                  ; Turn on logging
        test    ourarg.flgs,capt
        jz      mscon1
        mov     dh,'Q'                  ; Turn off logging
mscon1: mov     ds,ax                   ; Point DS to keytable segment
        mov     bx,offset m1+2
        mov     cx,6
mscon2: mov     [bx],dl
        add     bx,4
        loop    mscon2
        mov     bx,offset m6
        mov     [bx+3],dh               ; Setup log on/off
mscon3: pop     ds
        ret
MSCRON  ENDP

NOTIMP: mov     dx,offset noimp
        call    tmsg
        jmp     prserr

; Put the number in ax into the buffer pointed to by di.  di is updated.

NOUT    PROC    NEAR
        mov     dx,0
        mov     bx,10
        div     bx
        push    dx
        or      ax,ax
        jz      nout1
        call    nout
nout1:  pop     ax
        add     al,'0'
        stosb
        ret
NOUT    ENDP

; Put the char in AH to the serial port.  This assumes the
; port has been initialized.  XON/XOFF are handled by the port
; driver.  Skip returns on success, returns normally if the
; character cannot be written.

OUTCHR  PROC    NEAR
        push    bx
        push    cx
        push    dx                      ; Save register.
        sub     cx,cx
        mov     al,ah                   ; Parity routine works on AL.
        call    dopar                   ; Set parity appropriately.
        mov     dl,al
        mov     dh,0
        mov     cx,1                    ; Transmit char
        mov     bx,34H                  ; Serial Device Driver
        int     control                 ; System Control Device
        pop     dx
        pop     cx
        pop     bx
        jmp     rskp
OUTCHR  ENDP

;  Position the cursor according to contents of DX:
;  DH contains row, DL contains column.  Origin (top left) = 0, 0
;  Returns normally.

POSCUR  PROC    NEAR
        push    dx                      ; Save row & column position
        mov     dl,esc                  ; Start cursor positioning sequence
        call    tchr
        mov     dl,'Y'
        call    tchr
        pop     dx                      ; Retrieve row position
        mov     al,dh
        call    poscr1
        mov     al,dl
poscr1: push    dx
        add     al,' '
        mov     dl,al
        call    tchr
        pop     dx
        ret
POSCUR  ENDP

; Use for DOS 2.0 and above.  Check the port status.  If no data, skip
; return.  Else, read in a char and return.

PRTCHR  PROC    NEAR
        push    bx
        push    cx
        push    si
        push    bp
        mov     bx,34H
        mov     cx,2
        int     control                 ; Read serial port
        cmp     ax,-1                   ; Character there ?
        jnz     prtch1                  ; Yes, process it...
        pop     bp
        pop     si
        pop     cx
        pop     bx
        jmp     rskp                    ; No character, skip return.
prtch1: mov     bp,portval
        cmp     ds:[bp].parflg,PARNON   ; no parity?
        je      prtch3                  ; then don't strip
        and     al,7fh                  ; else turn off parity
prtch3: pop     bp
        pop     si
        pop     cx
        pop     bx
        ret
PRTCHR  ENDP

; Put a help message on the screen.
; Pass the message in ax, terminated by a null.  Returns normally.

PUTHLP  PROC    NEAR
        push    ax                      ; preserve this
        mov     dx,offset crlf
        call    tmsg
        mov     dx,offset invseq        ; Turn on high intensity
        call    tmsg
        pop     si                      ; point to string again
puthl3: lodsb                           ; get a byte
        cmp     al,0                    ; end of string?
        je      puthl4                  ; yes, stop
        mov     dl,al
        mov     ah,dconio
        int     dos                     ; else write to screen
        jmp     puthl3                  ; and keep going
puthl4: mov     dx,offset nrmseq        ; Back to normal
        call    tmsg
        mov     dx,offset crlf
        call    tmsg
        ret
PUTHLP  ENDP

; Write a line in high intensity on line 25.  The line is pointed to by
; ds:dx, terminated by a $.  Returns normally.

PUTMOD  PROC    NEAR
        push    dx                      ; preserve message pointer.
        mov     dx,offset on25          ; Move down to line 25
        call    tmsg
        mov     dx,offset invseq        ; Turn on high intensity
        call    tmsg
        pop     dx                      ; get message back
        call    tmsg                    ; write it out
        mov     dx,offset nrmseq        ; Normal (low) intensity again
        call    tmsg
        mov     dx,offset off25         ; Restore cursor position
        call    tmsg
        ret                             ; and return
PUTMOD  ENDP

; Jumping here is the same as a ret.

R       PROC    NEAR
        ret
R       ENDP

; Jumping to this location is like retskp.  It assumes the instruction
;   after the call is a jmp addr.

RSKP    PROC    NEAR
        pop     bp
        add     bp,3
        push    bp
        ret
RSKP    ENDP

; Send a break out to the serial port.  Returns normally.
; Need to handle port directly since ACT's Control Device doesn't
; have a 'send break' facility.

SENDBR  PROC    NEAR
        mov     al,5
        out     62H,al                  ; Select SIO write register 5
        mov     al,0FAH
        out     62H,al                  ; Start break
        mov     al,2
sendb0: mov     bx,-1
sendb1: dec     bx                      ; Delay for a while...
        jnz     sendb1
        dec     al
        jnz     sendb0
        mov     al,5
        out     62H,al                  ; Select SIO write register 5
        mov     al,0EAH
        out     62H,al                  ; Finished sending break
        ret
SENDBR  ENDP

; Initialization for using serial port.  XON/XOFF has already been set by
; the local initialization routine.  Returns normally.

SERINI  PROC    NEAR
        cmp     portin,0                ; Initialized already ?
        jne     serin0                  ; Yes, forget it.
        cld                             ; Do increments in string operations
; Some day we may have an interrupt handler to install...
        call    clrbuf                  ; Clear input buffer.
        mov     portin,1                ; Say we've been through once
serin0: ret                             ; We're done.
SERINI  ENDP

; Reset the serial port.  This is the opposite of serini.  Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.

SERRST  PROC    NEAR
        cmp     portin,0                ; Reset already ?
        je      srst1                   ; Yes, forget it
; One day soon we may want to restore the interrupt handler, I hope...
        mov     portin,0
srst1:  ret                             ; All done.
SERRST  ENDP

SHOWKEY PROC    NEAR
        mov     ax,offset shkmsg
        mov     cx,shkmln
        ret
SHOWKEY ENDP

; Send a character to the host, handle local echo.

SNDHST  PROC    NEAR
        push    ax
        mov     ah,al
        call    outchr                  ; Output the character
        nop
        nop
        nop
        pop     ax
        test    ourarg.flgs,lclecho     ; Echoing ??
        jz      sndhs2                  ; No, go on
        mov     dl,al
        mov     ah,dconio
        int     dos
sndhs2: ret
SNDHST  ENDP

; Print a character to the screen.  Returns normally.

TCHR    PROC    NEAR
        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,conout
        int     dos
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
TCHR    ENDP

; Dumb terminal emulator.

TERM    PROC    NEAR
        mov     si,ax                   ; this is source
        mov     di,offset ourarg        ; place to store arguments
        mov     ax,ds
        mov     es,ax                   ; address destination segment
        mov     cx,size termarg
        cld
        rep     movsb                   ; copy into our arg blk
;
        call    clrmod                  ; Clear mode line
        test    ourarg.flgs,modoff      ; Is mode line disabled ?
        jnz     term0                   ; Yes, skip this
        call    modlin
;
term0:  call    mscron                  ; Set up microscreen
        cmp     inited,0                ; inited yet ?
        jnz     term1                   ; yes, skip this bit...
        mov     bx,34H
        mov     dx,1
        mov     cx,12                   ; Turn on RTS
        int     control
        mov     cx,13                   ; Turn on DTR
        int     control
        mov     inited,1                ; Remember we've inited
term1:  call    prtchr
        jmp     short term2             ; have a char...
        nop
        nop
        jmp     short term3             ; no char, go on
term2:  and     al,7FH
        push    ax
        mov     dl,al
        mov     ah,conout
        int     dos                     ; go print it
        pop     ax
        test    ourarg.flgs,capt        ; capturing output?
        jz      term3                   ; no, forget it
        call    ourarg.captr            ; else call the routine
term3:  mov     ah,dconio
        mov     dl,0ffh
        int     dos
        jz      term1                   ; no character, go on
        cmp     al,ourarg.escc          ; escape char?
        je      term5                   ; yes, exit
        call    trnout                  ; translate and output character(s)
        jmp     term1                   ; and keep going
term5:  call    clrmod
        call    mscroff                 ; Clear microscreen
        ret
TERM    ENDP

; Print a message to the screen.  Returns normally.

TMSG    PROC    NEAR
        push    ax
        push    bx
        push    cx
        push    dx
        mov     ah,prstr
        int     dos
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret
TMSG    ENDP

; Enter with char and flags in AX.  Does any necessary character
; translations, then outputs the character(s).

TRNOUT  PROC    NEAR
        test    ourarg.flgs,havtt       ; Translation table given ??
        jz      trnou2                  ; No, just output normally
        mov     cx,ourarg.klen
        mov     di,ourarg.ktab          ; get redefined keys
        repne   scasw                   ; look for this one
        jne     trnou2                  ; Not found, try something else.
        sub     di,ourarg.ktab
        sub     di,2                    ; Get index
        add     di,ourarg.krpl          ; Get translation address
        mov     si,[di]                 ; This is translation
        mov     cl,[si]                 ; Pick up length, increment past it
        inc     si
        mov     ch,0
        jcxz    trnou6                  ; No translation, just return
trnou1: lodsb                           ; get a char
        push    si
        push    cx
        call    sndhst                  ; Send the character
        pop     cx
        pop     si
        loop    trnou1                  ; loop thru rest of translation
        ret                             ; and return
;
trnou2: call    sndhst                  ; output character
trnou6: ret
TRNOUT  ENDP

; Set heath emulation on/off.

VTS     PROC    NEAR
        jmp     notimp
VTS     ENDP

VTSTAT  PROC    NEAR                    ; For use by Status in mssset [jrd]
        ret                             ; no emulator status to report
VTSTAT  ENDP

CODE    ENDS
        END
