;       SCCSID = @(#)demutil.asm        6.2 92/02/06

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
;

.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
include mvdmexp.inc
include demsvc.inc
.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
        .if     <BX ae <ES:[PDB_JFN_Length]>>  ; is handle greater than allocated
                                               ; no, get offset
          mov     ax,ERROR_INVALID_HANDLE ; appropriate error
          STC                             ; signal error
          RET                             ; go back
        .endif
        LES     DI,ES:[PDB_JFN_Pointer] ; get pointer to beginning of table
        ADD     DI,BX                   ; add in offset
        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
        push    es
        push    di
        call    pJFNFromHandle
        .if     nc
          push    ax
          mov     al,es:[di]
          .if     <al eq -1>              ; Invalid VSFN ?
            pop     ax
            mov     ax,ERROR_INVALID_HANDLE
            stc
          .else
            xor     bh,bh
            mov     bl,al
            pop     ax
          .endif
        .endif
        pop     di
        pop     es
        ret

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
        .if     <<BYTE PTR ES:[DI]> eq -1>    ; unused handle
                                              ; nope, suck out SF
          mov     ax,ERROR_INVALID_HANDLE ; appropriate error
          stc                             ; signal error
          ret                             ; go back
        .endif
        push    bx                      ; save handle
        MOV     BL,BYTE PTR ES:[DI]     ; get SFN
        XOR     BH,BH                   ; ignore upper half
        CALL    SFFromSFN               ; get real sf spot
        pop     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
        .if     <bx b VSFN_DEV>         ; is handle in the table ?
          stc
          mov     ax,ERROR_INVALID_HANDLE
        .else
          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
        .endif
        ret
EndProc   SFFromSFN


Procedure glf_SFFromSFN,NEAR
        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


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
        .repeat
          CALL    pJFNFromHandle        ; get the appropriate handle
          .leave  c                     ; no more handles
          CMP     BYTE PTR ES:[DI],-1   ; free?
          JZ      JFNFound              ; yes, carry is clear
          inc     bx                    ; no, next handle
        .until                          ; and try again
        mov     ax,ERROR_TOO_MANY_OPEN_FILES
JFNFound:
        ret
EndProc   JFNFree

V86CODE ENDS

        END
