;       SCCSID = @(#)i_versio.asm	6.1 91/02/15
;       SCCSID = @(#)i_versio.asm	1.7 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;***  i_version.asm - routine to get the current version number
;
;       Internal routine used by API library routines
;       Bill Mershon
;       Copyright MicroSoft Corporation, 1986
;       05-Apr-1986
;
;       These routines are used by functions in the API library.
;       (A library of routines for use in DOS 2.x,3.x compatible
;       DOS 5.x programs.)
;
;       Special Information
;
;               none
;
;       Modification History
;
;       14-Oct-86 (billme): add api initialization code (called from
;       the envinit module of the stubloader)... all initialization
;       code, including api_getversion, will eventually move into
;       the stubloader.
;
;       28-Oct-86 (billme): add routines for DBCS support
;       (api_testdbcs,)
;
;       31-Dec-86 (billme): add initial versions of __api_begin and
;       __api_end for signal support and code size reduction (central
;       register saving pushes and pops instead of duplicated in each
;       routine).  (see also d_sig.asm) ... this code will eventually
;       contain complete code for the simpler FAPI routines - an int 21
;       call specified by a code given in AX.  This will probably be
;       implemented as a separate routine which a given fapi routine
;       will long-jump to after loading AX with a code specific to
;       that routine.  NOTE: this code should probably be moved to a
;       separate file, but maybe not.
;
;       13-Jan-86 (billme): reduce size of _api_getvrsn by initializing
;       __version_api through call to _api_init from stubloader.
;       We leave the call (rather than changing all the calls to moves)
;       since a near call is 3 bytes and a "mov ax,cs:__version_api"
;       is 4 bytes (though the call is much slower).
;
;       15-Jan-86 (billme): add "__api_begin_lsf" for fapi routines
;       that use a local stack frame.
;
;       02-Apr-87 (Tim Gray): add "__api_incTopCall" "__api_decTopCall"
;       for DOSREAD (PTM3591)
;
; @@    8-May-87 (Tarng): add "name_check" routine to check filename/pathname
;       is in the 8.3 range.
;
; @@    4-June-87 (Chernow): Modify crit_err_handler and create crit_err accum
;
; @@    18-June-87 (robertc): ADD TBLINIT to initialize handinfo table
;
; @@    22-June-87 (robertc): Modify TBLINIT to include conout,com1 and lpt1
;
;       15-July-87 (pauls): pass PSP segment into _api_init.
;
; @@    22-July-87 (giacomoa): change __PSP to __api_PSP to avoid name
; @@    conflict with slibc.lib (COBOL compiler problem)
;
; @@    06-Aug-87 (giacomoa): added api_ctrlbreak_off/_reset routines
; @@    to allow api's to disable and reset control-break checking
; @@    around critical paths.
;

IFDEF api_debug_pause
        %OUT *** DEBUG *** int 3 pauses included
ENDIF
include basemaca.inc
include realmac.inc
include dos2equ.inc
include api.inc
include kbdfapi.inc                     ; cpd12 (p1082)
INCLUDE error.inc                       ;@@ added support for 8.3 filename

?PLM = 0
INCLUDE cmacros.inc     ; NOT USED

MsgSeg          segment para public 'DATA'          ; cp111 4076
  TXT_MSG_DIVIDE_ZERO   DB 'A program tried to divide a number by zero, '
                        DB 'and a divide by zero',0DH,0AH
                        DB 'exception handler was not registered',0DH,0AH
  TXT_MSG_COUNT0        DW TXT_MSG_COUNT0 - TXT_MSG_DIVIDE_ZERO
  TXT_MSG_DIVIDE_OVER   DB 'The result of a division operation was too '
                        DB 'large, and a divide overflow',0DH,0AH
                        DB 'exception handler was not registered',0DH,0AH
  TXT_MSG_COUNT4        DW TXT_MSG_COUNT4 - TXT_MSG_DIVIDE_OVER
  TXT_MSG_BOUND         DB 'A program started a BOUND instruction without '
                        DB 'registering a bound',0DH,0AH
                        DB 'exception handler',0DH,0AH
  TXT_MSG_COUNT5        DW TXT_MSG_COUNT5 - TXT_MSG_BOUND
  TXT_MSG_BAD_OPCODE    DB 'A program started an invalid instruction without '
                        DB 'registering an invalid opcode',0DH,0AH
                        DB 'exception handler',0DH,0AH
  TXT_MSG_COUNT6        DW TXT_MSG_COUNT6 - TXT_MSG_BAD_OPCODE
  TXT_MSG_NPX_EXCEPTION DB 'A numeric coprocessor exception occurred '
                        DB 'and a numeric coprocessor exception ',0DH,0AH
                        DB 'handler was not registered',0DH,0AH
  TXT_MSG_COUNT2        DW TXT_MSG_COUNT2 - TXT_MSG_NPX_EXCEPTION
MsgSeg          ends

STDERR  EQU     2

CGRP    group   _TEXT,SIGCHECK

        assume  CS:CGRP, DS:nothing

        EXTRN   KbdType:BYTE            ; cpd12 (p1082)
        EXTRN   FapiAddSigCatch:FAR
        EXTRN   DosExit:FAR

;***    api_getvrsn - return the current version number
;
;       version = WORD far api_getvrsn();
;
;       ENTRY:
;
;       RETURN:
;               AH = major version number
;               AL = minor version number
;
;       EXIT:
;
;       USES:
;               AX
;
;       WARNING:
;               none
;
;       EFFECTS:
;               none
;

;
;       EXTRN   api_getvrsn:FAR
;
;       CALL    api_getvrsn
;

sBegin  CODE

        PUBLIC  __version_api
        public  __hook_table

__version_api   dw      0       ; loaded by __api_init thru stubloader pass
                                ; (minor/major version numbers)

cProc   api_getvrsn,<NEAR,PUBLIC>

cBegin

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF

        mov     ax,cs:__version_api     ; load version number into ax
cEnd


;***    _api_init - initialization for api
;
;       void far api_init();
;
;       Various initializations for api library;
;               - initialize dbcs lead byte table
;               - initialize console input flag (in api table) for handle 0
;               (for more information on this, see d_open.asm)
;
;       ENTRY:  AX = version number
;               BX = PSP segment
;
;       RETURN:
;               nothing
;       EXIT:
;
;       USES:
;               nothing
;       WARNING:
;               none
;       EFFECTS:
;               none

;       EXTRN   _api_init:FAR
;
;       CALL    _api_init


        public  _api_init
        extrn __api_dev_table : word

__lead_table    dw      5 dup (0)       ; lead byte table for DBCS


        mov     dx, offset _TEXT:Excp2Msg
__hook_table  label byte
                dw   5   ; number of entries in hook table
          _hooker <0,,offset _TEXT:Excp0Msg>           ; div zero     cp111 4076
          _hooker <4,,offset _TEXT:Excp4Msg>           ; overflow
hooker5   _hooker <5,,offset _TEXT:Int5Handler>        ; bound
          _hooker <6,,offset _TEXT:Excp6Msg>           ; bad opcode
          _hooker <2,,offset _TEXT:Excp2Msg>           ; NPX exception

pseudoint5vector  dd   Excp5Msg
        public  pseudoint5vector

        public  __api_PSP               ; @@
__api_PSP       dw      ?               ; @@ PSP segment

_api_init       proc    far

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        push    ax
        push    bx
        push    cx
        push    dx
        push    si
        push    di
        push    ds
        push    es

        push    cs
        pop     ds

        mov     __version_api,ax        ; store version number from stubloader
        mov     __api_PSP,bx            ; @@ and psp segment

        mov     si, offset _TEXT:__lead_table   ; DS:SI <- default lead_table
        mov     ah,63h                          ; AH <- lead byte table fcn
        xor     al,al
        int     21h                             ; DS:SI <- real lead table
        mov     cx,5
        push    cs
        pop     es
        mov     di, offset _TEXT:__lead_table   ; ES:DI <- lead table
        rep     movsw                           ; copy table

        mov     ah,D2_IOCTL
        xor     al,al                           ; AL <- 'get device data' fcn
        xor     bx,bx                           ; BX <- handle 0
        int     21h                             ; if error return from ioctl
        jc      init99                          ; then just continue
        and     dl,CHAN_IS_DEV or CHAN_IS_CONIN
        cmp     dl,CHAN_IS_DEV or CHAN_IS_CONIN ; if not a console input device
        jnz     init99                          ; then continue

        mov     bx,offset __api_dev_table        ; BX <- hi_attrdev of handle 0
        or      cs:[bx].hi_attrdev,CONIN_FLAG   ; set conin flag
init99:
        call    crit_err_set
        call    Tbl_Init                        ;@@PTM 5550
        mov     ax,BIOS_SEGMENT                 ; cpd12 (p1082) add support
                                                ; for enhanced KBD
        mov     es,ax                           ; cpd12 (p1082)
        test    byte ptr es:[kb_flag_3],KBX     ; cpd12 (p1082)
        jz      notenh                          ; cpd12 (p1082)
        mov     ax,12FFH                        ; cpd12 (p1437) check if the
                                                ; BIOS supports the enhanced
                                                ; keyboard
        int     16H                             ; cpd12 (p1437)
        cmp     al,0FFH                         ; cpd12 (p1437)
        je      notenh                          ; cpd12 (p1437)
        mov     cs:[KbdType],KBX                ; cpd12 (p1082)
notenh:

; hook interrupt handlers for NPX exceptions    cp111 4076
        mov     si, offset _TEXT:__hook_table    ; table of vectors
        mov     dx,cs
        mov     ds,dx
        lodsw
        mov     cx,ax

        cli
_set_hooks:
        mov     dx,[si].new_vect
        call    nextvec
        add     si, size _hooker
        loop   _set_hooks

; call FapiAddSigCatch to assure ctrlc cleanup


        mov     dx, SEG _TEXT
        mov     ds, dx
        mov     dx, offset _TEXT:cleanup
        mov     bx, CLEAN
        call    FapiAddSigCatch
        sti

        pop     es
        pop     ds
        pop     di
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     ax
        ret

                                                ; cp111 4076
Excp0Msg:
        sti
        mov     ax, seg MsgSeg                  ; @@
        mov     ds, ax                          ; @@
        mov     dx, offset MsgSeg:TXT_MSG_DIVIDE_ZERO        ; @@
        mov     cx,ds:[TXT_MSG_COUNT0]   ; @@
        jmp     ExcpExit

Excp4Msg:
        sti
        mov     ax, seg MsgSeg                  ; @@
        mov     ds, ax                          ; @@
        mov     dx, offset MsgSeg:TXT_MSG_DIVIDE_OVER        ; @@
        mov     cx,ds:[TXT_MSG_COUNT4]   ; @@
        jmp     ExcpExit

Excp5Msg:
        sti
        mov     ax, seg MsgSeg                  ; @@
        mov     ds, ax                          ; @@
        mov     dx, offset MsgSeg:TXT_MSG_BOUND              ; @@
        mov     cx,ds:[TXT_MSG_COUNT5]   ; @@
        jmp     ExcpExit

Excp6Msg:
        sti
        mov     ax, seg MsgSeg                  ; @@
        mov     ds, ax                          ; @@
        mov     dx, offset MsgSeg:TXT_MSG_BAD_OPCODE         ; @@
        mov     cx,ds:[TXT_MSG_COUNT6]   ; @@
        jmp     ExcpExit
Excp2Msg:
        sti
        mov     ax, seg MsgSeg                  ; @@
        mov     ds, ax                          ; @@
        mov     dx, offset MsgSeg:TXT_MSG_NPX_EXCEPTION      ; @@
        mov     cx,ds:[TXT_MSG_COUNT2]   ; @@

ExcpExit:
        mov     bx, STDERR                      ; @@
        mov     ah,D2_WriteForD                 ; @@
        int     21h
        mov     ax,1
        push    ax
        mov     ax,-1
        push    ax
        call    DosExit

Int5Handler:

        push    bp
        mov     bp,sp
frame   struc                   ;stack frame after "enter"
save_bp dw      ?               ;caller's BP
user_ip dw      ?               ;caller's IP
user_cs dw      ?               ;caller's CS
user_f  dw      ?               ;caller's flags
frame   ends
        push    ds              ;save registers
        push    si
        push    cx
        push    ax
        mov     si,[bp].user_cs ;ds:si -> user code stream
        mov     ds,si
        mov     si,[bp].user_ip
        mov     cx,0010h        ;cx = loop counter = 16
        cld
fs1:    lodsb                   ;al = byte from code stream
        ; The following instruction prefixes are taken from Intel's 1986
        ; "80386 Programmer's Reference Manual", page 17-3.
;       cmp     al,026h         ;check for a ES segment override
;       cmp     al,02Eh         ;check for a CS segment override
;       cmp     al,036h         ;check for a SS segment override
;       cmp     al,03Eh         ;check for a DS segment override
        mov     ah,al
        and     al,11100111b    ;check for 26,2e,36,3e
        cmp     al,00100110b
        je      fs3
;       cmp     al,064h         ;check for a FS segment override
;       cmp     al,065h         ;check for a GS segment override
;       cmp     al,066h         ;check for operand size override
;       cmp     al,067h         ;check for address size override
        mov     al,ah
        and     al,11111100b    ;check for 64-67
        cmp     al,01100100b
        je      fs3
;       cmp     al,0F0h         ;check for LOCK prefix
;       cmp     al,0F1h         ;check for REPNE/REPNZ prefix (should not ever be seen)
;       cmp     al,0F2h         ;check for REPE/REPZ prefix (should not ever be seen)
;       cmp     al,0F3h         ;check for REP prefix (should not ever be seen)
        mov     al,ah
        and     al,11111100b    ;check for F0-F3
        cmp     al,11110000b
        je      fs3
        cmp     ah,062h         ;check if it is a BOUND instruction
        je      fs2
fs3:    loop    fs1             ;loop if there is more to check
        pop     ax              ;restore registers
        pop     cx
        pop     si
        pop     ds
        pop     bp
        jmp     [hooker5.old_vect] ;assume its print screen
fs2:    pop     ax              ;restore registers
        pop     cx
        pop     si
        pop     ds
        pop     bp
        jmp     [pseudoint5vector]   ;its a bound instruction
_api_init       endp


;***    nextvec - hooks an interrupt vector

nextvec proc    near
; save old and set up new interrupt vector


        mov     al,[si].vec_num

        mov     ah, D2_GetVector
        int     21h                             ; get int vector
        mov     _TEXT:[si].old_vect.lsw, bx     ; save vector
        mov     _TEXT:[si].old_vect.msw, es

        mov     al,[si].vec_num
        mov     ah,D2_SetVector                 ; set an interrupt hnldr
        int     21h
        ret
nextvec endp


cleanup proc    far

        push    ds
        push    es
        push    si
        push    dx
        push    ax
        push    bx
        push    cx

        push    cs
        pop     ds
        ASSUME  ds:nothing

        mov     si, offset _TEXT:__hook_table    ; table of vectors
        lodsw
        mov     cx,ax

; set up old interrupt vector

        xor     bx,bx
        mov     es,bx
        assume  es:NOTHING

        cli

clean1:
        xor     bx,bx           ;es:bx -> IVT
        mov     bl,cs:[si].vec_num
        shl     bx,1
        shl     bx,1            ;es:bx -> IVT

        ; The vector is now restored to it's original value.
        ; NOTE: - temporary fix: This code replaces the interrupt vectors
        ; directly.  This was necessary because most int 21s cannot be used
        ; in a critical error handler.

        mov     ax, [si].old_vect.lsw
        mov     es:[bx].lsw, ax
        mov     ax, [si].old_vect.msw
        mov     es:[bx].msw, ax

        add     si,size _hooker                 ; point at next vector no.
        loop    clean1

        sti

        pop     cx
        pop     bx
        pop     ax
        pop     dx
        pop     si
        pop     es
        pop     ds
        ret
cleanup endp

;***    api_testdbcs - test if AL contains a lead byte
;
;       void far api_testdbcs();
;
;               Search the dbcs lead byte table for the given character.
;               If found, set carry and return.  Else, clear carry
;               and set not zero and return.  (We set non-zero in order
;               to allow multiple methods of checking - this reduces
;               code size in certain cases.)
;
;       ENTRY:
;               AL contains character to check
;
;       RETURN:
;               CY => AL contains a lead byte
;               NC => AL does NOT contain a lead byte
;               NZ => AL does NOT contain a lead byte
;
;       EXIT:
;
;       USES:
;               flags
;       WARNING:
;               none
;       EFFECTS:
;               none

;       EXTRN   api_testdbcs:far
;
;       CALL    api_testdbcs

        public  api_testdbcs

api_testdbcs    proc    far

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        push    bx
        push    si
        push    ds
        mov     bl,al                           ; BL <- byte in question
        or      bl,bl                           ; if byte is zero
        jz      test99                          ; then clear carry and return

        cld                                     ; set direction forward
        push    cs
        pop     ds
        mov     si, offset _TEXT:__lead_table   ; DS:SI <- lead byte table
test1:
        lodsw                                   ; AL <- min, AH <- max
        or      ax,ax                           ; if end of table
        jz      test99                          ; then clear carry and return
        cmp     bl,al
        jb      test1
        cmp     bl,ah
        ja      test1
        stc
test98:
        mov     al,bl                           ; restore AL
        pop     ds
        pop     si
        pop     bx
        ret
test99:
        or      al,1                            ; set NZ
        jmp     short test98                    ; (we want TZ => CY)

api_testdbcs    endp


;***    api_testdbcs_b - test and bump
;
;       void far api_testdbcs_b();
;
;       ENTRY:
;       RETURN:
;               NC => double byte character NOT found
;               NZ => double byte character NOT found
;
;               else    (carry is set)
;                       double byte character was found
;                       AH contains lead byte
;                       AL contains trailing byte
;                       SI has been incremented by one
;                       ZE => second byte is zero
;       EXIT:
;       USES:
;               AX
;       WARNING:
;       EFFECTS:

;       EXTRN   api_testdbcs_b:far
;
;       CALL    api_testdbcs_b

        public  api_testdbcs_b

api_testdbcs_b  proc    far

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        call    api_testdbcs
        jnc     bump99
        mov     ah,al
        lodsb                   ; AX <- double byte in reverse order
        or      al,al           ; set ZE if next byte is zero
        stc                     ; set CY since this was a double byte
bump99:
        ret

api_testdbcs_b  endp


;***    api_testdbcs_bst - test and bump and store
;
;       void far api_testdbcs_bst();
;
;       ENTRY:
;       RETURN:
;               NC => double byte character NOT found
;               NZ => double byte character NOT found
;
;               else    (carry is set)
;                       double byte character was found
;                       AH contains lead byte
;                       AL contains trailing byte
;                       SI has been incremented by one
;
;                       ZE => second byte is zero
;
;                       else    (character is OK)
;                               ES:[DI] contains word
;                               DI has been incremented by 2
;       EXIT:
;       USES:
;               AX
;       WARNING:
;       EFFECTS:

;       EXTRN   api_testdbcs_bst:far
;
;       CALL    api_testdbcs_bst

        public  api_testdbcs_bst

api_testdbcs_bst        proc    far

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        call    api_testdbcs_b  ; if not double byte char or char tainted
        jnc     bst99           ; then exit
        jz      bst99
        xchg    ah,al           ; prepare storage in reverse order
        stosw                   ; store double byte character
bst99:
        ret

api_testdbcs_bst        endp


;***    api_testdbcs_bdec - test and bump and store
;
;       void far api_testdbcs_bdec();
;
;       ENTRY:
;       RETURN:
;               NC => double byte character NOT found
;               NZ => double byte character NOT found
;
;               else    (carry is set)
;                       double byte character was found
;                       AH contains lead byte
;                       AL contains trailing byte
;
;                       ZE => second byte is zero
;                               SI has been incremented by one
;                       CX==0
;                               SI remains unchanged
;                               CX has been decremented by one
;                       else
;                               SI has been incremented by one
;                               CX has been decremented by one
;       EXIT:
;       USES:
;               AX
;       WARNING:
;       EFFECTS:

;       EXTRN   api_testdbcs_bdec:far
;
;       CALL    api_testdbcs_bdec

        public  api_testdbcs_bdec

api_testdbcs_bdec       proc    far

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        call    api_testdbcs_b
        jnc     bdec99
        jz      bdec99
        dec     cx
        jnz     bdec99
        dec     si
bdec99:
        ret

api_testdbcs_bdec       endp



;**     FindChar - Scan a string looking for a character.
;
;       In non DBCS code the following sequence is used to find
;       a character in a string:
;               mov     al, '.'
;               les     di, StringPtr
;               mov     cx, length
;               repne   scasb
;
;       With double byte character this sequence will not work.
;       It is possible to have a DBCS with the character as the trailing
;       byte value. This routine is does the DBCS aware equivalent
;       of repe scasb.
;               mov     al, '.'
;               les     di, StringPtr
;               mov     cx, length
;               call    FindChar
;
;       ENTRY   ES:DI points to beginning of text string
;               CX      length of string
;               AL      Search character.
;
;       EXIT    Zero set: character found.  ES:DI points to character
;                       CX has number of characters remaining in string.
;               Zero Clear: character not found in string.
;                       CX is zero.
;
;       USES    CX, DI, Flags
;
;       CALLS   TestDBCS
;
;       NOTES   The procedure does not match the repnz scasb instruction
;               exactly.  If CX is zero on entry the zero flag is reset.
;               The repnz scasb instruction does not affect the flags
;               in this case.
;

        public  api_dbcs_findchar

api_dbcs_findchar       proc    far

        ASSUME  DS:NOTHING,ES:NOTHING

        push    ax              ; save work register
        xchg    ah, al          ; put byte we are looking for in ah.
fc0:    jcxz    fc2
        mov     al, es:[di]     ; get character
        inc     di
        dec     cx
        call    api_testdbcs    ; double byte character?
        jc      fc1             ; yes -- jump down
        cmp     ah, al          ; character we want?
        jz      fc3             ; yes -- return
        jmp     short fc0

;       deal with double byte character

fc1:    jcxz    fc2
        inc     di              ; skip trailing byte
        dec     cx
        jmp     short fc0

fc2:    cmp     cx, 1           ; clear the zero flag
fc3:    pop     ax
        ret

api_dbcs_findchar       endp


;***    __api_devtab_ptr  - return pointer into device table for given handle
;
;       unsigned near pascal
;       __api_devtab_ptr();
;
;       ENTRY:
;               AL == handle of interest
;
;       EXIT:
;               AH == 0
;
;       RETURN:
;               CS:[BX] == pointer to correct place in __api_dev_table

;       EXTRN   __api_devtab_ptr:near
;
;       CALL    __api_devtab_ptr

        public  __api_devtab_ptr

__api_devtab_ptr        proc    near

        push    ax                              ; save handle
        xor     ah,ah                           ; AX <- handle number
        mov     bl,HANDINFO_SIZE                ; BL <- size of one entry
        mul     bl                              ; AX <- offset into table
        mov     bx,offset __api_dev_table       ; BX <- base of table
        add     bx,ax                           ; BX <- offset from _TEXT
        pop     ax                              ; restore handle
        ret

__api_devtab_ptr        endp


;***    __api_incTopCall - increment TopCall word
;
;       unsigned near pascal
;       __api_incTopCall();
;
;       ENTRY:
;
;       RETURN:
;               all registers preserved
;               flags are corrupted
;
;       NOTE:
;               called by (at the moment) DOSREAD to disallow signals
;               during file reading
;

;       EXTRN   __api_incTopCall:near
;
;       CALL    __api_incTopCall

        public  __api_incTopCall                                ;THG 3591

__api_incTopCall proc    near                                   ;THG 3591
        pop     CGRP:[temp]             ; save return address   ;THG 3591
        inc     word ptr CGRP:[TopCall] ; increment topcall     ;THG 3591
        jmp     CGRP:[temp]             ; return                ;THG 3591
__api_incTopCall endp                                           ;THG 3591


;***    __api_decTopCall - decrement TopCall word
;
;       unsigned near pascal
;       __api_decTopCall();
;
;       ENTRY:
;
;       RETURN:
;               all registers preserved
;               flags are corrupted
;
;       NOTE:
;               called by (at the moment) DOSREAD to re-allow signals
;               during file reading
;

;       EXTRN   __api_decTopCall:near
;
;       CALL    __api_decTopCall

        public  __api_decTopCall                                ;THG 3591

__api_decTopCall proc    near                                   ;THG 3591
        pop     CGRP:[temp]             ; save return address   ;THG 3591
        dec     word ptr CGRP:[TopCall] ; increment topcall     ;THG 3591
        jmp     CGRP:[temp]             ; return                ;THG 3591
__api_decTopCall endp                                           ;THG 3591


;***    __api_begin     - start fapi routine
;***    __api_begin_lsf - start fapi routine with local stack frame (ax == size)
;
;       unsigned near pascal
;       __api_begin();
;
;       ENTRY:
;
;       RETURN:
;               all registers preserved
;               flags are corrupted
;
;       NOTE:
;               Should be (but need not be) called at the start of every
;               FAPI routine - reduces the size of the code and increases
;               the liklihood of signal compatibility.
;

;       EXTRN   __api_begin:near
;
;       CALL    __api_begin

        public  __api_begin
        public  __api_begin_lsf

__api_begin     proc    near

        xor     ax,ax                   ; AX <- 0 (default locals size)

__api_begin     endp


__api_begin_lsf proc    near

        pop     CGRP:[temp]             ; save return address
        push    bp
        mov     bp,sp
        sub     sp,ax                   ; setup local stack frame
        push    ds                      ; save all registers except AX
        push    es
        push    bx
        push    cx
        push    dx
        push    si
        push    di

        inc     CGRP:[TopCall]          ; increment topcall (see note below)

        jmp     CGRP:[temp]             ; return

__api_begin_lsf endp


;***    __api_end - end a fapi routine
;
;       unsigned near pascal
;       __api_end();
;
;       ENTRY:
;
;       RETURN:
;               all registers preserved
;               flags are corrupted
;
;       NOTE:
;               Should be (but need not be) called at the start of every
;               FAPI routine - reduces the size of the code and increases
;               the liklihood of signal compatibility.
;

;       EXTRN   __api_end:near
;
;       CALL    __api_end

        public  __api_end

__api_end       proc    near

IFDEF api_debug_pause
        int     3       ; included ONLY IF api_debug_pause is defined
ENDIF
        dec     CGRP:[TopCall]          ; decrement topcall (see note below)
        call    SignalCheck

        pop     CGRP:[temp]     ; save return address
        pop     di              ; restore all registers
        pop     si
        pop     dx
        pop     cx
        pop     bx
        pop     es
        pop     ds
        mov     sp,bp           ; clear locals (restore sp)
        pop     bp

        jmp     CGRP:[temp]             ; return

__api_end       endp




get_crit_err    equ     3524h           ; DOS function call to get INT 24 vector
set_crit_err   equ     2524h           ; DOS function call to set INT 24 vector

PUBLIC  crit_err_AX
PUBLIC  crit_err_BX
PUBLIC  crit_err_CX
PUBLIC  crit_err_set
PUBLIC  crit_err_accum
PUBLIC  crit_err_flag

EXTRN   api_get_extended:far

crit_err_AX             dw      ?
crit_err_BX             dw      ?
crit_err_CX             dw      ?
crit_err_flag           dw      ?
crit_vector_offset      dw      ?
crit_vector_segment     dw      ?

;-----------------------------------------------------------------------------
;       Entry point for interrupt 24 handler
;-----------------------------------------------------------------------------

crit_err_handler proc far
        call    crit_err_accum          ; get error information
        pushf
        call    dword ptr crit_vector_offset    ;pass control to next handler
        iret
crit_err_handler  endp

;-----------------------------
;
crit_err_set proc near
        push    ax
        push    bx
        push    es
        push    ds
        mov     ax,get_crit_err         ; Get INT 24h vector
        int     21H                     ; call DOS INT 21 handler

        mov     crit_vector_offset,bx   ; Save it
        mov     ax,es                   ; es hase segment for resident code
        mov     crit_vector_segment,ax

        lea     dx,crit_err_handler     ; DS:DX = New INT 21h vector
        push    cs
        pop     ds
        mov     ax,set_crit_err         ; function code for setting critical error vector
        int     21H                     ; call DOS INT 21 handler
        pop     ds
        pop     es
        pop     bx
        pop     ax
        ret                             ; go back to the caller

crit_err_set    endp

;-----------------------------------------------------------------------------
; Error accumulating routine for INT 24 Handlers (DOSERROR & crit_err_handler)
;-----------------------------------------------------------------------------

crit_err_accum proc near
        cmp     crit_err_flag,0ffh              ;have we been here before
        je      get_out                         ; if so leave

        mov     crit_err_flag,0ffh
        push    ax
        push    bx
        push    cx
        call    api_get_extended                ;get and save extended error
        mov     crit_err_AX,ax
        mov     crit_err_BX,bx
        mov     crit_err_CX,cx
        pop     cx
        pop     bx
        pop     ax
get_out:
        ret
crit_err_accum  endp


 ;************************** START OF SPECIFICATIONS ****************/
 ;*                                                                 */
 ;*      SUBROUTINE NAME: NAME_CHECK                                */
 ;*                                                                 */
 ;*     DESCRIPTIVE NAME: Check directory/file name in 8.3 range    */
 ;*                                                                 */
 ;*     FUNCTION: This routine will check the whole path name       */
 ;*               to see its directory name or file name is in the  */
 ;*               8.3 range. If not, return the bad return code     */
 ;*               and the carry flag is set; otherwise, the carry   */
 ;*               flag is clear.                                    */
 ;*                                                                 */
 ;*               It also check the meta characters. If the caller  */
 ;*               choice is 1 or 3, this routine will reject the    */
 ;*               meta character, and return the bad return code    */
 ;*               according to the meta characters in the file name */
 ;*               or the path name. If the caller choice is 0,      */
 ;*               this routine will accept the meta characters, and */
 ;*               check the whole name in the 8.3 range or not.     */
 ;*                                                                 */
 ;*     ENTRY POINT:    NAME_CHECK                                  */
 ;*        LINKAGE:     CALL FAR                                    */
 ;*                                                                 */
 ;*     INPUT:          DS:SI = pointer to the beginning of the     */
 ;*                             path string                         */
 ;*                     AH = caller choice                          */
 ;*                          0 means meta character is   valid      */
 ;*                                  in path name or file name      */
 ;*                          2 means meta character is   valid      */
 ;*                                  in path name(no file name)     */
 ;*                          1 means meta character is invalid      */
 ;*                                  in path name or file name      */
 ;*                          3 means meta character is invalid      */
 ;*                                  in path name                   */
 ;*                                                                 */
 ;*     EXIT:                                                       */
 ;*     Carry Clear means the path string is in the 8.3 range.      */
 ;*                                                                 */
 ;*     Carry Set means the path string is not in the 8.3 range.    */
 ;*        AX = ERROR_FILENAME_EXCED_RANGE                          */
 ;*             ERROR_FILE_NOT_FOUND                                */
 ;*             ERROR_PATH_NOT_FOUND                                */
 ;*             ERROR_META_EXPANSION_TOO_LONG                       */
 ;*                                                                 */
 ;*     EFFECTS: AX, FLAGS                                          */
 ;*                                                                 */
 ;*     INTERNAL REFERENCES:                                        */
 ;*        ROUTINES:                                                */
 ;*                                                                 */
 ;*     EXTERNAL REFERENCES:                                        */
 ;*        ROUTINES:                                                */
 ;*                                                                 */
 ;*************************** END OF SPECIFICATIONS *****************/

; ************************** START OF PSEUDO CODE ****************/
;  /* initialization */
;  dbcs = 0 means no leading byte;
;  meta = 0 means no meta char exists;
;  ext_flag = 0 means now handling filename;
;  counter = 0;
;* version = os/2|dos version number;
;  save SI value;
;  load AL the character where DS:SI points to;
;
;  /* inspect filespec loop */
;  while not end of path {
;     increment SI;
;     increment counter;
;     call api_testdbcs to verify whether AL is the leading byte;
;
;     If (AL is not the leading byte) {
;        if (AL is equal to :) {
;           if (ext_flag = 1 or ( ext_flag = 0 & (counter = 1 or counter > 2) )
;              or ( ext_flag = 0 & counter = 2 &
;              ( prev_char is not alphabet or leading = 1 ) )) {
;              goto err_rpt2 to report failure;
;           }/*if*/
;        }/*if*/
;
;        if (AL is equal to :, /, \, ' ', or ';') {
;           if ((ext_flag = 1 & counter > 4) or (ext_flag = 0 & counter > 9)) {
;              goto err_rpt to report failure;
;           }/*if*/
;           reset counter = 0;
;           reset ext_flag = 0 means handling new filename;
;        }/*if*/
;
;        if (AL is equal to .) {
;           if (ext_flag = 1 & counter > 1) {
;              goto err_rpt2 to report failure;
;           }/*if*/
;           if ( ext_flag = 0 & counter > 9) {
;              goto err_rpt to report failure;
;           }/*if*/
;           set counter = 0;
;           set ext_flag = 1 to start processing extension;
;        }/*if*/
;
;        if (AL is equal to * or ?) {
;           if (choice = 1 or 3) {
;               goto err_rpt2 to report failure;
;           }/*if*/
;           else {
;              set meta = 1
;           /* Separate out the old and new META rules for easy maintenance */
;*          if (version < 10.2) {
;              if (AL = *)  {
;                 if (ext_flag = 0) {
;                    if (counter <= 8) {
;                        counter = 8;
;                    }/*if*/
;                    else {
;                       goto err_rpt to report failure;
;                    }/*else*/
;                 }/*if*/
;                 else {         /* ext_flag = 1 */
;                    if (counter <= 3) {
;                       counter = 3;
;                    }/*if*/
;                    else {
;                       goto err_rpt to report failure;
;                    }/*else*/
;                 }/*else*/
;              }/*if*/
;           }/*if*/
;*          else  {/* NEW META RULES */
;*             if (AL = *)  {
;*                /* validate extension count */
;*                if (ext_flag = 0) {
;*                   if (counter <= 8) {
;*                      counter = counter - 1;
;*                   }/*if*/
;*                   /* an * is a . in position 9*/
;*                   else if (counter = 9) {
;*                      ext_flag = 1;
;*                      counter = 0;
;*                   }/*else if*/
;*                   else {
;*                      goto err_rpt to report failure;
;*                   }/*else*/
;*                }/*if*/
;*                /* validate filename count */
;*                else {         /* ext_flag = 1 */
;*                   if (counter <= 3) {
;*                      counter = counter -1;
;*                   }/*if*/
;*                   else {
;*                      goto err_rpt to report failure;
;*                   }/*else*/
;*                }/*else*/
;*             }/*if*/
;*             /* a ? is usually 1 character except when count exhausted */
;*             else { /* AL = ? */
;*                if ((ext_flag = 0 and counter = 9) or
;*                   ( ext_flag = 1 and counter = 4)) {
;*                   counter = counter -1;
;*                }/*if*/
;*             }/*else*/
;*          }/*else*/
;        }/*else*/
;        leading = 0;
;        }/*if*/
;     }/*if*/
;     else { /* is a leading byte */
;        load AL the character where DS:SI points to
;        if (end of path) {
;           break;
;        }/*if*/
;        increment SI;
;        increment counter;
;        leading = 1;
;     }/*else*/
;
;     prev_char = AL;
;     load AL the character where DS:SI points to;
;  }/*while*/
;
;  if ((ext_flag = 1 & counter > 3) or (ext_flag = 0 & counter > 8)){
;     goto err_rpt to report failure;
;  }/*if*/
;  return;
;
;
;  err_rpt:    if (meta = 0) {
;                 set AX = ERROR_FILENAME_EXCED_RANGE;
;              }/*if*/
;              else {
;                 set AX = ERROR_META_EXPANSION_TOO_LONG;
;              }/*else*/
;              set carry flag on;
;              return;
;
;  err_rpt2:   if (choice = 2 or 3) {
;                 AX = ERROR_PATH_NOT_FOUND;
;              }/*if*/
;              else if (AL is part of filename) {
;                 AX = ERROR_FILE_NOT_FOUND;
;              }/*else if*/
;              else {
;                 AX = ERROR_PATH_NOT_FOUND;
;              }/*else*/
;              set carry flag on;
;              return;
;
;************************** END   OF PSEUDO CODE ****************/

version         dw      ?               ;*1.2 save the version

name_check      proc    far
                public  name_check
                push    si              ;save si
                push    di              ;save di
                push    bx              ;save bx
                push    cx              ;save cx
                push    dx              ;save dx
                xor     bh,bh           ;BH = extension flag = 0
                mov     bl,ah           ;BL = caller choice
                xor     di,di           ;di = counter = 0
                call    api_getvrsn     ;*1.2 get dos version
                mov     version,ax      ;*1.2 save it for later use
                xor     dx,dx           ;DL = meta char flag = 0
                                        ;DH = dbcs flag = 0 =no leading byte

                cld                     ;clear direction flag
checking:
                lodsb
                test    al,al           ;Is end of string?
                jnz     check_1         ;No, jump
                jmp     end_str         ;Yes, jump

check_1:        inc     di              ;increment counter
                call    api_testdbcs    ;Is AL leading byte?
                jnc     check_2         ;No, jump
                jmp     dbcs_hdl        ;Yes, handle dbcs trail byte

check_2:        cmp     al,':'          ;
                jz      colon_1
                cmp     al,'/'          ;
                jz      ntest1
                cmp     al,'\'          ;
                jz      ntest1
                cmp     al,' '          ;
                jz      ntest1
                cmp     al,';'          ;
                jz      ntest1
                cmp     al,'.'
                jz      test2
                cmp     al,'*'
                jnz     check_3
                jmp     meta_1

check_3:        cmp     al,'?'
                ljz     meta_1
                mov     cl,al           ;save the current char
                jmp     short checking

;  examine drive name
colon_err:
                jmp     err_rpt2
colon_1:
                test    bh,bh           ;ext_flag = 1?
                jnz     colon_err       ;Yes, jump
                cmp     di,1            ;counter = 1?
                jz      colon_err       ;Yes, jump
                cmp     di,2            ;counter > 2?
                ja      colon_err       ;Yes, jump
                test    dh,dh           ;Is prev char dbcs char?
                jnz     colon_err       ;Yes, jump
                or      cl,20h          ;convert to capital char
                cmp     cl,'a'          ;prev char < 'a'
                jb      colon_err       ;Yes, jump
                cmp     cl,'z'          ;prev char > 'z'
                ja      colon_err       ;Yes, jump

ntest1:         test    bh,bh           ;extension flag is on?
                jz      test11          ;No, jump
                cmp     di,4            ;counter > 4?

handle1:        jbe     handle1_1
                jmp     err_rpt         ;Yes, goto error handling
handle1_1:
                xor     bh,bh           ;reset extension flag
                xor     di,di           ;reset counter
                jmp     short chk_2

test11:         cmp     di,9            ;counter > 9?
                jmp     short handle1

test2:          test    bh,bh           ;extension flag is on?
                jz      test21          ;No, jump
                cmp     di,1            ;counter > 1?
                jbe     handle2_1
                jmp     err_rpt2ext     ;cpd12 p2520 Yes, goto error handling
handle2_1:

                mov     bh,1            ;set extension flag on
                xor     di,di           ;reset counter
                jmp     short chk_2

test21:         cmp     di,9            ;counter > 9?
                jbe     handle2_1
                jmp     err_rpt         ;Yes, goto error handling

chk_2:
                xor     dh,dh           ;set dbcs flag = 0
                mov     cl,al           ;save the current char
                jmp     checking

dbcs_hdl:
                lodsb
                test    al,al           ;Is end of string?
                jz      end_str         ;Yes, jump
                inc     di              ;increment counter
                mov     dh,1            ;set dbcs flag = 1
                mov     cl,al           ;save the current char
                jmp     checking

end_str:
                test    bh,bh           ;extension flag is on?
                jz      test41          ;No, jump
                cmp     di,3            ;counter > 3?

handle4:        lja     err_rpt         ;Yes, goto error handling
                clc                     ;clear carry flag
                jmp     exit_rest

test41:         cmp     di,8            ;counter > 8?
                jmp     short handle4

meta_1:
                test    bl,1            ;Is caller choice=1 or 3?
                jnz     err_rpt2        ;Yes, jump
                mov     dl,1            ;meta = 1
                cmp     version,0A14h   ;*1.2 If 1.2 or above
                jae     new_meta        ;*1.2 use new META rules
                cmp     al,'*'
                jnz     chk_2
                                        ;*1.2 changed order of ext_flag check
                test    bh,bh           ;extension flag is on?
                jnz     meta_2          ;Yes,jump
                cmp     di,8            ;counter > 8?
                ja      err_rpt         ;Yes, jump
                mov     di,8            ;counter = 8
                jmp     short chk_2
meta_2:
                cmp     di,3            ;counter > 3?
                ja      err_rpt         ;Yes, jump
                mov     di,3            ;counter = 3
                jmp     chk_2

new_meta:
                cmp     al,'*'          ;*1.2 got an *
                jnz     meta_question   ;*1.2 no, then a ?

meta_splat:
                test    bh,bh           ;*1.2 extension flag on
                jnz     splat_ext

splat_name:
                cmp     di,8            ;*1.2 check counter
                ja      maybe_ext       ;*1.2 after 8 either invalid or ext
                dec     di              ;*1.2 before 9 * takes no space
                jmp     chk_2           ;*1.2 get next char

maybe_ext:
                cmp     di,9            ;*1.2 is this a pseudo .
                ja      err_rpt         ;*1.2 no, then error
                mov     bh,1            ;*1.2 yes, no on extension
                xor     di,di           ;*1.2 with 0 counter
                jmp     chk_2           ;*1.2 get next char

splat_ext:
                dec     di              ;*1.2 counter = counter -1
                jmp     chk_2           ;*1.2 get next char

meta_question:
                or      bh,bh           ;*1.2 ext or filename?
                jnz     quest_ext       ;*1.2

quest_name:
                cmp     di,9            ;*1.2 if before 9th char ?'s count
                ljb     chk_2           ;*1.2
                dec     di              ;*1.2 after 8th they are null
                jmp     chk_2           ;*1.2

quest_ext:
                cmp     di,4            ;*1.2 if before 4rd char ?'s count
                ljb     chk_2           ;*1.2
                dec     di              ;*1.2 after 3rd they are null
                jmp     chk_2           ;*1.2

err_rpt2ext:
                cmp     al,'.'          ; cpd12 p2520 two dots given
                je      err_rpt         ; cpd12 p2520
err_rpt2:
                cmp     bl,2            ;choice=2 or 3?
                jae     err_rpt23
err_rpt20:
                lodsb
                test    al,al           ;Is end of string?
                jnz     err_rpt22       ;No, jump
err_rpt21:
                mov     ax,ERROR_FILE_NOT_FOUND
                jmp     short err_rpt0

err_rpt22:      call    api_testdbcs    ;Is AL leading byte?
                jc      err_rpt24       ;Yes, jump
                cmp     al,'/'          ;
                jz      err_rpt23
                cmp     al,'\'          ;
                jz      err_rpt23
                jmp     short err_rpt20

err_rpt23:
                mov     ax,ERROR_PATH_NOT_FOUND
                jmp     short err_rpt0

err_rpt24:
                lodsb
                test    al,al           ;Is end of string?
                jz      err_rpt21       ;Yes, jump
                jmp     short err_rpt20

err_rpt:
                mov     ax,ERROR_FILENAME_EXCED_RANGE
                test    dl,dl           ;meta flag = 0?
                jz      err_rpt0        ;Yes, jump
                mov     ax,ERROR_META_EXPANSION_TOO_LONG
err_rpt0:
                stc                     ;set carry flag on
exit_rest:
                pop     dx              ;restore dx
                pop     cx              ;restore cx
                pop     bx              ;restore bx
                pop     di              ;restore di
                pop     si              ;restore si
                ret
name_check      endp

;Name: Tbl_Init
;
; Internal Subroutine to initialize the device table (__api_dev_table)
;       which is defined in D_OPEN.ASM
;
;
;       PsuedoCode:
;
;       handle = 0
;       do
;               issue int21 fn 44 sub fn 0 (get dev parms)
;               if (is valid handle) {
;                       set handle valid in table
;                       if (is device)
;                               set device flag in table
;                               if (is nul device)
;                                       set nul flag in table
;                               if (is conin)
;                                       set conin flag in table
;                               if (is conout)
;                                       set conout flag in table
;               }
;               else
;                       set handle invalid in table
;               increment handle
;       while (handle < MAX_HANDLE)
;       if (handle 3 is device and not nul)
;               set com1 flag
;       if (handle 4 is device and not nul)
;               set lpt1 flag
;
;
;
;
Tbl_Init        PROC    NEAR
                push    ax
                push    bx
                push    cx
                push    dx

                xor     cx,cx                   ; handle = 0

initloop:

                mov     ah,D2_IOCTL
                xor     al,al                           ; AL <- 'get device data' fcn
                mov     bx,cx                           ; BX <- handle
                int     21h                             ; if error return
                cmp     ax,ERROR_INVALID_HANDLE         ; return error
                je      Invalid

ISDev:
                mov     ax,bx                           ; AX <= handle
                call    __api_devtab_ptr                ; BX <- address of entry
                or      cs:[bx].hi_validity,HANDLE_VALID; mark valid

                test    dx,CHAN_IS_DEV                  ; if (is device)
                jz      while                           ; no, loop
                or      cs:[bx].hi_attrdev,DEV_FLAG     ; yes set bit

ISNul:
                test    dx,CHAN_IS_NUL                  ; if (is nul)
                jz      ISConout                        ;@@5590 no, maybe con
                or      cs:[bx].hi_attrdev,NUL_FLAG     ;@@5590  yes, set bit

ISConout:
                test    dx,CHAN_IS_CONOUT               ;@@5590  if (is nul)
                jz      ISConin                         ;@@5590  no, maybe con
                or      cs:[bx].hi_attrdev,CONOUT_FLAG  ;@@5590  yes, set bit

ISConin:
                test    dx,CHAN_IS_CONIN                ;@@5590  if (is con)
                jz      while                           ;@@5590  no, loop
                or      cs:[bx].hi_attrdev,CONIN_FLAG   ;@@5590  yes, set bit
                jmp     while                           ;@@5590  loop
Invalid:

                mov     ax,bx                           ; AX <= handle
                call    __api_devtab_ptr                ; BX <- address of entry
                and     cs:[bx].hi_validity,0           ; mark invalid

while:
                inc     cx                              ; next handle
                cmp     cx,MAX_HANDLES                  ; too far ?
                jb      InitLoop                        ; no , loop

; This code will test to see if handle 3 is not NUL and is a DEVICE.
; If so we assume AUX and set COM_FLAG and UNIT = 1

                mov     ax,3                        ;@@5590 handle = 3
                call    __api_devtab_ptr            ;@@5590 get pointer
                test    cs:[bx].hi_attrdev,DEV_FLAG ;@@5590 is it a device?
                jz      testlpt                     ;@@5590 no, next test
                test    cs:[bx].hi_attrdev,NUL_FLAG ;@@5590 is it a nul device
                jnz     testlpt                     ;@@5590 yes, next test
                                                    ;@@5590 ASSUME COM1
                or      cs:[bx].hi_attrdev,(COM_FLAG)
                and     cs:[bx].hi_attrdev,(NOT UNIT_FLAG)

; This code will test to see if handle 4 is not NUL and is a DEVICE.
; If so we assume LPT1 and set LPT_FLAG and UNIT = 1
Testlpt:
                mov     ax,4                        ;@@5590 handle = 4
                call    __api_devtab_ptr            ;@@5590 get pointer
                test    cs:[bx].hi_attrdev,DEV_FLAG ;@@5590 is it a device?
                jz      tblexit                     ;@@5590 no, next test
                test    cs:[bx].hi_attrdev,NUL_FLAG ;@@5590 is it a nul device
                jnz     tblexit                     ;@@5590 yes, next test
                                                    ;@@5590 ASSUME LPT1
                or      cs:[bx].hi_attrdev,(LPT_FLAG)
                and     cs:[bx].hi_attrdev,(NOT UNIT_FLAG)

Tblexit:
                pop     dx
                pop     cx
                pop     bx
                pop     ax
                ret
Tbl_Init        ENDP


;**     api_ctrlbreak_off - Set KBD Ctrl-Break check state off     ; @@
;                                                                  ; @@
;       void api_ctrlbreak_off();                                  ; @@
;                                                                  ; @@
;       Routine to get current ctrl-break check state,             ; @@
;       save it, and turn check state off.                         ; @@
;                                                                  ; @@
;       ENTRY   none                                               ; @@
;                                                                  ; @@
;       EXIT    none                                               ; @@
;                                                                  ; @@
;       USES    Flags                                              ; @@
;                                                                  ; @@
;       NOTES                                                      ; @@
                                                                   ; @@
__api_ctrlbreak_state     db      0                                ; @@
                                                                   ; @@
        public  api_ctrlbreak_off                                  ; @@
                                                                   ; @@
api_ctrlbreak_off       proc    near                               ; @@
                                                                   ; @@
; GET AND SET CTRL-BREAK STATE                                     ; @@
                                                                   ; @@
        push    ax                                                 ; @@
        push    dx                                                 ; @@
        xor     al,al           ; al = get call                    ; @@
        mov     ah,D2_ChkCC     ; get ctrl-break state             ; @@
        int     21h             ;                                  ; @@
        mov     __api_ctrlbreak_state, dl ; save ctrl-break state  ; @@
        inc     al              ; set ctrl-break state             ; @@
        xor     dl,dl           ; to OFF                           ; @@
        int     21h             ;                                  ; @@
        pop     dx                                                 ; @@
        pop     ax                                                 ; @@
        ret                                                        ; @@
                                                                   ; @@
api_ctrlbreak_off      endp                                        ; @@



;**     api_ctrlbreak_reset - Reset KBD Ctrl-Break check state     ; @@
;                                                                  ; @@
;       void api_ctrlbreak_reset();                                ; @@
;                                                                  ; @@
;       Routine to reset ctrl-break check state to previously      ; @@
;       saved state.                                               ; @@
;                                                                  ; @@
;       ENTRY   none                                               ; @@
;                                                                  ; @@
;       EXIT    none                                               ; @@
;                                                                  ; @@
;       USES    Flags                                              ; @@
;                                                                  ; @@
;       NOTES:                                                     ; @@
;                                                                  ; @@
;   *** api_ctrlbreak_off must always be called first ***          ; @@
;   *** or else __api_ctrlbreak_state may be invalid! ***          ; @@
                                                                   ; @@
        public  api_ctrlbreak_reset                                ; @@
                                                                   ; @@
api_ctrlbreak_reset    proc    near                                ; @@
                                                                   ; @@
; RESTORE ORIGINAL CTRL-BREAK STATE                                ; @@
                                                                   ; @@
        push    ax                                                 ; @@
        push    dx                                                 ; @@
        mov     dl, __api_ctrlbreak_state ; get saved state        ; @@
        mov     al,1            ; al = set call                    ; @@
        mov     ah,D2_ChkCC     ; reset ctrl-break check state     ; @@
        int     21h             ;                                  ; @@
        pop     dx                                                 ; @@
        pop     ax                                                 ; @@
        ret                                                        ; @@
                                                                   ; @@
api_ctrlbreak_reset    endp                                        ; @@

_TEXT   ends


SIGCHECK        segment byte common 'CODE'

        public  SignalCheck

; Top-call is used by the generic fapi routine interface to
; maintain knowledge of which call is highest in the dynamic scope
; relative to FAPI routines.  Each fapi routine which adheres to the
; rule (of calling the generic push/pop/check interface routine) will,
; through the routines __api_begin and __api_end, proceed as follows;
;
;       push registers
;       increment TopCall
;
;       (work)
;
;       decrement TopCall
;       call SignalCheck
;       pop registers
;
; In this way we may conclude that signal-check may execute the user's
; signal handler only when TopCall is zero.
;
;

TopCall dw      0
temp    dw      0                               ; for return address


; SignalCheck is a noop unless d_sig.asm is included in the link.  Since
; we have no clean way to force the order of the link (i.e. to force
; i_versio.obj to be seen first so that d_sig.obj, if needed, overlays
; it), we use the following method of segment overlay.  In this case,
; no matter which, d_sig.obj OR i_versio.obj, is loaded first, the
; correct code will be generated.

SHORT_JMP_OP    equ     0EBh

SignalCheck     proc    near

        db      SHORT_JMP_OP
        db      1 dup (?)
        ret

SignalCheck     endp

SIGCHECK        ends

        end

