;       SCCSID = @(#)kbdstrng.asm	6.1 91/02/15
;       SCCSID = @(#)kbdstrng.asm	1.6 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;***  kbdstrng.asm - API stub routine KBDStringIn
;
;       Member of API library
;       ?
;       Copyright MicroSoft Corporation, 1986
;       23-Jul-1986
;
;       These are API library routines for use in DOS 2.x,3.x compatible
;       DOS 5.x programs.
;
;       Special Information
;
;
;       Modification History
;
;       12-Aug-86 (billme): rewrite raw and cooked i/o according to spec
;
;       19-Aug-86 (billme): redesign to use int 21h, fcns 3F and 44, using
;       up one handle in the process, for security
;
;       28-Aug-86 (billme): include code to add CR to end of input string
;       (according to PTM 3170)
;
;       10-Sep-86 (billme): in response to ptm 3446, install special loop
;       (27 bytes) to beep while waiting for CR when count of characters
;       to be input is 1... also, change code to NOT count the CR as a
;       return character
;
;       06-Jan-87 (billme): Replace initial pushes and final pops
;       with calls to __api_begin and __api_end resp.  This will
;       reduce the size of FAPI and allow support for signals.
;
;       09-Feb-87 (Rich Andresen): fixed ptm 1949 or changed code to return
;       number of characters typed in the second word as apposed to the
;       1st word.  This change supports the 1.1 spec.
;
;       27-Mar-87 (Tim Gray): KBDSTRINGIN now jumps around COOKED code
;       after processing RAW code.  As it was, the "length read" field
;       was being trashed by the COOKED code.  (PTM P3504)
;
;
;       04-May-87 (robertc): Install hooks for DOSErrorClass Support.
;       All int 21h errors are passed through api_get_extended to get the
;       extended errorcode and to provide the class, action, and locus for
;       the dynamic error FIFO queue.
;
;       19-Nov-87 (marieu):  Change D2_BuffKbdIn (0AH) to D2_ReadForD
;       (03FH) to insure that input is echoed to the screen during
;       redirection (PTM 1250).
;
;       09-Dec-87 (marieu):  Correct the length of string returned.
;                            (PTM 1424).
;
;       09-Dec-87 (marieu):  Clean up keyboard buffer
;                            (PTM 1522).
;
;       26-Jan-88 (jimmyg):  Correct string returned when input = max. length
;                            (PTM 1680).
;
;       24-Feb-88 (jimmyg):  The code for kbdstringin should use 0A instead
;                            of 3D . This has been corrected. Echoing problem
;                            for P1250 fixed in DosRead. (PTM 1823)

.xlist
include dos2equ.inc
include kbdfapi.inc
include error2.inc
INCLUDE basemaca.inc
INCLUDE error.inc
        EXTRN   api_get_extended:far    ;@@ added support for DOSErrorClass
        EXTRN   __api_begin:near
        EXTRN   __api_end:near
        EXTRN   SignalCheck:near                                        ;THG

.list

        EXTRN   StatusFlag:BYTE

APIBUF  segment byte common 'CODE'

__api_buffer    db      KBD_BUF_SIZE dup(0)

APIBUF  ends

CR      equ     0Dh
BEL     equ     07h


_TEXT   segment word public 'CODE'

        assume  CS:_TEXT,DS:NOTHING

;**     kbd_prep
;
;
;       call    kbd_prep
;       jc      error
;
;       ENTRY:
;
;       RETURN:
;               CARRY => error return from dos open call
;
;       EXIT:
;
;       CALLS:
;               int 21h function 03Dh
;
;       WARNING:
;               *** check for carry upon return ***
;
;       EFFECTS:
;               uses registers AX, BX, CX, DX, DS
;

constr  db      "con",0         ; string for console open
handkp  dw      ?               ; to keep saved handle

        public  kbd_prep

kbd_prep        PROC NEAR

        mov     ah,D2_DupFileHndl       ; save handle 0 in new handle
        xor     bx,bx                   ; BX <- file handle 0
        int     21h                     ; if duplication fails
        jc      prep99                  ; then return error

        mov     handkp,ax               ; save duplicate handle
        mov     ah,D2_CloseHndl
        int     21h                     ; close handle 0 (ignore failure)

; NOTE: for the following code we depend on the handle allocation
; algorithm to choose the first 'free' handle starting from 0.  Since
; we have just freed up handle 0, the open will yield handl 0.

        mov     ax,cs                   ; open handle 0 as con
        mov     ds,ax
        mov     dx,offset constr        ; DS:DX <- pointer to "con"
        mov     al,0                    ; request read only
        mov     ah,D2_OpenHndl
        int     21h                     ; if open fails, then carry is set
prep99:
        ret

kbd_prep        ENDP



;**     kbd_rest
;
;
;       call    kbd_rest
;       jc      error
;
;       ENTRY:
;
;       RETURN:
;               CARRY => error return from dos open call
;
;       EXIT:
;
;       CALLS:
;               int 21h function 03Dh
;
;       WARNING:
;               *** check for carry upon return ***
;
;       EFFECTS:
;               uses registers AX, BX, CX
;


        public  kbd_rest

kbd_rest        PROC NEAR

        mov     ah,D2_ForceDupFileHndl  ; save handle 0 in new handle
        mov     bx,handkp               ; BX <- saved file handle
        xor     cx,cx                   ; CX <- file handle 0
        int     21h                     ; if duplication fails
        jc      rest99                  ; then return error

        mov     ah,D2_CloseHndl
        int     21h                     ; close saved handle
        clc                             ; ignore error, if any
rest99:
        ret

kbd_rest        ENDP


;***    KBDSTRINGIN - stub to emulate KBDSTRINGIN function call
;
;       simulates DOS 5.0 call from DOS 2.x,3.x environment
;
;       errorcode = WORD pascal far
;               KBDStringIn (ptr_CharBuffer, ptr_Length, IOWait, KbdHandle)
;
;       ENTRY:
;               ptr_CharBuffer - pointer to buffer for characters
;               ptr_Length - pointer to structure that has
;                               dw length of buffer
;                               dw # of characters typed excluding <CR>
;               IOWait - 1 => wait, 0 => do not wait
;               KbdHandle - 0 (reserved word)
;
;       RETURN:
;               0 if no error, else error code (see DOS 5 spec)
;
;       EXIT:
;               *ptr_Length+2 = number of characters read
;
;       CALLS:
;
;       WARNING:
;               - Error codes may be returned from from DOS 2.x or DOS 3.x.
;               - No support for echo ON/OFF, double byte character codes.
;               - KbdHandle is ignored for Version 1.0.
;               - Maximum string length is 255.
;
;       EFFECTS:
;               none
;

;       EXTRN   KBDSTRINGIN : FAR
;
;       PUSH    @ptr_CharBuffer
;       PUSH    @ptr_Length
;       PUSH    IOWait
;       PUSH    KbdHandle
;       CALL    KBDSTRINGIN


        public  KBDSTRINGIN

ptr_CharBuffer  equ     [BP+14]
ptr_Length      equ     [BP+10]
IOWait          equ     [BP+8]
KbdHandle       equ     [BP+6]

KBDSTRINGIN     proc    far
;THG
;THG    call    __api_begin     ; init bp and save bp,ds,bx,cx,dx,si,di,es
;THG                            ; required to save: bp,bx,cx,dx,si,di,ds,es
        xor     ax,ax                   ; AX <- 0 (default locals size) ;THG
        push    bp                                                      ;THG
        mov     bp,sp                                                   ;THG
        sub     sp,ax                   ; setup local stack frame       ;THG
        push    ds                      ; save all registers except AX  ;THG
        push    es                                                      ;THG
        push    bx                                                      ;THG
        push    cx                                                      ;THG
        push    dx                                                      ;THG
        push    si                                                      ;THG
        push    di                                                      ;THG

        call    kbd_prep                ; if kbd preparation fails
        jnc     cont
        jmp     ErrorExit               ;@@ added support for DOSErrorClass
cont:
        cld                             ; clear direction flag just in case
        les     di,ptr_CharBuffer       ; ES:DI <- pointer to character buffer
        lds     si,ptr_Length           ; DS:SI <- pointer to user's byte count
        mov     cx,word ptr ds:[si]     ; CX <- number of bytes to read
        cmp     cx,KBD_MAX_IN           ; if too many or few chars requested
        mov     ax,ERROR_KBD_INVALID_LENGTH
        ja      kbderrexit              ; then return error

        test    cs:StatusFlag,RAW_NOECHO ; if NOT raw mode
        jz      kbd09                   ; then process 'cooked'

; raw mode:
; if (IOWait == WAITIO) then process until buffer is full
; else process until no more keystrokes in BIOS keyboard buffer
;      OR the buffer is full

        .erre   WAITIO EQ 0             ; fail if definitions change
        .erre   NOWAITIO EQ 1
        mov     si,IOWait               ; si <- IOWait parameter
        cmp     si,NOWAITIO             ; if parameter is not valid
        mov     ax,ERROR_KBD_INVALID_IOWAIT
                                        ;@@ added support for DOSErrorClass
        ja      NormalExit              ; then return error

kbd01:                                  ; *** RAW: WAIT or NOWAIT ***
                                        ; CX == number of bytes to read
        xor     dx,dx                   ; DL <- count of bytes read so far
kbd05:
        jcxz    kbd20                   ;@@ use shorter inst.
        mov     ah,D2_GetKbdStat        ; read keyboard status
        int     21h
        or      al,al                   ; if character ready
        jnz     kbd06                   ; then process it
        .erre   WAITIO EQ 0             ; (fail if definitions change)
        .erre   NOWAITIO EQ 1
        or      si,si                   ; else if using NOWAIT io
        jnz     kbd20                   ; then return
kbd06:
        mov     ah,D2_DrctConIn         ; else read keyboard character
        int     21h
        stosb                           ; store char, and bump pointer
        inc     dx                      ; bump count
        loop    kbd05                   ;@@ loop is shorter than dec and jmp
        jmp     kbd20                   ;jump around COOKED code     ;THG_P3504
kbd09:                                  ; *** COOKED ***
        assume  ds:APIBUF

        mov     ax,seg APIBUF
        mov     ds,ax
        mov     dx,offset __api_buffer  ; DS:DX <- pointer to local buffer
        mov     si,dx                   ; DS:SI <- pointer to local buffer
        mov     byte ptr [si],cl        ; store number of bytes requested
        mov     ah,D2_BuffKbdIn         ; 0ah function call
        int     21h                     ; read input until CR

        inc     si                      ; DS:SI <- pointer to count read
        mov     dl, byte ptr [si]       ; DL <- number of bytes read
        inc     si                      ; DS:SI now points to start of input
        xor     cx,cx
        mov     cl,dl                   ; CX <- number of bytes read
        inc     cl                      ; account for added CR
        rep     movsb
        assume  ds:nothing
        xor     dh,dh                   ; DX <- number of bytes read
kbd20:
        les     di,ptr_Length           ; ES:DI <- pointer to user's byte count
        mov     word ptr es:[di]+2,dx   ; store count of characters read
kbdexit:
        xor     ax,ax                   ; return no error
kbderrexit:
        mov     dx,ax
        call    kbd_rest
        jc      ErrorExit
        mov     ax,dx
        jmp     NormalExit              ;@@ Added support for DOSErrorClass
ErrorExit:                              ;@@ added support for DOSErrorClass
        call    api_get_extended        ;@@ added support for DOSErrorClass
NormalExit:                             ;@@ added support for DOSErrorClass
        call    SignalCheck                                             ;THG
        pop     di                                                      ;THG
        pop     si                                                      ;THG
        pop     dx                                                      ;THG
        pop     cx                                                      ;THG
        pop     bx                                                      ;THG
        pop     es                                                      ;THG
        pop     ds                                                      ;THG
        mov     sp,bp                                                   ;THG
        pop     bp                                                      ;THG
;THG
;THG    call    __api_end       ; check sigs & restore es,di,si,dx,cx,bx,ds,bp
;THG
        ret     12      ; clear stack of entry parameters (bytes)
KBDSTRINGIN     endp

_TEXT   ends


        end

