;       SCCSID = @(#)demutil.asm        6.2 92/02/06
;               aka  util.asm
TITLE   UTIL - Handle utilities

; Handle related utilities for MSDOS 2.X.
;
;   pJFNFromHandle  written
;   VSFNFromHandle
;   SFFromHandle    written
;   SFFromSFN       written
;   JFNFree         written
;   SFNFree         written
;   SFNFromHandle
;
;   Modification history:
;
;       Created: MZ 1 April 1983
;       Modified for MVDM: danno 17-Feb-1989
;
;       REVISIONS
;Local  DCR/PTR
;Tag    PTR            Who          When          What
;                      danno        31-Jan-1989   Created for MVDM
; 56006 cmvc 56006     Rick Giroux  14 Dec 92     Added glf_SFFromSFN, per r206
;

.xlist
;
; get the appropriate segment definitions
;
include v86seg.inc

.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include devsym.inc
include pdb.inc
include error.inc
include dos3dev.inc
include struc30.inc                     ; 56006, as is
include mvdmexp.inc                     ; 56006, as is
include demsvc.inc                      ; 56006, chgd also
.cref
.list
.sall
        CpuMode 286

        I_need  CurrentPDB,WORD         ; current process data block location
        I_Need  PROC_ID,WORD            ; current process ID
        I_Need  USER_ID,WORD            ; current user ID
        I_Need  RMDevHandleInfo,rmdi

V86LoL  SEGMENT
        EXTRN   SFT_Addr: Dword
V86LoL  ENDS

V86CODE SEGMENT
        ASSUME  CS:V86GROUP,ES:NOTHING,DS:NOTHING,SS:NOTHING


BREAK   <pJFNFromHandle - return pointer to JFN table entry>

;
;   pJFNFromHandle - Given a handle, return the pointer to the JFN location
;       in the user's data space
;   Inputs:     BX - Handle
;   Outputs:    Carry Set
;                   AX has error code
;               Carry reset
;                   ES:DI point to the handle spot
;   Registers modified:
;               If no error, ES:DI, else AX,ES
; NOTE:
;   This routine is called from $CREATE_PROCESS_DATA_BLOCK which is called
;       at DOSINIT time with SS NOT V86GROUP

Procedure pJFNFromHandle,NEAR
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        MOV     ES,[CurrentPDB]         ; get user process data block
        CMP     BX,ES:[PDB_JFN_Length]  ; is handle greater than allocated
        JB      JFNAdd                  ; no, get offset
        MOV     AX,ERROR_INVALID_HANDLE ; appropriate error
ReturnCarry:
        STC                             ; signal error
        RET                             ; go back

JFNAdd: LES     DI,ES:[PDB_JFN_Pointer] ; get pointer to beginning of table
        ADD     DI,BX                   ; add in offset
ReturnNoCarry:
        CLC                             ; no holes
        RET                             ; bye!
EndProc   pJFNFromHandle

BREAK <VSFNFromHandle - Return VSFN from the given handle>

;
; VSFNFromHandle - Return VSFN from the given handle
;
;   Input:      BX has handle
;   Output:     Carry Set
;                   AX has error code
;               Carry Reset
;                   BX has VSFN
;   Registers modified: If error, AX, else BX
;
;   This is added for MVDM, since we could have a VSFN, without an
;   associated RMDI (aka SF) entry.  This is the case for OS/2 files
;   and devices.
;
Procedure VSFNFromHandle,NEAR
        SaveReg <es,di>
        call    pJFNFromHandle
        jc      short vsfh1
        push    ax
        mov     al,es:[di]
        cmp     al,-1               ; Invalid VSFN ?
        je      short vsfh2
        xor     bh,bh
        mov     bl,al
        pop     ax
vsfh1:  RestoreReg <di,es>
        ret

vsfh2:  pop     ax
        mov     ax,ERROR_INVALID_HANDLE
        stc
        jmp     vsfh1
EndProc   VSFNFromHandle


BREAK <SFFromHandle - return pointer (or error) to RMDI entry from handle>

;
; SFFromHandle - Given a handle, get JFN and then index into RMDI table
;
;   Input:      BX has handle
;   Output:     Carry Set
;                   AX has error code
;               Carry Reset
;                   ES:DI has pointer to SF entry
;   Registers modified: If error, AX,ES, else ES:DI
; NOTE:
;   This routine is called from $CREATE_PROCESS_DATA_BLOCK which is called
;       at DOSINIT time with SS NOT V86GROUP
procedure   SFFromHandle,NEAR
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        CALL    pJFNFromHandle          ; get jfn pointer
        retc                            ; return if error
        CMP     BYTE PTR ES:[DI],-1     ; unused handle
        JNZ     GetSF                   ; nope, suck out SF
        MOV     AX,ERROR_INVALID_HANDLE ; appropriate error
        jmp     ReturnCarry             ; signal it
GetSF:
        SaveReg <BX>                    ; save handle
        MOV     BL,BYTE PTR ES:[DI]     ; get SFN
        XOR     BH,BH                   ; ignore upper half
        CALL    SFFromSFN               ; get real sf spot
        RestoreReg  <BX>                ; restore
        ret                             ; say goodbye
EndProc SFFromHandle


BREAK <SFFromSFN - index into RMDI table for SFN>

;
; SFFromSFN - index into RMDI tables for SFN.
;
;   Input:      BX has SF index
;   Output:     ES:DI points to SF entry
;   Registers modified: ES:DI only
; NOTE:
;   This routine is called from SFFromHandle which is called
;       at DOSINIT time with SS NOT V86GROUP

Procedure SFFromSFN,NEAR
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        push    cs
        pop     es
        mov     di,offset V86GROUP:RMDevHandleInfo
        cmp     bl,VSFN_DEV             ; is handle in the table ?
        jb      sfs20                   ; no, exit (carry already set)
ifdef DEMSTRICT
        or      bh,bh
        jnz     sfs20                   ; exit if not
endif
        push    bx
        sub     bl,VSFN_DEV             ; get RMDI index
        shl     bx,3
        .errnz  (size rmdi) - (1 SHL 3) ; make sure following SHL is correct
        add     di,bx                   ; offset by size
        pop     bx
sfs10:  ret

sfs20:  stc
        mov     ax,ERROR_INVALID_HANDLE
        jmp     sfs10
EndProc   SFFromSFN

Procedure glf_SFFromSFN,NEAR            ; 56006
        assume  cs:V86GROUP,ds:nothing,es:nothing,ss:nothing
        push    bx
        .if     <BX eq 0FFh>
          mov     ax,ERROR_INVALID_HANDLE
          stc
        .else
          .if     <BX ae VSFN_DEV>
            push    cs
            pop     es
            sub     bl,VSFN_DEV         ; get RMDI index
            shl     bx,3
            .errnz  (size rmdi) - (1 SHL 3) ;make sure following SHL is correct
            add     di,bx               ; offset by size
            mov     bx,word ptr es:[di].rmdi_devPtr+2
            .if     <<word ptr es:[di].rmdi_devPtr> ne -1>
              stc
              mov     ax,ERROR_INVALID_HANDLE
              pop     bx
              ret
            .endif
          .endif
          LES     DI,cs:[SFT_Addr]      ; (es:di) = start of SFT table
          SVC     SVC_DEMGETSFT
        .endif
        pop     bx
        ret
EndProc glf_SFFromSFN                   ; 56006

BREAK <JFNFree - return a jfn pointer if one is free>

;
; JFNFree - scan through the JFN table and return a pointer to a free slot
;
;   Input:  None.
;   Output: Carry Set
;               AX has error code, BX,ES,DI garbage
;           Carry Reset
;               BX has new handle, ES:DI is pointer to JFN slot
;   Registers modified: As above only.

Procedure JFNFree,NEAR
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING
        XOR     BX,BX                   ; try starting low
JFNScan:
        CALL    pJFNFromHandle          ; get the appropriate handle
        JC      JFNNone                 ; no more handles
        CMP     BYTE PTR ES:[DI],-1     ; free?
        JZ      JFNFound                ; yes, carry is clear
        INC     BX                      ; no, next handle
        JMP     JFNScan                 ; and try again
JFNNone:
        MOV     AX,ERROR_TOO_MANY_OPEN_FILES
JFNFound:
        RET                             ; bye
EndProc   JFNFree

V86CODE ENDS

        END
