        page    ,132
        title   File -

;   Revisions:
;
;Local  DCR/
;Tag    PTM(R)  Who     When/What
;               danno   11-Jan-1989
;                       Created for MVDM
;
;***********************************************************************;BN001;
;  15May91 - G.L.Fulk                                                   ;BN001;
;  Int 21h, function 5700h, returns a date and time of 0:0 for a handle ;BN001;
;  open to a DOS device driver.  I've changed this call to return the   ;BN001;
;  current date and time if the handle is a DOS device.                 ;BN001;
;***********************************************************************;BN001;
;  17May91 - G.L.Fulk                                                   ;BN002;
;  Int 21h, function 60h, translates an asciiz string at DS:SI to a     ;BN002;
;  fully-qualified asciiz string at ES:DI, returning in ES:DI the true  ;BN002;
;  name of the file.  OS/2 2.0 file system returns a device as          ;BN002;
;  "\DEV\CON".  This is done by TransPath2 in filesys\macro.asm.        ;BN002;
;  Unfortunately, DOS 3.3 4.0 and 5.0 all have a different way of       ;BN002;
;  returning this value, "A:/CON".  I've made a change here to match    ;BN002;
;  DOS.                                                                 ;BN002;
;                                                                       ;BN002;
;  Also, I am introducing the use of the STRUC30.INC structured macros  ;BN002;
;  to this file.                                                        ;BN002;
;                                                                       ;BN002;
;***********************************************************************;BN002;
;                                                                       ;BN003;
;  B003  10/18/91  CP20 AA03990  Mark Rogalski                          ;BN003;
;        DOS apps may try to open devices by calling INT 21 func 3c     ;BN003;
;        which is create. We need to be able to handle this.            ;BN003;
;        Add code to $create to check for OS/2 devices. Also, I noticed ;BN003;
;        a bug in $open - the device handle needs to be put in BX       ;BN003;
;        before DemClose is called.                                     ;BN003;
;***********************************************************************;BN003;
;                                                                       ;BN004;
;  B004  01/05/92  CP20 AZ09066  Mark Rogalski                          ;BN004;
;        It's possible for OS/2 to return a file handle greater than    ;BN004;
;        what DEM can handle (since it has an arbitrary limit of D0h    ;BN004;
;        (the split point between OS/2 file and device handles).        ;BN004;
;        Therefore, after doing an DEMOPEN, check to make sure the      ;BN004;
;        file handle is within range, else close the handle.            ;BN004;
;***********************************************************************;BN004;
;                                                                       ;BN005;
;  B005  01/14/92  CP20 B731539  Mark Rogalski                          ;BN005;
;        In the above fix I called the check_limit routine after        ;BN005;
;        a handle may have been converted to a device handle. The       ;BN005;
;        routine needs to be called immediately after the SVC_DEMOPEN.  ;BN005;
;***********************************************************************;BN005;
;  24Jan92 - G.L.Fulk                                                   ;BN006;
;  Change the number_of_SFTs variable when performing an int 21, ah=67  ;BN006;
;***********************************************************************;BN006;
;  12Feb92 - G.L.Fulk                                                   ;BN007;
;  MicroSoft Windows "File Manager" has a brain-dead bug.  It looks at  ;BN007;
;  AX following a Get File Mode 43h.  It should look at CX.  We'll also ;BN007;
;  send the results back in AX and CX.  Stupid app!                     ;BN007;
;***********************************************************************;BN007;
;  20Feb92 - G.L.Fulk                                                   ;BN008;
; Forced handle duplicate (46h, $DUP) fails if the new handle (CX)      ;BN008;
; does not exist.                                                       ;BN008;
;***********************************************************************;BN008;
;  10Aug92 - G.L.Fulk                                                   ;BN009;
;  Make $DUP and $DUP2 callable from within V86INIT.                    ;BN009;
;***********************************************************************;BN009;
;  08Oct92 - G.L.Fulk                                                   ;BN010;
; Since CDS structures aren't supported yet, comment out the code.      ;BN010;
;***********************************************************************;BN010;
;  29Jul93 - J.M.Hare    defect 71358                                   ;BN040;
; Add propogating of DOSFLAG through files system for exec_only test.   ;BN040;
;***********************************************************************;BN040;
;  13Sept93 - ChangeTeam defect 73751                                   ;73751;
;   Added check to see if Windows made the Int21 call for $UNLINK       ;73751;
;       We need to know this because Windows 3.1 converts the addr of   ;73751;
;       the environment variable from segment to selector - demDelete   ;73751;
;       needs to know if this conversion has occured.                   ;73751;
;***********************************************************************;75460;
;  11Dec93 - B.Clare (changeteam defect 75460)                          ;75460;
;  Added wildcard handling to $unlink so that when called from $srv_call;75460;
;  wildcard deletes are allowed. This makes function 41h calls generated;75460;
;  from function 5D00h calls compatible with DOS.                       ;75460;
;***********************************************************************;75460;
;  16Dec93 - B.Clare (changeteam defect 75460)                          ;75460;
;  Moved wildcard handling to separate subroutine to allow for future   ;75460;
;  re-use.                                                              ;75460;
;***********************************************************************;74297;
;  16Dec93  - ChangeTeam defect 74297                                   ;74297;
;  Changed $Open to check for filenames beginning with "/dev/" and      ;74297;
;  change them to "\dev\", so they will be recognized as DOS devices.   ;74297;
;***********************************************************************;90667;
;  01Aug94  - JMH        defect 90667                                   ;90667;
;  Changed 75460 jumps to use short modifier to remove warning messages ;90667;
;  generated by masm -w2.                                               ;90667;
;***********************************************************************;147399;
;  10Jan96  - ChangeTeam defect 147399                                  ;147399;
;  Changed $Unlink to return with an access denied error if trying to   ;147399;
;  delete a device.                                                     ;147399;
;***********************************************************************;147399;


.xlist
include v86seg.inc
.xcref
include basemaca.inc
include osmaca.inc
include oldmaca.inc
include demmac.inc
include dossymc.inc
include filemode.inc
include opncreat.inc
include error.inc
include mi.inc
include mvdmexp.inc
include demsvc.inc
include dirent.inc
include pdb.inc
include demdbcs.inc
include devhdr.inc
include dos3dev.inc
include syscalls.inc
include extattr.inc
include struc30.inc
include demcd.inc
.cref
.list
        CpuMode 386

        ReferV86    ConSwap,BYTE
        ReferV86    ConSFT,DWORD
        ReferV86    CurrentPDB,WORD
        ReferV86    Temp_Var,WORD
        ReferV86    ExtErr_Locus,BYTE
        ReferV86    ExtErr,WORD
        ReferV86    User_In_AX,WORD        ; initial input user AX   ;75460;BClare
        ReferV86    SrvCallEntFLG,BYTE                               ;75460;BClare
        ReferV86    DMAADD,DWORD                                     ;75460;BClare

V86LoL  SEGMENT
        EXTRN   CDSADDR: Dword
V86LoL  ENDS

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

        EXTRN   JFNFree:NEAR
        EXTRN   RMDevCheckName:NEAR
        EXTRN   RMDevAllocDI:NEAR
        EXTRN   pJFNFromHandle:NEAR
        EXTRN   Sys_Ret_OK:NEAR
        EXTRN   Sys_Ret_Err:NEAR
        EXTRN   Sys_Return:NEAR
        EXTRN   RMDevWrite:NEAR
        EXTRN   VSFNFromHandle:NEAR
        EXTRN   RMDevRead:NEAR
        EXTRN   Get_User_Stack:NEAR
        EXTRN   SFFromSFN:NEAR
        EXTRN   RMDevCloseDI:NEAR
        EXTRN   RMDevOpen:NEAR
        EXTRN   RMDevClose:NEAR
        EXTRN   $Alloc:NEAR
        EXTRN   $Dealloc:NEAR
        EXTRN   RMDevCheck:NEAR
        EXTRN   RMDevXFlags:NEAR
        EXTRN   $GET_DATE:NEAR                                          ;BN001;
        EXTRN   $GET_TIME:NEAR                                          ;BN001;
        EXTRN   $GET_VERSION:NEAR                                       ;BN002;
        EXTRN   $CLOSE:near
        EXTRN   $Set_DMA:NEAR                                           ;75460;
        EXTRN   $Find_First:NEAR                                        ;75460;
        EXTRN   $Find_Next:NEAR                                         ;75460;
        EXTRN   $NameTrans:NEAR                                         ;75460;

sTempPath       DB      128 dup (?)     ;Filespec to be deleted. This   ;75460
                                        ;is local to SrvCallHandler, but;75460
                                        ;it would eat stack space if    ;75460
                                        ;declared as LocalVar there.    ;75460

SaveWINOS2Check DW      0               ;Saves ret val from INT 2F,160Ah;75460

;***LP  Set_EA_Field - Check if the current PDB process is EA aware.
;       In any casr update the TCB field to let the kernel proper know
;       EA awareness.
;
;       ENTRY
;           None
;
;       EXIT
;           None (TCB field set if EA aware PDB)
;
;       USES
;           None
;
Procedure Set_EA_Field,NEAR

        push    ds
        push    ax

        xor     ax,ax                   ; by default PDB not EA aware
        mov     ds,[CurrentPDB]
        test    word ptr ds:[PDB_flags],EKNOWEAS   ;<BIT and >
        .if     nz
          inc     ax                    ; Yes, PDB is EA Aware
        .endif
        SVC     SVC_DEMSETEAFIELD       ; Set the TCB field

        pop     ax
        pop     ds

        ret

EndProc   Set_EA_Field

subttl  $UNLINK - delete a file entry
page
;
;INT 21h (AH=41h) $Unlink               v86code\dempath.asm        #1/3
;INT 21h (AH=41h) [SVC]demDelete        mvdm\dempath2.asm          #2/3
;INT 21h (AH=41h) w_Unlink              filesys\file.asm           #3/3
;
;   Assembler usage:
;           LDS     DX, name
;           IF VIA SERVER DOS CALL
;            MOV     CX,SEARCH_ATTRIB
;           MOV     AH, Unlink
;           INT     21h
;
;   Error returns:
;           AX = error_file_not_found
;              = error_access_denied
;
;   Expanded logic to handle Wildcard deletes from Server Call           ;75460;
;   (INT 21 function 5D00 h). Change Team (BClare) 12-04-93.             ;75460;
;   Pseudocode:                                                          ;75460;
;       Save Registers that INT 2Fh trashes.                             ;75460;
;       If trying to delete a device                                     ;147399;
;           Cleanup Stack                                                ;147399;
;           return with access denied error                              ;147399;
;       Run INT  2F to check if Windows is active                        ;75460;
;       If called from server function ( SrvCallEntFlg=TRUE )            ;75460;
;           push registers for use by SrvCallHandler                     ;75460;
;           call SrvCallHandler                                          ;75460;
;                                                                        ;75460;
;       ELSE                                                             ;75460;
;           Delete File                                                  ;75460;
;       ENDIF                                                            ;75460;
;       Cleanup Stack                                                    ;75460;
;       Exit                                                             ;75460;
;
Procedure $Unlink
        push    es
        push    ds                      ;Save regs before INT 2f trasshes;75460
        push    cx                                                       ;75460
        push    dx                                                       ;75460
        call    RMdevCheckName                                           ;147399
        .if nc                                                           ;147399
          pop     dx                                                     ;147399
          pop     cx                                                     ;147399
          pop     ds                                                     ;147399
          pop     es                                                     ;147399
          mov     ax,ERROR_ACCESS_DENIED                                 ;147399
          jmp     Sys_Ret_Err                                            ;147399
        .endif                                                           ;147399

        mov     es,[CurrentPDB]
        mov     es,es:[PDB_environ]     ;es:=CurrentPDB[002Ch]
                                        ;
        mov     ax,160Ah                ;73751 determine if Win-OS/2
        int     2Fh                     ;73751  is currently running
                                        ;73751  demDelete needs this info
                                        ;73751  Retns AX=0 if Windows running
                                        ;73751  Trashes AX,BX,CX

        cmp     SrvCallEntFlg,FALSE                                      ;75460;
        jz      short Not_ServCall                                       ;75460;
; We have entered $unlink from SRV_CALL ( in srvcall.asm )               ;75460;
; copy path in DS:DX to sTempPath.  This allows us to perform            ;75460;
; FindFirst/FindNext searches without destroying original search string. ;75460;
        pop     dx                                                       ;75460;
        pop     cx                                                       ;75460;
        pop     ds                                                       ;75460;
        mov     CS:[SaveWINOS2Check], AX                                 ;75460;
        call    SrvCallHandler                                           ;75460;
        jmp     short Unlink_Exit                                        ;75460;
Not_ServCall:   SVC     SVC_DEMDELETE   ; do delete for non-servercall
                pop     dx                                               ;75460;
                pop     cx                                               ;75460;
                pop     ds                                               ;75460;
Unlink_Exit:    pop     es
                jmp     Sys_Return
EndProc   $Unlink


subttl  $RENAME - move directory entries around
page
;
;INT 21h (AH=56h) $Rename               v86code\dempath.asm        #1/3
;INT 21h (AH=56h) [SVC]demRename        mvdm\dempath2.asm          #2/3
;INT 21h (AH=56h) w_Rename              filesys\file.asm           #3/3
;
;   Assembler usage:
;           LDS     DX, source
;           LES     DI, dest
;           IF VIA SERVER DOS CALL
;            MOV     CX,SEARCH_ATTRIB
;           MOV     AH, Rename
;           INT     21h
;
;   Error returns:
;           AX = error_file_not_found
;              = error_not_same_device
;              = error_access_denied

Procedure $Rename
        SVC     SVC_DEMRENAME
        jmp     Sys_Return
EndProc   $Rename


;***LP  $Open - open a file.  Int21 interlude to DemOpen
;***    $OpenExtended - allow the full range of OS/2 open modes
;***LP  $Open_Exec_Only - open a file for execution  Int21 interlude to DemOpen exec_only BN040
;
;       ENTRY
;           DS:DX
;               pointer to ASCIIZ name
;           AL ($OPEN)
;               open mode
;           BH (exec_only from loader)       ; exec_only BN040
;               open mode                    ; exec_only BN040
;           CX ($OpenExtended)
;               open mode
;
;       EXIT
;           SUCCESS
;               User_Flags.CY = 0
;               User_AX = handle
;           FAILURE
;               User_Flags.CY = 1
;               User_AX = error code
;
;       CONTEXT
;           Executes in V86 mode
;
;       STEPS
;           hFile = JFNFree
;           if handle available -->
;               dev = RMDevCheckName
;               if OS2 Device -->
;                   SFN2 = DemOpen
;                   if device -->
;                       SFN = RMDevAllocDI(SFN2)
;                   else -->
;                       SFN = SFN2
;               else -->
;                   SFN = RMDevAllocDI(dev)
;                   DI.ptr = dev
;               DemSetHandle(hFile, SFN)
;
;       NOTES
;           None
;
;       WARNINGS
;           None
;
;       CALLS
;           DemOpen (SVC)
;           DemClose (SVC)
;           Sys_Ret_OK
;           Sys_Ret_Err
;           JFNFree
;           pJFNFromHandle
;           RMDevAllocDI
;           RMDevCheckName
;
;       USES
;           AX,BX,CX,DX,SI,DI,ES,DS
;

Procedure $OpenExtended,NEAR

LocalVar  pszSpec,DWORD
LocalVar  uMode,WORD
LocalVar  hFile,WORD
LocalVar  execonly,WORD                 ; DOSflag     exec_only BN040
LocalVar  opx_execdw,DWORD              ; work varb   exec_only BN040

        mov     BL,1                    ; set for not exec_only BN040
        mov     ax,cx                   ; Allow extended open mode
        jmp     short opn1

Entry   $Open_Exec_Only
        mov     BL,2                    ; set for     exec_only BN040
        jmp     short opn0              ; exec_only BN040

Entry   $Open
        mov     BL,3                    ; set for not exec_only BN040
        push    si                      ;                                74297
        mov     si,dx                   ;                                74297
        cmp     dword ptr ds:[si],'ved/'; Does name begin "/dev"?        74297
        jne     short opn00             ;                                74297
        cmp     byte ptr ds:[si+4],'/'  ; Does name begin "/dev/"?       74297
        jne     short opn00             ;   No, continue.                74297
        mov     byte ptr ds:[si],'\'    ;   Yes, change the slashes.     74297
        mov     byte ptr ds:[si+4],'\'  ;                                74297
opn00:  pop     si                      ;                                74297

opn0:   test    al, open_monitor
        jnz     opn13                   ; Exit if prot-mode flag
        xor     ah,ah                   ; dis-allow extended modes

        call    Set_EA_Field            ; Set the TCBNewFlags be set for EAs

opn1:   EnterProc

        cmp    bl,2                     ; if this was from $open_exec_only    exec_only BN040
        jz     short opn1a              ; then go to preserve open_mode flag  exec_only BN040

; assume $OpenExtended or $Open was called      exec_only BN040

        xor     BH,BH                   ; exec_only BN040
        and     BH, not EXECOPEN        ; exec_only BN040

opn1a:  mov     byte ptr execonly,BH    ; exec_only BN040
        xor     BX,BX                   ; exec_only BN040


        mov     uMode,ax                ; Save the mode for later
        mov     pszSpec.loword,dx
        mov     pszSpec.hiword,ds
        call    JFNFree                 ; Find a free handle  bx returned
        jc      short opn9              ; Exit if none available
        mov     hFile,bx                ; Save the handle

opn2:   lds     dx,pszSpec
        call    RMDevCheckName          ; See if it's a DOS device
        jnc     short OpenDev           ; Skip if a DOS device
        mov     si,dx                   ; ds:si = filespec
        mov     bx,uMode                ; Get mode
        mov     cx,0                    ; Attributes don't matter
        mov     dx,exist_open+nexist_fail   ; OPEN, fail if does not exist
        xor     ax,ax
        mov     es,ax                   ; No EA's
        mov     di,ax

;------ initialize Exec_only flag from the loader     exec_only BN040

        push    edx                        ; 112811
        xor     edx,edx                    ; zero temp reg                    exec_only BN040
        mov     opx_execdw,edx             ; zero save area                   exec_only BN040
        mov     dh,byte ptr execonly       ; get DOSFLAG in dh                exec_only BN040
        mov     word ptr opx_execdw+1,dx   ; save dx in hi word               exec_only BN040
        mov     edx,opx_execdw             ; restore edx with edl as DOSFLAG  exec_only BN040
        mov     dx,exist_open+nexist_fail  ; OPEN, fail if does not exist     exec_only BN040

        SVC     SVC_DEMOPEN             ; Open the OS/2 file/device
        pop     edx                     ; 112811
        jc      short opn9              ; exit if error

;       AX = TRUE JFN = VSFN (e.g. 1..234)

        call    check_limit             ;BN004 check handle limit
        jc      short opn9              ;BN004 if over limit error exit

        test    bx,RMDI_DEVICE
        jz      short opn5              ; skip if not a device
        mov     es,ax                   ; Real handle to ES
        mov     ax,bx                   ; flags to AX
        mov     bx,-1                   ; Flag as an OS/2 device
        jmp     short opn4              ; Jump to common device code

Entry   OpenDev
        mov     ax,es:[bx].SDevAtt      ; Get device attributes
        call    RMDevXFlags             ; Translate to RMDI flags
        call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
        jc      short opn9              ; Exit if none available
        mov     bx,ax
        SaveReg <ax>
        call    SFFromSFN               ; ES:DI points there
        dec     es:[di].rmdi_refcnt     ; Remove extra reference
        call    RMDevOpen               ; Open it
        RestoreReg <ax>
        jc      short opn10             ; Exit if cannot open
        jmp     short opn5
;
; This is a device.
;   DOS device - ES:BX points to device header, ax=rmdi_flags
;   OS2 device - BX = -1, ES=fake SFN, AX=rmdi_flags
;
opn4:   call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
        jc      short opn10             ; exit if none available

;       AX = V86 SFN (e.g. 235..254)

opn5:   mov     bx,hFile                ; Get the handle
        call    pJFNFromHandle
        mov     es:[di],al              ; Store the VSFN in the JFT
        mov     ax,bx                   ; Get the fake handle in AX
        LeaveProc NoCheck
        jmp     Sys_Ret_OK

opn9:   LeaveProc NoCheck               ; Return error to the app
        jmp     Sys_Ret_Err

opn10:  push    ax                      ; Save the error code
        cmp     bx,-1                   ; OS2 Device?
        jne     short opn12             ; Skip if not
        mov     bx,es                   ; restore os/2 JFN for close   ;BN003
        SVC     SVC_DEMCLOSE            ; Close the OS2 device
opn11:  pop     ax
        jmp     opn9                    ; error exit

opn12:  call    RMDevClose              ; Close the real-mode device
        jmp     opn11

opn13:  mov     ax,ERROR_INVALID_ACCESS
        jmp     Sys_Ret_Err
EndProc   $OpenExtended

BREAK <$CHMOD - change file attributes>
;
;   Assembler usage:
;           LDS     DX, name
;           MOV     CX, attributes
;           MOV     AL,func (0=get, 1=set)
;           INT     21h
;   Error returns:
;           AX = error_path_not_found
;           AX = error_access_denied
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $CHMOD,NEAR
        push    ax
        push    cx
        call    RMDevCheckName          ; V86 Device?
        pop     cx
        pop     ax
        .if     c                       ; can't CHMOD a device
          SVC     SVC_DEMCHMOD
          jc      short chm2
          call    get_user_stack
          mov     ax,cx                                                 ;BN007;
          mov     [si].User_CX,cx
          jmp     Sys_Ret_OK
        .endif
        mov     ax,ERROR_FILE_NOT_FOUND
        mov     EXTERR_LOCUS,errLoc_Unk ; extended error locus
chm2:   jmp     Sys_Ret_Err
EndProc   $CHMOD

BREAK <$Creat - create a brand-new file>

;
;   $Creat - create the directory entry specified in DS:DX and give it the
;       initial attributes contained in CX
;   Inputs:     DS:DX - ASCIZ path name
;               CX - initial attributes
;   Outputs:    Carry set - AX has error code
;               Carry reset - AX has handle
;   Registers modified: all
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $Creat,NEAR

LocalVar   JFN,WORD                                                     ;BN003
LocalVar  crt_execdw,DWORD              ; exec_only BN040

        push    cx
        call    RMDevCheckName
        pop     cx
        jnc     $OpenExtended           ; error if a device has that name

        call    JFNFree                 ; find a free handle
        jc      Sys_Ret_Err             ; exit if none available

        EnterProc                       ;                               ;BC003
        mov     JFN,bx                  ; save JFN for use later        :BN003
        mov     si,dx                   ; ds:si = filespec
        mov     bx,sharing_compat+open_for_both ; Open for read/write
        xor     ax,ax
        mov     es,ax                   ; no EA's
        mov     di,ax

;------ initialize Not Exec_only flag from the loader                            exec_only BN040
        push    edx                        ; 112811
        xor     edx,edx                    ; only need Edl part                  exec_only BN040
        mov     crt_execdw,edx             ; zero save area                      exec_only BN040
        and     dh, not EXECOPEN           ; set exec_only bit off               exec_only BN040
        mov     word ptr crt_execdw+1,dx   ; save dx in hi word                  exec_only BN040
        mov     edx,crt_execdw             ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,exist_replace+nexist_create

        SVC     SVC_DEMOPEN             ; open the OS/2 file/device
        pop     edx                     ; 112811
        jc      short crt_err           ;                               ;BC003

        call    check_limit             ;BN004 check handle limit
        jc      short crt_err           ;BN004 if over limit error exit

        test    bx,RMDI_DEVICE          ; test if device was opened     ;BN003
        jz      short crt5              ; skip if not a device          ;BN003

; This is an OS/2 device.                                               ;BN003
;   OS2 device - BX = -1, ES=fake SFN, AX=rmdi_flags                    ;BN003

        mov     es,ax                   ; Real handle to ES             ;BN003
        mov     ax,bx                   ; flags to AX                   ;BN003
        mov     bx,-1                   ; Flag as an OS/2 device        ;BN003
        call    RMDevAllocDI            ; Assign a DevInfo entry -V86SFT;BN003
        jc      short crt6              ; exit if none available        ;BN003
                                        ; AX = V86 SFN (e.g. 235..254)  ;BN003

crt5:   mov     bx,JFN                  ; Get the handle
        call    pJFNFromHandle
        mov     es:[di],al              ; Store the VSFN in the JFT
        mov     ax,bx                   ; Get the fake handle in AX
        LeaveProc NoCheck
        jmp     Sys_Ret_OK

crt6:   push    ax                      ; Save the error code           ;BN003
        mov     bx,ax                   ; restore os/2 jfn              ;BN003
        SVC     SVC_DEMCLOSE            ; Close the OS2 device          ;BN003
        pop     ax                                                      ;BN003

crt_err:
        LeaveProc NoCheck
        jmp     Sys_Ret_Err
EndProc $Creat

Break <$CreateNewFile - Create a new directory entry>

;
;   CreateNew - Create a new directory entry.  Return a file handle if there
;       was no previous directory entry, and fail if a directory entry with
;       the same name existed previously.
;
;   Inputs:     DS:DX point to an ASCIZ file name
;               CX contains default file attributes
;   Outputs:    Carry Clear:
;                   AX has file handle opened for read/write
;               Carry Set:
;                   AX has error code
;   Registers modified: All
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $CreateNewFile,near
        push    cx
        call    RMDevCheckName
        pop     cx
        jnc     $OpenExtended           ; open device

        call    JFNFree                 ; find a free handle, (BX) = JFN
        jc      Sys_Ret_Err             ; exit if none available

        SVC     SVC_DEMCREATENEW
        jc      Sys_Ret_Err             ; exit if creation error

        call    check_limit             ;BN004 check handle limit
        .if     nc                      ;BN004 if over limit error exit

          call    pJFNFromHandle
          mov     es:[di],al            ; store the VSFN in the JFT
          mov     ax,bx                 ; get the fake handle in AX
          jmp     Sys_Ret_OK
        .endif

cnf_err:
        jmp     Sys_Ret_Err
EndProc   $CreateNewFile

Break   <$CreateTempFile - create a unique name>

;
;   $CreateTemp - given a directory, create a unique name in that directory.
;       Method used is to get the current time, convert to a name and attempt
;       a create new.  Repeat until create new succeeds.
;
;   Inputs:     DS:DX point to a null terminated directory name.
;               CX  contains default attributes
;   Outputs:    Unique name is appended to DS:DX directory.
;               AX has handle
;   Registers modified: all
;
        ASSUME  CS:V86GROUP,DS:NOTHING,ES:NOTHING,SS:NOTHING

Procedure $CreateTempFile,near
        call    JFNFree                 ; find a free handle
        jc      Sys_Ret_Err             ; exit if none available

        SVC     SVC_DEMCREATETEMP
        jc      Sys_Ret_Err

        call    check_limit             ;BN004 check handle limit
        jc      cnf_err                 ;BN004 if over limit error exit

        call    pJFNFromHandle
        mov     es:[di],al              ; store the VSFN in the JFT
        mov     ax,bx                   ; get the fake handle in AX
        jmp     Sys_Ret_OK
EndProc   $CreateTempFile

Break   <Extended_Open- Extended open the file>

; Input: AL= 0 (no ext attr) or 1 (ext attr)  AH=6CH
;        BX= mode
;        CL= create attribute  CH=search attribute (from server)
;        DX= flag
;        DS:SI = file name
;        ES:DI = parm list
;                          DD  SET EA list (-1) null
;                          DW  n  parameters
;                          DB  type (TTTTTTLL)
;                          DW  IOMODE
; Function: Extended Open
; Output: carry clear
;                    AX= handle
;                    CX=1 file opened
;                       2 file created/opened
;                       3 file replaced/opened
;         carry set: AX has error code
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure $Extended_Open,NEAR                        ;AN000;

LocalVar    hFile,WORD
LocalVar    usMode,WORD
LocalVar    pExtAttr,DWORD
LocalVar    fExtAttr,WORD
LocalVar    xop_execdw,DWORD              ; exec_only BN040

        EnterProc
        .if     <BIT BX and open_monitor>                               ;BN002;
          mov     ax,ERROR_INVALID_ACCESS                               ;BN002;
          jmp     exo50                                                 ;BN002;
        .endif                                                          ;BN002;

        cmp     al,1
        ja      exo40                   ; Exit if reserved mode
        test    dx,o_flag_reserved
        jnz     exo40                   ; Exit if bad create flags
        mov     fExtAttr,ax
        mov     usMode,bx
        mov     pExtAttr.Offst,di
        mov     pExtAttr.Segmt,es
        call    JFNFree                 ; Find a free handle
        jc      exo50                   ; Exit if none available
        mov     hFile,bx                ; Save it for later

        call    Set_EA_Field            ; Set TCBNewFlags for EAs

        push    dx
        push    cx
        mov     dx,si                   ; (DS:DX) = path name
        call    RMDevCheckName
        mov     si,dx                   ; (DS:SI) = path name
        pop     cx
        pop     dx
        jnc     short exo20             ; Skip if opening a device

        mov     bx,usMode
        les     di,pExtAttr

;------ initialize Not Exec_only flag from the loader                            exec_only BN040
        mov     ax,dx                      ; save dx in ax and init ax later     exec_only BN040
        push    edx                        ; 112811
        xor     edx,edx                    ; only need Edl part                  exec_only BN040
        mov     xop_execdw,edx             ; zero save area                      exec_only BN040
        and     dh, not EXECOPEN           ; set exec_only bit off               exec_only BN040
        mov     word ptr xop_execdw+1,dx   ; save dx in hi word                  exec_only BN040
        mov     edx,dword ptr xop_execdw   ; restore edx with edl as DOSFLAG     exec_only BN040
        mov     dx,ax                      ; restore dx part with normal value   exec_only BN040
        mov     ax,fExtAttr                ; init ax with Extended Attrib from up above exec_only BN040


        SVC     SVC_DEMOPEN             ; Open the OS/2 file/device
        pop     edx                     ; 112811
        jc      short exo50

        call    check_limit             ;BN004 check handle limit
        jc      short exo50             ;BN004 if over limit error exit


;       (AX) = TRUE JFN = VSFN (e.g. 1..234)

        test    bx,RMDI_DEVICE
        jz      short exo10             ; skip if not a device
        mov     es,ax                   ; Real handle to ES
        mov     ax,bx                   ; flags to AX
        mov     bx,-1                   ; Flag as an OS/2 device
        jmp     short exo30             ; Jump to common device code

exo10:  mov     bx,hFile                ; Get the handle
        call    pJFNFromHandle
        mov     es:[di],al              ; Store the VSFN in the JFT
        mov     ax,bx                   ; Get the fake handle in AX
        call    get_user_stack
        mov     [si].User_CX,cx         ; return open disposition
        LeaveProc NoCheck
        jmp     Sys_Ret_OK

exo20:  test    dl,exist_mask
        mov     ax,ERROR_FILE_EXISTS
        jz      short exo50             ; Fail, since the device exists
        mov     ax,es:[bx].SDevAtt      ; Get device attributes
        call    RMDevXFlags             ; Translate to RMDI flags
        mov     cx,usMode
        and     cx,open_autofail+open_no_inherit
.errnz ( open_autofail SHL 1 ) - RMDI_FAIL
.errnz ( open_no_inherit SHL 5 ) - RMDI_NO_INHERIT
        shr     ch,4                    ; Prepare for shifting left 5
        shl     cx,5                    ; Shift both bits into position
        or      ax,cx                   ; Get new attributes

; This is a device.
;   DOS device - ES:BX points to device header, AX=rmdi_flags

        call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
        jc      short exo50             ; Exit if none available
        mov     bx,ax
        SaveReg <ax>
        call    SFFromSFN               ; ES:DI points there
        dec     es:[di].rmdi_refcnt     ; Remove extra reference
        call    RMDevOpen               ; Open it
        RestoreReg <ax>
        jc      short exo50             ; Exit if cannot open
        jmp     short exo10

; This is a device.
;   OS2 device - BX = -1, ES=fake SFN, AX=rmdi_flags

exo30:  mov     cx,usMode
        and     cx,open_autofail+open_no_inherit
        shr     ch,4                    ; Prepare for shifting left 5
        shl     cx,5                    ; Shift both bits into position
        or      ax,cx                   ; Get new attributes
        call    RMDevAllocDI            ; Assign a DevInfo entry (V86 SFT)
        jc      short exo60             ; exit if none available

;       (ax) = V86 SFN (e.g. 235..254)

        mov     cx,file_exist           ; File (device) already existed
        jmp     short exo10

exo40:  mov     ax,ERROR_INVALID_FUNCTION
exo50:  LeaveProc NoCheck
        jmp     Sys_Ret_Err
;
;   We opened the device, but cannot allocate a DevInfo entry.
;   Clean up by closing the device.
;

exo60:  push    ax                      ; Save the error code
        SVC     SVC_DEMCLOSE            ; Close the OS2 device
        pop     ax
        jmp     short exo50             ; error exit
EndProc   $Extended_Open
subttl  $JSA - int 21 interface for join/subst
page

;
;INT 21h (AH=61h) $JSA               v86code\demfile.asm           #1/3 ;BN002;
;INT 21h (AH=61h) [SVC]demJSA        mvdm\demsvc.asm               #2/3 ;BN002;
;INT 21h (AH=61h) w_JSA              filesys\joinsbst.asm          #3/3 ;BN002;
;
; This entry point is used for the int 21 interface for join/subst.
;
; ENTRY:
;       bp = JSA_MAGIC = "dg"
;       si = JSA_JOIN(=2), JSA_SUBST(=3)
;       es:di, al, bx, cx join/subst arguments
;
; EXIT:
;       AX = error code (0 if no error)
;
;       See workers for other exit conditions.
;
; USES:
;       ALL
;

Procedure $JSA
        push    ds
        push    si
        push    bx
        push    ax
        SVC     SVC_DEMJSA
        .if     c
          pop     bx
        .else
          pop     ax
;AH=61h
;AL=0,1,2 (list,add,delete)
;BH=0
;BL=drive#
;CX=sizeof(buffer)
;ES:DI=&buffer
;BP=magic signature
;SI=2,3 (join,subst)
          push    si
          LDS     SI,cs:[CDSaddr]
          assume  ds:nothing
          .if     <SI eq -1> and                                        ;BN010;
          .if     <<word ptr cs:[CDSaddr]+2> eq -1>                     ;BN010;
            mov     ax,si               ;If no CDS exists,              ;BN010;
          .endif                        ;don't try to play with it!     ;BN010;
          mov     bh,al
          mov     al,SIZE CurDir_list
          mul     bl
          add     si,ax
          pop     ax
;DS:SI=&CDS[drive#]
;BH=1(add) 2(delete) -1(no CDS)
;AX=2(join) 3(subst)
          .if     <AL eq 2>           ;2=JOIN
            mov     ax,CurDir_Splice
          .else                       ;3=SUBST
            mov     ax,CurDir_local
          .endif
          .if     <BH eq 1>             ;1=ADD
            ;--- turn on CDS bit
            or      ds:[SI].CurDir_flags,ax
            ;--- copy DirBuf into CDS_text
            xor     ah,ah
            mov     bx,di
            push    si
            .repeat
              mov      al,es:[bx]
              mov      ds:[si],al
              inc      si
              inc      bx
              inc      ah
            .until   <ZERO AL> or
            .until   <AH ae RMDIRSTRLEN>
            pop     si
            xor     al,al
            xchg    ah,al
            dec     ax
            mov     ds:[SI].CurDir_end,ax
          .elseif <BH eq 2>             ;2=DELETE
            ;--- turn off CDS bit
            not     ax
            and     ds:[SI].CurDir_flags,ax
            ;--- assign a new drive CDS_text
            mov     bh,":"
            add     bl,"A"
            mov     word ptr ds:[SI].CurDir_text+0,bx
            mov     word ptr ds:[SI].CurDir_text+2,"\"
            mov     ds:[SI].CurDir_end,2
          .endif
          xor     ax,ax
        .endif
        pop     bx
        pop     si
        pop     ds
        jmp     Sys_Return
EndProc $JSA

subttl  GetVisDrv - return visible drive
page

;
;   GetVisDrv - correctly map non-spliced inuse drives
;
;   Inputs:     AL has drive identifier (0=default)
;   Outputs:    Carry Set - invalid drive/macro
;               Carry Clear - AL has physical drive (0=A)
;                   ThisCDS points to CDS
;   Registers modified: AL

Procedure GetVisDrv,NEAR
 ;-----DOS 5.0-----
 ; call    GetThisDrv
 ; .if     nc
 ;   push    ds
 ;   push    si
 ;   LDS     SI,[ThisCDS]
 ;   .if     <BIT <ds:[si].CurDir_flags> and CurDir_splice>
 ;     ;Joined drive
 ;     pop     si
 ;     pop     ds
 ;     mov     [DrvErr],Error_invalid_drive
 ;     stc
 ;   .endif
 ; .endif
 ; ret
 ;-----------------
        SVC     SVC_DEMGETVISDRV
        ret
EndProc   GetVisDrv

subttl  DOS_ABORT -- CLOSE all files for process
page

; Inputs:
;       [CurrentPDB] set to PID of process aborting
; Function:
;       Close all files and free all SFTs for this PID
; Returns:
;       None
; All destroyed except stack
;
        ASSUME  DS:NOTHING,ES:NOTHING

Procedure DOS_ABORT,NEAR
        mov     es,[CurrentPDB]
        mov     cx,es:[PDB_JFN_Length]  ; Number of JFNs
        .repeat                                                         ;BN002;
          mov     bx,cx
          push    cx
          dec     bx                    ; get jfn (start with last one)
          call    $Close
          pop     cx
        .loop                           ; and do 'em all                ;BN002;
        SVC     SVC_DEMDOSABORT
        ret
EndProc   DOS_ABORT


subttl  check_limit
page

;
;   check_limit check if OS/2 file handle is beyond DEM limit
;
;   Inputs:     AL has handle
;   Outputs:    Carry Set - handle too high, file closed
;               Carry Clear - handle is within range
;   AX is chnaged to no more file handle error code if carry set

Procedure check_limit,NEAR             ;BN004
        .if       <AX ge VSFN_DEV>
          mov       bx,ax              ;BN004
          SVC       SVC_DEMCLOSE       ;BN004
          mov       ax,04h             ;BN004   no more file handles error
          stc                          ;BN004
          ret                          ;BN004
        .endif
        clc                            ;BN004
        ret                            ;BN004
EndProc  check_limit                   ;BN004

subttl  SrvCallHandler                                                   ;75460;
page                                                                     ;75460;
;                                                                        ;75460;
;  SrvCallHandler  -- Handle wildcard file processing for $unlink and    ;75460;
;                     other functions that are called from Srv_Call      ;75460;
;                                                                        ;75460;
;       Inputs --  AX = function number                                  ;75460;
;                  CL = file attributes                                  ;75460;
;               DS:DX = pointer to path/filename                         ;75460;
;           sTempPath = local var. in Code segment.  Copy area for the   ;75460;
;                       path/filename                                    ;75460;
;           WinOS2Flg = local var. in Code segment.  Result of INT 2Fh   ;75460;
;                       function 160Ah. = 0 if WIN-OS2 is active.        ;75460;
;                                                                        ;75460;
;       Internal variables:                                              ;75460;
;        pFileNameOfs = Offset of filename portion of sTempPath          ;75460;
;             TempDTA = Local DTA for $Find_first, $Find_Next.           ;75460;
;          pOldDTAOfs = pointer to Offset of Entry DTA                   ;75460;
;          pOldDTASeg = pointer to Segment of Entry DTA                  ;75460;
;                                                                        ;75460;
;       Output    No error (CF = 0 )                                     ;75460;
;           copy wildcard file/path request to holding variable.         ;75460;
;           parse path & filename from overall string                    ;75460;
;           Set the DTA to local area and other setup for $Find_First    ;75460;
;           Do $Find_First call                                          ;75460;
;           If Successful                                                ;75460;
;               While success  ( carry=0 )                               ;75460;
;                   copy found filename into holding string              ;75460;
;                   setup to perform file delete                         ;75460;
;                   delete file                                          ;75460;
;                   If delete fails, exit with error                     ;75460;
;                   setup to do $Find_Next                               ;75460;
;                   Do $Find_Next Call                                   ;75460;
;               EndWhile                                                 ;75460;
;               If $Find_Next failed with No_more_files (AX=12h)         ;75460;
;                   Clear error                                          ;75460;
;               Endif                                                    ;75460;
;           Endif                                                        ;75460;
;                                                                        ;75460;
Procedure SrvCallHandler                                                 ;75460;
        LocalVar        pFileNameOfs,WORD     ;Offset of filename portion;75460
                                              ;of sTempPath              ;75460
        LocalVar        TempDTA,43            ;Local DTA for $Find_First ;75460
        LocalVar        pOldDTAOfs, WORD      ;Hold addr of orig. DTA    ;75460
        LocalVar        pOldDTASeg, WORD      ;                          ;75460
                EnterProc                                                ;75460
                push    ds                                               ;75460;
                push    cx                                               ;75460;
                mov     si,dx           ;Setup offset of source string   ;75460;
                mov     SrvCallEntFlg, FALSE                             ;75460;
                push    cs              ;setup destination string        ;75460;
                pop     es              ;need to ensure es==cs (dest.)   ;75460;
                lea     di, sTempPath                                    ;75460;
                                                                         ;75460;
                push    ax                                               ;75460;
                push    bx                                               ;75460;
                push    bp                                               ;75460;
                                                                         ;75460;
; Canonicalize path/filename.  Input is supposed to be canonicalized     ;75460;
; already, but this validates it.                                        ;75460;
; Change current value of User_In_AX (should be 41h) to allow $NameTrans ;75460;
; to handle errors correctly. 60h is value of NameTrans  DOS function.   ;75460;
                push    WORD PTR [User_In_AX]                            ;75460;
                mov     BYTE PTR [User_In_AX +1], 60h                    ;75460;
                call    $NameTrans                                       ;75460;
                pop     WORD PTR [User_In_AX]                            ;75460;
                pop     bp                                               ;75460;
                pop     bx                                               ;75460;
                pop     ax                                               ;75460;
                jc      SCHandler_Exit  ;di now points to the beginning  ;75460;
                                        ;of the filespec. Now look for   ;75460;
                                        ;the end.                        ;75460;
GetEndString:   cld                                                      ;75460;
                mov     cx,(SIZE sTempPath) ;Buffer size                 ;75460;
                mov     al,0            ;search for end of string        ;75460;
                repne   scasb                                            ;75460;
                jnz     SCHandler_Err   ;buffer overflow: ERROR          ;75460;
                                        ;di now points to end of filespec;75460;
CopyDone:       std                     ;prepare to scan DOWNward        ;75460;
                lea     si,sTempPath    ;SI=start of path                ;75460;
                mov     al, '\'                                          ;75460;
                mov     cx, di                                           ;75460;
                sub     cx, si                                           ;75460;
                dec     di              ;DI now points at \0 byte        ;75460;
;Since our filespec is in canonical form, we are guaranteed to have a '\';75460;
;character in it.                                                        ;75460;
                                                                         ;75460;
ScanPath:         repne   scasb           ;Scan for '\'                    ;75460;
                  jnz     SCHandler_Err   ;didn't find one: ERROR          ;75460;
                                                                         ;75460;
EndPath:        inc     di              ;after increments:               ;75460;
                inc     di              ;di = first char in filename     ;75460;
                                        ;si = first char in path         ;75460;
                mov     pFileNameOfs,di ;save pointer to filename        ;75460;
SaveOldDTA:     mov     es, WORD PTR [DMAADD + 2]  ;Get current DTA      ;75460;
                mov     bx, WORD PTR [DMAADD]                            ;75460;
                mov     pOldDTASeg, es                                   ;75460;
                mov     pOldDTAOfs, bx                                   ;75460;
SetNewDTA:      push    ss                                               ;75460;
                pop     ds                                               ;75460;
                lea     dx, TempDTA                                      ;75460;
                call    $Set_DMA        ;new DTA=ss:TempDTA=DS:DX        ;75460;
;Ready to do findfirst ( more or less )                                    ;75460;
;Current es=ss=ds                                                          ;75460;
                pop     cx              ;restore original CX=file        ;75460;
                                        ;attribs.                        ;75460;
                push    cx              ;re-save file attribs            ;75460;
                lea     dx, sTempPath   ;DS:DX=canonical path string     ;75460;
; Change current value of User_In_AX (should be 41h) to allow $Find_First;75460;
; to handle errors correctly. 4Eh is value of Find_First DOS function.   ;75460;
                push    WORD PTR [User_In_AX]                            ;75460;
                mov     BYTE PTR [User_In_AX +1], 4Eh                    ;75460;
                call    $Find_First     ;Uses internal DS:DX, CX         ;75460;
                pop     WORD PTR [User_In_AX]                            ;75460;
                jc   short   FindFirst_Err                                 ;75460 90667;
FindFiles:        push    ss                                               ;75460;
                  pop     ds                                               ;75460;
                  lea     si, TempDTA+1Eh ;offset of filename in DTA       ;75460;
                  mov     di, pFileNameOfs   ;offset of filename in string ;75460;
                  push    cs              ;path string is in CS            ;75460;
                  pop     es                                               ;75460;
                  mov     cx,0Dh          ;max length of filename          ;75460;
                  cld                                                      ;75460;
CopyFileName:     repnz   movsb           ;copy filename to pFileNameOfs   ;75460;
                  lea     dx, sTempPath   ;DS:DX = delete filespec         ;75460;
                  pop     cx              ;CX=file attribs                 ;75460;
                  push    cx              ;re-save file attribs            ;75460;
                  mov     es,[CurrentPDB]                                  ;75460;
                  mov     es,es:[PDB_environ]     ;es:=CurrentPDB[002Ch]   ;75460;
DoFunction41h:    cmp     [User_In_AX], 4100h                              ;75460;
                  jnz     short DoFunction00h     ;Error: Unsupported func.;75460;
                    mov     ax, CS:[SaveWINOS2Check] ;restore results from   ;75460;
                                                     ;Int 2Fh, func 160A     ;75460;
                                                     ;(from $UNLINK)         ;75460;
                    SVC     SVC_DEMDELETE                                    ;75460;
                    jc short RestoreDTA      ;exit on error. We only get     ;75460 90667;
                          ;one return value, even though multiple results  ;75460;
                          ;are possible with wildcard filespecs. Best to   ;75460;
                          ;notify user of error while error info is still  ;75460;
                          ;intact.                                         ;75460;
                  ;;jmp   short DoFindNext  ;use if support for additional ;75460;
                                            ;functions is added later.     ;75460;
DoFunction00h:            ;Placeholder for handling additional DEM services;75460;
                          ;                                                ;75460;
DoFindNext:       pop     cx                                               ;75460;
                  push    cx                                               ;75460;
; Change current value of User_In_AX (should be 41h) to allow $Find_Next     ;75460;
; to handle errors correctly. 4Fh is value of Find_Next DOS function.        ;75460;
                  push    WORD PTR [User_In_AX]                            ;75460;
                  mov     BYTE PTR [User_In_AX +1], 4Fh                    ;75460;
                  call    $Find_Next                                       ;75460;
                  pop     WORD PTR [User_In_AX]                            ;75460;
                  jnc     FindFiles     ; end of loop                      ;75460;
; Fallthrough = $Find_Next failed ( =  out of files or ERROR )             ;75460;
                clc                     ; assume error = no more files     ;75460;
                cmp     ax,ERROR_NO_MORE_FILES; = No more files error = OK.    ;75460;
                je      short RestoreDTA; Go to cleanup & exit           ;75460;
                stc                     ; We had an unexpected error     ;75460;
                jmp     short RestoreDTA                                 ;75460;
SCHandler_Err:  mov     ax, ERROR_FILE_NOT_FOUND                         ;75460;
                stc                                                      ;75460;
                jmp     short SCHandler_Exit  ;can't fallthrough because we    ;75460 90667;
                                        ;don't have a DTA to restore     ;75460;
FindFirst_Err:  cmp     ax,ERROR_NO_MORE_FILES;                          ;75460;
                jnz     short RestoreDTA                                 ;75460;
                mov     ax,ERROR_FILE_NOT_FOUND ;change no_more_files to ;75460;
                                        ; file_not_found                 ;75460;
                stc                                                      ;75460;
RestoreDTA:     pushf                   ; save prev error info           ;75460;
                push      ax                                             ;75460;
                mov       ds,pOldDTASeg   ; restore orig DTA             ;75460;
                mov       dx,pOldDTAOfs                                  ;75460;
                call      $Set_DMA        ;                              ;75460;
                pop       ax              ;                              ;75460;
                popf                                                     ;75460;
SCHandler_Exit: pop       cx                                             ;75460;
                pop       ds                                             ;75460;
                LeaveProc       NoCheck                                  ;75460;
                ret                                                      ;75460;
EndProc         SrvCallHandler                                           ;75460;

V86CODE ENDS

        END
