     page ,132

;***************************************************************************
;*                                                                         *
;*   VAPIASM.ASM                                                           *
;*                                                                         *
;*   Copyright (C) 1996-1997 Galacticomm, Inc.    All Rights Reserved.     *
;*                                                                         *
;*   This is the assembly companion to the DOS version of VIDAPI.C.  In    *
;*   combination, these sources form the cross-platform Galacticomm video  *
;*   API for DOS.                                                          *
;*                                                                         *
;*   This file is 16-bit DOS only for at least the following reasons:      *
;*   curatr has UINT's hard-wired as dw's and assembly is 16-bit.          *
;*                                                                         *
;*                                                   - T. Stryker 2/8/89   *
;*                                                     and others ongoing  *
;*                                                                         *
;***************************************************************************

ifdef LARGEMAC
; large model
     include modelmtl.mac
else
; huge model
     include modelhpl.mac
endif
        dseg    vapiasm

     public    _colseg
     public    _monseg
     public    _curatr

_curatr label  byte      ;start of 64-byte ansi status region
attrib    db   7         ;attribute byte for video RAM
ansifls db     ANSIOF         ;default to ANSI disabled
ansicnt dw     ?         ;number of ANSI args preceding action letter
ansiarg db     20 dup(?) ;up to 20 individual args
scpreg    dw   0         ;ANSI save-cursor-position register
saveal    db   ?         ;save reg for original ANSI command char
ansiatr db     07H       ;default ANSI attribute
oldcur    dw   0         ;saved (old) cursor coords
scnstt    dw   0         ;default screen start addr (offset)
     dw   0         ;                 (segment)
oscnstt dw     0         ;saved (old) screen start addr (offset)
     dw   0         ;                     (segment)
actcur    db   1         ;cursor is active by default
nacurp    dw   0         ;default non-active cursor position
lacurp    dw   0         ;last active cursor position
period    dw   700H      ;bell period (higher => faster and shorter)
ulx  db   0         ;internal copy of window upper left x
uly  db   0         ;internal copy of window upper left y
lrx  db   79        ;internal copy of window lower right x
lry  db   24        ;internal copy of window lower right y
scropt    db   1         ;internal copy of window scroll option
topscr    db   0         ;internal copy of window scroll top
botscr    db   24        ;internal copy of window scroll bottom
oulx db   0         ;saved internal copy of window upper left x
ouly db   0         ;saved internal copy of window upper left y
olrx db   79        ;saved internal copy of window lower right x
olry db   24        ;saved internal copy of window lower right y
oscropt db     1         ;saved internal copy of window scroll option
usetop    db   0         ;which limit is being used
usebot    db   0         ;which limit is being used
     db   5 dup (0) ;spare space for future enhancements

byte10    db   10        ;constant for decoding field lengths
speedy  dw      1               ;internal copy of fastprintf() speed
iscstt    dw   ?         ;internal ver of screen starting addr (offset)
     dw   ?         ;                         (segment)
dspseg    dw   ?         ;display seg when ddos not running
initted db     0         ;ddos-vectors-initialized flag
canscro db     0         ;Flag, can we scroll with Cur UP/DOWN
_colseg dw     0B800h         ;segment/selector for color screen
_monseg dw     0B000h         ;segment/selector for mono screen

andmsk    db   000H,0FFH,0F7H,0FFH,0F8H,0FFH,0FFH,0F8H   ;ANSI attrib-chg
     db   000H,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH   ;  AND-mask
     db   0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0FFH   ;  lookup table
     db   0FFH,0FFH,0FFH,0FFH,0FFH,0FFH,0F8H,0F8H
     db   0F8H,0F8H,0F8H,0F8H,0F8H,0F8H,0FFH,0FFH
     db   08FH,08FH,08FH,08FH,08FH,08FH,08FH,08FH
     db   0FFH,0FFH

orbits    db   007H,008H,000H,000H,001H,080H,080H,070H   ;ANSI attrib-chg
     db   000H,000H,000H,000H,000H,000H,000H,000H   ;  OR-in bits
     db   000H,000H,000H,000H,000H,000H,000H,000H   ;  lookup table
     db   000H,000H,000H,000H,000H,000H,000H,004H
     db   002H,006H,001H,005H,003H,007H,000H,000H
     db   000H,040H,020H,060H,010H,050H,030H,070H
     db   000H,000H

     endds

ESCAPE    equ  27        ;ANSI sequence starter (followed by '[')

                    ;ansifls bit flag values
ANSIOF    equ  1         ;ANSI recognition disabled
ANSIER    equ  2         ;ANSI escape-received, waiting for bracket
ANSIWD    equ  4         ;ANSI waiting for first digit or letter
ANSIAN    equ  8         ;ANSI accumulating a number

movco     macro     dest,codelabel     ; used like mov for code offsets
     if   SMALL_MOD OR COMPACT_MOD
     mov  dest,offset _text:codelabel
     endif
     if   MEDIUM_MOD OR LARGE_MOD
     mov  dest,offset codelabel
     endif
     endm

        pseg    vapiasm

     proc_def    prxset

     chappy              ; keep C happy
     push es
     test initted,0ffh        ;have vectors been initialized?
     jnz  takem               ;yes
     mov  initted,1      ;no, we'll initialize them then

     mov  ah,0fh              ;find display segment address
     int  10h
     cmp  al,7
     je   dmono
     mov  ax,_colseg
     jmp short fndvid
dmono:    mov  ax,_monseg
fndvid:
     mov  es,ax
     mov  dgroup:dspseg,es    ;remember it

takem:    mov  ax,dspseg
if MICROSOFT
     mov  dx,ax               ;return stuff to caller in dx:ax
     xor  ax,ax               ; (MSC & LAT use different registers)
else
     xor  bx,bx               ;return stuff to caller in ax:bx
endif
     pop  es
     goaway
     end_proc


     proc_def    auxcrt
     chappy              ; keep C happy
     mov  ah,0fh              ;find display segment address
     int  10h
     cmp  al,7
     je   axcol
     mov  ax,_monseg
     jmp short axdun
axcol:    mov  ax,_colseg
axdun:
if MICROSOFT
     mov  dx,ax               ;return stuff to caller in dx:ax
     xor  ax,ax               ; (MSC & LAT use different registers)
else
     xor  bx,bx               ;return stuff to caller in ax:bx
endif
     goaway
     end_proc

     if   lcode
         if        MICROSOFT
                public  _fastprintf
                _fastprintf  proc    far
         else
                public  fastprintf
                fastprintf  proc    far
         endif
     else
         if        MICROSOFT
                public  _fastprintf
                _fastprintf  proc    near
         else
                public  fastprintf
                fastprintf  proc    near
         endif
     endif

     chappy                   ; keep C happy
     push ds
     push es

     call supisc              ;setup internal screen start ptr
     call rdcurp              ;get current cursor pos in dh,dl
     call compsi              ;compute screen offset in si

     if   ldata               ;point at control string
     mov  bx,[bp+@]
     mov  es,[bp+@+2]
     add  bp,@+4
     else
     mov  bx,[bp+@]
     mov  ax,ds
     mov  es,ax
     add  bp,@+2
     endif

pfloop: mov    al,byte ptr es:[bx] ;get next char of ctl stg
     inc  bx             ;bump to next ctl stg char
     or   al,al               ;if null, we're done
     jz   pfdone
        call    outbyt                  ;output it
     jmp short pfloop

pfdone: call   wrcurp              ;reposition cursor to match results
     pop  es
     pop  ds
     goaway

     if  MICROSOFT
            _fastprintf  endp
     else
            fastprintf  endp
     endif

outlit    proc near      ;output literal byte in al, update dx & si
     push ds             ;hoss manuer
     push bx
     mov  ah,attrib      ;get attribute while we still can
     mov  bh,lrx              ;similar sentiments
     mov  ds,iscstt+2
     mov  [si],ax        ;output char & attribute
     add  si,2
     cmp  dl,bh               ;last guy on this line?
     je   isllit              ;yes
     inc  dl             ;no, bump column
     jmp short byelit
isllit: call   donewl              ;do new-line function
byelit: pop    bx
     pop  ds
     ret
outlit    endp

outbyt    proc near      ;output byte in al, update dx & si
     push bx
     mov  bx,speedy      ;slow down a little if desired
slowdn: dec    bx
     jnz  slowdn
     pop  bx

     test ansifls,ANSIOF+ANSIER+ANSIWD+ANSIAN ; unusual case at all?
     jnz  unusul              ;yes
     cmp  al,ESCAPE      ;start of ANSI seq?
     je   gotesc              ;yes

obnorm: mov    ah,attrib      ;get attribute while we still can
     push ds             ;for speed
     mov  ds,iscstt+2
     cmp  al,' '                  ;printable char?
     jb   nprtch              ;no, handle specially
kluge:    mov  [si],ax        ;yes, output char & attribute
     add  si,2

     push ax             ;gack, estab addressability to lrx
     push ds
     mov  ax,dgroup
     mov  ds,ax
     cmp  dl,lrx              ;last guy on this line?
     je   islstg              ;yes
     pop  ds
     pop  ax
     inc  dl             ;no, bump column
     jmp short byebye
islstg: pop    ds
     pop  ax
     call donewl              ;do new-line function
     jmp short byebye

unusul: test   ansifls,ANSIOF      ;is what's unusual that ANSI's off?
     jnz  obnorm              ;yes
     call pransi              ;no, go process ansi
     ret
gotesc: or     ansifls,ANSIER      ;ANSI escape received
     mov  ansicnt,0      ;no args at first
     mov  ansiarg,1      ;(default first two to 1's)
     mov  ansiarg+1,1
     ret

nprtch: cmp    al,10               ;c newline char?
     jne  notnew              ;no
     call donewl              ;yes
     jmp short byebye

notnew: cmp    al,7           ;bell?
     jne  notbel              ;no
     call dobell              ;yes
     jmp short byebye

notbel: cmp    al,13               ;carriage return?
     jne  notcr               ;no
     call docr           ;yes
     jmp short byebye

notcr:    cmp  al,12               ;form feed?
     jne  notff               ;no
     call ffeed               ;yes
     jmp short byebye

notff:    cmp  al,8           ;backspace?
     jne  kluge               ;no, take our chances
     call doback

byebye: pop    ds
     ret
outbyt    endp

pransi    proc near      ;process ANSI activity
     mov  canscro,0      ;reset scroll flag
     test ansifls,ANSIAN      ;accumulating a number yet?
     jz   noanum              ;not yet
     cmp  al,'0'                  ;is this latest a continuation?
     jb   termed              ;no
     cmp  al,'9'
     ja   termed              ;no
     sub  al,'0'                  ;yes, convert digit to binary
     push di
     mov  di,ansicnt          ;index to current digit position
     xchg al,ansiarg[di]      ;multiply existing stuff by 10
     mul  byte10
     add  ansiarg[di],al      ;and add latest digit
     pop  di
     jmp  praret
termed: inc    ansicnt        ;one more argument in place
     cmp  al,';'                  ;yes, end of it, with more to follow?
     jne  nosemi              ;no
     and  ansifls,0FFH-ANSIAN ;yes
     jmp  praret
nosemi: call   doansi              ;go for it!
     jmp short praret

noanum: test   ansifls,ANSIWD      ;waiting for digits yet?
     jz   noawdg              ;no, must be waiting for a bracket
     cmp  al,';'                  ;terminated already?
     je   termed
     cmp  al,'0'                  ;is this a digit or a letter?
     jb   noadig              ;not a digit
     cmp  al,'9'
     ja   noadig              ;not a digit
     sub  al,'0'                  ;convert digit to binary
     push di
     mov  di,ansicnt          ;index to current digit position
     mov  ansiarg[di],al      ;drop digit into next array element
     pop  di
     or   ansifls,ANSIAN      ;flag as accumulating a number
     jmp short praret
noadig: call   doansi              ;go for it!
     jmp short praret

noawdg: cmp    al,'['                  ;it is the confirmation we've awaited?
     jne  maybed              ;no, false alarm
     or   ansifls,ANSIWD      ;yes, now awaiting digits or whatnot
     jmp short praret
maybed: cmp    al,'D'                  ;ANSI scroll down command?
     jne  maybem
     jmp short cangod
maybem: cmp    al,'M'                  ;ANSI scroll up command?
     jne  afalse
     jmp short cangou
afalse: push   ax             ;emit data as presented
     mov  al,ESCAPE
     call outlit
     pop  ax
     mov  ansifls,0      ;return to normal text processing
     call outbyt
praret: ret
cangod: mov    al,'B'                  ;Do a <ESC>[1B with scroll
     jmp short canbye
cangou: mov    al,'A'                  ;Do a <ESC>[1A with scroll
canbye: mov    ansiarg,1
     mov  canscro,1
     call doansi
     ret
pransi    endp

doansi    proc near      ;execute ANSI function, exec letter in al
     mov  ansifls,0      ;munching it, return to norm afterward
     mov  saveal,al      ;save original char in case need echo
     and  al,0DFH        ;make case-independent
     cmp  al,'M'                  ;set graphics rendition
     jne  ck4a

     push bx
     push di
     xor  di,di
     mov  bx,di
sgrlp:    mov  bl,ansiarg[di]           ;get next ansi arg
     mov  al,andmsk[bx]            ;AND-out approp attrib bits
     and  attrib,al
     mov  al,orbits[bx]            ;OR-in approp new ones
     or   attrib,al
     inc  di                  ;done with this?
     cmp  di,ansicnt
     jb   sgrlp                    ;no, go back for more
     pop  di
     pop  bx
     ret

ck4a:     cmp  al,'A'                  ;cursor up
     jne  ck4b
     sub  dh,ansiarg
     jmp  pinhvp
ck4b:     cmp  al,'B'                  ;cursor down
     jne  ck4c
     add  dh,ansiarg
     jmp  pinhvp
ck4c:     cmp  al,'C'                  ;cursor forward
     jne  ck4d
     add  dl,ansiarg
     jmp  pinhvp
ck4d:     cmp  al,'D'                  ;cursor backward
     jne  ck4s
     sub  dl,ansiarg
     jmp  pinhvp
ck4s:     cmp  al,'S'                  ;save cursor position
     jne  ck4u
     mov  scpreg,dx
     ret
ck4u:     cmp  al,'U'                  ;restore cursor position
     jne  ck4j
     mov  dx,scpreg
     jmp  pinhvp              ;ignore ? ansi commands
ck4j:     cmp  al,'J'                  ;clear?
     jne  ck4r           ;no
     cmp  ansicnt,0      ;any ansi arguments?
     je   doceos              ;no, must be clear to end of screen
     cmp  ansiarg,0      ;clear to end of screen?
     jne  ckcscn              ;no
doceos: call   ceoscn              ;clear to end of screen
     ret
ckcscn: cmp    ansiarg,2      ;clear full screen?
     jne  ck4r
     mov  ah,attrib
     push ds
     mov  ds,iscstt+2
     call ffeed
     pop  ds
     ret
ck4r:     cmp  saveal,'r'              ;set scroll range
     jne  ck4k
     mov  ah,ansiarg+1
     or   ah,ah               ;can't be zero
     jz   blooff
     sub  ah,1
     mov  al,ansiarg
     or   al,al               ;can't be zero
     jz   blooff
     sub  al,1
     add  al,uly
     add  ah,uly

     cmp  ah,lry
     jg   blooff
     cmp  ah,al               ;make sure top < bottom
     jl   blooff

     mov  botscr,ah
     mov  topscr,al
blooff: ret
ck4k:     cmp  al,'K'                  ;clear to end of line
     jne  ck4hf
     call ceolut
     ret
ck4hf:    cmp  al,'H'                  ;cursor position function
     je   cuphvp
     cmp  al,'F'
     jne  abarf
cuphvp: mov    dh,ansiarg
     add  dh,uly
     sub  dh,1
     mov  dl,ansiarg+1
     add  dl,ulx
     sub  dl,1
pinhvp: call   prep4r
     cmp  dh,usetop      ;don't let y go above window top
     jge  ulyok
     mov  dh,usetop
     test canscro,0ffh
     jnz  revscol
ulyok:    cmp  dh,usebot      ;don't let y go below window bottom
     jle  lryok
     mov  dh,usebot
     test canscro,0ffh
     jnz  scrlju
lryok:    cmp  dl,ulx              ;don't let x go beyond left edge
     jge  ulxok
     mov  dl,ulx
ulxok:    cmp  dl,lrx              ;don't let x go beyond right edge
     jle  lrxok
     mov  dl,lrx
lrxok:    call compsi              ;recompute data destination
     ret

scrlju: push   ax
     push ds
     mov  ah,attrib      ;Get attribute for blank line
     mov  ds,iscstt+2
     call donewl
     pop  ds
     pop  ax
     jmp short lryok

revscol:
     push ax
     push ds
     mov  ah,attrib      ;Get attribute for blank line
     mov  ds,iscstt+2
     call dorevl
     pop  ds
     pop  ax
     jmp short lryok

abarf:    mov  al,ESCAPE      ;none of the above, output literal
     call outlit
     mov  al,'['
     call outlit
     mov  al,saveal
     call outlit
     ret
doansi    endp

docr proc near      ;do a carriage return
     push ds             ;establish addressability to ulx
     push ax
     mov  ax,dgroup
     mov  ds,ax
     mov  dl,ulx              ;cursor back to start of line
     call compsi              ;figure si anew
     pop  ax
     pop  ds
     ret
docr endp

ffeed     proc near      ;do a "form feed" (clear screen window)
     push cx             ;save regs
     push bx
     push es
     push di
     push ax
     mov  ax,ds               ;point es at screen
     mov  es,ax
     mov  ax,dgroup      ;establish addressability to ulx etc.
     mov  ds,ax
     call prep4r
     xor  cx,cx               ;get count of bytes to clear each time
     mov  cl,lrx
     sub  cl,ulx
     mov  dl,ulx              ;point at first byte to clear
     mov  dh,usetop
     call compsi
     mov  bh,usebot      ;grab it while still can
     mov  ax,es               ;point ds back at screen
     mov  ds,ax
     pop  ax             ;get attrib byte back
     mov  al,' '                  ;make a space with that attrib
     cld
ffdnxt: mov    di,si               ;clear out a line
     add  di,2
     mov  [si],ax
     jcxz ffddbt
     push cx
     push si
     rep movsw
     pop  si
     pop  cx
ffddbt: add    si,160              ;bump to next line
     inc  dh
     cmp  dh,bh               ;done?
     jbe  ffdnxt              ;no

     pop  di             ;restore regs
     pop  es
     pop  bx
     pop  cx

     push ax             ;establish addressability to ulx etc.
     push ds
     mov  ax,dgroup
     mov  ds,ax
     mov  dl,ulx              ;point si at "home" byte of window
     mov  dh,usetop
     pop  ds
     pop  ax
     call compsi
     ret
ffeed     endp

prep4r    proc near      ; prepare usebot and usetop for screen writes
     push ax
     test ansifls,ANSIOF      ; if not ANSI, just use setwin() lims
     jnz  stanli
     mov  al,uly              ; if ANSI, use greater of uly & topscr
     cmp  al,topscr
     jge  pp4sut
     mov  al,topscr
pp4sut: mov    usetop,al
     mov  al,lry              ; if ANSI, user lesser of lry & botscr
     cmp  al,botscr
     jle  pp4sub
     mov  al,botscr
pp4sub: mov    usebot,al
     pop  ax
     ret
stanli: mov    al,uly              ; if not ANSI, use uly and lry
     mov  usetop,al
     mov  al,lry
     mov  usebot,al
     pop  ax
     ret
prep4r    endp

donewl    proc near           ;do a "newline"
     push ax             ;establish addressability to ulx etc.
     push ds
     mov  ax,dgroup
     mov  ds,ax
     call prep4r
     mov  dl,ulx              ;cursor back to start of line
     cmp  dh,usebot      ;will this involve scrolling?
     jge  pscrl               ;yes
     inc  dh             ;no
     jmp short fgasc          ;but compute si anew for windowing

pscrl:    mov  dh,usebot
scroll: test   scropt,0ffh         ;scrolling enabled?
     jz   fgasc               ;no, forget about scrolling
     pop  ds             ;get screen segment and attrib back
     pop  ax
     push ax             ;   (but keep them on the stack too)
     push ds
     push cx             ;save regs
     push bx
     push es
     push di
     push dx
     push ax
     mov  ax,ds               ;point es at screen
     mov  es,ax
     mov  ax,dgroup      ;establish addressability to ulx etc.
     mov  ds,ax
     call prep4r
     xor  cx,cx               ;get count of bytes to move each time
     mov  cl,lrx
     sub  cl,ulx
     mov  dl,ulx              ;point at first destination byte
     mov  dh,usetop
     call compsi
     mov  bh,usebot      ;get lry while we still can
     mov  ax,es               ;point ds at screen again
     mov  ds,ax
     add  cl,1
     cld
scrnxt: cmp    dh,bh               ;done?
     je   scrldn              ;yes
     mov  di,si               ;make last source the new destination
     add  si,160              ;and the new source one line beyond
     push cx             ;remember how many bytes to move
     push si             ;and where they're from
     rep movsw           ;scroll one line
     pop  si
     pop  cx
     inc  dh             ;no, bump to next line
     jmp short scrnxt

scrldn: pop    ax             ;get attrib byte back
     mov  al,' '                  ;make a space with that attrib
     mov  di,si               ;now clear out bottom line
     add  di,2
     mov  [si],ax
     dec  cx
     jz   dntbth
     rep movsw

dntbth: pop    dx             ;restore regs and go home
     pop  di
     pop  es
     pop  bx
     pop  cx
fgasc:
     pop  ds
     pop  ax
     call compsi              ;figure si anew
     ret
donewl    endp

dorevl    proc near           ;do a reverse scroll
     push ax             ;establish addressability to ulx etc.
     push ds
     mov  ax,dgroup
     mov  ds,ax
     call prep4r
     mov  dl,ulx              ;cursor back to start of line
     cmp  dh,usetop      ;will this involve scrolling?
     je   rscrol              ;yes
     inc  dh             ;no
     jmp short fgasc          ;but compute si anew for windowing

rscrol: test   scropt,0ffh         ;scrolling enabled?
     jz   fgarv               ;no, forget about scrolling
     pop  ds             ;get screen segment and attrib back
     pop  ax
     push ax             ;   (but keep them on the stack too)
     push ds
     push cx             ;save regs
     push bx
     push es
     push di
     push dx
     push ax
     mov  ax,ds               ;point es at screen
     mov  es,ax
     mov  ax,dgroup      ;establish addressability to ulx etc.
     mov  ds,ax
     call prep4r
     xor  cx,cx               ;get count of bytes to move each time
     mov  cl,lrx
     sub  cl,ulx
     mov  dl,ulx              ;point at first destination byte
     mov  dh,usebot
     call compsi
     mov  bh,usetop      ;get top line while we still can
     mov  ax,es               ;point ds at screen again
     mov  ds,ax
     inc  cl
     cld
rvsnxt: cmp    dh,bh               ;done?
     je   rvscdn              ;yes
     mov  di,si               ;make last source the new destination
     sub  si,160              ;and the new source one line beyond
     push cx             ;remember how many bytes to move
     push si             ;and where they're from
     rep movsw           ;scroll one line
     pop  si
     pop  cx
     dec  dh             ;no, bump to next line
     jmp short rvsnxt

rvscdn: pop    ax             ;get attrib byte back
     mov  al,' '                  ;make a space with that attrib
     mov  di,si               ;now clear out bottom line
     add  di,2
     mov  [si],ax
     dec  cx
     jz   rvfibo
     rep movsw

rvfibo: pop    dx             ;restore regs and go home
     pop  di
     pop  es
     pop  bx
     pop  cx
fgarv:
     pop  ds
     pop  ax
     call compsi              ;figure si anew
     ret
dorevl    endp

dobell    proc near      ;make a beep
     push bx             ; push regs used
     push cx
     push dx
     push ds
     mov  ax,dgroup      ; address data group
     mov  ds,ax
     mov  ax,period      ; get frequency
     or   ax,ax
     jz   beldun              ; do nothing if zero
     mov  cx,ax
     cli
     in   al,61H              ; turn on speaker
     or   al,3
     out  61H,al
     sti
     mov  ax,cx               ; output frequency
     out  42H,al
     mov  al,ah
     out  42H,al
beloop: push   cx
     mov  cx,25               ; don't let this go on forever
beloo2: mov    bx,ax               ; cycled yet?
     in   al,42H
     mov  ah,al
     in   al,42H
     xchg al,ah
     cmp  ax,bx
     ja   belpop
     loop beloo2              ; no
belpop: pop    cx
     loop beloop              ; yes, count one more cycle
     in   al,61H              ; turn off speaker
     and  al,0FFH-2
     out  61H,al
beldun: pop    ds             ; pop regs used
     pop  dx
     pop  cx
     pop  bx
     ret
dobell    endp

doback    proc near      ;do a backspace
     push ax             ;establish addressability to ulx etc.
     push ds
     mov  ax,dgroup
     mov  ds,ax
     call prep4r
     cmp  dl,ulx              ;at left margin?
     jne  jstbkp              ;no, just back up
     cmp  dh,usetop      ;yes, on top line too?
     je   dbexit              ;yes, ignore
     dec  dh             ;no, go to end of prev line
     mov  dl,lrx
     inc  dl
     call compsi
jstbkp: sub    si,2           ;no, back up
     pop  ds             ;address screen again
     pop  ax
     mov  al,' '                  ;overwrite with space
     mov  [si],ax
     dec  dl             ;keep dh/dl in sync
     ret
dbexit: pop    ds             ;scram, do nothing
     pop  ax
     ret
doback    endp

supisc    proc near
if  MICROSOFT
     call _prxset         ;freeze segment uncond
     mov  bx,ax
     mov  ax,dx
else
     call prxset              ;freeze segment uncond
endif
     mov  cx,scnstt      ;express screen addr start set?
     or   cx,scnstt+2
     jz   usaxbx              ;no, use default
     mov  bx,scnstt      ;yes, set up to use it
     mov  ax,scnstt+2

usaxbx: mov    iscstt,bx
     mov  iscstt+2,ax

     ret
supisc    endp


compsi    proc near      ;return screen offset of row dh, column dl in si
     push ax
     push dx
     push ds
     mov  ax,dgroup      ;establish addressability to iscstt
     mov  ds,ax
     mov  al,80               ;multiply row number by screen width
     mul  dh
     xor  dh,dh               ;add row number (word add!)
     add  ax,dx
     shl  ax,1           ;double to account for attrib byte
     mov  si,ax               ;set output reg
     add  si,iscstt
     pop  ds
     pop  dx
     pop  ax
     ret
compsi    endp


     proc_def    setatr

     chappy                   ; keep C happy

     mov  al,[bp+@]      ;set attribute byte
     mov  attrib,al

     goaway
     end_proc


        proc_def    cleareol

     chappy                   ; keep C happy

     call supisc              ;setup internal screen start ptr
     call rdcurp              ;get current cursor pos in dh,dl
     call compsi              ;compute screen offset in si
     call ceolut              ;call clear to end of line utility
     goaway
     end_proc

ceolut    proc near      ;clear-to-end-of-line utility
     push ds
     push bx
     push cx
     push si
     mov  bh,attrib      ;get attribute byte while we can
     mov  cl,lrx              ;find number of chars to zap
     inc  cl
     xor  ch,ch
     sub  cl,dl
     mov  ds,iscstt+2         ;get addressability to screen
     mov  bl,32
celoop: mov    [si],bx        ;zap those chars
     add  si,2
     loop celoop
     pop  si
     pop  cx
     pop  bx
     pop  ds
     ret
ceolut    endp

ceoscn    proc near           ; clear to end of screen
     push ds
     push bx
     push cx
     push si
     push di
     push dx
     push ax
     call prep4r              ;prep 'usebot' for writes
     mov  bh,attrib      ;get attribute byte while we can
     mov  bl,32               ;set chars to space
     mov  ah,usebot      ;get bottom of screen
     mov  al,lrx              ;...and char count for full lines
     inc  al
     sub  al,ulx
     xor  ch,ch
     mov  cl,lrx              ;find number of chars left on this line
     inc  cl
     sub  cl,dl
     push si             ;save current si
     mov  dl,ulx              ;point at first char of current line
     call compsi
     mov  di,si               ;save for later
     pop  si             ;restore to current cursor pointer
     mov  ds,iscstt+2         ;get addressability to screen
ceoslp: mov    [si],bx        ;zap characters
     add  si,2
     loop ceoslp
     xor  cx,cx               ;now set count for full lines
     mov  cl,al
     add  di,160              ;point to first char of next line
     mov  si,di
     inc  dh             ;done yet?
     cmp  dh,ah
     jbe  ceoslp              ;no
     pop  ax             ;restore regs
     pop  dx
     pop  di
     pop  si
     pop  cx
     pop  bx
     pop  ds
     ret
ceoscn    endp

     proc_def    locate

     chappy                   ; keep C happy

     call rdcurp              ;get current cursor pos in dh,dl
     mov  oldcur,dx      ;save in case rstloc later
     mov  dl,[bp+@]      ;load dx with dest coords
     mov  dh,[bp+@+2]
     call wrcurp              ;put cursor there

     goaway
     end_proc



     proc_def    rstloc

     chappy                   ; keep C happy

     mov  dx,oldcur      ;get coords as of last locate
     call wrcurp              ;put cursor there

     goaway
     end_proc



     proc_def    curcurx

     chappy                   ; keep C happy

     call rdcurp              ;get current cursor pos in dh,dl
     xor  ax,ax               ;return x to caller
     mov  al,dl

     goaway
     end_proc



     proc_def    curcury

     chappy                   ; keep C happy

     call rdcurp              ;get current cursor pos in dh,dl
     xor  ax,ax               ;return y to caller
     mov  al,dh

     goaway
     end_proc



     proc_def    setwin

     chappy                   ; keep C happy

     mov  ax,[bp+@]    ;write parms to internal copies
     xchg scnstt,ax      ;and save old values for restore
     mov  oscnstt,ax
     mov  ax,[bp+@+2]
     xchg scnstt+2,ax
     mov  oscnstt+2,ax
     mov  al,[bp+@+4]
     xchg ulx,al
     mov  oulx,al
     mov  al,[bp+@+6]
     xchg uly,al
     mov  ouly,al
     mov  al,[bp+@+8]
     xchg lrx,al
     mov  olrx,al
     mov  al,[bp+@+10]
     xchg lry,al
     mov  olry,al
     mov  al,[bp+@+12]
     xchg scropt,al
     mov  oscropt,al
     goaway
     end_proc



     proc_def    rstwin

     chappy                   ; keep C happy

     mov  ax,oscnstt          ;restore old parms from saved copies
     mov  scnstt,ax
     mov  ax,oscnstt+2
     mov  scnstt+2,ax
     mov  al,oulx
     mov  ulx,al
     mov  al,ouly
     mov  uly,al
     mov  al,olrx
     mov  lrx,al
     mov  al,olry
     mov  lry,al
     mov  al,oscropt
     mov  scropt,al

     goaway
     end_proc



     proc_def    prfspd

     chappy                   ; keep C happy

     mov  ax,[bp+@]    ;write parm to internal copy
     mov  speedy,ax

     goaway
     end_proc

     proc_def   ansion

     chappy                   ; keep C happy

     test word ptr [bp+@],0FFFFH   ;turning ANSI on or off?
     jz   turnoff        ;off
     and  ansifls,0FFH-ANSIOF ;on (turn "off" off)
     mov  al,ansiatr          ;restore saved ANSI attrib
     mov  attrib,al
     mov  al,uly              ;Make sure we are in bounds....
     cmp  al,topscr
     jle  ulok4n
     mov  topscr,al
ulok4n: mov    al,lry
     cmp  al,botscr
     jge  aonret
     mov  botscr,al
     jmp short aonret

turnoff:or     ansifls,ANSIOF      ;turn ANSI off (but save context bits)
     mov  al,attrib      ;save ANSI attrib for later
     mov  ansiatr,al

aonret: goaway
     end_proc

     proc_def   belper

     chappy                   ; keep C happy

     mov  ax,word ptr [bp+@]  ;set bell period
     mov  period,ax

     goaway
     end_proc

     proc_def cursact    ; set cursor active (actually moving) or not

     chappy                   ; keep C happy

     mov  al,[bp+@]      ; any change in status here?
     cmp  al,actcur
     je   cactex              ; no
     or   al,al               ; are we going active?
     jnz  cacton              ; yes
     call rdcurp              ; no, inactive, remember current pos
     mov  nacurp,dx
     mov  lacurp,dx      ; remember last-active spot too
     mov  actcur,0
     jmp short cactex
cacton: mov    actcur,al      ; going active
     mov  dx,nacurp      ; has pos changed since last active?
     cmp  dx,lacurp
     je   cactex              ; no, no need to call wrcurp then
     call wrcurp
cactex:
     goaway
     end_proc

rdcurp    proc near      ; read cursor position, return in dh,dl (r,c)

     test actcur,0FFH         ; cursor active?
     jnz  rdccca              ; yes
     mov  dx,nacurp      ; no, return ram copy
     ret

rdccca: cmp    dspseg,0F000H       ;Charge Card is active?
     jae  rdhdwe              ;yes, read hardware directly

; the following "int 10h" call screws up the ALL ChargeCard in 960K mode
;
     xor  bh,bh               ;get current cursor pos in dh,dl
     mov  ah,3
     int  10h
     ret

; so, we access the CRT controller hardware directly instead

rdhdwe: push   ax
     push cx
     mov  dx,3B4H        ; read cursor offset hi byte
     mov  al,14
     out  dx,al
     inc  dx
     in   al,dx
     and  al,3FH
     mov  ah,al
     dec  dx             ; read cursor offset low byte
     mov  al,15
     out  dx,al
     inc  dx
     in   al,dx
     mov  cl,80
     div  cl             ; form row # in al, column in ah
     mov  dh,al               ; translate to expected output form
     mov  dl,ah
     pop  cx
     pop  ax
     ret

rdcurp    endp

wrcurp    proc near      ; write cursor position, input in dh,dl (r,c)

     test actcur,0FFH         ; cursor active?
     jnz  wrccca              ; yes
     mov  nacurp,dx      ; no, write ram copy
     ret

wrccca: cmp    dspseg,0F000H       ;Charge Card is active?
     jae  wrhdwe              ;yes, read hardware directly

; the following "int 10h" call screws up the ALL ChargeCard in 960K mode
;
     xor  bh,bh               ;reposition cursor
     mov  ah,2
     int  10h
     ret

; so, we access the CRT controller hardware directly instead

wrhdwe: push   ax
     push cx
     push dx
     mov  al,dh               ; multiply row number by 80
     mov  cl,80
     mul  cl
     xor  dh,dh               ; add column number
     add  ax,dx
     mov  cx,ax
     mov  dx,3B4H        ; write cursor offset hi byte
     mov  al,14
     out  dx,al
     inc  dx
     mov  al,ch
     out  dx,al
     dec  dx             ; write cursor offset low byte
     mov  al,15
     out  dx,al
     inc  dx
     mov  al,cl
     out  dx,al
     pop  dx
     pop  cx
     pop  ax
     ret

wrcurp    endp

     endps

     end

