;       SCCSID = @(#)doansi.asm	6.2 92/01/24
;       SCCSID = @(#)doansi.asm	6.2 92/01/24
        PAGE    60,132
        TITLE   DOANSI.ASM - ANSI Function Dispatch Routine
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************

;********************** START OF SPECIFICATIONS *******************************
;*
;*                      *** IBM CONFIDENTIAL ***
;*
;*   Subroutine Name:  DoAnsiFn
;*
;*   Descriptive Name:  ANSI Function Dispatch routine
;*
;*   Function:  Determines which of the ANSI functions is being requested
;*              and prepares the stack with the parameters required before
;*              calling the appropriate VIO function.
;*
;*   Notes: Uses the carry flag (CF).  CF = 1 indicates that the terminating
;*          character (in AL) was invalid, ie. no function was performed.
;*          CF = 0 indicates that an ANSI function was performed.  Preserves
;*          any VIOxxx Error Return Code in AX on exit.
;*
;*   Entry Point:  DoAnsiFn
;*       Linkage:  CALL  doAnsiFn  (NEAR from  AnsiInterp)
;*
;*   INPUT:   (AL) = terminator character (ASCII code > 40 Hex)
;*            (ES) = segment address for PSG data (bvscb)
;*            (DS) = GROUP data segment selector for ANSI routines
;*
;*   Exit - NORMAL:   AX = 0
;*                    CF = 0            ; Carry Flag used to indicate that
;*                                      ; status of function request
;*
;*   Exit - ERROR:    AX = VIOxxx error code
;*                    CF = 1            ; invalid terminator - no action taken
;*
;*   Internal References:  ANSIDAT      ; structure for calling VioSetMode
;*            Routines:    ANSIINJECT   ; process CPR command
;*                         ANSIKEYDEF   ; process Key Definition command
;*
;*   External References:  BVSCB        ; the BVS per-screen-group data struc
;*            Routines:    VIOSCROLLUP  ; process cursor oriented commands
;*                         VIOSETCURPOS
;*                         VIOSETMODE   ; process mode change command
;*
;***********************  END OF SPECIFICATIONS  ******************************
;       Change History
;
;       87/08/09  TPL   Change graphics ModeData length from 8 to 12 to
;                       accomodate VIO changes to setmode.
;       88/12/15  TPL   Use default for cursor sequence when 0 parm supplied
;
;       89/09/13  ICH   DCR309    (Tag:J-DB01)
;                     - Support set mode 40 and 47 (DBCS video mono and color).
;                 KKJ - Set attribute_2 for World wide format.
;                        Bit 2  for Horizontal grid On (SGR 38)
;                        Bit 3  for Vertical grid On   (SGR 39)
;                        Bit 5  for Blink On           (SGR  5)
;                        Bit 7  for UnderScore On      (SGR  4)
;                     - Changed the handling for VioScrollUp
;                       Added to set 0FFh into the Attribute 3rd, this means
;                       CGA attribute.
;       90/01/31  TPL - DCR 309 Fix (Tag:J-DB02)
;
;       92/01/19  TRM - Check for DBCS mode (Tag B728215 )
;******************************************************************************
;
.xlist
INCLUDE         bvscb.inc               ; BVS structure definitions
INCL_VIO        EQU 1                   ; PTR B728215
INCLUDE         bsesub.inc              ; PTR B728215
INCLUDE         ansidecl.inc            ; ANSI common data declarations
INCLUDE         error.inc               ; DOS ERROR declarations
INCLUDE         ansiextr.inc            ; External declarations
.list
        .386p                           ;  Assemble for iAPX-386 processor

        EXTRN   VIOSETCURPOS:FAR        ; Set cursor position
        EXTRN   VIOSCROLLUP:FAR         ; Scroll line
        EXTRN   VIOSETMODE:FAR          ; Set display mode
        EXTRN   VIOGETMODE:FAR          ; Set display mode       ;PTR B728215
        EXTRN   ANSIINJECT:FAR          ; Build CPR
        EXTRN   ANSIKEYDEF:FAR          ; Build key definition

ANSIDAT SEGMENT WORD PUBLIC 'DATA' USE16 ; Instance data segment        ;@T52
ANSIDAT ENDS

ANSIGSEG SEGMENT WORD PUBLIC 'FAR_DATA' USE16 ; Global data segment     ;@T52
ANSIGSEG ENDS                           ;   among all processes in the system

ANSI1   SEGMENT WORD  PUBLIC 'CODE' USE16                               ;@T52
ANSI1   ENDS

        PUBLIC  AttNew
        PUBLIC  AttMask
        PUBLIC  TermTab
        PUBLIC  JumpTab

ANSI1   SEGMENT WORD  PUBLIC 'CODE' USE16                               ;@T52

        ASSUME  CS:ANSI1,DS:ANSIDAT,ES:NOTHING
;
;  Look-up tables are declared in CODE segment so only one copy will exist.
;  The following look-up tables are used with Select Graphic Rendition fn:
;
; -- index ----- 0 -- 1 -- 2 -- 3 -- 4 -- 5 -- 6 -- 7

AttNew  DB      007h,008h,000h,000h,001h,080h,000h,070h  ; 7
        DB      000h,000h,000h,000h,000h,000h,000h,000h  ; 15
        DB      000h,000h,000h,000h,000h,000h,000h,000h  ; 23
        DB      000h,000h,000h,000h,000h,000h,000h,004h  ; 31
        DB      002h,006h,001h,005h,003h,007h,000h,000h  ; 39
        DB      000h,040h,020h,060h,010h,050h,030h,070h  ; 47

AttMask DB      000h,0F7h,0FFh,0FFh,0F8h,07Fh,0FFh,088h  ; 7
        DB      088h,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh  ; 15
        DB      0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0FFh  ; 23
        DB      0FFh,0FFh,0FFh,0FFh,0FFh,0FFh,0F8h,0F8h  ; 31
        DB      0F8h,0F8h,0F8h,0F8h,0F8h,0F8h,0FFh,0FFh  ; 39
        DB      08Fh,08Fh,08Fh,08Fh,08Fh,08Fh,08Fh,08Fh  ; 47
;
;   TermTab is a terminator character lookup table:
;   The table is arranged in descending frequency of expected occurence.
;
TermTab   LABEL    BYTE
        DB   CUD_TERM                   ;  0 - ASCII 'B'
        DB   CUU_TERM                   ;  1 - ASCII 'A'
        DB   CUF_TERM                   ;  2 - ASCII 'C'
        DB   CUB_TERM                   ;  3 - ASCII 'D'
        DB   CUP_TERM                   ;  4 - ASCII 'H'
        DB   HVP_TERM                   ;  5 - ASCII 'f'
        DB   SGR_TERM                   ;  6 - ASCII 'm'
        DB   ED_TERM                    ;  7 - ASCII 'J'
        DB   EL_TERM                    ;  8 - ASCII 'K'
        DB   RM_TERM                    ;  9 - ASCII 'l'
        DB   SM_TERM                    ; 10 - ASCII 'h'
        DB   KKR_TERM                   ; 11 - ASCII 'p'
        DB   EKR_TERM                   ; 12 - ASCII 'q'
        DB   DSR_TERM                   ; 13 - ASCII 'n'
        DB   RCP_TERM                   ; 14 - ASCII 'u'
        DB   SCP_TERM                   ; 15 - ASCII 's'
        DB   CPR_TERM                   ; 16 - ASCII 'R'
        DB   0                          ; 17 - dummy term char for end of table
EndTermTab   LABEL   BYTE

TermTabLen      EQU     EndTermTab - TermTab
ANSIMODE_LEN    EQU     TYPE Modes
;
;  JumpTab is a jump table scanned to find proper jump point:
;  The table is arranged in reverse order of the term char table.
;
JumpTab  LABEL   BYTE
        DW   OFFSET ANSI1:dofnx         ; function "not handled" exit point
        DW   OFFSET ANSI1:clrax
        DW   OFFSET ANSI1:doSCP
        DW   OFFSET ANSI1:doRCP
        DW   OFFSET ANSI1:doDSR
        DW   OFFSET ANSI1:doEKR
        DW   OFFSET ANSI1:doKKR
        DW   OFFSET ANSI1:doSM
        DW   OFFSET ANSI1:doRM
        DW   OFFSET ANSI1:doEL
        DW   OFFSET ANSI1:doED
        DW   OFFSET ANSI1:doSGR
        DW   OFFSET ANSI1:doHVP
        DW   OFFSET ANSI1:doHVP
        DW   OFFSET ANSI1:doCUB
        DW   OFFSET ANSI1:doCUF
        DW   OFFSET ANSI1:doCUU
        DW   OFFSET ANSI1:doCUD
EndJumpTab   LABEL     BYTE

JumpTabLen   EQU   EndJumpTab - JumpTab

        PUBLIC  DoAnsiFn
        PUBLIC  dofnx
        PUBLIC  clrax
        PUBLIC  doSCP
        PUBLIC  doRCP
        PUBLIC  doDSR
        PUBLIC  doEKR
        PUBLIC  doKKR
        PUBLIC  doSM
        PUBLIC  doRM
        PUBLIC  doEL
        PUBLIC  doED
        PUBLIC  doSGR
        PUBLIC  doHVP
        PUBLIC  doCUB
        PUBLIC  doCUF
        PUBLIC  doCUU
        PUBLIC  doCUD

DoAnsiFn PROC   NEAR

;       int     3                       ; ******** BUG-BUG ********
        push    BP                      ; save all registers used on stack
        push    BX
        push    CX
        push    DI
        push    SI
        push    ES

        sub     bx,bx                   ;
        mov     SI,bvs_ParmBuffPtr      ; (SI) = offset to parm buffer
        cmp     ES:[bvs_ParmCount],0    ; check parameter count
        jne     dofn1                   ; IF parmcount = 0
        inc     bx                      ; THEN (BL) = 1 (default parameter)
        jmp     SHORT dofn2
dofn1:
        mov     BL,ES:[SI]              ; ELSE (BL) = first parameter in parmbf
dofn2:
;
;  Jump to appropriate routine based on term character (in AL):
;
        cld                             ; clear DF to auto-increment DI
        mov     CX,TermTabLen           ; (CX) = length of TermTab
        mov     DI,OFFSET ANSI1:TermTab ; (DI) = index to TermTab
        push    CS
        pop     ES                      ; (ES) = selector of code seg (ANSI1)
        repne   scasb                   ; scan TermTab for char in AL
        shl     CX,1                    ; (CX) = WORD offset in JumpTab
        mov     BP,CX                   ; (BP) = index into JumpTab
        add     BP,OFFSET ANSI1:JumpTab ; (BP) = offset into JumpTab
        mov     ES,BvscbSel             ; (ES) = selector for bvscb
        mov     AX,ES:[bvs_rows]        ; (AX) = number of text rows
        dec     AX                      ; (AX) = maximum row #
        mov     max_row,AX              ; max_row = maximum row #
        mov     AX,ES:[bvs_cols]        ; (AX) = number of text columns
        dec     AX                      ; (AX) = maximum col #
        mov     max_col,AX              ; max_col = maximum col #
        sub     DI,DI
        jmp     CS:[BP]                 ; jump to sequence handling routine
;
;  FIRST PARAMETER assumed in BL.  The second parm, if any, is in ParmBuff.
;  BH is clear, so word data (BX) may also be used.
;
doCUU:                                  ; CURSOR UP
        or      bx,bx
        jnz     cuu0
        inc     bx
cuu0:
        mov     AX,ES:[bvs_CursorRow]   ; (AX) = current row position
        sub     AX,BX                   ; subtract parameter from row position
        jns     cuu1                    ; IF row less than zero
        xor     AX,AX                   ;  THEN (AX) = 0
cuu1:
        push    AX                      ; push row on stack
        push    ES:[bvs_CursorCol]      ; push column on stack
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doCUD:                                  ; CURSOR DOWN
        or      bx,bx
        jnz     cud0
        inc     bx
cud0:
        mov     AX,ES:[bvs_CursorRow]
        add     AX,BX                   ; add parameter to row position
        cmp     AX,max_row              ; IF row < max_row
        jb      cud1                    ; THEN push row value
        mov     AX,max_row              ; ELSE set row to maximum
cud1:
        push    AX                      ; push row on stack
        push    ES:[bvs_CursorCol]      ; push column on stack
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doCUF:                                  ; CURSOR FORWARD
        or      bx,bx
        jnz     cuf0
        inc     bx
cuf0:
        mov     AX,ES:[bvs_CursorCol]
        add     AX,BX                   ; add parameter to column position
        cmp     AX,max_col              ; IF col < max_col
        jb      cuf1                    ; THEN push column value
        mov     AX,max_col              ; ELSE set column to maximum
cuf1:
        push    ES:[bvs_CursorRow]      ; push row on stack
        push    AX                      ; push column on stack
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doCUB:                                  ; CURSOR BACKWARD
        or      bx,bx
        jnz     cub0
        inc     bx
cub0:
        mov     AX,ES:[bvs_CursorCol]
        sub     AX,BX                   ; subtract parameter from column pos.
        jns     cub1                    ; IF column less than zero
        xor     AX,AX                   ;  THEN (AX) = 0
cub1:
        push    ES:[bvs_CursorRow]      ; push row on stack
        push    AX                      ; push column on stack
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doHVP:                                  ; HORIZONTAL AND VERTICAL POSITION
;       Input parameters for row and column based on HOME position at 1,1
;       Parameters must be positive non-zero values (ie 1 to 255)
;
        or      BX,BX                   ; IF BX = 0
        jz      hvp1                    ; THEN do not decrement
        dec     BX                      ; ELSE (BX) = new row position
        cmp     BX,max_row              ; IF row value is <= max row
        jle     hvp1                    ; THEN push this row value
        mov     BX,max_row              ; ELSE (BX) = max_row
hvp1:
        push    BX                      ; push row on stack
        xor     BX,BX                   ; clear the BX register
        cmp     ES:[bvs_ParmCount],2    ; IF length of parm buffer >= 2
        jge     hvp2                    ; THEN get column pos from buffer
        jmp     SHORT hvp3              ; ELSE push column value in BX (0)
hvp2:
        inc     SI                      ; (DI) = index of second parameter
        add     BL,ES:[SI]              ; (BL) = second parameter
        jz      hvp3                    ; IF BX = 0, push that value
        dec     BX                      ; ELSE decrement BX
        cmp     BX,max_col              ; IF new column is <= max_col
        jle     hvp3                    ; THEN push that value
        mov     BX,max_col              ; ELSE (BX) = # cols
hvp3:
        push    BX                      ; push column on stack
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doRCP:                                  ; RESTORE CURSOR POSITION
        mov     AX,ES:[bvs_SaveCursor]  ; (AX) = row (LO), column (HI)
        mov     DI,bvs_ParmBuffPtr      ; (DI) = offset to parm buffer
        inc     AL                      ; (AL) = AL + 1
        inc     AH                      ; (AH) = AH + 1 (reset for 1-based #s)
        mov     ES:[DI],AX              ; put row & column in Parm Buff
        mov     ES:[bvs_ParmCount],2    ; parameter count = 2
        mov     AL,'f'                  ; ELSE set AL to term char for doHVP
        jmp     dofn1                   ;   go to init dofn code
;
;
doSCP:                                  ; SAVE CURSOR POSITION
        mov     BX,ES:[bvs_CursorRow]   ; (BX) = current row position
        mov     AX,ES:[bvs_CursorCol]   ; (AX) = current column position
        mov     AH,AL                   ; (AH) = column
        mov     AL,BL                   ; (AL) = row
        mov     ES:[bvs_SaveCursor],AX  ; save the cursor position
        jmp     clrax                   ; goto "CLEAR AX HANDLED" exit
;
;
doEL:                                   ; ERASE IN LINE
        push    word ptr ES:[bvs_ScrAttr2] ; Save  2nd,3rd Attribute    ;J-DB01
        mov     byte ptr ES:[bvs_ScrAttr3],0FFh ; Means CGA Attribute   ;J-DB01
        mov     AX,ES:[bvs_CursorRow]   ; top & bottom row for scroll
        push    AX                      ; push top row to scroll on stack
        push    ES:[bvs_CursorCol]      ; push left column to scroll on stack
        push    AX                      ; push bottom row to scroll on stack
        push    max_col                 ; push maximum column position
        push    1                       ; push number of lines to blank = 1
        push    ES                      ; push selector for bvs_ttycell
        push    bvs_ttycell             ; (BX) = offset bvs_ttycell
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSCROLLUP             ; effect is erase to end of line
        pop     word ptr ES:[bvs_ScrAttr2] ; Restore 2nd,3rd Attribute  ;J-DB01
        jmp     commx                   ; goto "Function Handled" exit
;
;
doED:                                   ; ERASE IN DISPLAY
        push    word ptr ES:[bvs_ScrAttr2] ; Save  2nd,3rd Attribute    ;J-DB01
        mov     byte ptr ES:[bvs_ScrAttr3],0FFh ; Means CGA Attribute   ;J-DB01
        push    DI                      ; top row to scroll is zero
        push    DI                      ; left column to scroll is zero
        push    max_row                 ; push maximum row value on screen
        push    max_col                 ; push maximum column value on screen
        push    -1                      ; push number of lines to blank = -1
        push    ES                      ; push selector for bvs_ttycell
        push    bvs_ttycell             ; (BX) = offset bvs_ttycell
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSCROLLUP             ; effect is erase entire display
        pop     word ptr ES:[bvs_ScrAttr2] ; Restore 2nd,3rd Attribute  ;J-DB01
;       or      AX,AX                   ; IF no VIO error
;       jz      ed1                     ; THEN continue
;       jmp     commx                   ; ELSE goto "function handled" exit
ed1:
        push    DI                      ; push row
        push    DI                      ; push column
        push    DI                      ; push the VIOxxx dummy "handle"
        call    VIOSETCURPOS            ; set cursor at HOME position
        jmp     commx                   ; goto "Function Handled" exit
;
;
doSGR:                                  ; SELECT GRAPHIC RENDITION


;******************************************************************************
;   The following values apply as valid parameters for the SGR command:
;       0 - all attributes OFF (white on black default = 07h)
;       1 - high intensity ON (affects hue in color text modes)
;       4 - underscore ON (monochrome display only)
;       5 - blink ON
;       7 - reverse video ON
;       8 - cancelled ON (makes characters invisible)
;
;       30 - black FOREGROUND         40 - black BACKGROUND
;       31 - red      "               41 - red      "
;       32 - green    "               42 - green    "
;       33 - yellow   "               43 - yellow   "
;       34 - blue     "               44 - blue     "
;       35 - magenta  "               45 - magenta  "
;       36 - cyan     "               46 - cyan     "
;       37 - white    "               47 - white    "
;
;******************************************************************************
;   Using the above parameter values (0 - 47) as an index into these two data
;   tables, "AttMask" and "AttNew", which are defined in the declarations for
;   DoAnsiFn.  AttMask and AttNew are combined with the current attribute
;   (CurrAtr) to derive the new attribute value (ResultAttr).  The operation
;   is performed using the following Boolean logic:
;
;       ResultAttr = (CurrAttr AND AttMask) OR ((NOT AttMask) AND AttNew)
;
;   Or more briefly:    R = (C & M) | ( (!M) & N)
;
;   This simplifies this function's logic and performs the correct attribute
;   computation using only 4 fast logical operators on registers.
;
;******************************************************************************
;
                                        ; (DI) = pointer to parm buffer
        mov     AL,ES:[bvs_ScrAttr]     ; get current screen attribute
        mov     CX,ES:[bvs_parmCount]   ; (CX) = number of parms
        or      CX,CX                   ; check for no parameters
        jnz     sgr1                    ; if parmcount > 0 get parm from buffer
        mov     BYTE PTR ES:[SI],0      ; else default parameter = 0
        inc     CX                      ; make count valid for loop
sgr1:
        xor     BH,BH                   ; clear BH register
        mov     BL,ES:[SI]              ; (BL) = byte type parameter value
        mov     BP,BX                   ; (BP) = word type parameter value
        cmp     BP,47d                  ; check for invalid parameter
        jg      sgr2                    ; if parm > 47 skip this parm


        ;PTR B728215  First find out what is the MODE ???????
        push    SI                      ; Save regs
        push    ES                      ;
        push    AX                      ; Save AX, VIOGETMODE affects it
        lea     SI,ANSIGSEG:GetSysMode  ; Get address of mode structure buffer
        push    ANSIGSEG                ; Push Sel
        push    SI                      ; Push Offset
        push    DI                      ; Handle
        call    VIOGETMODE              ; Get the mode
        mov     BX, ANSIGSEG            ;
        mov     ES, BX                  ;
        cmp     ES:[SI].viomi_fmt_ID, 1 ; IF format ID is 1, DBCS mode
        pop     AX                      ; Restore regs
        pop     ES                      ;
        pop     SI                      ;
        jnz     NotDBCS                 ; If not DBCS, jump over DBCS code

;;-----------------------------------------------------------------------------
;; Handling for Screen Attribute 2
        mov     bl,byte ptr ES:[bvs_ScrAttr2]    ; Get Attr2            ;J-DB02
        cmp     BP,38d                  ; check horizontal grid line    ;J-DB01
        jne     sgrskp1                 ; parameter.                    ;J-DB01
        or      bl,4                    ; Bit 2 ON                      ;J-DB02
sgrskp1:                                ;                               ;J-DB02
        cmp     BP,39d                  ; check vertical   grid line    ;J-DB01
        jne     sgrskp2                 ; parameter.                    ;J-DB01
        or      bl,8                    ; Bit 3 ON                      ;J-DB02
sgrskp2:                                ;                               ;J-DB02
        or      BP,BP                   ; check all bit off.            ;J-DB02
        jne     sgrskp3                 ;                               ;J-DB01
        mov     bl,0                    ; Clear all bits                ;J-DB02
sgrskp3:                                ;                               ;J-DB01
        cmp     BP,4                    ; check UnderScore              ;J-DB01
        jne     sgrskp4                 ;                               ;J-DB01
        or      bl,80h                  ; Bit 7 ON                      ;J-DB02
sgrskp4:                                ;                               ;J-DB01
        cmp     BP,5                    ; check Blink On                ;J-DB01
        jne     sgrskp5                 ;                               ;J-DB01
        or      bl,20h                  ; Bit 5 ON                      ;J-DB02
sgrskp5:                                ;                               ;J-DB01
        cmp     BP,7                    ; check Reverse                 ;J-DB02
        jne     sgrskp6                 ;                               ;J-DB02
        or      bl,40h                  ; Bit 6 ON                      ;J-DB02

;; In US reverse handling, previous color setting is ignored except     ;J-DB02
;; for the high intensity bit.  The final result should be 70h which    ;J-DB02
;; is white background.  In DBCS (Epoch) color mode, however, must      ;J-DB02
;; convert the Blue+Reverse request into Blue background color.         ;J-DB02
;; Therefore, previous foreground color bits must be saved in           ;J-DB02
;; bvs_ScrAttr2 as follow:                                              ;J-DB02
;;                                                                      ;J-DB02
;; bvs_ScrAttr2 bits                                                    ;J-DB02
;;                                                                      ;J-DB02
;;      7 : Underline                                                   ;J-DB02
;;      6 : Reverse                                                     ;J-DB02
;;      5 : Blink                                                       ;J-DB02
;;      4 :             FG Red   <==                                    ;J-DB02
;;      3 : V-Grid                                                      ;J-DB02
;;      2 : H-Grid                                                      ;J-DB02
;;      1 :             FG Green <==                                    ;J-DB02
;;      0 :             FG Blue  <==                                    ;J-DB02
;;                                                                      ;J-DB02
        push    ax                      ; Save current screen attribute ;J-DB02
        mov     ah, al                  ;                               ;J-DB02
        shl     ah, 2                   ; Get FG Red                    ;J-DB02
        and     ax, 1003h               ; Mask OFF unwanted bits        ;J-DB02
        or      bl, al                  ; Merge with bvs_ScrAttr2       ;J-DB02
        or      bl, ah                  ;                               ;J-DB02
        pop     ax                      ; Restore current screen attr   ;J-DB02
sgrskp6:                                ;                               ;J-DB02
        cmp     BP, 30d                 ; Check black FG                ;J-DB02
        je      sgrskp7                 ;                               ;J-DB02
        cmp     BP, 8                   ; Check Invisible               ;J-DB02
        jne     sgrskpx                 ;                               ;J-DB02
sgrskp7:                                ;                               ;J-DB02
        and     bl, 0ECh                ; Clear all FG color bits       ;J-DB02
sgrskpx:                                ;                               ;J-DB02
        mov     byte ptr ES:[bvs_ScrAttr2], bl                          ;J-DB02
;;-----------------------------------------------------------------------------

NotDBCS:                                ; PTR B728215 jumps here for NON-DBCS
        mov     BH,ANSI1:AttMask[BP]    ; get parameter's attribute mask
        mov     BL,ANSI1:AttNew[BP]     ; get parameter's attribute value
        and     AL,BH                   ; (AL) = (C & M)
        not     BH                      ; (BH) = (!M)
        and     BL,BH                   ; (BL) = ((!M) & N)
        or      AL,BL                   ; (AL) = (C & M) | ((!M) & N)
        mov     ES:[bvs_ScrAttr],AL     ; save resulting screen attribute
sgr2:
        inc     SI                      ; (DI) = index of next parameter
        dec     cx                                                      ;J-DB02
        jz      sgrexit                                                 ;J-DB02
        jmp     sgr1                    ; handle next parameter, if any
sgrexit:                                                                ;J-DB02
        jmp     clrax                   ; goto "CLEAR AX HANDLED" exit
;
;
doDSR:                                  ; DEVICE STATUS REPORT
;
;  Set up the parameter data block and call AnsiInject routine
;
        mov     InputData.In_Action,BUILD  ; make AnsiInject ACTION = BUILD
        push    DS                      ; selector for parameter data struc
        push    OFFSET DS:InputData     ; offset for parameter data struc
        call    FAR PTR ANSIINJECT      ; build the CPR buffer
        or      AX,AX                   ; IF (AX) = 0
        jnz     dsr1
        jmp     commx                   ; THEN goto "FUNCTION HANDLED" exit
dsr1:
        jmp     dofnx                   ; ELSE goto "not handled" exit
;
;                                       ; Disable or Enable enhanced keyboard
doEKR:                                  ;   reassignment
        mov     ax,es:[bvs_ParmCount]   ; Get parameter count
        or      ax,ax                   ;
        jz      disable                 ; Parameter supplied?
        or      bl,bl                   ;
        jz      disable                 ; Disable?
        or      es:[bvs_flags],bvs_f_Ansikey     ; Set support bit
        jmp     clrax                   ;
disable:
        and     es:[bvs_flags],NOT bvs_f_Ansikey ; Clear support bit
        jmp     clrax                   ;
;
doKKR:                                  ; KEYBOARD KEY REASSIGNMENT
;
;  (BL) = first parameter (byte).  If parmCount=0, do not handle definition.
;
        mov     AX,ES:[bvs_ParmCount]   ; (AX) = length of parm buff (bytes)
        or      AX,AX                   ; IF parmCount = 0 it is INVALID
        jz      kkr2                    ; THEN do not handle key def
                                        ; ELSE continue to check parameters
;       sub     BH,BH                   ; (BL) = ASCII code
                                        ; (BH) = NULL Scan code
        or      BL,BL                   ; Normal extended ASCII?
        jz      kkr0                    ;
        test    ES:[bvs_flags],bvs_f_Ansikey ; Extended Ferrari key support?
        jz      kkr1                    ;
        cmp     BL,0E0H                 ; Extended Ferrari key?
        jnz     kkr1                    ;
        cmp     BYTE PTR ES:[SI+1],0    ;
        jz      kkr1                    ;
kkr0:
        dec     AX                      ; ELSE decrement length twice
        jz      kkr2                    ; IF parm=NULL THEN do not handle
                                        ; ELSE continue to check parameters
        inc     SI                      ; (DI) = index to next byte in buffer
        mov     BH,ES:[SI]              ; (BL) = lo byte of extended ASCII char
kkr1:
        dec     AX                      ; (AX) = adjusted length of definition
        inc     SI                      ; (DI) = offset to first char of def
        mov     InputData.In_Length,AL  ; put length in data block (byte)
        mov     InputData.In_Char,BX    ; character to redefine
        mov     InputData.In_Action,BUILD   ; requested action is BUILD
        mov     WORD PTR InputData.In_String,SI     ; offset to def string
        mov     WORD PTR InputData.In_String[2],ES  ; selector to def string
        push    DS                      ; push selector for InputData struc
        push    OFFSET DS:InputData     ; push offset for InputData struc
        call    FAR PTR ANSIKEYDEF      ; build the key definition
        or      AX,AX                   ; IF (AX) = 0
;J-DB01 jz      commx                   ; THEN goto "Function Handled" exit
        jnz     kkr2                    ; For Long JMP                  ;J-DB01
        jmp     commx                   ;                               ;J-DB01

kkr2:
;J-DB01 jmp     SHORT dofnx             ; ELSE goto "Not Handled" exit
        jmp     dofnx                   ; ELSE goto "Not Handled" exit  ;J-DB01
;
;
doSM:                                   ; SET MODE
        cmp     BX,7                    ; IF  parameter (in BX) != 7
        jne     setmode                 ; THEN jump to common setmode routine
        or      ES:[bvs_flags],bvs_f_ansiwrap   ; ELSE set line wrap on
        jmp     SHORT clrax             ;   goto "CLEAR AX HANDLED" exit
;
;
doRM:                                   ; RESET MODE
        cmp     BX,7                    ; IF parameter (in BX) != 7
        jne     setmode                 ; THEN jump to common mode set routine
        and     ES:[bvs_flags],NOT bvs_f_ansiwrap  ; ELSE set line wrap off
        jmp     SHORT clrax             ;   goto "CLEAR AX HANDLED" exit
;
;   SETMODE is the common mode set routine for doSM and doRM (also does ED)
;
setmode:
        mov     CX,BX                   ; Save Index for mode 16 exception
        cmp     BX,7                    ; Mode 0 to 6?
        jb      sm0                     ;
        cmp     BX,13                   ; Mode 13 to 19?
        jb      clrax                   ;
        cmp     BX,19                   ;
;;--------------------------------------------------------------------------
;; Handling for SetMode
;J-DB01 ja      clrax                   ;
        jbe     smsb0                   ; 13 - 19 goto smsb0            ;J-DB01
        cmp     BX,40                   ;                               ;J-DB01
        je      smdb1                   ; 40      goto smdb1            ;J-DB01
        cmp     BX,47                   ;                               ;J-DB01
        je      smdb0                   ; 47      goto smdb0            ;J-DB01
        jmp     SHORT clrax             ; else    goto exit             ;J-DB01
;                                                                       ;J-DB01
smsb0:                                  ; VGA video mode                ;J-DB01
;;--------------------------------------------------------------------------
        sub     BX,6                    ; Index to proper mode data
;;--------------------------------------------------------------------------
        jmp     sm0                     ;                               ;J-DB01
smdb0:                                  ; DBCS video mode               ;J-DB01
        sub     BX,6                    ;                               ;J-DB01
smdb1:  sub     BX,25                   ;  BX  40 -> 15 , 47 -> 16      ;J-DB01
;;--------------------------------------------------------------------------
sm0:
;       cmp     ES:[bvs_type],0         ; IF display type is MONOCHROME
;       je      clrax                   ; THEN  goto "CLEAR AX HANDLED" exit
        cmp     ES:[bvs_ParmCount],0    ; check parameter count
        jne     sm1                     ; IF parmcount = 0
        sub     BL,BL                   ; THEN set default mode 0
sm1:
        imul    BX,ANSIMODE_LEN         ; (BX) = BX * 12 (index in SysModes)
        lea     SI,ANSIGSEG:SysModes[BX]                                ;@T52
        push    ANSIGSEG                ;                               ;@T52
        push    SI                      ;
        push    DI                      ;
        call    VIOSETMODE              ;
        or      AX,AX                   ; IF VIO error
        jnz     sm2                     ; THEN check to see if mode 16
        mov     AL,'J'                  ; ELSE set AL to term char for doED
        jmp     dofn2                   ;   go to init dofn code
sm2:
        xchg    BX,CX                   ; Recall mode parameter
        cmp     BX,16                   ; Mode 16?
        jnz     commx                   ;
        sub     BX,2                    ; Use the 2nd mode 16 data (4 color)
        jmp     SHORT sm1               ;
;
;
clrax:
;  This exit point is used after successful interpret of the ANSI escape
;  sequence where a DOS or VIO call is NOT made.  Both AX and CF are cleared.
;
;       xor     AX,AX                   ; no VIO call, clear AX
;
commx:
;  After every VIO or DOS call, this exit point is used.  The Carry Flag is
;  cleared to indicate the ANSI function was "HANDLED".
;
        clc                             ; clear the carry flag
        jmp     SHORT doexit
;
dofnx:
;  This exit point is used after an UNSUCCESSFUL interpret of the escape
;  sequence.  CF is set to indicate that the function was NOT handled.
;  AX is cleared so AnsiInterp will not detect a false VIO or DOS error.
;
;       xor     AX,AX                   ; no VIO call, so clear AX
        stc                             ; set the carry flag
;
doexit:
        pop     ES                      ; restore saved registers
        pop     SI
        pop     DI
        pop     CX
        pop     BX
        pop     BP

        ret                             ; return to caller (AnsiInterp)

DoAnsiFn ENDP

ANSI1   ENDS
        END
