;       SCCSID = @(#)bvsext.asm 6.4 91/05/20
        PAGE    58,132
        TITLE   BvsExt.Asm -- Base Video Subsystem Extended calls
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;/*********************** START OF SPECIFICATIONS ***********************/
;/*                                                                     */
;/* SOURCE FILE NAME:    BvsExt.Asm                                     */
;/*                                                                     */
;/* DESCRIPTIVE NAME:    BVS Extended Routines                          */
;/*                                                                     */
;/* COPYRIGHT:   Microsoft, 1988                                        */
;/*                                                                     */
;/* STATUS:      na                                                     */
;/*                                                                     */
;/* NOTES:       Executes on level 3                                    */
;/*                                                                     */
;/*    DEPENDENCIES:     none                                           */
;/*                                                                     */
;/*    RESTRICTIONS:     none                                           */
;/*                                                                     */
;/*    PATCH LABEL:      na                                             */
;/*                                                                     */
;/* ENTRY POINT: BvsCheckCharType                                       */
;/*              BvsCreateCA, BvsSetCAState,BvsDestroyCA                */
;/*                                                                     */
;/* EXTERNAL REFERENCES: RBufferUpdate                                  */
;/*                                                                     */
;/************************ END OF SPECIFICATIONS ************************/

.xlist
        INCLUDE bvscb.inc               ; BVS Data Structures
        INCLUDE bvsparms.inc            ; BVS stack parmeters
        INCLUDE bvsextrn.inc            ;BVS external definitions       ;@T52
        INCLUDE error2.inc              ; Error Equates
        INCLUDE bvsdbcs.inc
        INCLUDE infoseg.inc
        INCLUDE struc.inc
        INCLUDE dc1segs.inc                                             ;MDLL
.list

        .386p                   ;@D549


BVSISEG SEGMENT WORD PUBLIC 'FAR_DATA' USE16    ;@D549             ;@T52;MDLL
BVSISEG ENDS



        EXTRN   DOSALLOCSEG:FAR
        EXTRN   DOSFREESEG:FAR
        EXTRN   DOSGETDBCSEV:FAR        ;Get DBCS environment vector
        EXTRN   DOSGETSEG:FAR
        EXTRN   DOSEXITLIST:FAR

        EXTRN   AllBuffer:NEAR
        EXTRN   AllVDH:NEAR
        EXTRN   CallTbl:NEAR
        EXTRN   AllSetVarInfo:NEAR      ;Common VDH routine in BvsState ;B790218

BVS3SEG SEGMENT BYTE PUBLIC 'CODE' USE16        ;@D549
        ASSUME  CS:CODE02                                               ;MDLL

LVBrefresh equ  0
CAcopy     equ  1

CABMIN          equ     10      ; minmum size of a CA Block
CABOPTION       equ     12      ; minmum size of a CA Block with options
CABFORMAT       equ     13      ; minmum size of a CA Block with format ID
CABATTRCOUNT    equ     14      ; minmum size of a CA Block with attr count
CABMAX          equ     size CAB; maximum size of a CA Block

empty           equ     0
invalid_handle  equ    -1
partial_isect   equ     1
full_isect      equ     2

CA_Formats      equ     3       ; number of formats                     ;j-ys3m
CA_FormatTable  label byte      ; formatID / Attribute count
        db      00h,01h
        db      70h,03h
        db      01h,01h         ; Epoch hardware support                ;j-ys3m

;***    ManageCAS
;
;   This routine determines which LVB (CA or screen group) is affected
;   by the current read or write calls and directs that read or write
;   to the appropriate buffer.  If the call is a write call and some CAs
;   need to be redrawn, ManageCAS has this done.
;
;   PSEUDOCODE
;
;       call SetExtBufUpParms to set up for using the main LVB
;       if (this process is the CA process)
;           Call IsInRect on the origin of the write and ActCARect
;           if (the write starts inside ActCARect)
;               call FindCA to locate the CA that should be used
;               if (a valid CA is returned)
;                   call SetExtBufUpParms to set up for using the CA LVB
;       call CallTbl[BvsFunc.SBCS_FUNC] to realize the BVS function
;       if (was the PVB touched by the call)
;           copy the affected rect from the parmblock to TouchRect
;           call IsectRect on VisCARect and TouchRect
;           if (some conversion area was touched)
;               call RedrawCAS with the CA above and TouchRect to redraw CAs
;
;   ENTRY:  si - offset in of function in BVS function call table
;           ds - BVSCB
;           es - BVSISEG
;
;   EXIT:   dependent on function
;
;   USES:   all
;

ManageCAS   PROC    NEAR
        PUBLIC  ManageCAS

        xor     di,di                   ; (di) = 0, main LVB  (Invalid CA)
        xchg    si,di                   ; (si) = main LVB, (di) = function offst
        call    SetExtBufUpParms        ; prepare to use screen group LVB
        test    es:bvsi_flags,bvsi_f_caproc ; Is this the CA process?
        jz      mcas10                  ;   no, preceed to execute call

        call    GetOrigin               ; Is there an origin for this call?
        jc      mcase                   ;   no, signal error, invalid call
                                        ; (ax,dx) = origin for the call
        call    FindCA                  ; find the CA that contains origin
        or      si,si                   ; Is the origin in a CA?
        jz      mcas10                  ;   no, preceed to execute call

        call    SetExtBufUpParms        ; set up the BufferUpdate parm block

mcas10: xchg    di,si                   ; (si) = CA, (di) = function offst
        push    si                      ; save si
        push    di                      ; save di
        push    ds
        call    cs:CallTbl[si].func_sbcs; call the appropriate BVS routine
        pop     ds
        pop     di                      ; restore di
        pop     si                      ; restore si
        or      ax,ax                   ; was there an error?
        jnz     mcasx                   ;   yes, do not redraw CAs

        cmp     [bp].vp_touchxleft,-1   ; was the PVB written to?
        jz      mcasx                   ;   no, do not redraw CAs

        mov     bx,bvs_TouchRect        ; (bx) = offset of TouchRect
                                        ; copy rect from parmblock to TouchRect
        mov     ax,[bp].vp_touchxleft   ; (ax) = left side of affected rect
        mov     [bx].rec_xLeft,ax       ; left side of TouchRect = left CA
        mov     ax,[bp].vp_touchxright  ; (ax) = right side of affected rect
        mov     [bx].rec_xRight,ax      ; right side of TouchRect = right CA
        mov     ax,[bp].vp_touchytop    ; (ax) = top side of affected rect
        mov     [bx].rec_yTop,ax        ; top side of TouchRect = top CA
        mov     ax,[bp].vp_touchybottom ; (ax) = bottom side of affected rect
        mov     [bx].rec_yBottom,ax     ; bottom side of TouchRect = bottom CA

; MCH begin mod
; rationale: if (!TopCA && Touch^VisCA) redraw Touch

        .if <ZERO di> OR
        .if <di ne ds:bvs_CA_lru>       ; not top CA

            push   di                   ; save CA written to (if any)

            mov    di,bvs_WriteRect     ; don't actually care about result
            mov    si,bvs_VisCARect
            ; bx is still the TouchRect returned by Update

            call   IsectRect

            pop    si                   ; now si is CA written to (if any)

            .if <nc>
                .if <ZERO si>
                    mov    si,ds:bvs_CA_lru
                    mov    si,[si].cas_Up
                .endif
                call    RedrawCAS       ; redraw if Touch^VisCA
            .endif

        .endif
; MCH end mod

mcas40: xor     ax,ax
mcasx:  xor     bx,bx                   ; (bx) = 0
        ret

mcase:  mov     ax,ERROR_VIO_INVALID_PARMS  ; (ax) = error code
        jmp     short mcasx


ManageCAS   ENDP



;***    SetExtBufUpParms - Set up DBCS only BufferUpdate parameters
;
;   This routine sets up the DBCS only BufferUpdate parameters in the
;   parameter block on the stack.
;
;   PSEUDOCODE
;
;       set packet length to DBCS_length
;       if (CA to be set is 0)
;           set LVB for write to general LVB
;           set LVB origin offset to (0,0)
;           set LVB column count to general LVB column count
;           set LVB row count to general LVB row count
;           set LVB format ID to format ID for current mode
;           set LVB attribute count to attribute count for current mode
;       else
;           set LVB for write to CA LVB
;           set LVB origin offset to CA origin offset
;           set LVB column count to CA LVB column count
;           set LVB row count to CA LVB row count
;           set LVB format ID to format ID for CA
;           set LVB attribute count to attribute count for CA
;           if (CA is invisible)
;               set parameter block flags to believe BackGround
;
;   ENTRY:  si - offset of the CA to be written to, zero if screen group LVB
;           ds - BVSCB
;           es - BVSISEG
;
;   EXIT:   extended parameters set up in parameter packet
;
;   USES:   ax
;
                    PUBLIC  SetExtBufUpParms
SetExtBufUpParms    PROC    NEAR

        mov     [bp].vp_parmlength,46   ; ParmList length
        mov     [bp].vp_touchxleft,-1   ; Left most column affected by write
        mov     [bp].vp_touchytop,-1    ; Top most row affected by write
        mov     [bp].vp_touchxright,-1  ; Left most column affected by write
        mov     [bp].vp_touchybottom,-1 ; Bottom most row affected by write
        or      si,si                   ; Use the screen group LVB?
        jnz     sebp10                  ;   no, use the CA LVB

        mov     ax,es:bvsi_lvbsel       ; (ax) = LVB selector
        mov     [bp].vp_lvbsel,ax       ; Selector of Logical Buffer
        mov     [bp].vp_lvbcoloff,0     ; Screen row offset of LVB in cells
        mov     [bp].vp_lvbrowoff,0     ; Screen col offset of LVB in cells
        mov     ax,ds:bvs_cols          ; (ax) = width of the screen in cells
        mov     [bp].vp_lvbwidth,ax     ; Width of LVB in cells
        mov     ax,ds:bvs_rows          ; (ax) = height of the screen in cells
        mov     [bp].vp_lvbheight,ax    ; Height of LVB in cells
        mov     ax,word ptr ds:bvs_attrformat ; (al) = format ID, (ah) = # attr
        mov     [bp].vp_lvbfidattr,ax   ; Format ID and attribute count of LVB
        jmp     short sebpx             ; parameters set, exit

sebp10: mov     ax,[si].cas_areasel     ; (ax) = CA LVB selector
        mov     [bp].vp_lvbsel,ax       ; Selector of Logical Buffer
        mov     ax,[si].cas_xLeft       ; (ax) = X offset of LVB
        mov     [bp].vp_lvbcoloff,ax    ; Screen row offset of LVB in cells
        mov     ax,[si].cas_yTop        ; (ax) = Y offset of LVB
        mov     [bp].vp_lvbrowoff,ax    ; Screen col offset of LVB in cells
        mov     ax,[si].cas_xRight      ; (ax) = X offset of LVB
        sub     ax,[si].cas_xLeft       ; (ax) = width of LVB - 1
        inc     ax                      ; (ax) = width
        mov     [bp].vp_lvbwidth,ax     ; Width of LVB in cells
        mov     ax,[si].cas_yBottom     ; (ax) = Y offset of LVB
        sub     ax,[si].cas_yTop        ; (ax) = height of LVB - 1
        inc     ax                      ; (ax) = height
        mov     [bp].vp_lvbheight,ax    ; Height of LVB in cells
        mov     ax,word ptr [si].cas_formatid ; (al) = format ID, (ah) = # attr
        mov     [bp].vp_lvbfidattr,ax   ; Format ID and attribute count of LVB

        test    [si].cas_flags,cas_f_visible; Is the CA visible
        jnz     sebpx                   ;   yes, allow AllVDH to specify FG/BG

        mov     [bp].vp_flags,vp_f_physical+vp_f_logical; do not copy onto PVB
;       mov     [bp].vp_flags,0         ; pretend we are in the background
sebpx:  ret

SetExtBufUpParms    ENDP


;***    GetOrigin - Determine the (X,Y) origin of a read or write call
;
;   This routine take the offset of a function in the main BVS call table
;   and the parameters pushed on the stack and determines whether the call
;   is allowed for CAs and if it is, gets the origin of the read or write.
;
;   The list functions that can read or write to CAs is:
;
;       ReadCharStr
;       ReadCellStr
;       WrtNChar
;       WrtNAttr
;       WrtNCell
;       WrtCharStr
;       WrtCharStrAtt
;       WrtCellStr
;
;   Note: This routine makes assumptions about the relationships between
;   VIO function numbers.  The list of VIO function number can be found
;   in BVSPARMS.INC.
;
;   PSEUDOCODE
;
;       convert the table offset into a function number
;       If ((function is < lowest numbered read function) ||
;           (function is > highest numbered read function))
;           return error
;       get (X,Y) for the common case
;       if (function is VioWrtCharStrAtt)
;           get (X,Y) for this function
;       return success
;
;   ENTRY:  si - offset of the function address in the CallTbl
;
;   EXIT:   carry clear
;               ax - X coordinate of the read or write
;               dx - Y coordinate of the read or write
;           carry set
;               call is not valid for CAs
;
;   USES:   ax,dx
;
                PUBLIC  GetOrigin
GetOrigin       PROC    NEAR

        mov     ax,[bp].p_viofunc       ; Get function code in SI
        cmp     ax,vf_ReadCharStr       ; Is function code below valid range?
        jb      gorge                   ;   yes, return error

        cmp     ax,vf_WrtCellStr        ; Is function code in a valid range?
        jbe     gorg10                  ;   yes, get the origin

        cmp     ax,vf_CheckCharType     ; Is function code valid?
        jne     gorge                   ;   no, return error

gorg10: cmp     ax,vf_WrtCharStrAtt     ; Is the function VioWrtCharStrAtt?
        jne     gorg20                  ;   no, (ax,dx) is correct

        mov     ax,[bp].wa_col          ; (ax) = X coordinate of function
        mov     dx,[bp].wa_row          ; (dx) = Y coordinate of function
        jmp     short gorg30            ; exit no error

gorg20: mov     ax,[bp].w_col           ; (ax) = X coordinate of function
        mov     dx,[bp].w_row           ; (dx) = Y coordinate of function

gorg30: clc                             ; clear carry - no error
        jmp     short gorgx             ; exit

gorge:  stc                             ; set carry - not valid for CA process
gorgx:  ret

GetOrigin       ENDP


;***    FindCA - Locate the CA to be used for the read or write
;
;   This routine scans the list of CAs, starting with the CA passed,
;   to find a CA closest to the top of the Z order in which the indicated
;   coordinate is contained.
;
;   Note: if the CA passed is not in the list of created CAs, this
;         procedure will behave unpredictably.
;
;   PSEUDOCODE
;
;       for each CA starting with the CA passed, moving down the Z order
;           if (CA is active)
;               call IsInRect on the coodinates past and CA Rect
;               if (the coordinates are inside CA Rect)
;                   return the CA
;       return Invalid CA
;
;   ENTRY:  si - offset to the top CA to be searched
;           ax - X coordinate of the write
;           dx - Y coordinate of the write
;
;   EXIT:   found the CA
;               si - offset of the CA in which the coordinate belongs
;           otherwise
;               si - Zero
;
;   USES:   si
;
        PUBLIC  FindCA
FindCA  PROC    NEAR

        push    cx                      ; save cx
        mov     si,ds:bvs_CA_lru        ; (si) = first CA to examine

fca10:  mov     cx,si                   ; (cx) = offset of CA being examined
        test    [si].cas_flags,cas_f_inactive   ; Is the CA active?
        jnz     fca20                   ;   No, do not add it to ActCARect

        add     si,cas_xLeft            ; ds:[si] is the CA rectangle
        call    IsInRect                ; Is the origin in the CA rect?
        mov     si,cx                   ; (si) = offset of CA
        jnc     fcax                    ;   yes, origin in CA, return success

fca20:  mov     si,[si].cas_Dn          ; (si) = offset of next CA in list
        cmp     ds:bvs_CA_lru,si        ; Have we examined all CAs in list
        jne     fca10                   ;   no, go do the next one

        xor     si,si                   ; (si) = 0, indicate failure
fcax:   pop     cx                      ; restore cx
        ret

FindCA ENDP


;***    RedrawCAS - Redraw all CAs from a given one to the top of the Z order
;
;   This routine starts redrawing the affected regions of CAs, starting
;   at the lowest CA indicated and working its way to the top CA.  Only
;   the parts of the CA that are affected are drawn.
;
;   Note: the behavior of this routine will be unpredicatable if the CA
;   passed is not on the list of created CAs.
;
;   PSEUDOCODE
;
;       for each CA starting with the CA indicated
;           if (CA is visible)
;               call IsectRect on TouchRect and CA Rect to form WriteRect
;               if (CA was touched)
;                   if (not CA process)
;                       call DosGetSeg on the CA LVB
;                   call BufferUpdate CopyRect with WriteRect and the CA LVB
;                   if (not CA process)
;                       call DosFreeSeg on the CA LVB
;
;   ENTRY:  si - offset of first CA to be redrawn
;           bx - offset of rectangle to be redrawn
;           ds - BVSCB
;
;   EXIT:   all CAs from the affected one on up are updated
;
;   USES:   bvs_WriteRect,bvs_ScratchRect,ax,bx
;

            PUBLIC  RedrawCAS
RedrawCAS   PROC    NEAR

        push    cx                      ; save cx
        push    di                      ; save di
        push    es
        mov     cx,bvsiseg              ; (cx) = BVSISEG
        mov     es,cx                   ; (es) = BVSISEG

;******* MCH - begin mod
        push    si
        mov     di,bvs_ScratchRect
        mov     si,bx                   ; input parm TouchRect

        call    CopyRect                ; initialize ScratchRect

        ; use ScratchRect to determine what to draw:
        ; it's used just like TouchRect, but it expands
        ; as redrawing touched more area.
        mov     bx,di
        pop     si
;******* MCH - end mod

        mov     di,bvs_WriteRect        ; (di) = offset of WriteRect

        test    es:bvsi_flags,bvsi_f_caproc ; Is this the CA process?
        jz      rdca30                  ;   No, do get and release segments

; This loop is for the CA process.  It assumes CA LVB segment ownership.

rdca10: mov     cx,si                   ; (cx) = offset of CA
        test    [si].cas_flags,cas_f_visible; Is the CA visible?
        jz      rdca20                  ;   no, no need to redraw it

        add     si,cas_xLeft            ; (si) = offset of CA rectangle
        call    IsectRect               ; Does CA rect intersect TouchRect
        mov     si,cx                   ; (si) = offset of CA
        jc      rdca20                  ;   no, no need to redraw it

        call    LVBRectToPVB            ; Copy the affected region to PVB

rdca20: cmp     ds:bvs_CA_lru,si        ; Is this CA the top of the Z order?
        jz      rdcax                   ;   yes, done with redraw

        mov     si,[si].cas_Up          ; (si) = offset of next CA up Z order
        jmp     short rdca10            ; redraw the next CA

; This loop is for non-CA processes.  It assumes no CA LVB segment ownership.

rdca30: mov     cx,si                   ; (cx) = offset of CA
        test    [si].cas_flags,cas_f_visible; Is the CA visible?
        jz      rdca40                  ;   no, no need to redraw it

        add     si,cas_xLeft            ; (si) = offset of CA rectangle
        call    IsectRect               ; Do TouchRect and WriteRect intersect?
        mov     si,cx                   ; (si) = offset of CA
        jc      rdca40                  ;   no, no need to redraw it

        push    [si].cas_areasel        ; selector to be gotten
        call    DosGetSeg               ; get addressablility to the CA LVB
        or      ax,ax                   ; Did we get the segment?
        jnz     rdca40                  ;   no, skip redrawing this CA

        call    LVBRectToPVB            ; Copy the affected region to PVB

        push    [si].cas_areasel        ; selector to be gotten
        call    DosFreeSeg              ; remove addressablility to the CA LVB
rdca40: cmp     ds:bvs_CA_lru,si        ; Is this CA the top of the Z order?
        jz      rdcax                   ;   yes, done with redraw

        mov     si,[si].cas_Up          ; (si) = offset of next CA up Z order
        jmp     short rdca30            ; redraw the next CA

rdcax:  pop     es                      ; restore es
        pop     di                      ; restore di
        pop     cx                      ; restore cx
        ret

RedrawCAS   ENDP


;***    LVBRectToPVB - copy a rectangle from an LVB to the PVB
;
;   This routine copies a rectangle from an LVB to the PVB using the
;   copy rectangle function in the LVB.  This routine sets up all of
;   the parameter block values for the call.
;
;   PSEUDOCODE
;
;       call SetExtBufUpParms to set the extended parameters
;       place the coordinates of the rectangle into the parameter block
;       call AllBuffer to have the function executed
;
;   ENTRY:  si - offset of CA whose LVB is to be used (zero is main LVB)
;           di - offset of rectangle to be redrawn
;           bx - offset of rectangle to accumulate touched region
;                if this parm is NULL, no unioning happens
;
;   EXIT:   ax - return code from the VDH
;
;   USES:   ax
;           bvs_ScratchRect - the rect touched by this write
;

LVBRectToPVB    PROC    NEAR
                PUBLIC  LVBRectToPVB

        call    SetExtBufUpParms        ; set up the extended BU parameter block

        mov     [bp].vp_index,sx_CopyRect   ; Index of subroutine
        mov     ax,ds:[di].rec_yTop     ; (ax) = top side of copy rectangle
        mov     [bp].vp_startrow,ax     ; top border of rectangle
        mov     ax,ds:[di].rec_xLeft    ; (ax) = left side of copy rectangle
        mov     [bp].vp_startcol,ax     ; left border of rectangle
        mov     ax,ds:[di].rec_yBottom  ; (ax) = bottom side of copy rectangle
        mov     [bp].vp_secondrow,ax    ; bottom border of rectangle
        mov     ax,ds:[di].rec_xRight   ; (ax) = right side of copy rectangle
        mov     [bp].vp_secondcol,ax    ; right border of rectangle

        push    bx                      ; required by AllBuffer
        xor     bx,bx
        call    AllBuffer               ; execute the function
        pop     bx

; ********** MCH - union returned TouchRect with the rect in bx, if provided
        or      bx,bx
        jz      lrtp_done

        mov     ax,[bp].vp_touchxleft
        .if <ax a [bx].rec_xLeft>
            mov    ax,[bx].rec_xLeft
        .endif
        mov     [bx].rec_xLeft,ax

        mov     ax,[bp].vp_touchxright
        .if <ax b [bx].rec_xRight>
            mov    ax,[bx].rec_xRight
        .endif
        mov     [bx].rec_xRight,ax

        mov     ax,[bp].vp_touchytop
        .if <ax a [bx].rec_yTop>
            mov    ax,[bx].rec_yTop
        .endif
        mov     [bx].rec_yTop,ax

        mov     ax,[bp].vp_touchybottom
        .if <ax b [bx].rec_yBottom
            mov    ax, [bx].rec_yBottom
        .endif
        mov     [bx].rec_yBottom,ax

lrtp_done:

; ********** MCH - end mod

        ret

LVBRectToPVB    ENDP


;***    GetLVBInfo - get information about the LVB.
;
;   This routine calls to the VDH to get information about how large
;   to allocate the LVB and information about the default attribute
;   for the give Format ID/Attribute count.
;
;   PSEUDOCODE
;
;       set up the parameters for the call.
;       call AllVDH to have the function executed
;
;   ENTRY:  si - offset of CA describing the LVB to be gotten (0 is main LVB)
;
;   EXIT:   ax - return code from the VDH
;
;   USES:   ax,di
;

GetLVBInfo      PROC    NEAR
                PUBLIC  GetLVBInfo

        mov     [bp].vp_parmlength,20   ; set the length of the parameter block
        mov     [bp].vp_li_allocl,0     ; Low word of the LVB allocation size
        mov     [bp].vp_li_alloch,0     ; High word of the LVB allocation size
        or      si,si                   ; Is this a valid CA?
        jnz     glbi10                  ;   no, get info about main LVB

        mov     ax,word ptr ds:bvs_attrformat ; (al) = format ID, (ah) = # attr
        mov     [bp].vp_li_fidatt,ax    ; Format ID/Attribute Count
        mov     ax,ds:bvs_cols          ; (ax) = Width of the screen in cells
        mov     [bp].vp_li_width,ax     ; Width of the LVB
        mov     ax,ds:bvs_ScrlRectBtm   ; (ax) = Height of the screen in cells
        mov     [bp].vp_li_height,ax    ; Height of the LVB
        mov     [bp].vp_li_attrsize,cbAttr  ; Byte of space for the default attr
        mov     [bp].vp_li_attroffst,bvs_scrattr; Offset of default attr buffer
        mov     [bp].vp_li_attrseg,ds   ; Segment of default attribute buffer
        jmp     short glbix

glbi10: mov     ax,word ptr [si].cas_formatid ; (al) = format ID, (ah) = # attr
        mov     [bp].vp_li_fidatt,ax    ; Format ID/Attribute Count
        mov     ax,[si].cas_xRight      ; (ax) = Right boarder of LVB rect
        sub     ax,[si].cas_xLeft       ; (ax) = Width of LVB - 1
        inc     ax                      ; (ax) = width
        mov     [bp].vp_li_width,ax     ; Width of the LVB
        mov     ax,[si].cas_yBottom     ; (ax) = Bottom boarder of LVB rect
        sub     ax,[si].cas_yTop        ; (ax) = Height of LVB - 1
        inc     ax                      ; (ax) = height
        mov     [bp].vp_li_height,ax    ; Height of the LVB
        mov     [bp].vp_li_attrsize,0   ; Byte of space for the default attr
        mov     [bp].vp_li_attroffst,0  ; Offset of default attribute buffer
        mov     [bp].vp_li_attrseg,0    ; Segment of default attribute buffer

glbix:  mov     di,fn_GetLVBInfo
        call    AllVDH                  ; execute the function
        ret

GetLVBInfo      ENDP


;/********************** START OF SPECIFICATIONS ************************/
;/*                                                                     */
;/* SUBROUTINE NAME:    BvsCreateCA                                     */
;/*                                                                     */
;/* DESCRIPTIVE NAME:   Create a Conversion Area                        */
;/*                                                                     */
;/* FUNCTION:   A conversion area buffer is allocated.                  */
;/*                                                                     */
;/* NOTES:      Executes on level 3, protect mode only                  */
;/*                                                                     */
;/* ENTRY POINT:  BvsCreateCA                                           */
;/*   LINKAGE:  Call BvsCreateCA from BVSMAIN                           */
;/*                                                                     */
;/* INPUT:  StackFrame and Registers (see BVSMAIN) with:                */
;/*     parmn   = x_hCAoff      Offset of CA Handle                     */
;/*     parmnm1 = x_hCAsel      Sel of CA Handle                        */
;/*     parmnm2 = x_CABoff      Offset of CA Block                      */
;/*     parmnm3 = x_CABsel      Sel of CA Block                         */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:                                                         */
;/*                                                                     */
;/* EFFECTS:    None                                                    */
;/*                                                                     */
;/* INTERNAL REFERENCES: BVSCB                                          */
;/*   ROUTINES:  None                                                   */
;/*                                                                     */
;/* EXTERNAL REFERENCES: None                                           */
;/*   ROUTINES:  None                                                   */
;/************************ END OF SPECIFICATIONS ************************/
; PSEUDOCODE
;
;   BvsCreateCA
;
;   if (active code page is NOT DBCS)
;       return (ERROR_VIO_MODE)
;   if (length of the user passed CA description is out of range)
;       return (ERROR_VIO_INVALID_PARMS)
;   if (no process is the CA process)
;       call InitCAS to initialize CA structures
;   else
;       if (this process != CA process)
;           return (ERROR_VIO_FUNCTION_OWNED)
;   call MoveCAS (lru_CAS, free_CAS) to get a CA structure to use
;   if (no CA structures left)
;       return (ERROR_VIO_INVALID_PARMS)
;   initialize the flags field of the CA structure | INVISIBLE | ACTIVE
;   initialize the attribute count field of the CA structure
;   initialize the format ID field of the CA structure to
;   if (user passed option flags)
;       set the flags field to the user passed flags
;   if (user passed a format ID)
;       set the format ID field to the user passed value
;   if (user passed an attribute count)
;       set the attribute count to the user passed value
;   if (format ID or attribute count is not valid)
;       return (ERROR_VIO_INVALID_PARMS)
;   if (the user passed an invalid rectangle)
;       return (ERROR_VIO_INVALID_PARMS)
;   set the CA rectagle to the user passed value
;   call BvsGetLVBSize for the requested Format ID, attr count, rows and col.
;   if (error was returned)
;       return (ERROR_VIO_INVALID_PARMS)
;   LVB size = returned size
;   if (LVB size == 0)
;       return (ERROR_VIO_INVALID_PARMS)
;   call DosAllocSeg to allocate the LVB for the CA
;   if (DosAllocSeg failed)
;       return (ERROR_VIO_INVALID_PARMS)
;   call CalcCARects to initialize the screen group CA boundry rectangles
;   call CallTbl[BvsWrtNCell.DBCS_FUNC] to fill the LVB with the default cell
;   put the CA handle into user data
;   if ((user specified VISIBLE option) ||
;      (user specified INACTIVE option))
;       call BvsSetCAState to set the CA to the user requested state
;       if (BvsSetCAState failed)
;           return the error
;   return (NO_ERROR)
;

BvsCreateCA PROC NEAR
        PUBLIC  BvsCreateCA

        test    [bx].bvs_flags2,bvs_f2_dbcscp

        .if     <z>                     ; active code page is not DBCS
            mov     ax,ERROR_VIO_MODE
            jmp     cca_error           ;    error (wrong mode)
        .endif

        ;
        ; get process ID
        ;
        push    ds
        mov     ds,es:bvsi_ldtsel
        mov     dx,[bx].LIS_CurProcID   ; dx = our process ID
        pop     ds

        ; check CAB size and FormatId (if provided)
        ; (This version only supports xAttrFormat)
        ; LATER: add table driven code to support multiple format
        ;
        les     di,dword ptr [bp].x_CABoff      ; check CAB size
        mov     cx,es:[di].cab_length
        .if     <cx b CABMIN> or
        .if     <cx a CABMAX>
            mov     ax,ERROR_VIO_INVALID_PARMS
            jmp     cca_error           ;    error (wrong parameters)
        .endif

        mov     [bx].bvs_scratch,dx     ; save temporarily CA pid
        mov     ax,[bx].bvs_CA_pid

        .if     <ZERO AX>               ; if no CA already used and
            .if     <[bx].bvs_CA_died eq CA_OWNER_DIED>
                push    es              ; save es
                push    di              ; save di
                xor     si,si           ; (si) = 0, copy main LVB to PVB
                mov     di,bvs_WriteRect; (di) = offset of temporary rectangle
                mov     [di].rec_xLeft,bx   ; left side of screen
                mov     [di].rec_yTop,bx; top of screen
                mov     ax,[bx].bvs_rows ; (ax) = bottom of screen      ;B790218
                dec     ax                                              ;B790218
;B790218        mov     ax,[bx].bvs_ScrlRectBtm ; (ax) = bottom of screen
; MCH need dec ax here too???
                mov     [di].rec_yBottom,ax ; bottom of screen
                mov     ax,[bx].bvs_cols; (ax) = right of screen
                dec     ax              ; MCH - zero-based numbering
                mov     [di].rec_xRight,ax  ; right of screen

                mov     ax,BVSISEG
                mov     es,ax           ; (es) = BVSISEG
                call    LVBRectToPVB    ; copy the LVB to the PVB
                                        ; MCH - bx==0 so no rect accumulation

                pop     di              ; restore di
                pop     es              ; restore es
            .endif
            call    InitCAS             ; initialize CA structures
        .elseif <ax ne dx>              ; if a different process
            mov     ax,ERROR_VIO_FUNCTION_OWNED
            jmp     cca_error           ;     error
        .endif

        ; Check if any CA still available
        ;
        push    bvs_CA_free
        push    bvs_CA_lru
        call    moveCAS                 ; move from free list -> lru list

        .if     <ZERO AX>               ; Z = no CA was free
            mov     ax,ERROR_VIO_INVALID_PARMS
            jmp     cca_error           ; error
        .endif

        ; We found an empty slot, AX = offset
        ;
        mov     si,ax                   ; si = ptr on empty slot structure

        ; set options, format attribute count defaults

        mov     ax,es:[di].cab_option        ; if CA option             ;B790217
                                             ; other than LVB           ;B790217
        .if     < BIT ax AND cas_f_format>                              ;B790217
            mov     [si].cas_flags,bx        ; active and invisible     ;B790217
            mov     [si].cas_attrcount,1     ; attribute count == 1     ;B790217
                                             ; use 3                    ;B790217
            mov     [si].cas_formatID,bl     ; format ID = 0            ;B790217
                                             ;use 70h??                 ;B790217
        .else                                                           ;B790217
            ; set CA defaults same as LVB                               ;B790217
            mov     al,[bx].bvs_attrbytes                               ;B790217
            mov     [si].cas_attrcount,al                               ;B790217
            mov     al,[bx].bvs_attrformat                              ;B790217
            mov     [si].cas_formatID,al                                ;B790217
        .endif                                                          ;B790217

;B790217 mov     [si].cas_flags,bx       ; active and invisible
;B790217 mov     [si].cas_attrcount,1
;B790217 mov     [si].cas_formatID,bl

        ; set the requested values

        .if     <cx ae CABOPTION> and
          mov   ax,es:[di].cab_option
          ;
          ; restrict flags to a few
          ;
          and   ax, cas_f_visible OR cas_f_format OR cas_f_inactive OR cas_f_nomove ;@tb22
          mov   [si].cas_flags,ax

        .if     <BIT ax AND cas_f_format> and
        .if     <cx ae CABFORMAT> and
          mov   al,es:[di].cab_formatID
          mov   [si].cas_formatID,al
        .if     <cx ae CABATTRCOUNT>
          mov   al,es:[di].cab_attrcount
          mov   [si].cas_attrcount,al
        .endif
        ;
        ; Check for valid format ID and attribute count         ;j-ys3m BEGIN
        ;
        .if     <BIT [si].cas_flags and cas_f_format>   ; not system default
            push    di
            mov     di,offset CA_FormatTable                    ;j-ys3mf
            mov     cx,CA_Formats
            sub     ah,ah
            .repeat
                mov     al,cs:[di]                      ; get format ID
                inc     di                              ; index to attribute cnt
                .if     <al e [si].cas_formatID>
                    mov    al,cs:[di]                   ; get attribute count
                    .leave <al e [si].cas_attrcount>    ; match found
                .endif
                inc     di                              ; next format ID
            .loop
            pop     di

            .if     <cxz>                               ;
                mov     ax,ERROR_VIO_INVALID_PARMS
                jmp     cca_error
            .endif
        .endif                                                  ;j-ys3m END

        ; Use the CA block structure to determine the CA rectangle

        ; BUGBUG replace bvs_ScrlRectBtm with the actual number of
        ; screen rows returned from VDH GetVarInfo

        mov     ax,es:[di].cab_Srow     ; check the rectangle values
        .if     <ax be [bx].bvs_ScrlRectBtm> and near
        mov     [si].cas_yTop,ax
        mov     dx,es:[di].cab_Scol
        .if     <dx b [bx].bvs_cols> and near
        mov     [si].cas_xLeft,dx
        add     ax,es:[di].cab_rows
        .if     <es:[di].cab_rows ne 0> and near        ; MCH rows != 0
        dec     ax
        .if     <ax b [bx].bvs_rows> and near           ;B790218
;B790218 .if     <ax be [bx].bvs_ScrlRectBtm> and near
        mov     [si].cas_yBottom,ax
        add     dx,es:[di].cab_cols
        .if     <es:[di].cab_cols ne 0> and near        ; MCH cols != 0
        dec     dx
        mov     [si].cas_xRight,dx

        .if     <dx b [bx].bvs_cols> and near
        ;
        ; allocate memory for extra video buffer
        ;

        call    GetLVBInfo

        .if     <ZERO ax> and near
        mov     ax,[bp].vp_li_alloch    ; High word of the LVB allocation size
        .if     <ZERO ax> and near
        mov     ax,[bp].vp_li_allocl    ; Low word of the LVB allocation size
        .if     <NONZERO ax> and near   ; not Null size

        push    ax
        push    ds
        lea     ax,[si].cas_areasel
        push    ax
        push    2                       ; sharable
        call    DOSALLOCSEG

        .if     <ZERO ax> near          ;B790218 (near)
            ;
            ; initialize the buffer with ANK space
            ;

            mov     ds:[bvs_CA_crnt],si     ; si points to the first CA
            call    CalcCARects             ; calculate the boundry rectangles

            mov     ax,[bx].bvs_ScrlRectLft     ; left                  ;B790218
            mov     [bp].vp_scrlleft,ax                                 ;B790218
            mov     ax,[bx].bvs_ScrlRectTop     ; top                   ;B790218
            mov     ax,[bx].bvs_ScrlRectTop     ; top                   ;B790218
            mov     [bp].vp_scrltop,ax                                  ;B790218
            mov     ax,[bx].bvs_ScrlRectRt      ; right                 ;B790218
            mov     [bp].vp_scrlright,ax                                ;B790218
            mov     ax,[bx].bvs_rows            ; bottom = max row      ;B790218
            dec     ax                                                  ;B790218
            mov     [bp].vp_scrlbottom,ax                               ;B790218
            mov     ax,vp_f_scrlrect            ; set scroll rect       ;B790218
            Call    AllSetVarInfo                                       ;B790218

            call    SetExtBufUpParms        ; set up the additional parms
            mov     [bp].vp_index,sx_ScrollDn   ; Set the subroutine index
            mov     [bp].vp_startrow,bx
            mov     [bp].vp_startcol,bx     ; Set the upper left corner
            mov     ax,-1
            mov     [bp].vp_secondrow,ax
            mov     [bp].vp_secondcol,ax    ; Set maximum lower right corner
            mov     [bp].vp_repeatlength,ax ; Set maximum number of times
            mov     [bp].vp_secondoff,bvs_ttycell
            mov     [bp].vp_secondsel,ds    ; Set the cell address
                                            ; Note use of ANSI attribute
            mov     [bp].vp_flags,vp_f_attrxlate OR vp_f_logical ;Use the LVB
            test    [si].cas_flags,cas_f_visible
            .if     <z>
                or      [bp].vp_flags,vp_f_physical ; make the CA invisible
            .endif
            push    es                      ; save es
            push    BVSISEG
            pop     es                      ; (es) = BVSISEG
            call    AllBuffer               ; Clear the CA LVB
            pop     es

            mov     ax,[bx].bvs_ScrlRectLft     ; left                  ;B790218
            mov     [bp].vp_scrlleft,ax                                 ;B790218
            mov     ax,[bx].bvs_ScrlRectTop     ; top                   ;B790218
            mov     [bp].vp_scrltop,ax                                  ;B790218
            mov     ax,[bx].bvs_ScrlRectRt      ; right                 ;B790218
            mov     [bp].vp_scrlright,ax                                ;B790218
            mov     ax,[bx].bvs_ScrlRectBtm     ; bottom                ;B790218
            mov     [bp].vp_scrlbottom,ax                               ;B790218
            mov     ax,vp_f_scrlrect            ; restore scroll rect   ;B790218
            Call    AllSetVarInfo                                       ;B790218

            ; set the CA handle in user data
            ;
            les     di,dword ptr [bp].x_hCAoff
            mov     ax,si
            stosw


            .if     <[bx].bvs_CA_pid eq bx>     ; first CA being created
                push    EXLST_ADD               ; add to the exit list
                push    cs                      ; segment of exit list routine
                push    offset BvsCAExitList    ; offset of exit list routine
                call    DosExitList             ; add the routine to exit list
            .endif
            mov     ax,[bx].bvs_scratch
            mov     [bx].bvs_CA_pid,ax          ; set CA pid
            push    es                          ; save es
            mov     ax,bvsiseg                  ; (ax) = BVSISEG
            mov     es,ax                       ; (es) = BVSISEG
            or      es:bvsi_flags,bvsi_f_caproc ; mark ourselves as CA proc
            pop     es                          ; restore es
            sub     ax,ax                       ; normal exit code
        .else
            push    bvs_CA_lru
            push    bvs_CA_free
            call    moveCAS             ; move from lru list -> free list

            mov     ax,ERROR_VIO_INVALID_PARMS
            ;
            ; error, invalidate user handle location in case he does not
            ; check the error code.
            ;
cca_error:
            les     di,dword ptr [bp].x_hCAoff
            mov     es:word ptr [di],invalid_handle
        .endif
        ret
BvsCreateCA ENDP

;/********************** START OF SPECIFICATIONS ************************/
;/*                                                                     */
;/* SUBROUTINE NAME:    BvsDestroyCA                                    */
;/*                                                                     */
;/* DESCRIPTIVE NAME:   Destroy a Conversion Area                       */
;/*                                                                     */
;/* FUNCTION:   A conversion area buffer is freed.                      */
;/*                                                                     */
;/* NOTES:      Executes on level 3, protect mode only                  */
;/*                                                                     */
;/* ENTRY POINT:  BvsDestroyCA                                          */
;/*   LINKAGE:  Call BvsDestroyCA from BVSMAIN                          */
;/*                                                                     */
;/* INPUT:  StackFrame and Registers (see BVSMAIN) with:                */
;/*     parmn   = x_hCA         CA handle                               */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:                                                         */
;/*                                                                     */
;/* EFFECTS:    None                                                    */
;/*                                                                     */
;/* INTERNAL REFERENCES: BVSCB                                          */
;/*   ROUTINES:  None                                                   */
;/*                                                                     */
;/* EXTERNAL REFERENCES: None                                           */
;/*   ROUTINES:  None                                                   */
;/************************ END OF SPECIFICATIONS ************************/
;
; PSEUDOCODE
;
;   BvsDistroyCA
;
;   call CheckCAParms to verify the user passed CA handle
;   if (user passed handle is invalid)
;       return the error from CheckCAParms
;   call BvsSetCAState to make the CA invisible
;   if (BvsSetCAState returned an error)
;       return the error
;   call DosFreeSeg to free the LVB for the CA
;   if (DosFreeSeg returned an error)
;       return the error
;   call MoveCAS to move the CA structure from the lru list to the free list
;   if (there are no more active CAs)
;       set the CA process to zero
;   else
;       call CalcCARects to update the screen group CA boundry rectangles
;

BvsDestroyCA PROC NEAR
        PUBLIC  BvsDestroyCA

; check valid handle and PID
;
        mov     si,[bp].x_dhCA          ; si = caller handle
        call    CheckCAParms
        .if     <nz>
            jmp     dca_exit
        .endif
        ;
        ; make it invisible before destroying it
        ;
        push    si                      ; save the caller handle

        push    si                      ; Caller CA handle
        push    cas_f_inactive          ; set hidden and inactive
        push    bx                      ; VIOHandle (=0)
        bvsfunc vf_SetCAState,3

        pop     si
        .if     <nonzero ax>
            jmp short dca_exit
        .endif

        push    [si].cas_areasel
        call    DOSFREESEG
        .if     <nonzero ax>
            jmp short dca_exit
        .endif
        ;
        ; free the current CA and reset bvs_CA_pid if was last
        ;
        .if     <si e [bx].bvs_CA_lru>  ; current CA is topmost
            push    bvs_CA_lru          ; use list head pointer
        .else                           ; else
            mov     [bx].bvs_CA_crnt,si ; set current pointer
            push    bvs_CA_crnt         ; and use it
        .endif
        push    bvs_CA_free             ; pointer to free list
        call    moveCAS                 ; move current -> free list

        .if     <[bx].bvs_CA_lru e bx > ; none left
            mov     [bx].bvs_CA_pid,bx  ; reset bvs_CA_pid
            push    EXLST_REMOVE        ; remove to the exit list
            push    cs                  ; segment of exit list routine
            push    offset BvsCAExitList; offset of exit list routine
            call    DosExitList         ; remove the routine to exit list
            push    es                  ; save es
            mov     ax,bvsiseg          ; (ax) = BVSISEG
            mov     es,ax               ; (es) = BVSISEG
            xor     es:bvsi_flags,bvsi_f_caproc ; mark ourselves not CA proc
            pop     es                  ; restore es
        .endif
        sub     ax,ax                   ; set good return code
dca_exit:
        ret
BvsDestroyCA ENDP


;/********************** START OF SPECIFICATIONS ************************/
;/*                                                                     */
;/* SUBROUTINE NAME:    BvsGetCAState                                   */
;/*                                                                     */
;/* DESCRIPTIVE NAME:   Return a Conversion Area Status                 */
;/*                                                                     */
;/* FUNCTION:   Report conversion area flags                            */
;/*                                                                     */
;/* NOTES:      Executes on level 3, protect mode only                  */
;/*                                                                     */
;/* ENTRY POINT:  BvsGetCAState                                         */
;/*   LINKAGE:  Call BvsGetCAState from BVSMAIN                         */
;/*                                                                     */
;/* INPUT:  StackFrame and Registers (see BVSMAIN) with:                */
;/*     parmn   = x_gfCAoff     offset to CA flags storage area         */
;/*     parmnm1 = x_gfCAseg     segment to CA flags storage area        */
;/*     parmnm2 = x_ghCA        CA handle                               */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:                                                         */
;/*                                                                     */
;/* EFFECTS:    Destroys CX, DX, SI, DI                                 */
;/*                                                                     */
;/* INTERNAL REFERENCES: BVSCB                                          */
;/*   ROUTINES:  None                                                   */
;/*                                                                     */
;/* EXTERNAL REFERENCES: None                                           */
;/*   ROUTINES:  None                                                   */
;/************************ END OF SPECIFICATIONS ************************/
;
; PSEUDOCODE
;
;   BvsGetCAState
;
;   call CheckCAParms to verify the user passed CA handle
;   if (user passed handle is invalid)
;       goto EXIT
;   load the CA flags into the user passed flags buffer
;   EXIT:
;   return (error if one occurred)

BvsGetCAState PROC NEAR
        PUBLIC  BvsGetCAState

; check valid handle and PID
;
        mov     si,[bp].x_ghCA          ; si = caller handle
        call    CheckCAParms
        .if     nz                      ; if error
            jmp     gca_exit_error      ;   exit
        .endif

        mov     ax,[si].cas_flags       ; (ax) = CA flags
        push    es                      ; save es
        les     di,dword ptr [bp].x_gfCAoff ; (es:di) = pointer to flags buffer
        stosw                           ; *(es:di) = CA flags
        pop     es                      ; restore es
        sub     ax,ax                   ; done OK
gca_exit_error:
        ret
BvsGetCAState ENDP


;/********************** START OF SPECIFICATIONS ************************/
;/*                                                                     */
;/* SUBROUTINE NAME:    BvsSetCAState                                   */
;/*                                                                     */
;/* DESCRIPTIVE NAME:   Modify a Conversion Area Status                 */
;/*                                                                     */
;/* FUNCTION:   Make a conversion area visible/invisible                */
;/*                                                                     */
;/* NOTES:      Executes on level 3, protect mode only                  */
;/*                                                                     */
;/* ENTRY POINT:  BvsSetCAState                                         */
;/*   LINKAGE:  Call BvsSetCAState from BVSMAIN                         */
;/*                                                                     */
;/* INPUT:  StackFrame and Registers (see BVSMAIN) with:                */
;/*     parmn   = x_hCA         CA handle                               */
;/*     parmnm1 = x_fCA         CA flags                                */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:                                                         */
;/*                                                                     */
;/* EFFECTS:    Destroys CX, DX, SI, DI                                 */
;/*                                                                     */
;/* INTERNAL REFERENCES: BVSCB                                          */
;/*   ROUTINES:  None                                                   */
;/*                                                                     */
;/* EXTERNAL REFERENCES: None                                           */
;/*   ROUTINES:  None                                                   */
;/************************ END OF SPECIFICATIONS ************************/
;
; PSEUDOCODE
;
;   BvsSetCAState
;
;   call CheckCAParms to verify the user passed CA handle
;   if (user passed handle is invalid)
;       goto EXIT
;   set the active flag to the user passed value
;   if (user passed visible flag == VISIBLE)
;       call CASetLRUTop to move the CA to the top of the Z order
;   if (user passed visible flag != CA visible flag)
;       invert the CA visible flag
;   else
;       if (this screen group is background)
;           goto EXIT
;   if (this process screen group is foreground)
;       if (CA visible flag != VISIBLE)
;           call LVBRectToPVB to copy the main LVB onto the old CA rect
;       call RedrawCAS with the Rectangle touched and the CA indicated
;   EXIT:
;   call CalcCARects to update the screen group CA boundry rectangles
;   return (error if one occurred)

BvsSetCAState PROC NEAR
        PUBLIC  BvsSetCAState

; check valid handle and PID
;
        mov     si,[bp].x_shCA          ; si = caller handle
        call    CheckCAParms
        .if     nz                      ; if error
            jmp     sca_exit_error      ;   exit
        .endif

        ; Process nomove/movestate change request       ;@tb22
        ;
        mov     dx,[bp].x_sfCA                          ;@tb22
        mov     ax,[si].cas_flags                       ;@tb22
        and     ax,cas_f_nomove                         ;@tb22
        and     dx,cas_f_nomove                         ;@tb22
        .if     <dx ne ax>                              ;@tb22
             xor    [si].cas_flags,cas_f_nomove         ;@tb22
        .endif                                          ;@tb22


        ; process inactive/active state change request
        ;
        mov     dx,[bp].x_sfCA          ; DX = CA flags
        mov     ax,[si].cas_flags
        and     ax,cas_f_inactive
        and     dx,cas_f_inactive
        .if     <dx ne ax>              ; change of state requested
            xor     [si].cas_flags,cas_f_inactive
                                        ; set flag accordingly
        .endif

        ; process visible/hidden state change request

        mov     dx,[bp].x_sfCA          ; DX = CA flags
        ;
        ; visible requested: this call moves CA to top of LRU list
        ;
        .if <BIT dx and cas_f_visible> and ; if going or staying visible
        .if <BIT dx nand cas_f_nomove>  ; and not explicitly held in place
            call   CASetLRUTop  ; promote CA to last updated
        .endif

        mov     ax,[si].cas_flags
        and     ax,cas_f_visible
        and     dx,cas_f_visible

        .if     <dx ne ax>              ; change of state requested
            xor     [si].cas_flags,cas_f_visible
                                        ; set flag accordingly
        .elseif <BIT [bx].bvs_flags and bvs_f_backgrnd >
            jmp    sca_exit_normal      ; exit with (AX =0)
        .elseif <BIT [bp].x_sfCA and cas_f_nomove >
            jmp    sca_exit_normal      ; exit with (AX =0)
        .endif

        .if <BIT [bx].bvs_flags and bvs_f_backgrnd >
            jmp    sca_exit_normal      ; exit with (AX =0)
        .endif

        mov     bx,si                   ; (bx) = offset of CA
        add     bx,cas_xLeft            ; (bx) = offset of CA rectangle
        mov     di,bx                   ; (di) = rectangle to be redrawn
        test    dx,cas_f_visible        ; Is the CA going hidden?

        .if     <z>                     ;   yes, redraw the main LVB

            ; MCH - make the redraw rect the TouchRect
            mov     bx,bvs_ScratchRect
            mov     [bx].rec_yBottom,0  ; initialize to minimal rect
            mov     [bx].rec_xRight,0
            mov     [bx].rec_xLeft,-1
            mov     [bx].rec_yTop,-1
            ; MCH end mod

            xor     si,si               ; (si) = 0, use main LVB
            call    LVBRectToPVB        ; Copy the LVB rect to PVB

            mov     si,ds:bvs_CA_lru    ; (si) = offset of top CA
            mov     si,[si].cas_Up      ; (si) = offset of bottom CA
        .endif

        call    RedrawCAS               ; redraw the CAs
        xor     bx,bx                   ; (bx) = 0
sca_exit_normal:
        sub     ax,ax                   ; done OK
sca_exit_error:
        push    ax                      ; save ax
        call    CalcCARects             ; recalculate CA bounds rectangles
        pop     ax                      ; restore ax
        ret
BvsSetCAState ENDP



;***    CalcCARects - calculate rects to circumscribe active and visible CAs
;
;   This routine scans the list of created CAs to calculate ActCARect
;   and VisCARect.  ActCARect is the union of all of the CA rects for
;   all active CAs.  VisCARect is the union of all of the CA rects for
;   all visible CAs.
;
;   PSEUDOCODE
;
;       set CACirVisRect to INVALID
;       set CACirActRect to INVALID
;       for each CA, starting at the bottom of the Z order
;           if (CA is active)
;               if (CACirActRect == INVALID)
;                   CACirActRect = CA Rect
;               else
;                   call UnionRect on CACirActRect and CA Rect
;           if (CA is visible)
;               if (CACirVisRect == INVALID)
;                   CACirVisRect = CA Rect
;               else
;                   call UnionRect on CACirVisRect and CA Rect
;
;   ENTRY:  none
;
;   EXIT:   VisCARect - circumscribes all visible CAs
;           ActCARect - circumscribes all active CAs
;
;   USES:   none
;

CalcCARects PROC

        mov     ds:[bx].bvs_ActCARect.rec_xLeft,-1  ; make rectangle invalid
        mov     ds:[bx].bvs_VisCARect.rec_xLeft,-1  ; make rectangle invalid

        push    es                      ; save es
        push    si                      ; save si
        push    cx                      ; save cx
        push    bx                      ; save bx
        push    ax                      ; save ax

        mov     si,ds:[bvs_CA_crnt]     ; si points to the first CA
        or      si,si                   ; Are there any CAs created?
        je      ccarx                   ;   No, rectangles are complete

        push    ds
        pop     es                      ; (es) = BVSCB
ccar10: mov     cx,si                   ; (cx) = offset of CA being examined
        test    [si].cas_flags,cas_f_inactive   ; Is the CA active?
        jnz     ccar30                  ;   No, do not add it to ActCARect

        add     si,cas_xLeft            ; ds:si is the CA rectangle
        mov     bx,bvs_ActCARect        ; (bx) = offset of active CAs rect
        mov     di,bvs_ActCARect        ; (di) = offset of active CAs rect
        cmp     [bx].rec_xLeft,-1       ; Is the rectangle valid?
        jne     ccar20                  ;   yes, take the union of the rects

        call    CopyRect                ; copy the CA Rect to ActCARect
        jmp     short ccar25            ; proceed to repeat for VisCARect

ccar20: call    UnionRect               ; "add" the rectangles

ccar25: mov     si,cx                   ; (si) = the pointer to CA

ccar30: test    [si].cas_flags,cas_f_visible; Is the CA visible?
        jz      ccar50                  ;   No, do not add it to VisCARect

        add     si,cas_xLeft            ; ds:si is the CA rectangle
        mov     bx,bvs_VisCARect        ; (bx) = offset of visible CAs rect
        mov     di,bvs_VisCARect        ; (di) = offset of visible CAs rect
        cmp     [bx].rec_xLeft,-1       ; Is the rectangle valid?
        jne     ccar40                  ;   yes, take the union of the rects

        call    CopyRect                ; copy the CA Rect to VisCARect
        jmp     short ccar50            ; proceed to get next CA in the list

ccar40: call    UnionRect               ; "add" the rectangles

ccar50: mov     si,cx                   ; (si) = offset of CA being examined
        mov     si,[si].cas_Up          ; (si) = offset of next CA in list
        cmp     ds:bvs_CA_crnt,si       ; Have we examined all CAs in list
        jne     ccar10                  ;   no, go do the next one

ccarx:  pop     ax                      ; restore ax
        pop     bx                      ; restore bx
        pop     cx                      ; restore cx
        pop     si                      ; restore si
        pop     es                      ; restore es
        ret

CalcCARects ENDP


;***    CopyRect - copy one rectangle onto another
;
;   Copy the source rectangle to the destination rectangle
;
;   PSEUDOCODE
;
;       dest.xLeft = source.xLeft
;       dest.xRight = source.xRight
;       dest.yTop = source.yTop
;       dest.yBottom = source.yBottom
;
;   ENTRY:  DS:SI - pointer to the source rectangle
;           ES:DI - pointer to the destination rectangle
;
;   EXIT:   destination rectangle = source rectangle
;
;   USES:   AX
;

CopyRect    PROC

        mov     ax,[si].rec_xLeft       ; (ax) = left side of the CA rect
        mov     [di].rec_xLeft,ax       ; left side of ActCARect = left CA
        mov     ax,[si].rec_xRight      ; (ax) = right side of the CA rect
        mov     [di].rec_xRight,ax      ; right side of ActCARect = right CA
        mov     ax,[si].rec_yTop        ; (ax) = top side of the CA rect
        mov     [di].rec_yTop,ax        ; top side of ActCARect = top CA
        mov     ax,[si].rec_yBottom     ; (ax) = bottom side of the CA rect
        mov     [di].rec_yBottom,ax     ; bottom side of ActCARect = bottom CA
        ret

CopyRect    ENDP


;***    IsectRect - intersect two rectangle and save the result
;
;   Intersect two rectangles, place the result in a third
;
;   PSEUDOCODE
;
;       Xleft = max (Xleft1,Xleft2)
;       Xright = min (Xright1,Xright2)
;       if (Xleft >= Xright)
;           Ytop  = max (Ytop1,Ytop2)
;           Ybottom = min (Ybottom1,Ybottom2)
;           if (Ytop <= Ybottom)
;               return RECT_INTERSECT
;       return NO_RECT_INTERSECT
;
;   ENTRY:  DS:SI - pointer to the first rectangle to be intersected
;           DS:BX - pointer to the second rectangle to be intersected
;           DS:DI - pointer to the destination rectangle
;
;   EXIT:   carry clear
;               DS:DI - points to intersection of first and second rectangles
;           carry set
;               rectangles did not intersect
;   USES:   AX
;

IsectRect   PROC    NEAR

        mov     ax,[si].rec_xRight      ; (ax) = right side of first rect
        cmp     ds:[bx].rec_xRight,ax   ; Is the second rect further right?
        jae     isr10                   ;   yes, use the first rectangle

        mov     ax,ds:[bx].rec_xRight   ; (ax) = right side of second rect

isr10:  mov     [di].rec_xRight,ax      ; dest = leftt most right side
        mov     ax,[si].rec_xLeft       ; (ax) = left side of first rect
        cmp     ds:[bx].rec_xLeft,ax    ; Is the second rect further left?
        jbe     isr20                   ;   yes, use the first rectangle

        mov     ax,ds:[bx].rec_xLeft    ; (ax) = left side of second rect

isr20:  mov     [di].rec_xLeft,ax       ; dest = right most left side
        cmp     [di].rec_xRight,ax      ; Is right <= left?
        jb      isrx                    ;   Yes, rect is invalid, carry set

        mov     ax,[si].rec_yBottom     ; (ax) = bottom side of first rect
        cmp     ds:[bx].rec_yBottom,ax  ; Is second rect further down?
        jae     isr30                   ;   yes, use first rectangle

        mov     ax,ds:[bx].rec_yBottom  ; (ax) = bottom side of second rect

isr30:  mov     [di].rec_yBottom,ax     ; dest = top most bottom side
        mov     ax,[si].rec_yTop        ; (ax) = top side of first rect
        cmp     ds:[bx].rec_yTop,ax     ; Is the second rect further up?
        jbe     isr40                   ;   yes, use first rectangle

        mov     ax,ds:[bx].rec_yTop     ; (ax) = top side of second rect

isr40:  mov     [di].rec_yTop,ax        ; dest = bottom most top side
        cmp     [di].rec_yBottom,ax     ; Is bottom <= top?
                                        ;   yes, rect is invalid, carry set
                                        ;   no, rect is valid, carry clear
isrx:   ret

IsectRect   ENDP


;***    IsInRect - determine if (X,Y) is in a give rectangle
;
;   Given a coordinate, (X,Y), determine if it is in a given rectangle.
;
;   PSEUDOCODE
;
;       IsInRect
;
;       if ((X coordinate is >= left boarder of rectangle)  &&
;          (X coordinate is <= right boarder of rectangle)  &&
;          (Y coordinate is <= bottom boarder of rectangle) &&
;          (Y coordinate is >= top boarder of rectangle))
;           return (IN_RECTANGLE)
;       else
;           return (NOT_IN_RECTANGLE)
;
;   ENTRY:  AX - X coordinate
;           DX - Y coordinate
;           DS:SI - rectangle to be examine
;
;   EXIT:   carry clear
;               coordinate in rectangle
;           carry set
;               coordinate not in rectangle
;
;   USES:   none
;

IsInRect    PROC    NEAR

        cmp     [si].rec_xLeft,ax   ; is X < left side?
        ja      iire                ; yes, not it rectangle

        cmp     [si].rec_xRight,ax  ; is X > right side?
        jb      iire                ; yes, not it rectangle

        cmp     [si].rec_yTop,dx    ; is Y < top side?
        ja      iire                ; yes, not it rectangle
                                    ; no, carry not set
        cmp     [si].rec_yBottom,dx ; is Y > bottom side?
        jb      iire                ; yes, not it rectangle

iirx:   ret                         ; return

iire:   stc                         ; coordinate not in rectangle
        jmp short iirx              ; exit with carry set

IsInRect    ENDP



;***    UnionRect - calculate the rectangle that contain two source rectangles
;
;   Given two rectangles, calculate the smallest rectangle that contains
;   both of the rectangles.
;
;   PSEUDOCODE
;
;       Xleft = min (Xleft1,Xleft2)
;       Xright = max (Xright1,Xright2)
;       Ytop  = min (Ytop1,Ytop2)
;       Ybottom = max (Ybottom1,Ybottom2)
;
;   ENTRY:  DS:SI - pointer to the first rectangle to be intersected
;           DS:BX - pointer to the second rectangle to be intersected
;           DS:DI - pointer to the destination rectangle
;
;   EXIT:   DS:DI - points to the union of first and second rectangles
;
;   USES:   AX
;

UnionRect   PROC    NEAR

        mov     ax,[si].rec_xRight      ; (ax) = right side of first rect
        cmp     ds:[bx].rec_xRight,ax   ; Is the second rect further left?
        jbe     unr10                   ;   yes, use the first rectangle

        mov     ax,ds:[bx].rec_xRight   ; (ax) = right side of second rect

unr10:  mov     [di].rec_xRight,ax      ; dest = leftt most right side
        mov     ax,[si].rec_xLeft       ; (ax) = left side of first rect
        cmp     ds:[bx].rec_xLeft,ax    ; Is the second rect further right?
        jae     unr20                   ;   yes, use the first rectangle

        mov     ax,ds:[bx].rec_xLeft    ; (ax) = left side of second rect

unr20:  mov     [di].rec_xLeft,ax       ; dest = right most left side
        mov     ax,[si].rec_yBottom     ; (ax) = bottom side of first rect
        cmp     ds:[bx].rec_yBottom,ax  ; Is second rect further up?
        jbe     unr30                   ;   yes, use first rectangle

        mov     ax,ds:[bx].rec_yBottom  ; (ax) = bottom side of second rect

unr30:  mov     [di].rec_yBottom,ax     ; dest = top most bottom side
        mov     ax,[si].rec_yTop        ; (ax) = top side of first rect
        cmp     ds:[bx].rec_yTop,ax     ; Is the second rect further down?
        jae     unr40                   ;   yes, use first rectangle

        mov     ax,ds:[bx].rec_yTop     ; (ax) = top side of second rect

unr40:  mov     [di].rec_yTop,ax        ; dest = bottom most top side
        ret

UnionRect   ENDP


;***    CheckCAParms - Check if caller is entitled to use CA
;
;   This routine is used to validate the callers parameters for
;   BvsSetCAState and BvsDestroyCA.
;
;   PSEUDOCODE
;
;       CheckCAParms
;
;       if (this process != CA process)
;           return (ERROR_VIO_MODE)
;       for each CA structure in the active list
;           if the CA handle points to the current structure
;               break out of the for loop
;       if (the CA is not in the active list)
;           return (ERROR_VIO_INVALID_PARMS)
;       return (NO_ERROR)
;
;   ENTRY:  es = ppbvs
;           si = unchecked CA handle
;           stack srguments (parmn,...)
;
;   EXIT:   si = checked CA handle
;           valid
;               Z flag set
;               ax = 0
;           invalid
;               Z flag clear
;               ax = error code
;
;   USES:   AX,ES
;

CheckCAParms PROC NEAR
        mov     ax,bvsiseg
        mov     es,ax
        .if     <BIT es:bvsi_flags nand bvsi_f_caproc>; is it the CA owner PID?
            mov     ax,ERROR_VIO_MODE   ; no, set error
            jmp     short ccp_exit
        .endif

        mov     ax,si
        mov     si,[bx].bvs_CA_lru
        .repeat                         ; top down
            .if   <ax e si>             ; if it is a valid CA handle
                sub   ax,ax             ; return ok
                jmp   short  ccp_exit
            .endif
            mov si,[si].cas_dn          ; go to next down
        .until <si e [bx].bvs_CA_lru>   ; until all active seen

        mov     ax,ERROR_VIO_INVALID_PARMS
ccp_exit:
        or      ax,ax                   ; set Z / NZ
        ret
CheckCAParms ENDP



;***    CASetLRUTop - move a CA to the top of the Z order
;
;   This routine takes a CA and moves it to the top of the Z order
;   in the list of created CAs
;
;   PSEUDOCODE
;
;       call MoveCAS to move the current CA to the top of the LRU list
;
;   ENTRY:  SI - offset of the CA to be moved
;
;   EXIT:   no error
;               AX = offset of CAS
;           error
;               AX = 0
;
;   USES:   CX,DI
;

CASetLRUTop PROC    NEAR

        mov     [bx].bvs_CA_crnt,si
        push    bvs_CA_crnt
        push    bvs_CA_lru
        call    moveCAS
        ret

CASetLRUTop ENDP

;***    moveCAS - move a CA from one list to another
;
;   procedure moveCAS moves CAS structures between list positions
;   source and dest.  It can be used to create/destroy or promote
;   a Conversion area.  Creating a Conversion area will promote it.
;
;   The procedure expects source and dest to be pointers to an element
;   in a doubly linked list.  Source and Dest may point to the same
;   element, which makes the procedure a NO OP.  Dest may be
;   the null pointer, in that case a new dest list is created.
;   Source may be the null pointer, in that case an error (AX=0) is
;   returned.
;
;   The element pointed to by source is unlinked (if it exists ) and
;   made the new listhead of the destination list. Its offset is returned
;   in AX.  AX=0 means the source element was not found.
;
;   PSEUDOCODE
;
;       if ((the source pointer == destination pointer) ||
;           (the source pointer == NULL))
;           return (pointer to the CA)
;       if (source CA is the only element in the source list)
;           set the source pointer to NULL
;       else
;           set the source pointer to point to the next CA down the list
;       remove the source CA from the list by connecting the list without it
;       if (destination list is empty)
;           close the destination list by pointing up and down pointers to the CA
;       else
;           close the destination list by inserting the CA into the list
;       set the destination pointer to the CA just inserted
;       return (pointer to the CA)
;
;
;   ENTRY:  srcpp  - offset to the offset of CA to be moved
;           destpp - offset to the offset of CA list to move the CA to
;
;   EXIT:   no error
;               ax - offset of the CA moved
;           error
;               ax - zero
;
;   USES:   BX,DX,SI,DI
;

moveCAS PROC
        PUBLIC  moveCAS

srcpp   equ     <[bp+6]>
destpp  equ     <[bp+4]>

        enter   0,0
        push    bx
        push    dx
        push    si
        push    di
        mov     di,destpp       ; DX = offset of destination list head
        mov     dx,[di]
        mov     si,srcpp        ; SI = pointer to source pointer
        mov     bx,[si]         ; BX = offset of element we are working with

        .if <bx e dx > OR       ; if source equal destination
        .if <ZERO bx >          ; or the source doesn't  exist
            jz  short mcas_exit ; exit
        .endif                  ;

        mov     di,[bx].cas_dn  ; di = pointer to preceding in source list
        mov     ax,[bx].cas_up  ; ax = pointer to following in source list

        .if < bx e ax >         ; if this is the last element in the source
            mov    word ptr [si], empty ; zero source pointer to indicate empty list
        .else
            mov    [si],di      ; save new list_head in source pointer
        .endif

        mov     si,ax           ; si = pointer to following in source list

        mov     [di].cas_up,si  ; fix up source list pointers
        mov     [si].cas_dn,di  ;

        .if <ZERO dx>           ; if no dest, create new dest list
            ;
            ; create a one element list from source element
            ;
            mov     [bx].cas_dn,bx
            mov     [bx].cas_up,bx
        .else
            ;
            ; add source element to destination list
            ;
            mov     di,dx                       ; DI = dest pointer
            mov     [bx].cas_dn,di              ;
            mov     si,[di].cas_up              ; SI = dest->cas_up
            mov     [bx].cas_up,si              ;
            mov     [si].cas_dn,bx              ;
            mov     [di].cas_up,bx              ;
        .endif
        mov     di,destpp       ; DX = offset of destination list head
        mov     [di],bx         ; make element new dest list head

mcas_exit:
        mov     ax,bx           ; return offset of element
        pop     di
        pop     si
        pop     dx
        pop     bx

        leave
        ret     4
moveCAS ENDP



;***    initCAS - initialize the array of CA data structures
;
;   Initialize the CAS array to be one doubly linked (free) list
;   of CAS structures.
;
;   PSEUDOCODE
;
;       if (there are CAs)
;           for (each CA in the array of CAs, starting with the second one)
;               set the down pointer to the CA above it in the array
;               set the up pointer of the CA below it to the current CA
;           set the down pointer of the first CA to point to the last CA
;           set the up pointer of last CA to point to the first CA
;       return
;
;   ENTRY:  none
;
;   EXIT:   CA structures initialized and linked into free list
;
;   USES:   none
;

initCAS PROC
        PUBLIC  initCAS

        push    cx
        push    si
        mov     si,bvs_CAS      ; SI = offset of first element
        mov     [bx].bvs_CA_free,si  ; initialize free pointer
        mov     [bx].bvs_CA_lru,bx   ; initialize lru pointer

        mov     cx,CAMAX-1      ; initialize CAMAX CAS structures
        or      cx,cx
        .if     ae              ; just in case this runs w/CAMAX==0

            .repeat
                mov     [si+SIZE CAS].cas_dn,si ; back pointer of next
                add     si,SIZE CAS
                mov     [si-SIZE CAS].cas_up,si ; fowrw pointer of this
            .loop

            ; special cases:

            mov    [bx].bvs_CAS.cas_dn,si       ; first back pointer
            mov    [si].cas_up,bvs_CAS          ; last forward pointer

        .endif
        pop     si
        pop     cx
        ret
initCAS ENDP

;***    BvsCAExitList - exit list processing for CA support
;
;   Do clean up necessary if the CA process dies with CAs created.
;
;   PSEUDOCODE
;
;       if (this process is the CA process)
;           clear the CA PID variable
;           set the CA Clean up variable
;       call DosExitList to continue to the next routine
;
;   ENTRY:  none
;
;   EXIT:   none
;
;   USES:   none
;

BvsCAExitList   PROC    FAR
        PUBLIC  BvsCAExitList

        push    ax                      ; save ax
        push    ds                      ; save ds
        push    es                      ; save es

        push    BVSISEG
        pop     es                      ; (es) = BVSISEG, BVS instance data

        mov     ds,es:bvsi_ldtsel       ; (ds) = Local Info Seg
        mov     ax,ds:LIS_CurProcID     ; (ax) = PID for this process
        mov     ds,es:bvsi_bvssel       ; (ds) = BVSCB, screen group data
        .if     <ax eq ds:bvs_CA_PID>   ; this process is still CA process
            mov     ds:bvs_CA_pid,0     ; we are no longer the CA process
            mov     ds:bvs_CA_died,CA_OWNER_DIED; indicate clean up needed
        .endif

        pop     es                      ; restore es
        pop     ds                      ; restore ds
        pop     ax                      ; restore ax

        push    EXLST_EXIT              ; continue to next exit list routine
        push    cs                      ; segment of exit list routine
        push    offset BvsCAExitList    ; offset of exit list routine
        call    DosExitList             ; continue to next routine on exit list

        int     3                       ; we should NEVER get here
BvsCAExitList   ENDP


;/********************** START OF SPECIFICATIONS ************************/
;/*                                                                     */
;/* SUBROUTINE NAME:    BvsCheckCharType                                */
;/*                                                                     */
;/* DESCRIPTIVE NAME:   Return information about a cell                 */
;/*                                                                     */
;/* FUNCTION:   Return leading/trailing byte information about a cell   */
;/*                                                                     */
;/* NOTES:      Executes on level 3, protect mode only                  */
;/*                                                                     */
;/* ENTRY POINT:  BvsCheckCharType                                      */
;/*   LINKAGE:  Call BvsCheckCharType from BVSMAIN                      */
;/*                                                                     */
;/* INPUT:  StackFrame and Registers (see BVSMAIN) with:                */
;/*     parmn   = ct_col        column of cell to be examined           */
;/*     parmnm1 = ct_row        row of cell to be examined              */
;/*     parmnm2 = ct_typeoff    offset of type return buffer address    */
;/*     parmnm3 = ct_typeseg    segment of type return buffer address   */
;/*                                                                     */
;/* EXIT-NORMAL:  AX = 0                                                */
;/*                                                                     */
;/* EXIT-ERROR:                                                         */
;/*                                                                     */
;/* EFFECTS:    Destroys CX, DX, SI, DI                                 */
;/*                                                                     */
;/* INTERNAL REFERENCES: BVSCB                                          */
;/*   ROUTINES:  None                                                   */
;/*                                                                     */
;/* EXTERNAL REFERENCES: None                                           */
;/*   ROUTINES:  None                                                   */
;/************************ END OF SPECIFICATIONS ************************/
;
; PSEUDOCODE
;
;   BvsCheckCharType
;
;   copy the user parameters from the stack to the parameter block
;   set the function code
;   call AllBuffer to execute the function
;   return (error if one occurred)

BvsCheckCharType    PROC    NEAR
        PUBLIC  BvsCheckCharType

        mov     [bp].vp_index,sx_ReadCellTypes  ;Set the subroutine index

        mov     ax,[bp].ct_row
        mov     [bp].vp_startrow,ax
        mov     ax,[bp].ct_col
        mov     [bp].vp_startcol,ax     ;Set the row and column

        mov     ax,[bp].ct_typeoff
        mov     [bp].vp_offset,ax
        mov     ax,[bp].ct_typesel
        mov     [bp].vp_selector,ax     ;Set the string address

        mov     [bp].vp_repeatlength,2  ;Setup the length

        Call    AllBuffer

        ret
BvsCheckCharType    ENDP

BVS3SEG ENDS                                                            ;MDLL


CTEXT_TUNE5  SEGMENT BYTE PUBLIC 'CODE' USE16                           ;MDLL
        ASSUME  CS:CODE02                                               ;MDLL


;***    RestoreCAS - Restore all CAs
;
;   This routine redraws all of the visible CAs.
;
;   PSEUDOCODE
;
;       Set up parameters to redraw all CAs
;       call RedrawCAS to draw all of the CAs
;
;   ENTRY:  ds - BVSCB
;
;   EXIT:   all CAs redrawn
;
;   USES:   bvs_TouchRect, bvs_WriteRect, AX
;

RestoreCAS  PROC    NEAR
            PUBLIC  RestoreCAS

        .if     <[bx].bvs_CA_pid ne bx>; No CAs are active
            push    bx
            push    si
            mov     bx,bvs_TouchRect        ; (bx) = offset of TouchRect
            mov     [bx].rec_xRight,-1      ; right side of screen
            mov     [bx].rec_yBottom,-1     ; bottom side of screen
            mov     [bx].rec_xLeft,0        ; left side of screen
            mov     [bx].rec_yTop,0         ; top side of screen
            mov     si,ds:bvs_CA_lru        ; (si) = top CA
            mov     si,[si].cas_Up          ; (si) = bottom CA

            call    RedrawCAS

            pop     si
            pop     bx
        .endif
        ret

RestoreCAS  ENDP


;***    GetDBCSInfo - get current DBCS display information from VDH
;
;   Call the VDH to get the list of ranges for characters that require
;   two cells to display on the screen.
;
;   PSEUDOCODE
;
;       set up the pointer to return buffer and buffer length in parmblock
;       call AllVDH to execute the function
;       if (error from AllVDH)
;           return doing nothing
;       save the length of the table in the BVSCB
;       if (length of the table == zero)
;           return
;       if (length of the table > space available in BVSCB)
;           set the length of the table to space available in BVSCB
;       copy the table from parameter block into BVSCB
;       return
;
;   ENTRY:  none
;
;   EXIT:   success - ax == 0
;           failure - ax != 0
;
;   USES:   ax,cx
;

GetDBCSInfo PROC
        PUBLIC  GetDBCSInfo

        mov     ds:bvs_dbcstbllen,0             ; default is 1 cell characters
        and     ds:bvs_flags2,NOT bvs_f2_dbcscp ; default to SBCS code page

        push    bvs_CountryCode-bvs_DBCSEvBuff  ; length of buffer
        push    ds                              ; segment of country code
        push    bvs_CountryCode                 ; offset of country and CP
        push    ds                              ; segment of DBCS buffer
        push    bvs_DBCSEvBuff                  ; offset of DBCS buffer
        Call    DOSGETDBCSEV                    ; get the DBCS data
        or      ax,ax                           ; Did the function return error?
        jnz     gdi05                           ;   yes, use default result

        cmp     word ptr ds:bvs_DBCSEvBuff,0    ; Is this a DBCS code page?
        je      gdi05                           ;   no, use default result

        or      ds:bvs_flags2,bvs_f2_dbcscp     ; DBCS code page        @T31

gdi05:  mov     [bp].vp_parmlength,di_totallen  ; length of parameter packet
        mov     [bp].vp_di_tbloff,vp_di_table   ; offset of table
        mov     [bp].vp_di_tbllen,di_tblbuflen  ; size of table
        mov     ax,[bx].bvs_ActiveCP            ; (ax) = codpage for table
        mov     [bp].vp_di_codepage,ax          ; size of table
        mov     di,fn_GetDBCSInfo               ; function number

        call    AllVDH                  ; (ax) = rc for VDH GetDBCSDisplayInfo
        or      ax,ax                   ; Did we get the DBCS Display range?
        jnz     gdix                    ;   no, do not change table, exit

        mov     cx,[bp].vp_di_tbllen    ; (cx) = table length
        mov     ds:bvs_dbcstbllen,cx    ; save the table length
        jcxz    gdix                    ; the table empty, nothing to fill in

        cmp     cx,MaxDispTblLen        ; Is there enough space in BVSCB?
        jbe     gdi10                   ;   yes, copy the table

        mov     cx,MaxDispTblLen        ; (cx) = table length
        mov     ds:bvs_dbcstbllen,cx    ; save the table length

gdi10:  shr     cx,1                    ; (cx) = table length in words
        xor     bx,bx                   ; (bx) = 0, offset into both tables
        push    bp                      ; save bp

gdi20:  mov     ax,[bp].vp_di_table     ; (ax) = value from table
        mov     [bx].bvs_dbcstbl,ax     ; copy element into BVSCB table
        add     bx,2                    ; (bx) = offset of next table entry
        add     bp,2                    ; (bp) = offset of next table entry
        loop    gdi20                   ; continue until entire table copied

        pop     bp                      ; restore bp
        xor     bx,bx                   ; (bx) = 0
        xor     ax,ax                   ; (ax) = 0 = good return code

gdix:   ret

GetDBCSInfo ENDP

CTEXT_TUNE5 ENDS                                                        ;MDLL
        END
;@T25 = 04/04/89 TPL, Sizzle work, B701685
;@T31 = 05/18/89 TPL, PhilipL suggested changes for DCR 132, B783850
;mch = 09/21/89 MCH, Changes from Mark Hahn for PTR B785861
;@tb22 = 09/22/89 TLB, Changes from Mark Hahn for PTR B785869
;@D549 = 11/02/89 CJJ, Seltable changes due to rangeless sessions, DCR 549
;@T52  = 02/08/90 TPL, DCR 704 work
;B790217 = 08/23/90 WKB, Changes from Takumi(MS)
;B790218 = 08/23/90 WKB, Changes from Takumi(MS)
;B790220 = 08/23/90 WKB, Changes from Takumi(MS)
;j-ys3m = 02/14/91 TPL, Validate input format ID and attribute count , J200264
;j-ys3mf= 05/20/91 TPL, Code missing in the J200264 fix from IBM-J, B721940
;MDLL   = 01/10/94 BJN, Page Tune segments for Merged DLL.
