;       SCCSID = @(#)bksstrin.asm	6.2 91/06/17
; ****************************************************************************
; *                                                                          *
; *                       IBM/Microsoft Confidential                         *
; *                                                                          *
; *                 Copyright (c) IBM Corporation  1987, 1990                *
; *                 Copyright (c) Microsoft Corp.  1987, 1990                *
; *                           All Rights Reserved                            *
; *                                                                          *
; ****************************************************************************
        PAGE    60,132
        TITLE   BKSSTRIN.ASM - Keyboard String Input

;******************************************************************************
;*******   C H A N G E       H I S T O R Y   **********************************
;
;       87/01/05  JMP   Change OUT to OUT_ for new IBM MASM
;       87/01/13  TPL   Issue KEYDEFCHK instead of READCHAR to provide DBCS
;                       support on ANSI KEYDEFs
;       87/01/21  TPL   Validate template length prior to calling Instring
;                       to avoid GP Fault
;       87/01/26  TPL   Fix FINDOLD routine to handle F2 & F4 processing
;                       of DBCS string
;       87/03/25  TPL   Call DOSWRITE to Stdout instead of going through
;                       VIOWrTTTY in case redirection has been done to
;                       the Stdout (for cooked mode only)
;       87/04/03  TPL   Correct handling of DBCS overflow problem.
;       87/04/17  TPL   Validate IOWAIT parameter for both RAW and COOKED mode
;       87/05/01  TPL   Back out 87/03/25 fix
;       87/05/10  TPL   Allow Ctrl_T and Ctrl_U to be displayed as normal
;                       characters.  Also update WORDDEL function to handle
;                       them as normal characters.
;       88/03/18  TPL   Fix extended TA character problem.  "D" should not be
;                       treated as F10 when F10 is defined as the TA char.
;P2847  88/06/01  THG   Call Win API with logical handle -or- Win_Handle
;P3088  88/07/08  TPL   Handle Tab and Backspace over Ctrl_T, Ctrl_U char.
;CP12 4843 9-22-89 THG  Don't backup in template on BackSpace in working area.
;@T52   90/01/15  TPL   DCR 704 work
;B723426 06/17/91 GDW   Binary mode no/wait does not return the buffer contents
;******************************************************************************

        .286p                           ; 286 Protect Mode instructions

        .xlist
        INCLUDE error2.inc              ; Extended error code file
        INCLUDE struc.inc               ; Structured Macros
        INCLUDE bksxxx.inc              ; Equates and structure template file
        INCLUDE bksextrn.inc            ; External data declaration file
        INCLUDE pmwinp.inc
        INCLUDE pmaviop.inc
        .list

CSEG    SEGMENT BYTE PUBLIC 'CODE'
CSEG    ENDS

IDSEG   SEGMENT BYTE PUBLIC 'DATA'      ; Per process data segment
IDSEG   ENDS

GDSEG   SEGMENT BYTE PUBLIC 'FAR_DATA'  ; Global data segment           ;@T52
GDSEG   ENDS

        EXTRN   ANSIINJECT:FAR          ; Get Cursor Position Report (CPR)
        EXTRN   DOSBEEP:FAR             ; Generate Sound from Speaker
        EXTRN   DOSDEVIOCTL:FAR         ; DOS Generic IOCTL
        EXTRN   VIOGETCURPOS:FAR        ; Get Cursor Position
        EXTRN   VIOWRTTTY:FAR           ; RAM BIOS Write TTY
;       EXTRN   DOSWRITE:FAR            ; Echo character input to Stdout
        EXTRN   VIOGETANSI:FAR          ; Get ANSI (ON/OFF) State
        EXTRN   KBDGETSTATUS:FAR        ; Get keyboard status

        EXTRN   ChkDBCS:NEAR            ; Check for DBCS character
        EXTRN   KeyDefChk:NEAR          ; Check for KeyDef character
        EXTRN   RawFilBuf:NEAR          ; Raw mode buffer fill
        EXTRN   GetKeyDef:NEAR          ; Get character from KeyDef string
        EXTRN   GetDBCS_String:NEAR     ; Get DBCS environment vector
        EXTRN   WINSYNCWITHPS:DWORD     ;@@DTF adjust window origin CDB2
        EXTRN   LOCKVIOPS:DWORD         ;@@DTF PS Semaphore Lock CDB2
        EXTRN   UNLOCKVIOPS:DWORD       ;@@DTF PS Semaphore Unlock CDB2

        PUBLIC  GetStringIn
        PUBLIC  InString

CSEG    SEGMENT BYTE    PUBLIC  'CODE'
        ASSUME  CS:CSEG,DS:NOTHING,ES:NOTHING
        PAGE

;************************ START OF SPECIFICATIONS ***********************
;*                                                                      *
;*  SUBROUTINE NAME:    GetStringIn                                     *
;*                                                                      *
;*  DESCRIPTIVE NAME:   Read a String of Characters from the Keyboard   *
;*                      Input Buffer.                                   *
;*                                                                      *
;*  FUNCTION:   Provides a character string read function by issuing    *
;*              multiple calls to KBDCHARIN until the number of char.   *
;*              requested has been satisfied.                           *
;*                                                                      *
;*              For RAW/BINARY mode:                                    *
;*                    - with NOWAIT option, this function terminates    *
;*                      when either no character is available or the    *
;*                      user supplied buffer is filled.                 *
;*                    - with WAIT option, this function terminates      *
;*                      when the user supplied buffer is filled.        *
;*                                                                      *
;*              For COOKED/ASCII mode:                                  *
;*                      this function termainates when the TurnAround   *
;*                      key is struck.  The default TurnAournd key      *
;*                      In addition, if echo mode is ON, each char.     *
;*                      typed will be display via the VIOWRTTTY call.   *
;*                      Support for ANSI Cursor Position Report (CPR)   *
;*                      and ASNI Key Redefinition function are also     *
;*                      supported here.                                 *
;*                                                                      *
;*                      Note:   The Length parameter specifies the      *
;*                              the size of the user buffer.            *
;*                                                                      *
;*  NOTES:      Executes on level 3 - Protect Mode ONLY                 *
;*                                                                      *
;*  ENTRY POINT:        GetStrinIn                                      *
;*      LINKAGE:        call near                                       *
;*                                                                      *
;*  INPUT:      Input parameters are on stack                           *
;*                                                                      *
;*                      KBD_Handle      word                            *
;*                      IoWait          word                            *
;*                      CharLengthO     @ of buffer length              *
;*                      CharBufferO     @ of string buffer              *
;*                                                                      *
;*  EXIT NORMAL:        AX = 0                                          *
;*                                                                      *
;*  EXIT ERROR:         AX = ERROR_KBD_INVALID_IOWAIT                   *
;*                           ERROR_KBD_INVALID_LENGTH                   *
;*                           ERROR_BAD_COMMAND                          *
;*                                                                      *
;*  INTERNAL REFERENCES:  Char_Code, Dev_Handle, Echo_Mode, TA_Char     *
;*                        TA_Type                                       *
;*           ROUTINES:    GetDBCS_String   - Get DBCS range             *
;*                                                                      *
;*  EXTERNAL REFERENCES:  none                                          *
;*           ROUTINES:    DOSDEVIOCTL, KBDSETFGND                       *
;*                        INSIINJECT:FAR   - Get CPR                    *
;*                        DOSBEEP:FAR      - Generate BEEP              *
;*                        DOSDEVIOCTL:FAR  - DOS Generic IOCTL          *
;*                        VIOGETCURPOS:FAR - Get Cursor Position        *
;*                        VIOWRTTTY:FAR    - RAM BIOS Write TTY         *
;*                        VIOGETANSI:FAR   - Get ANSI (ON/OFF) State    *
;*                        KBDGETSTATUS:FAR - Get keyboard status        *
;*                                                                      *
;************************* END OF SPECIFICATIONS ************************
        PAGE



ESCFUNC   dw    OFFSET  CSEG:GETCH      ; End of Table
          dw    OFFSET  CSEG:SKIPONE    ; Del - Skip one character
          dw    OFFSET  CSEG:ENTERINS   ; Ins - Insert mode toggle
          dw    OFFSET  CSEG:COPYONE    ; ->  - Copy one character
          dw    OFFSET  CSEG:BACKSP     ; <-  - Backspace
          dw    OFFSET  CSEG:TWOESC     ; F7  - Escape character
          dw    OFFSET  CSEG:CTRLZ      ; F6  - Ctrl_Z
          dw    OFFSET  CSEG:REEDIT     ; F5  - Re-edit line (new template)
          dw    OFFSET  CSEG:SKIPSTR    ; F4  - Skip to character
          dw    OFFSET  CSEG:COPYLIN    ; F3  - Copy line
          dw    OFFSET  CSEG:COPYSTR    ; F2  - Copy to character
          dw    OFFSET  CSEG:COPYONE    ; F1  - Copy one character
          dw    OFFSET  CSEG:GETCH      ; Control Break

EDITFUNC  dw    OFFSET  CSEG:SAVCH
          dw    OFFSET  CSEG:CTRLZ
          dw    OFFSET  CSEG:KILNEW
          dw    OFFSET  CSEG:PHYCRLF    ; Ctrl_ENTER
;         dw    OFFSET  CSEG:LineDel    ; Ctrl_U
          dw    OFFSET  CSEG:WordDel    ; Ctrl_W
          dw    OFFSET  CSEG:BACKSP
          dw    OFFSET  CSEG:BACKSP
          dw    OFFSET  CSEG:GETCH

GetStringIn PROC  NEAR
        ASSUME  DS:IDSEG,ES:NOTHING
;
;************************************************************************
;*  On entry:  DS = IDSEG   AX = 0                                      *
;************************************************************************
;
       .IF <[bp].IoWait BE NOWAIT>      ; Within validate parameter range?
         les    di,[bp].CharLengthO     ; Establish addressability to input
                                        ;   buffer length parameter from stack
         mov    dx,es:[di]              ; Get input buffer length
         or     dh,dh                   ; DL = WorkBuf length
                                        ; DH = WorkBuf byte count
        .IF Z                           ; Within valid buffer range?
          call  GetDBCS_String          ; Get DBCS range
          or    ax,ax
         .IF Z
           mov  bx,es:[di+2]            ; BL = Template length
                                        ; BH = Template byte count
          .IF <dx B bx>                 ; Template is inconsistent with
            mov bx,dx                   ;   buffer length?
          .ENDIF
           push bp
           call Instring                ; Get string input
           pop  bp
           les  di,[bp].CharLengthO
           mov  cl,dh                   ; Get character count
           mov  es:WORD PTR[di+2],cx    ; Return character count to caller
         .ENDIF
        .ELSE
          mov   ax,ERROR_KBD_INVALID_LENGTH
        .ENDIF
       .ELSE
         mov    ax,ERROR_KBD_INVALID_IOWAIT
       .ENDIF
        ret

GetStringIn ENDP
        PAGE



InString PROC   NEAR
        ASSUME  DS:IDSEG

        sub     cx,cx                   ; CH = 0 (always)
        ;
        ;****************************************************************
        ;*  Issue a KbdGetStatus to find out the current input mode     *
        ;*  state.                                                      *
        ;****************************************************************
        ;
        mov     si,OFFSET WorkBuf       ; Set up the destination address
        mov     [si].S_LENGTH,10        ; Set up length of status buffer
        push    ds
        push    si
        push    [bp].KBD_Handle         ; caller's KBD handle           ;p2847
        call    KBDGETSTATUS            ; Get status
        or      ax,ax                   ; Encountered error?
       .IF Z    NEAR
         les    di,[bp].CharBufferO     ; Establish addressibility to
                                        ;   caller's input buffer
         cld
         test   [si].S_MASK,COOKED_ON
        .IF Z                           ; Raw mode ON?
         .IF <dl A ch>                  ; Non-zero buffer length for RAW mode?
           ;
           ;*************************************************************
           ;*  RAW Mode Processing                                      *
           ;*************************************************************
           ;
          .IF <[bp].IoWait EQ NOWAIT>   ; No wait option?
            ;
            ;***********************************************************
            ;*  No Wait Option - RAW Mode                              *
            ;***********************************************************
            ;
;           loop exits on: error condition - buffer is empty
           .WHILE <dh B dl> AND         ; Stop: Keyboard queue is       ;B723426
             call RAWFILBUF             ;       empty, user input buffer;B723426
             or   ax,ax                 ;       is full or encountered  ;B723426
           .WHILE Z        AND          ;       read error.             ;B723426
             test  Transfer_Count,1                                     ;B723426
           .WHILE NZ                    ; Place character into buffer   ;B723426
           .ENDWHILE
          .ELSE
            ;
            ;***********************************************************
            ;*  Wait Option - RAW Mode                                 *
            ;***********************************************************
            ;
            mov   cl,NORMAL             ; Intialize sentinel indicator
           .WHILE <dh B dl> AND         ; Stop when: Input buffer is
            or    cl,cl                 ;            full or the input
           .WHILE Z         AND         ;            buffer can not
            or    ax,ax                 ;            accomodate extended
           .WHILE Z                     ;            ASCII character
             call RAWFILBUF             ; Place character into buffer
           .ENDWHILE
          .ENDIF
         .ENDIF
        .ELSE      NEAR
          ;
          ;**************************************************************
          ;*  Cooked mode processing:                                   *
          ;*                                                            *
          ;*  Check to see if ANSI is ON.  If so, look to see if CPR    *
          ;*  is available.  If CPR is available then return CPR.       *
          ;**************************************************************
          ;
          push  ds                      ; Setup ANSI ON/OFF parameter
          push  OFFSET ANSI_State
          push  cx                      ; VIOHANDLE (reserved to 0000H)
          call  VIOGETANSI              ; Get ANSI state
         .IF <ANSI_State EQ ON>         ; ON?
           mov  CPR_BufO,di             ; Pass user buffer address to ANSI,
           mov  CPR_BufS,es             ;   in case CPR is available
           mov  CPR_Length,dl           ; Pass buffer length
           mov  CPR_Action,READ         ; Read operation
           push ds                      ; Setup address to parameter block
           push OFFSET CPR_BufO
           call ANSIINJECT
           mov  dh,CPR_Length
         .ENDIF
          or    dh,dh
         .IF Z  NEAR                    ; CPR not available?
          .IF <dl A TA_Type> NEAR       ; Make sure there is enough room to
                                        ;   at least hold the TA character
            mov   cl,TA_Char            ; Get TurnAround character
           .IF <TA_Type EQ ch>          ; Check TurnAround character type
             mov  al,es:[bx+di]         ; Get normal TA char from template
           .ELSE
             mov  ax,es:[bx+di]         ; Get extended TA char from template
             xchg al,ah
             dec  dl                    ; Make room for extended TA character
           .ENDIF
            dec   dl                    ; Make room for normal TA character
           .IF <ax NE cx>               ; TA character is incorrectly placed
                                        ;   in template ?
             sub  bl,bl                 ; Reset template byte count
           .ENDIF
            sub   cx,cx
            push  ds                    ; Query for initial hardware cursor
            push  OFFSET Char_Code      ;   position
            push  ds
            push  OFFSET StartPos       ; It is being used to note the
                                        ;   starting column position when
                                        ;   echo mode is ON
            push  cx                    ; Dummy device handle
            call  VIOGETCURPOS

            mov   al,StartPos
            mov   CurrentPos,al         ; Intialize starting cursor position

PUBLIC  NEWLIN
NEWLIN:     push  di                    ; Save offset to template
            mov   si,OFFSET WorkBuf     ; Start of internal work buffer
            mov   Insert_Mode,REPLACE   ; Default "replace" mode
            sub   bh,bh                 ; Initialize templete byte count
            mov   dh,bh                 ; Initialize input buffer byte count
            call  KEYDEFCHK             ; Get a character
            or    ax,ax
           .IF Z  NEAR                  ; No read error
             ;
             ;***********************************************************
             ;*  Register usage:                                        *
             ;*                                                         *
             ;*  BH - has the template byte count                       *
             ;*  BL - has the template length                           *
             ;*  DH - has the input buffer byte count                   *
             ;*  DL - has the input buffer length                       *
             ;*                                                         *
             ;*  ES:DI address of template buffer (caller's buffer)     *
             ;*  DS:SI address of input buffer (WorkBuf)                *
             ;***********************************************************
             ;
            .IF <Char_Code EQ LF>       ; Line Feed? (Ctrl_J, Ctrl_CR, etc.)
                                        ; Filter out LF so < works
PUBLIC  GETCH
GETCH:        call KEYDEFCHK            ; Get a character
            .ENDIF
             or    ax,ax                ; Error on read?
            .IF Z  NEAR
              mov   al,Char_Code        ; Get character just read
              ;
              ;*********************************************************
              ;*  Check function keys 1st:  F1, F2, F3, F4, F5, F6,    *
              ;*                            F7, F8, Ins, Del           *
              ;*********************************************************
              ;
              or   al,al                ;                               @@#5
             .IF Z                      ; Extended ASCII input found?   @@#5
               mov  al,Scan_Code        ; Get extended ASCII code       @@#5
              .IF <al EQ TA_Char>       ; Extended TA character found?  @@#5
                mov  Sentinel,al        ;                               @@#5
                jmp  ENDLIN             ;                               @@#5
              .ENDIF                    ;                               @@#5
               push cx                  ; Save all necessary registers  @@#5
               push di                  ;   for scan                    @@#5
               mov  cx,ESCTABLEN        ; Setup scan table length       @@#5
               mov  di,OFFSET ESCTAB    ;   and offset                  @@#5
               mov  bp,OFFSET ESCFUNC   ; Setup index to handling routine @@#5
             .ELSE                      ; Normal TA character defined!! @@#5
              ;
              ;*********************************************************
              ;*  Check edit keys next:  BackSpace, ->, <-, etc.       *
              ;*********************************************************
              ;
              .IF <al EQ TA_Char> AND   ; Normal TA character found?    @@#5
              .IF <TA_Type E ch>        ; No extended TA char. defined? @@#5
                mov  Sentinel,al        ; Save TA character             @@#5
                jmp  ENDLIN             ;                               @@#5
              .ENDIF                    ;                               @@#5
               push cx                  ; Save all necessary registers  @@#5
               push di                  ;   for scan                    @@#5
               mov  cx,EDITTABLEN       ; Setup scan table length and   @@#5
               mov  di,OFFSET EDITTAB   ;   offset for noraml edit keys @@#5
               mov  bp,OFFSET EDITFUNC  ; Setup index to handling routine @@#5
             .ENDIF                     ;                               @@#5
              mov   Sentinel,ah         ; Reset end of function indicator @@#5
              push  es                  ; Save template buffer selector
              push  GDSEG               ; Set ES to point to GDSEG
              pop   es
              repne scasb               ; Look for a match on edit keys
              pop   es                  ; Restore template buffer selector
              pop   di
              shl   cx,1                ; Word align index
              add   bp,cx               ; Calculate offset to handler routine
              pop   cx
              jmp   cs:[bp]             ; Dispatch control to appropriate
                                        ;   edit function
PUBLIC  SAVCH
SAVCH:        call  SAVECHAR            ; Put it in input buffer
              jmp   SHORT GETCH         ; Process next character

PUBLIC  SAVECHAR
SAVECHAR:    .IF <dh B dl>              ; Input buffer full?

;********** DBCS Enabling **************
;********** DBCS Enabling  DBCS double byte character is 2 bytes
;********** DBCS Enabling  long, but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling  PAY ATTENTION TO BUFFER FULL.
;********** DBCS Enabling **************;
               call  CHKDBCS            ; Check for DBCS lead byte
              .IF C                     ; DBCS lead byte found?
                inc  dh                 ; Update input buffer byte count
               .IF <dh EQ dl>           ; Input buffer full?
                 dec  dh                ; Adjust input buffer byte count
                 call KEYDEFCHK         ; Discard 2nd DBCS byte
                 jmp  SAVC3             ; Ignore DBCS lead byte
               .ENDIF                   ;
                mov   BYTE PTR [si],al  ; Put DBCS lead byte into buffer
                inc   si                ; Update input buffer offset
                call  BUFOUT            ; Echo DBCS lead byte to screen
                call  KEYDEFCHK         ; Get the 2nd DBCS byte
                mov   al,Char_Code      ; Place it in AL
              .ENDIF                    ;
;********** DBCS Enabling **************;

               mov   BYTE PTR [si],al   ; Put char read into input buffer
               inc   si                 ; Update input buffer offset
               inc   dh                 ; Increment input buffer byte count
               call  BUFOUT             ; Echo character to screen
              .IF <bh B bl> AND         ; Not end of template and
              .IF <Insert_Mode EQ ch>   ; Replace Mode in effect?

;********** DBCS Enabling **************;
;********** DBCS Enabling **************;
;********** DBCS Enabling **************;
                mov   al,es:[di]        ; Get character from template
                call  CHKDBCS           ; Check for DBCS lead byte
               .IF C                    ; DBCS lead byte found?
                 inc  di                ; Skip over DBCS lead byte
                 inc  bh                ;
               .ENDIF                   ;
;********** DBCS Enabling **************;

               .IF <bh B bl>            ; Check again to make sure
                                        ;   overflow doesn't occur
                 inc  di                ; Update template buffer offset
                 inc  bh                ; Update template byte count
               .ENDIF
              .ENDIF
               ret
             .ENDIF

SAVC3:        push  440                 ; Frequency in Hertz
              push  5                   ; Duration in milliseconds
              call  DOSBEEP             ; Bell to signal full buffer
              push  587                 ; Frequency in Hertz
              push  5                   ; Duration in milliseconds
              call  DOSBEEP             ; Bell to signal full buffer
              ret

PUBLIC  ENDLIN
ENDLIN:       test  TA_Type,ON
             .IF Z                      ; Normal TA character found?
               mov  BYTE PTR [si],al    ; Put normal TA char into input buffer
             .ELSE
               xchg al,ah               ; Convert to Extended TA char format
               mov  WORD PTR [si],ax    ; Put extended TA char into buffer
               xchg al,ah               ; Restore TA char
               inc  dh                  ; Update input buffer type count
             .ENDIF
              push  ax                  ; Save current character
              mov   al,CR               ; Generate a carriage return
              call  OUT_                ; Echo it, if necessary
              pop   ax                  ; Recover character read
              pop   di                  ; Recover template buffer offset
              inc   dh                  ; Update input buffer byte count

PUBLIC  COPYNEW
COPYNEW:      mov   si,OFFSET WorkBuf
              mov   cl,dh               ; Get input buffer byte count
              jcxz  SKIPREP             ; Skip on byte count 0
              rep   movsb               ; Copy final line to template buffer

PUBLIC  SKIPREP
SKIPREP:     .IF <Sentinel EQ al>       ; End of function?
               dec  dh                  ; Adjust input buffer byte count
               sub  dh,TA_Type
               sub  ax,ax               ; Return with normal return code
             .ENDIF
              ret
              ;
              ;*********************************************************
              ;*  Output CRLF to the screen and DO NOT place them      *
              ;*  into the input buffer.                               *
              ;*********************************************************
              ;
PUBLIC  PHYCRLF
PHYCRLF:      call  CRLF                ; Output CRLF as necessary
              jmp   GETCH               ; Wait for the next character
              ;
              ;*********************************************************
              ;*  Delete the current input string                      *
              ;*********************************************************
              ;
;LINEDEL:      or    dh,dh
;            .WHILE NZ                  ; Loop until WorkBuf is empty
;              call BACKSPACE           ; Backup one character at a time
;              or   dh,dh
;            .ENDWHILE
;             jmp   GETCH
              ;
              ;*********************************************************
              ;*  Delete a word from input string                      *
              ;*********************************************************
              ;
PUBLIC  WORDDEL
WORDDEL:      call  BACKSPACE           ; Backup one character
              or    dh,dh               ;
             .IF NZ                     ; Input buffer NOT empty?

;********** DBCS Enabling **************;
;********** DBCS Enabling  A DBCS double byte character is 2 bytes
;********** DBCS Enabling  long, but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling **************;
;             .IF <dh AE 2>             ; At least 2 bytes in input buffer
;               mov  al,ds:[si-2]       ; Get char from input buffer
;               call CHKDBCS            ; DBCS lead byte?
;               jc   WORDDEL            ; Delete it
;             .ENDIF                    ;
;********** DBCS Enabling **************;

               mov    al,ds:[si-1]      ; Get the previous character read
              .IF <al E <"T"-"@">> OR   ; Ctrl_T?
              .IF <al E <"U"-"@">> OR   ; Ctrl_U?
              .IF <al AE '0'>      AND  ; Skip til non-blank found
              .IF <al BE '9'>      OR   ;
               or   al,BLANK            ;
              .IF <al AE 'a'>      AND  ;
              .IF <al BE 'z'>           ;
                jmp   SHORT WORDDEL     ;
              .ENDIF                    ;
             .ENDIF                     ;
              jmp     GETCH             ;
              ;
              ;*********************************************************
              ;*  Discard the entire input string, start again with    *
              ;*  the last template.  Print a backslash and then go    *
              ;*  to the next line and tab to the correct spot to      *
              ;*  begin the buffered input.                            *
              ;*********************************************************
              ;
PUBLIC  KILNEW
KILNEW:       mov   al,"\"              ;
              call  OUT_                ; Print the CANCEL indicator
              pop   di                  ; Recover start template offset

PUBLIC  PUTNEW
PUTNEW:       call  CRLF                ; Go to next line on screen
              mov   al,StartPos         ; Get starting cursor position
              call  TAB                 ; Tab over
              jmp   NEWLIN              ; Start over again
              ;
              ;*********************************************************
              ;*  Put a ^Z into input buffer                           *
              ;*********************************************************
              ;
PUBLIC  CTRLZ
CTRLZ:        mov   al,"Z"-"@"          ;
              call  SAVECHAR            ;
              jmp   GETCH               ;
              ;
              ;*********************************************************
              ;*  Destructively back up one character position         *
              ;*********************************************************
              ;
PUBLIC  BACKSP
BACKSP:       call  BACKSPACE
              jmp   GETCH

PUBLIC  BACKSPACE
BACKSPACE:    or    dh,dh
             .IF NZ                     ; Input buffer NOT empty?
               call   BACKUP            ; Delete one char from input buffer
               mov    al,[si]           ; Get the deleted char
              .IF <al B BLANK>          ; Ctrl character?
               .IF <al E TABCHAR>       ; TAB?
                 call BAKTAB            ; TAB char found, backup from there
               .ELSE                    ; Ctrl character found
                .IF <al NE <"T"-"@">> AND; Ctrl_T?
                .IF <al NE <"U"-"@">>   ; Ctrl_U?
                  call BACKMES          ; Zap the '^'from screen
                .ENDIF
               .ENDIF
              .ENDIF

;********** DBCS Enabling **************;
;********** DBCS Enabling  A DBCS double byte character is 2 bytes
;********** DBCS Enabling  long, but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling **************;
               or       dh,dh           ;
              .IF NZ                    ; Input buffer NOT empty?
                push    dx              ;
                push    bx              ;
                mov     bx,-1           ;
                mov     dl,ZERO         ; # of DBCS character found
                mov     al,ds:[si+bx]   ; Get previous char from input
                call    CHKDBCS         ; Check for DBCS lead byte
               .WHILE C AND             ;
                 inc    dl              ; Update DBCS character count
                 dec    dh              ;
               .WHILE NZ                ;
                 dec    bx              ;
                 mov    al,ds:[si+bx]   ;
                 call   CHKDBCS         ;
               .ENDWHILE                ;
                ror     dl,1            ;
                pop     bx              ;
                pop     dx              ;
               .IF C                    ;
                 call   BACKUP          ;
               .ENDIF                   ;
              .ENDIF                    ;
;********** DBCS Enabling **************;
             .ENDIF

PUBLIC  OLDBAK
OLDBAK:      .if <dh b bh> AND                                     ;CP12 4843
              or     bh,bh
             .IF NZ  AND                ; NOT at the start of template and
             .IF <Insert_Mode EQ ch>    ;   replace mode is in effect?
               dec   di                 ; Backup one character position
               dec   bh                 ;   in template buffer

;********** DBCS Enabling **************;
;********** DBCS Enabling  A DBCS double byte character is 2 bytes long
;********** DBCS Enabling  , but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling **************;
              .IF NZ                    ; NOT at the start of template
                push    dx              ;
                push    bx              ;
                mov     dx,bx           ;
                mov     dl,ZERO         ;
                mov     bx,-1           ;
                mov     al,es:[di+bx]   ; Get previous char from template
                call    CHKDBCS         ; Check for DBCS lead byte
               .WHILE C AND             ;
                 inc    dl              ;
                 dec    dh              ;
               .WHILE NZ                ;
                 dec    bx              ;
                 mov    al,es:[di+bx]   ;
                 call   CHKDBCS         ;
               .ENDWHILE                ;
                ror     dl,1            ;
                pop     bx              ;
                pop     dx              ;
               .IF C                    ;
                 dec    bh              ;
                 dec    di              ;
               .ENDIF                   ;
              .ENDIF                    ;
;********** DBCS Enabling **************;
             .ENDIF
              ret

PUBLIC  BAKTAB
BAKTAB:       push  es                  ; Save template buffer selector
              push  ds                  ; ES = input buffer selector
              pop   es
              push  si                  ; Save input buffer offset
              dec   si                  ; Back up one char in input buffer
              xchg  si,di               ; DI = input buffer offset,
                                        ; SI = template buffer offset
              std                       ; Scan backward
              mov   cl,dh               ; Get current input byte count
              mov   al,BLANK
              push  bx                  ;
              mov   bl,7                ; Max
              jcxz  FIGTAB              ; At start, do nothing

PUBLIC  FNDPOS
FNDPOS:       scasb                     ; Look back
             .IF A
               cmp  BYTE PTR [di+1],TABCHAR
               jz   HAVTAB              ; Found a tab!
              .IF <<BYTE PTR [di+1]> NE <"T"-"@">> AND  ; Ctrl_T?      P3088
              .IF <<BYTE PTR [di+1]> NE <"U"-"@">>      ; Ctrl_U?      P3088
                dec  bl                 ; Back one char in template buffer
              .ENDIF                    ;   if non tab character       P3088
             .ENDIF                     ;
              loop  FNDPOS

PUBLIC  FIGTAB
FIGTAB:       sub   bl,StartPos         ; Get starting cursor position

PUBLIC  HAVTAB
HAVTAB:       sub   bl,dh
              add   cl,bl
              and   cl,7                ; CX has correct number to erase
              cld                       ; Back to normal
              pop   bx
              xchg  si,di               ; Swap them back
              pop   si
              pop   es
              jz    OLDBAK              ; Nothing to erase

PUBLIC  TABBAK
TABBAK:       call  BACKMES
              loop  TABBAK              ; Erase correct number of chars
              jmp   OLDBAK

PUBLIC  BACKUP
BACKUP:       dec   dh                  ; Back up one character
              dec   si                  ;   position in input buffer

PUBLIC  BACKMES
BACKMES:      mov   al,BKSPACE          ; Backspace
              call  OUT_
              mov   al,BLANK            ; Erase
              call  OUT_
              mov   al,BKSPACE          ; Backspace
              jmp   OUT_                ; Done
              ;
              ;*********************************************************
              ;*  Put an ESC character into the input buffer           *
              ;*********************************************************
              ;
PUBLIC  TWOESC
TWOESC:       mov   al,EXTENDED
              jmp   SAVCH
              ;
              ;*********************************************************
              ;*  Copy the rest of the template                        *
              ;*********************************************************
              ;
PUBLIC  COPYLIN
COPYLIN:      mov   cl,bl               ; Total size of template
              sub   cl,bh               ; Minus position in template,
              jmp   SHORT COPYEACH      ;   is number to move
              ;
              ;*********************************************************
              ;*  Copy template up to a specific character             *
              ;*********************************************************
              ;
PUBLIC  COPYSTR
COPYSTR:      call  FINDOLD             ; Find the char
              or    cl,cl               ; Copy up to it
              jnz   COPYEACH
              jmp   GETCH
              ;
              ;*********************************************************
              ;*  Copy one char from template to line                  *
              ;*********************************************************
              ;
PUBLIC  COPYONE
COPYONE:      mov   cl,1

;********** DBCS Enabling **************;
;********** DBCS Enabling  A DBCS double byte character is 2 bytes
;********** DBCS Enabling  long, but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling **************;
              mov   al,es:[di]          ; Get character from template
              call  CHKDBCS             ; Check for DBCS lead byte
             .IF C                      ; DBCS lead byte?
               inc  cl                  ; Copy 2 bytes instead of 1
             .ENDIF                     ;
;********** DBCS Enabling **************;
              ;
              ;*********************************************************
              ;*  Copy CX number of characters from template to        *
              ;*  input buffer                                         *
              ;*********************************************************
              ;
PUBLIC  COPYEACH
COPYEACH:     mov   Insert_Mode,REPLACE ; All copies turn off insert mode

;********** DBCS Enabling **************;
;********** DBCS Enabling If this one character is DBCS double byte
;********** DBCS Enabling character, CHECK input buffer FULL/NOT FULL
;********** DBCS Enabling for this DBCS double byte character.
;********** DBCS Enabling **************;
              mov   al,es:[di]          ; Get character from template
              call  CHKDBCS             ; Check for DBCS lead byte
             .IF C                      ; DBCS lead byte?
               push dx                  ;
               dec  dl                  ; Make sure there is enough space in
               cmp  dh,dl               ;   in the input buffer to accommodate
               pop  dx                  ;   DBCS double byte character
              .IF Z                     ; End of input buffer reached?
                jmp GETCH               ; Ignore DBCS lead byte
              .ENDIF                    ;
             .ENDIF                     ;
;********** DBCS Enabling **************;
             .IF <dh B dl> AND          ; At end of input buffer?
             .IF <bh B bl>              ; At end of template buffer?
               mov  al,es:[di]          ; Get char from template buffer
               inc  di                  ; Advance char position in template
               mov  BYTE PTR [si],al    ; Put character into input buffer
               inc  si                  ; Advance char position in input buffer
               call BUFOUT              ; Echo to the screen
               inc  bh                  ; Update template buffer byte count
               inc  dh                  ; Update input buffer byte count
               loop COPYEACH
             .ENDIF
              jmp   GETCH
              ;
              ;*********************************************************
              ;*  Skip one char in template                            *
              ;*********************************************************
              ;
PUBLIC  SKIPONE
SKIPONE:     .IF <bh B bl>              ; End of template buffer?

;********** DBCS Enabling **************;
;********** DBCS Enabling  A DBCS double byte character is 2 bytes
;********** DBCS Enabling  long, but treated as ONE (NOT SEPARATED)
;********** DBCS Enabling  character.
;********** DBCS Enabling **************;
               mov  al,es:[di]          ; Get character from template
               call CHKDBCS             ; Check for DBCS lead byte
              .IF C                     ; DBCS lead byte?
                inc bh                  ; Skip pass DBCS lead byte
                inc di                  ;
              .ENDIF                    ;
;********** DBCS Enabling **************;

               inc  bh                  ; Update template byte count
               inc  di                  ; Update template offset
             .ENDIF
              jmp   GETCH
              ;
              ;*********************************************************
              ;*  Skip characters in template up to a specific         *
              ;*  character                                            *
              ;*********************************************************
              ;
PUBLIC  SKIPSTR
SKIPSTR:      call  FINDOLD             ; Find out how far to go
              add   di,cx               ; Go there
              add   bh,cl
              jmp   GETCH
              ;
              ;*********************************************************
              ;*  Get the next user char, and look ahead in template   *
              ;*  for a match, CX indicates how many chars to skip     *
              ;*  to get there on output                               *
              ;*  NOTE: WARNING: If the operation cannot be done,      *
              ;*        the return address is popped off and a jump    *
              ;*        to GETCH is taken.  Make sure nothing extra    *
              ;*        on stack when this routine is called!!!        *
              ;*        (no PUSHes before calling it).                 *
              ;*********************************************************
              ;
PUBLIC  FINDOLD
FINDOLD:      call  KEYDEFCHK           ; Read char from keyboard/keydef
              or    ax,ax
             .IF Z  NEAR                ; No error encountered?
               mov  al,Char_Code        ; Get character read
               mov  cl,bl               ; Get template length
;********** DBCS Enabling **************;
;********** DBCS Enabling  If the searched character is DBCS double
;********** DBCS Enabling  byte character, then do the DBCS processing.
;********** DBCS Enabling
;********** DBCS Enabling  - SEARCH every 2 byte in TEMPLATE buffer.
;********** DBCS Enabling **************;
               call  CHKDBCS            ; Check AL for DBCS lead character
              .IF C                     ; DBCS lead character found?
                push ax                 ; Save current character
                call KEYDEFCHK          ; Get the 2nd DBCS byte
                pop  ax                 ; Restore 1st character read
                mov  ah,Char_Code       ; AH = 2nd DBCS byte
                sub  cl,bh              ; CL = byte count to End of Template
               .IF NZ                   ; Not End of Template yet?
                 dec cl                 ; Make sure there is room for 2 bytes
                .IF NZ                  ; Enough room for DBCS?
                  push bx               ; Save Template counts
                  push di               ; Save Template offset
                  mov  bx,ax            ; BX = matching target
                  mov  al,es:[di]       ; Get a byte from Template
                  call SKIP1OR2         ; Skip pass 1st character or DBCS char
                 .WHILE NZ      AND     ; Loop until End of Template or
                  mov  ax,es:[di]       ;   match found
                 .WHILE <ax NE bx>
                   call SKIP1OR2        ; Advance Template count appropriately
                 .ENDWHILE
                  pop   di              ; Restore Template offset
                  cmp   ax,bx           ; Set Z flag
                  pop   bx              ; Restore Template counts
                 .IF Z                  ; Match found?
                   not cl               ; Convert how far to go into how
                   add cl,bl            ;   far we went
                   sub cl,bh            ;
                   ret
                 .ENDIF
                .ENDIF
               .ENDIF
              .ELSE
                or   al,al
               .IF NZ                   ; Normal character found (non-extended)
                 push bx                ; Save Template counts
                 push di                ; Save Template offset
                 mov  bl,al             ; BL = matching target
                 sub  cl,bh             ; CL = byte count to End of Template
                .IF NZ
                  mov  al,es:[di]       ; Get a byte from Template
                  call SKIP1OR2         ; Skip pass 1st character or DBCS char
                .ENDIF
                .WHILE NZ       AND     ; Loop until End of Template or
                 mov  al,es:[di]        ;   a match is found
                .WHILE <al NE bl>
                  call SKIP1OR2         ; Advance Template count appropriately
                .ENDWHILE
                 pop  di                ; Restore Template offset
                 pop  bx                ; Restore Template counts
                 or   cl,cl
                .IF NZ                  ; Character found?
                  dec cl                ; Adjust End of Template byte count
                  not cl                ; Convert how far to go into how
                  add cl,bl             ;   far we went
                  sub cl,bh             ;
                  ret
                .ENDIF
               .ENDIF
              .ENDIF
               pop   bp                 ; Discard return address
               jmp   GETCH
PUBLIC  SKIP1OR2
SKIP1OR2:
               call  CHKDBCS            ; Check AL for DBCS lead byte
              .IF C                     ; If so, then skip two bytes
                inc  di                 ; Update Template offset
                dec  cl                 ; Update End of Template count
              .ENDIF
               or    cl,cl
              .IF NZ                    ; Not End of Template yet?
                inc  di                 ; Update Template offset
                dec  cl                 ; Update End of Template count
              .ENDIF
               ret
               ;
               ;********************************************************
               ;*  Kill line, start again with new template            *
               ;********************************************************
               ;
PUBLIC  REEDIT
REEDIT:        mov   al,"@"             ; Output re-edit character
               call  OUT_
               mov   al,"@"             ; Output re-edit character
               pop   di                 ; Recall template pointer
               push  di
               call  COPYNEW            ; Copy current line into template
               pop   di
               mov   bl,dh              ; Size of line is new size template
               jmp   PUTNEW             ; Start over again
               ;
               ;********************************************************
               ;*  Exit or enter insert mode                           *
               ;********************************************************
               ;
PUBLIC  EXITINS
PUBLIC  ENTERINS
EXITINS:
ENTERINS:      xor   Insert_Mode,INSERT
               jmp   GETCH

PUBLIC  BUFOUT
BUFOUT:       .IF <al B BLANK> AND      ; Ctrl character?
              .IF <al NE TABCHAR> AND   ;   Don't display '^' for TAB,
              .IF <al NE <"U"-"@">> AND ;   Ctrl_U, and Ctrl_T
              .IF <al NE <"T"-"@">>     ;
                push ax                 ; Save original char
                mov  al,"^"             ;
                call OUT_               ; Print '^' before control char
                pop  ax                 ; Restore original char
                or   al,40H             ; Turn it into upper case
                call OUT_               ; Print control char
                ret
                ;
                ;********************************************************
                ;*  Output a CRLF                                       *
                ;********************************************************
                ;
PUBLIC  CRLF
CRLF:           mov  al,CR
                call OUT_
                mov  al,LF
              .ENDIF

PUBLIC  OUT_
OUT_:         .IF <Echo_Mode EQ ECHO_ON> near; Echo Mode ON?  ;@@DTF
               .IF <al B BLANK>
                .IF <al NE CR>          ; NOT TurnAround character?
                 .IF <al NE BKSPACE>    ; NOT Backspace character?
                  .IF <al EQ TABCHAR>   ; Tab character?
                    mov  al,CurrentPos  ; Calculate tab position
                    or   al,0F8H
                    neg  al

PUBLIC  TAB
TAB:                push cx             ; Display CX number of blanks
                    mov  cl,al          ;   til the tab position is reached
                    jcxz POPTAB

PUBLIC  TABLP
TABLP:              mov  al,BLANK
                    call OUT_
                    loop TABLP

PUBLIC  POPTAB
POPTAB:             pop  cx
                    ret
                  .ELSE                 ;                               P3088
                    .IF <al EQ <"U"-"@">> OR    ; Ctrl_U?               P3088
                    .IF <al EQ <"T"-"@">>       ; Ctrl_T?               P3088
                      inc CurrentPos    ; Advance cursor position       P3088
                    .ENDIF              ;                               P3088
                  .ENDIF
                 .ELSE
                   dec  CurrentPos
                 .ENDIF
                .ELSE
                  mov   CurrentPos,ch   ; Start from the beginning
                .ENDIF
               .ELSEIF <al NE DEL>
                 inc    CurrentPos
               .ENDIF
PUBLIC  OUTCH
PUBLIC  OUTSKIP
OUTCH:
OUTSKIP:        mov     Char_Code,al    ; Set up parameters for echo
                push    ds
                push    OFFSET Char_Code
                push    01H
                push    00H             ; Dummy VIO Handle
                call    VIOWRTTTY       ; Output the character
;@@DTF -- Begin  Autoscrolling mods for Winthorn
                push    dx
                push    cx              ;PTM 2223
                mov     dx,KBD_SG
                .if  <dx a LastBaseSG>
                   push   ds
;                  push   gdseg         ;@@DTF1
;                  pop    ds            ;@@DTF1
                   mov    ax,hConsole
                   push   bx
                   sub    bx,bx
                   push   PS_Sel
                   pop    ds
                   mov    dx,[bx].viops_WindowOriginColumn
                   add    dx,[bx].viops_WindowWidth
                   .if   <dx be [bx].viops_TextCursorColumn>
                       push   es        ;save es
                       push   GDSEG     ;CDB2
                       pop    es        ;CDB2
                       push   ax        ;i/p param for WinSyncWithPS
                       push   ds        ;PS Sel
                       push   viops_PresentationSpaceLock
                       call   ES:LockVioPS ;CDB2
                       push   GDSEG     ;CDB2
                       pop    es        ;CDB2
                       sub    bx,bx     ;reset bx after LockVioPS
                       inc    [bx].viops_WindowOriginColumn
                       call   ES:WINSYNCWITHPS ;CDB2
                       push   GDSEG     ;CDB2
                       pop    es        ;CDB2
                       push   ds        ;PS Sel
                       push   viops_PresentationSpaceLock
                       call   ES:UnLockVioPS ;CDB2
                       pop    es        ;restore es
                   .endif
                   pop    bx
                   pop    ds
                .endif
                pop   cx                ;PTM 2223
                pop   dx
;@@DTF -- End  Autoscrolling mods for Winthorn
;               push    1               ; Stdout handle
;               push    ds              ; Address of character to be displayed
;               push    OFFSET Char_Code;
;               push    1               ; Buffer length
;               push    ds              ; Address of bytes written
;               push    OFFSET Scan_Code;
;               call    DOSWRITE        ; Write to Stdout
              .ENDIF
               ret
             .ENDIF
            .ENDIF
           .ENDIF
            pop         di              ; Balance stack
          .ENDIF
         .ENDIF
        .ENDIF
       .ENDIF
        ret

InString ENDP

CSEG    ENDS
        END
