        Title   Share_2

;/*
; *                      IBM Corporation
; *                      Copyright (C) IBM Corporation 1991
; *                      All Rights Reserved.
; */

VCB_HMA = 1     ; Add support for moving code to HMA
VCB_SFT_OPT = 1 ; Define DEL_SFT in SHARE PSP

;
;       Revision History
;       ================
;
;       M000    SR      08/03/90        Fixed ShComndParse so that it exits
;                                       after displaying help text on a
;                                       Share /?
;
;       M001    SR      9/10/90 Removed all /NC support from the code
;                               and rewrote the init code to not use
;                               all the special Share int 2fh calls.
;
;       M002    SR      9/26/90 Bug #3013. The installed message and
;                               parse error message had identical
;                               message numbers. Also check the class.
;
;       M004    HKN     10/18/90        To determine whether the SFT is a
;                                       net SFT or a device we must check
;                                       the sf_flags. bug #3584
;
;       M005    SR      10/16/90        Bug #2914. Changed to ignore the /NC
;                               switch instead of making it an
;                               invalid switch.
;
;       M006    SR      10/22/90        Bug #3583. Changed parsing to check
;                               for multiple occurrences of a switch
;                               and give out an error message. Share
;                               still continues to load and uses the
;                               parameter value first specified.
;
;       M007    SR      11/16/90        Bug #4240. Added check to ShareInit
;                               to look for switcher and fail to load
;                               if switcher is present.
;
;       I001   DWR      02/26/93    DEFECT 688  Fix problem cause by
;                               DEL/REN SFT being corrupted by BIOS if
;                               share violation occurs.
;
;
;
         include SHAREHDR.INC
;
;     Label: "The DOS SHARE Utility"
;
;******************* END OF SPECIFICATIONS *************************************


                                   NAME Sharer2

                                           ;  INCLUDE DOSSYM.INC
                                           ;  INCLUDE SYSMSG.INC
                                   .xlist
                                   .xcref
                                   INCLUDE DOSSYM.INC
                                   INCLUDE SYSMSG.INC
                                        include filemode.inc
                                        include arena.inc
                                        include cpmfcb.inc
                                        include sf.inc
                                        include pdb.inc
                                        include sysvar.inc
                                        include syscall.inc
                                        include mult.inc
                                        include version.inc
                                        include vector.inc
                                        include int2a.inc
                                   .cref
                                   .list
                                   page 80,132

                                   MSG_UTILNAME <SHARE>

ShareDataVersion                   =    1

AsmVars                            <IBM, Installed>

Installed                          =    TRUE ; for installed version

OFF                                Macro reg,val
                                   IF   installed
                                   mov  reg,OFFSET val
                                   ELSE
                                   mov  si,OFFSET DOSGROUP:val
                                   ENDIF
                                   ENDM

ERRNZ                              Macro x
                                   IF   x    NE 0
                                   %out ERRNZ failed
                                   ENDIF
                                   ENDM
                                           ;---------------------------------------
                                           ; if we are installed, then define the
                                           ; base code segment of the sharer first
                                           ;---------------------------------------
;       $SALUT  (4,9,17,36)

        IF      Installed

            Share   SEGMENT BYTE PUBLIC 'SHARE'
            Share   ENDS
        include dosseg.inc
        ENDIF

                                   ;---------------------------------------
                                   ; include the rest of the segment
                                   ;  definitions for normal msdos

                                   ; segment ordering for MSDOS

                                   ;---------------------------------------


        DOSDATA SEGMENT

        extrn   DataVersion:BYTE   ; version number of DOS data.
        extrn   JShare:BYTE        ; location of DOS jump table.
        extrn   sftFCB:DWORD       ; [SYSTEM] pointer to FCB cache table
        extrn   KeepCount:WORD     ; [SYSTEM] LRU count for FCB cache
        extrn   CurrentPDB:WORD

        extrn   ThisSFT:DWORD      ; pointer to SFT entry
        extrn   WFP_start:WORD     ; pointer to name string
        extrn   User_ID:WORD
        extrn   Proc_ID:WORD
        extrn   SFT_addr:DWORD
        extrn   Arena_Head:WORD
        extrn   fshare:BYTE
        extrn   pJFN:DWORD
        extrn   JFN:WORD

        IF      DEBUG

            extrn   BugLev:WORD
            extrn   BugTyp:WORD
            include bugtyp.inc

        ENDIF


        DOSDATA    ENDS

                                   ;---------------------------------------
                                   ; if we are not installed, then the
                                   ; code here is just part of the normal
                                   ; MSDOS code segment otherwise,
                                   ; define our own code segment
                                   ;---------------------------------------



        .sall
        IF      NOT     INSTALLED

            CODE    SEGMENT BYTE PUBLIC 'CODE'

            ASSUME  SS:DOSGROUP,CS:DOSCODE

        ELSE

            Share   SEGMENT BYTE PUBLIC 'SHARE'

            ASSUME  SS:DOSDATA,CS:SHARE

        ENDIF



        Extrn   FreLock:WORD,Serial:WORD
        Extrn   MFT_Enter:NEAR,MFTClose:NEAR,MFTClu:NEAR,MFTCloseP:NEAR
        Extrn   MFTCloN:NEAR
        Extrn   Set_Mult_Block:NEAR,Clr_Mult_Block:NEAR,Chk_Block:NEAR
        Extrn   MFT_Get:NEAR
IFDEF VCB_HMA
        extrn   get_ds:near
        extrn   MFTPTR:word
ENDIF

IFNDEF VCB_SFT_OPT
IFDEF VCB_HMA
        extrn   DEL_sft:byte
ELSE
        PUBLIC  DEL_sft                                   ; I001
        DEL_sft         db    SIZE sf_entry  DUP (0)      ; I001
ENDIF
ELSE
        DEL_sft         equ     80h
ENDIF
        include mft.inc

;  $SALUT (4,4,9,41)

   BREAK <FNM - Find name in MFT>

;******************* START OF SPECIFICATIONS ***********************************
;
;       FNM - Find name in MFT
;
;       FNM searches the MFT for a name record.
;
;       ENTRY   (DS:SI) = pointer to name string (.asciz)
;               (al) = 1 to create record if non exists
;                    = 0 otherwise
;       EXIT    'C' clear if found or created
;                 (DS:BX) = address of MFT name record
;               'C' set if error
;                 If not to create, item not found
;                   (DS:SI) unchanged
;                 If to create, am out of space
;                   (ax) = error code
;       USES    ALL
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure FNM,NEAR

   push ds                              ; save string address
   push si
   xchg bh,al                           ; (bh) = create flag
   or   bh,bh                           ; if not creating
   jz   fnm01                           ; skip sft test

                                        ;---------------------------------------
                                        ; run down through string counting
                                        ;  and summing
                                        ;---------------------------------------

fnm01: sub dx,dx                        ; (dx) = byte count
   sub  bl,bl                           ; (bl) = sum

fnm1: lodsb                             ; (al) = next char
   add  bl,al
   adc  bl,0
   inc  dx
   and  al,al
   jnz  fnm1                            ; terminate after null char

                                        ;---------------------------------------
                                        ; Info computed.
                                        ;  Start searching name list

                                        ;  (bh) = create flag
                                        ;  (bl) = sum byte
                                        ;  (dx) = byte count
                                        ;  (TOS+2:TOS) = name string address
                                        ;---------------------------------------
IFDEF VCB_HMA
   call get_ds
   mov  si,ds:mftptr
ELSE
   push cs
   pop  ds
   Off  SI,mft
ENDIF

fnm2: cmp [si].mft_flag,MFLG_FRE
   jl   fnm10                           ; at end - name not found
   jz   fnm4                            ; is free, just skip it
   cmp  bl,[si].mft_sum                 ; do sums compare?
   jz   fnm5                            ; its a match - look further
fnm4: add si,[si].mft_len               ; not a match... skip it
   JMP  SHORT fnm2
                                        ;---------------------------------------
                                        ; name checksums match
                                        ;   - compare the actual strings
                                        ;
                                        ;   (dx)        = length
                                        ;   (ds:si      = MFT address
                                        ;   (bh)        = create flag
                                        ;   (bl)        = sum byte
                                        ;   (dx)        = byte count
                                        ;   (TOS+2:TOS) = name string address
                                        ;---------------------------------------

fnm5: mov cx,dx                         ; (cx) = length to match
   pop  di
   pop  es                              ; (ES:DI) = fba given name
   push es
   push di
   push si                              ; save MFT offset
   add  si,mft_name                     ; (ds:si) = fwa string in record
   repz cmpsb
   pop  si                              ; (ds:si) = fwa name record
   jnz  fnm4                            ; not a match

                                        ;---------------------------------------
                                        ; Yes, we've found it.  Return the info
                                        ;
                                        ;  (TOS+2:TOS) = name string address
                                        ;---------------------------------------

   fmt  TypShare,LevMFTSrch,<"FNM found name record at $x\n">,<si>
   pop  ax                              ; discard unneeded stack stuff
   pop  ax
   mov  bx,si                           ; (ds:bx) = fwa name record
   clc

   ret
                                        ;---------------------------------------
                                        ;**
                                        ;**  Its not in the list
                                        ;**  - lets find a free spot and put
                                        ;**    it there
                                        ;
                                        ;  (bh)        = create flag
                                        ;  (bl)        = sum byte
                                        ;  (dx)        = string length
                                        ;  (TOS+2:TOS) = ASCIZ string address
                                        ;  (ds)        = SEG CODE
                                        ;---------------------------------------
fnm10:
   and  bh,bh
   jnz  fnm10$5                         ; yes, insert it
   pop  si
   pop  ds                              ; no insert, its a "not found"
   stc

   fmt  TypShare,LevMFTSrch,<"FNM failing\n">

   mov  ax,error_path_not_found

   ret

fnm10$5:
   add  dx,mft_name                     ; (dx) = minimum space needed

IFDEF VCB_HMA
   mov  si,ds:mftptr
ELSE
   off  SI,mft
ENDIF

fnm11: cmp [si].mft_flag,MFLG_FRE

   IF   NOT  DEBUG
       jl   fnm20                       ; at END, am out of space
   ELSE
       jl   fnm20j
   ENDIF

   jz   fnm12                           ; is a free record
   add  si,[si].mft_len                 ; skip name record
   JMP  SHORT fnm11

   IF   DEBUG
fnm20j: jmp fnm20
   ENDIF

fnm12: mov ax,[si].mft_len              ; Have free record, (ax) = total length
   cmp  ax,dx
   jnc  fnm13                           ; big enough
   add  si,ax
   JMP  SHORT fnm11                     ; not large enough - move on

                                        ;---------------------------------------
                                        ; OK, we have a record which is big
                                        ;  enough.  If its large enough to hold
                                        ;  another name record of 6 characters
                                        ;  than we'll split the block, else
                                        ;  we'll just use the whole thing
                                        ;
                                        ; (ax)        = size of free record
                                        ; (dx)        = size needed
                                        ; (ds:si)     = address of free record
                                        ; (bl)        = sum byte
                                        ; (TOS+2:TOS) = name string address
                                        ;---------------------------------------

fnm13: sub ax,dx                        ; (ax) = total size of proposed fragment
   cmp  ax,mft_name+6
   jc   fnm14                           ; not big enough to split
   push bx                              ; save sum byte
   mov  bx,dx                           ; (bx) = offset to start of new name record
   mov  [bx][si].mft_flag,MFLG_FRE
   mov  [bx][si].mft_len,ax             ; setup tail as free record
   sub  ax,ax                           ; don't extend this record
   pop  bx                              ; restore sum byte
fnm14: add dx,ax                        ; (dx) = total length of this record
   mov  [si].mft_len,dx
   mov  [si].mft_sum,bl
   mov  [si].mft_flag,MFLG_NAM

   fmt  TypShare,LevMFTSrch,<"FNM creating record at $x\n">,<si>

   push ds
   pop  es                              ; (es) = MFT segment for "stow"
   sub  ax,ax
   mov  di,si
   add  di,mft_lptr
   stosw                                ; zero LCK pointer
   ERRNZ mft_sptr-mft_lptr-2
;       add     di,mft_sptr-mft_lptr-2
   stosw                                ; zero SFT pointer
   stosw                                ; zero SFT pointer
   inc  ds:serial                       ; bump serial number
   mov  ax,ds:serial
   ERRNZ mft_serl-mft_sptr-4
;       ADD     di,mft_serl-mft_sptr-4
   stosw
                                        ;---------------------------------------
                                        ; We're all setup except for the name.
                                        ;  Note that we'll block copy the whole
                                        ;  name field, even though the name may
                                        ;  be shorter than that (we may have
                                        ;  declined to fragment this memory block)
                                        ;
                                        ;       (dx) = total length of this record
                                        ;       (ds:si) = address of working record
                                        ;       (es) = (ds)
                                        ;       (TOS+2:TOS) = name string address
                                        ;---------------------------------------
   mov  cx,dx
   sub  cx,mft_name                     ; compute total size of name area
   ERRNZ mft_name-mft_serl-2
;       add     di,mft_name-mft_serl-2  ; (ES:DI) = target address
   mov  ax,si                           ; save name record offset
   pop  si
   pop  ds
   rep  movsb
   mov  bx,ax                           ; (bx) = name record offset
   push es
   pop  ds                              ; (DS:BX) = name record offset
   clc

   ret

;**
;**     OUT OF FREE SPACE
;**
;**     This is tough, folks.  Lets trigger a garbage collection and see if
;**     there is enough room.  If there is, we'll hop back and relook for a
;**     free hunk; if there isnt enough space, its error-city!
;
;       WARNING: it is important that the garbage collector be told how big a
;               name record hole we're looking for...  if the size given GCM
;               is too small we'll loop doing "no space; collect; no space;
;               ...)
;
;       (dx) = total length of desired name record
;       (ds) = SEG CODE
;       (bl) = sum byte
;       (TOS+2:TOS) = name string address

fnm20:
   mov  ax,dx                           ; (ax) = size wanted
   sub  dx,mft_name                     ; (dx) = string length for reentry at fnm10
   push dx
   push bx
   call GCM                             ; garbage collect MFT
   pop  bx
   pop  dx

   IF   DEBUG
       jnc  fnm10j
   ELSE
       jnc  fnm10                       ; go back and find that space
   ENDIF

                                        ;---------------------------------------
                                        ; no space, return w/error
                                        ;---------------------------------------

fnm50: pop ax
   pop  ax                              ; clean stack
   mov  ax,error_sharing_buffer_exceeded
   stc

   ret

   IF   DEBUG
fnm10j: jmp fnm10
   ENDIF

   EndProc FNM

   BREAK <GCM - Garbage Collect MFT>

;******************* START OF SPECIFICATIONS ***********************************
;
;       GCM - Garbage Collect MFT
;
;       GCM runs down the MFT structure squeezing out the free space and
;       putting it into one free block at the end.  This is a traditional heap
;       collection process.  We must be sure to update the pointer in the
;       SFTs.  This presumes no adjacent free blocks.
;
;       ENTRY   (ax) = space desired in last free block
;               (DS) + SEG CODE
;       EXIT    'C' clear if enough space in block
;               'C' set if not enough space
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure GCM,NEAR

   push ax                              ; save target
IFDEF VCB_HMA
   mov  si,ds:mftptr
ELSE
   off  si,mft                          ; (si) = from pointer
ENDIF
   mov  di,si                           ; (di) = to pointer

                                        ;---------------------------------------
                                        ; (DI) points to the beginning of
                                        ;       a free space block
                                        ; (SI) points to the next block.
                                        ;---------------------------------------

gcm1: mov cx,[si].mft_len               ; (cx) = size of whatever it is
   cmp  [si].mft_flag,MFLG_FRE
   jl   gcm10                           ; END marker
   jnz  gcm2                            ; have a name record

                                        ;---------------------------------------
                                        ; (SI) points to a free block.
                                        ;    We coalesce it by changing the size.
                                        ;---------------------------------------
   cmp  si,di
   jz   gcm15                           ; do NOT coalesce a block with itself
   add  [di].mft_len,cx                 ; coalesce
gcm15:
   add  si,cx                           ; skip the empty one
   JMP  SHORT gcm1
                                        ;---------------------------------------
                                        ; (SI) points to a non-free,
                                        ;       non-last block.
                                        ; (DI) points to the beginning of a
                                        ;        free block.
                                        ;
                                        ; We move the non-free block down over
                                        ;   the free block
                                        ;---------------------------------------
gcm2: cmp si,di
   jnz  gcm3                            ; have to copy

                                        ;---------------------------------------
                                        ; SI = DI => we are at a boundary
                                        ;            between allocated blocks.
                                        ;            We do no copying.
                                        ;---------------------------------------
   add  si,cx
   mov  di,si                           ; no emptys yet... no need to copy
   JMP  SHORT gcm1
                                        ;---------------------------------------
                                        ; CX is length of allocated block.
                                        ;      - Move it
                                        ;---------------------------------------

gcm3: mov bx,di                         ; (DS:BX) = new home for this record
   mov  ax,ds
   mov  es,ax
   rep  movsb
                                        ;---------------------------------------
                                        ; We've moved the record, now fix up
                                        ;  the pointers in the SFT chain
                                        ;
                                        ;  (si) = address of next record
                                        ;  (di) = address of next free byte
                                        ;  (bx) = address of record in its new home
                                        ;  (TOS) = needed space
                                        ;---------------------------------------
   push di
   push ds
   lds  di,[bx].mft_sptr                ; (ds:di) = chain of SFT
gcm4: or di,di
   jz   gcm5                            ; no more SFT
   mov  [di].sf_mft,bx                  ; install new MFT position
   lds  di,[di].sf_chain                ; link to next
   JMP  gcm4                            ; fix next SFT

gcm5: pop ds
   pop  di
                                        ;---------------------------------------
                                        ; (DI) points to beginning of
                                        ;       new free record (moved)
                                        ; (SI) points to next record
                                        ;
                                        ; Make sure that the (DI) record
                                        ;  has correct format
                                        ;---------------------------------------

   mov  [di].mft_flag,MFLG_FRE          ; indicate free record
   mov  [di].mft_len,si                 ; calculate correct length
   sub  [di].mft_len,di
                                        ;---------------------------------------
                                        ; MFT now has correct record structure.
                                        ;  Go find more free blocks
                                        ;---------------------------------------
   JMP  SHORT gcm1
                                        ;---------------------------------------
                                        ; We have scanned the entire table,
                                        ;  compacting all empty records together.
                                        ;
                                        ;   (di) = first free byte in table
                                        ;   (si) = address of END record
                                        ;   (TOS) = size needed
                                        ;
                                        ; Be extra careful!!!
                                        ;---------------------------------------
gcm10: mov ax,si
   sub  ax,di                           ; (ax) = free space
   pop  bx                              ; (bx) = space wanted
   sub  ax,bx

   ret

   EndProc GCM

   BREAK <RMN - Remove MFT Name record>

;******************* START OF SPECIFICATIONS ***********************************
;
;       RMN - Remove MFT Name record
;
;       RMN removes a name record from the MFT list.  The record is marked
;       free and all free space is coalesced.
;
;       ENTRY   (DS:BX) = FBA MFT name record
;       EXIT    to INTERR if lock and SFT chains are not empty
;       USES    ALL
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure RMN,NEAR

   mov  si,bx
   mov  ax,word ptr [si].mft_sptr
   or   ax,word ptr [si].mft_lptr
   jnz  RMNIER1                         ; not clean - internal error
   mov  si,bx                           ; (ds:si) = fwa name record

   mov  [si].mft_flag,MFLG_FRE          ; mark free

   call mrg                             ; coalesce all free space

   ret

RMNIER1:push ax
   off  ax,RmnErr1

RMNIER: call INTERR                     ; internal error


   EndProc RMN

   Break <MRG - merge all free space>

;******************* START OF SPECIFICATIONS ***********************************
;
;   MRG - merge all free space
;
;   MRG - walk through mft merging adjacent free space.
;
;   Inputs:     ds = CS
;   Outputs:    none (all free space coalesced)
;   Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure MRG,near

   assume ds:nothing,es:nothing

   push si
   push bx

IFDEF VCB_HMA
   mov  si,ds:mftptr
ELSE
   off  si,mft                          ; start at beginning
ENDIF
mrg1: mov bx,[si].mft_len               ; get length
   cmp  [si].mft_flag,MFLG_FRE          ; is record free?
   jl   mrg9                            ; done.
   jz   mrg2                            ; yes, try to merge with next
mrg15: add si,bx                        ; advance to next
   jmp  mrg1
                                        ;---------------------------------------
                                        ; (si) points to free record.
                                        ;  - See if next is free
                                        ;---------------------------------------
mrg2: cmp [bx][si].mft_flag,MFLG_FRE
   jnz  mrg15                           ; not free, go scan again
   mov  bx,[bx][si].mft_len             ; get length of next guy
   add  [si].mft_len,bx                 ; increase our length
   jmp  mrg1                            ; and check again
mrg9: pop bx
   pop  si

   ret

   EndProc MRG

   BREAK <RSC - Remove SFT from SFT chain>

;******************* START OF SPECIFICATIONS ***********************************
;
;       RSC - Remove SFT from SFT chain
;
;       RSC removes a given SFT from its chain.  The caller must insure that
;       any locks have been cleared and that the SFT is indeed free.  The
;       sf_mft field is zeroed to indicate that this SFT is no longer chained.
;
;       NOTE - RSC does NOT remove the name record if this was the last SFT on
;               it.  The caller must check for this and remove it, if
;               necessary.
;
;       ENTRY   (ES:DI) = SFT address
;       EXIT    (DS:BX) = FBA name record for this SFT
;               'Z' set if this is the last SFT
;       USES    ALL
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure RSC,NEAR

IFDEF VCB_HMA
   call get_ds
ELSE
   push cs
   pop  ds
ENDIF

   mov  ax,es                           ; easy spot for compare
   mov  bx,es:[di].sf_mft
   lea  si,[bx].mft_sptr-sf_chain       ; ds:[si].sf_chain point to prev link
rsc1:
IFNDEF VCB_HMA
   or   si,si
   jz   rscier
ENDIF
   cmp  word ptr [si].sf_chain,di
   jnz  rsc15
   cmp  word ptr [si].sf_chain+2,ax
   jz   rsc2
rsc15: lds si,[si].sf_chain
IFDEF VCB_HMA
   or   si,si
   jz   rscier
ENDIF
   jmp  rsc1
                                        ;---------------------------------------
                                        ; (es:di) is sft
                                        ; (ds:si) is prev sft link
                                        ;---------------------------------------
rsc2: mov ax,word ptr es:[di].sf_chain
   mov  word ptr ds:[si].sf_chain,ax
   mov  ax,word ptr es:[di].sf_chain+2
   mov  word ptr ds:[si].sf_chain+2,ax

IFDEF VCB_HMA
   call get_ds
ELSE
   push cs
   pop  ds
ENDIF
   xor  bx,bx
   xchg bx,es:[di].sf_MFT               ; (DS:bx) = MFT address
                                        ;    and 0 MFT pointer (show free)
   cmp  word ptr [bx].mft_sptr,0        ; set z flag if no more sft

   ret

rscier: push ax
   off  ax,RscErr

   call interr


   EndProc RSC

   BREAK <SLE - Scan for Lock Entry>

;******************* START OF SPECIFICATIONS ***********************************
;
;       SLE - Scan for Lock Entry
;
;       SLE scans a lock list looking for a lock range that overlaps the
;       caller-supplied range.  SLE indicates:
;
;               no overlap
;               partial overlay
;               1-to-1 match
;
;       ENTRY   (AX:BX) = FBA of area
;               (CX:DX) = LBA of area
;               (DS:SI) = address of name record
;               (DI)    = 0 to ignore locks by User_ID Proc_ID ThisSFT
;                       = 1 to consider all locks
;       EXIT    'C' clear if no overlap
;                 AX,BX,CX,DX preserved
;               'C' set if overlap
;                 (di) = address of pointer to found record
;                        (i.e., DS:((di)) = address of lock record)
;                 'Z' set if 1-to-1 match
;       USES    ALL but (ds), (es) (also see EXIT)
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure SLE,NEAR

   push es
   and  di,di
   pushf                                ; Z set to ignore own locks
   lea  di,[si].mft_lptr                ; (ds:di) = addr of ptr to lock record
   mov  si,[di]                         ; (ds:si) = address of 1st lock record

                                        ;---------------------------------------
                                        ; check out next lock
                                        ;
                                        ; (ds:si) = address of next lock record
                                        ; (ds:di) = address of pointer to next
                                        ;            lock record
                                        ; (TOS)   = flags (Z set to ignore
                                        ;             own locks)
                                        ; (TOS+1) = Saved ES
                                        ;---------------------------------------
sle1: and si,si
   jz   sle9                            ; list exhaused, ergo no overlap
   popf                                 ;
   pushf
   jnz  sle2                            ; am to check all locks

                                        ;---------------------------------------
                                        ; am to ignore own locks...
                                        ;  check the user and proc IDs on this one
                                        ;---------------------------------------

;dcl - this code used to compare the process id in the sft pointed to by the
;  lock.  now we compare the lock process id to the current process id.  this
;  allows a child process to lock an area and then do i/o with it.  before,
;  the child could lock it, but then could not access it


   mov  bp,[si].rlr_pid                 ;dcl
   cmp  bp,Proc_id                      ;dcl
   jnz  sce1$5                          ;dcl
   les  si,[si].rlr_sptr                ; (si) = sft address            ;dcl
   mov  bp,es:[si].sf_UID               ;dcl
   cmp  bp,User_ID                      ;dcl
   jnz  sce1$5                          ; doesn't belong to user        ;dcl
   mov  bp,es                           ;dcl
   cmp  bp,WORD PTR ThisSFT+2
   jnz  sce1$5
   cmp  si,WORD PTR ThisSFT
sce1$5: mov si,[di]                     ; (ds:si) = address of next lock record
   jz   sle3                            ; owned by user - ignore

sle2: mov bp,dx
   sub  bp,[si].rlr_fba                 ; compare proposed last to first of record
   mov  bp,cx
   sbb  bp,[si].rlr_fba+2
   jc   sle3                            ; proposed is above current
   mov  bp,[si].rlr_lba
   sub  bp,bx                           ; compare proposed first to last of record
   mov  bp,[si].rlr_lba+2
   sbb  bp,ax
   jnc  sle5                            ; we have a hit

                                        ;---------------------------------------
                                        ; This entry is harmless...
                                        ;    chain to the next one
                                        ;---------------------------------------
   ERRNZ rlr_next

sle3: mov di,si                         ; save addr of pointer to next
   mov  si,[di]
   JMP  SHORT sle1
                                        ;---------------------------------------
                                        ; We have an overlap.
                                        ;  - See if its an exact match
                                        ;
                                        ; (ds:di) = address of pointer
                                        ;           (offset only) to the lock record
                                        ; (ds:si) = address of lock record
                                        ; (TOS) = flags ('Z' set if to ignore
                                        ;         own locks)
                                        ; (TOS+1) = saved (es)
                                        ;---------------------------------------

sle5: xor ax,[si].rlr_fba+2             ; require a 4-word match
   xor  bx,[si].rlr_fba
   xor  cx,[si].rlr_lba+2
   xor  dx,[si].rlr_lba
   or   ax,bx
   or   ax,cx
   or   ax,dx                           ; 'Z' set if exact match
   stc                                  ; flag an overlap
   mov  ax,error_lock_violation
sle9: pop bp                            ; discard flags (pushf)
   pop  es                              ; restore (es)

                                        ;---------------------------------------
                                        ; (ds:si) = address of lock record
                                        ;           for Chk_Block
                                        ;---------------------------------------
   ret

   EndProc SLE

   BREAK <OFL - obtain free lock-record>

;******************* START OF SPECIFICATIONS ***********************************
;
;       OFL - obtain free lock-record
;
;       OFL returns a free lock-record, if one can be had.
;
;       ENTRY   (DS) = MFT Segment
;       EXIT    'C' clear if OK
;                 (DI) = FBA lock record
;               'C' set if no space
;                 (ax) = error code
;       USES    DI, FLAGS
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure OFL,NEAR

   mov  di,ds:Frelock
   and  di,di

;  $if  nz                              ; if something there
   JZ $$IF1

       push [di].rlr_next
       pop  ds:Frelock                  ; chain off of the list
                                        ; exit with 'C' clear

;  $else                                ; none on free list
;  JMP SHORT $$EN1
   ret
$$IF1:

       mov  ax,error_sharing_buffer_exceeded ; None on free list, give up until
       stc                              ;  garbage collector is ready

;  $endif
$$EN1:

   ret

   EndProc OFL

   Break <CPS - close process SFT>

;******************* START OF SPECIFICATIONS ***********************************
;
;   CPS - close process SFT.
;
;       During maintenance, it is necessary to close a
;       file given ONLY the SFT.  This necessitates walking all PDB's JFN
;       tables looking for the SFN.  The difficult part is in generating the
;       SFN from the SFT.  This is done by enumerating SFT's and comparing for
;       the correct SFT.  Finding all PDBs is easy:  walk arena and check
;       owner fields
;
;   Inputs:     ThisSFT points to SFT of interest
;   Outputs:    Handle is closed on user
;   Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure CPS,NEAR

   ASSUME DS:NOTHING,ES:NOTHING

   SaveReg <DS,SI,ES,DI,AX,BX,CX>

   lds  si,ThisSFT
   xor  bx,bx
cps01:

   CallInstall SFFromSFN,multDOS,22,bx,bx

   jc   cps31                           ; no more SFN's.  Must be FCB.

   CallInstall PointComp,multDOS,20

   jz   cps02                           ; found matching SFN, go scan.
   inc  bx                              ; did not match, go back for more
   jmp  cps01
                                        ;---------------------------------------
                                        ; BL is the sfn we want to find.  Walk
                                        ;  the memory arena enumerating all PDB's
                                        ;  and zap the handle tables for the
                                        ;  specified sfn.
                                        ;---------------------------------------
cps02:
   mov  al,bl
   mov  ds,Arena_Head                   ; get first arena pointer

                                        ;---------------------------------------
                                        ; DS:[0] is the arena header.
                                        ; AL is sfn to be closed
                                        ;---------------------------------------
cps1:
   mov  cx,ds:[arena_owner]
   mov  bx,ds
   inc  bx                              ; is the owner the same as the current
   cmp  cx,bx                           ; block?
   jnz  cps2                            ; no, go skip some more...

                                        ;---------------------------------------
                                        ; CX:0 is the correct pointer to a PDB.
                                        ;---------------------------------------
   push ds
   mov  ds,cx
                                        ;---------------------------------------
                                        ; Given a PDB at DS:0, scan his handle
                                        ;  table and then loop through the next
                                        ;  PDB link.
                                        ;---------------------------------------
cps15:
   call CPJ                             ; free for this PDB
   lds  cx,DS:[PDB_Next_PDB]            ; advance to next
   cmp  cx,-1
   jnz  cps15                           ; there is another link to process
   pop  ds
                                        ;---------------------------------------
                                        ; We have processed the current
                                        ;  allocation block pointed to by DS.
                                        ;  DS:[0] is the allocation block
                                        ;---------------------------------------
cps2:
   cmp  ds:[arena_signature],arena_signature_end
   jz   cps3                            ; no more blocks to do
   mov  bx,ds                           ; get current address
   add  bx,DS:[Arena_size]              ; add on size of block
   inc  bx                              ; remember size of header
   mov  ds,bx                           ; link to next
   jmp  cps1
                                        ;---------------------------------------
                                        ; Just for good measure, use CurrentPDB
                                        ;  and clean off him
                                        ;---------------------------------------
cps3:
   mov  ds,CurrentPDB

   call CPJ

cps31:

   RestoreReg <

   RestoreReg <CX,BX,AX,DI,ES,SI,DS>

   ret

   EndProc CPS

;******************* START OF SPECIFICATIONS ***********************************
;
; CPJ -
;
; Scan JFN table for SFT # and put in -1 if found
;
; Input: DS:0 is PDB
;        AL is SFT index # of interest
;
; Output: None
;
; Uses: Flags,CX,ES,DI
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure CPJ,NEAR

   assume ds:nothing,es:nothing

   mov  cx,ds:[PDB_JFN_length]
   les  di,ds:[PDB_JFN_pointer]
   cld
cpj1: repne scasb

   retnz                                ; none found

   mov  byte ptr es:[di-1],-1           ; free this
   jcxz CPJret                          ; Found one in last JFN entry
   jmp  cpj1                            ; keep looking
CPJret:

   ret

   EndProc CPJ

   Break <SFM - convert an mft pointer into a serial number>

;******************* START OF SPECIFICATIONS ***********************************
;
;   SFM - convert a pointer to a mft entry into the serial number for that
;   entry.  We keep these around to see if a FCB really points to the correct
;   SFT.
;
;   Inputs:     BX is the mft pointer
;   Outputs:    BX is the serial number
;   Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure SFM,NEAR

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSDATA

IFDEF VCB_HMA
   push ds
   call get_ds
   mov  bx,[bx].mft_serl
   pop  ds
ELSE
   mov  bx,cs:[bx].mft_serl
ENDIF

   ret

   EndProc SFM

   Break <ShChk - check a fcb for share related information>

;******************* START OF SPECIFICATIONS ***********************************
;
;   ShChk - check a fcb for share related information
;
;   ShChk - checks the reserved field contents of an FCB with a SFT to see
;   if they represent the same file.  The open ref count must be > 0.
;
;   Inputs:     DS:SI point to FCB
;               ES:DI point to SFT
;   Outputs:    Carry Set if contents do not match
;               Carry clear if contents match
;                   BX has first cluster
;   Registers Revised: none
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure ShChk,NEAR

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSDATA

   CMP  ES:[DI].sf_ref_count,0
   JZ   BadSFT
   MOV  BX,ES:[DI].sf_mft               ; Local file or dev with sharing

   call SFM

   CMP  BX,[SI].fcb_l_mfs
   JNZ  BadSFT
   MOV  BX,[SI].fcb_l_firclus

   ret

BadSFT: stc

   ret

   EndProc ShChk

   Break <ShSave - save information from SFT into an FCB>

;******************* START OF SPECIFICATIONS ***********************************
;
;   ShSave - save information from SFT into an FCB
;
;   ShSave - copy information into the reserved area of an FCB from a SFT.
;   This is so that we can later match the SFT with the FCB.
;
;   Inputs:     ES:DI point to SFT
;               DS:SI point to FCB
;   Outputs:    FCB reserved field is filled in
;               BL = FCBSHARE
;   Registers Revised: AX,BX
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure ShSave,NEAR

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSDATA

   MOV  AL,ES:[DI].sf_attr              ; move attribute (for reopen)
   MOV  [SI].FCB_l_attr,AL
   MOV  AX,ES:[DI].sf_firclus           ; get first cluster
   MOV  [SI].FCB_l_firclus,AX
   MOV  BX,ES:[DI].sf_mft               ; get sharing pointer

   call SFM

   MOV  [SI].FCB_l_mfs,BX
   MOV  BL,FCBSHARE

   ret

   EndProc ShSave

   Break <ShCol - collapse identical handle SFTs in mode 70 only>

;******************* START OF SPECIFICATIONS ***********************************
;
;   ShCol - collapse identical handle SFTs in mode 70 only
;
;   ShCol - collapse same 70-mode handles together.  This represents network
;   originated FCBs.  Since FCB's are incredibly mis-behaved, we collapse the
;   SFT's for identical files, thus using a single sft for each file instead
;   of a separate sft for each instance of the file.
;
;   Note that the redirectors will collapse multiple instances of these
;   files together.  FCB's are pretty misbehaved, so the redirector will
;   inform us of EACH close done on an FCB.  Therefore, we must increment
;   the ref count each time we see a collapse here.
;
;   Inputs:     DS:SI ThisSFT has new sft to find.
;   Outputs:    Carry set - no matching SFT was found
;               Carry clear - matching SFT was found and all collapsing done.
;                   AX has proper handle
;   Registers Revised: all.
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure ShCol,NEAR

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSDATA

                                        ;---------------------------------------
                                        ; Collapse the files ONLY if
                                        ;  the mode is for net FCB's
                                        ;---------------------------------------

   MOV  AL,BYTE PTR [SI].sf_mode
   AND  AL,sharing_mask
   CMP  AL,sharing_net_FCB
   JNZ  UseJFN

                                        ;---------------------------------------
                                        ; In share support
                                        ;---------------------------------------

   XOR  BX,BX                           ;   for (i=0; sffromsfn(i); i++) {
OpenScan:

   CallInstall SFFromSFN,multDOS,22,bx,bx

   JC   UseJFN

   CallInstall PointComp,multDOS,20     ;       if (!pointcomp (s,d))

   JZ   OpenNext
   CMP  ES:[DI].sf_ref_count,0
   JZ   OpenNext
   MOV  AX,ES:[DI].sf_mode
   CMP  AX,[SI].sf_mode
   JNZ  OpenNext
   MOV  AX,ES:[DI].sf_mft
   CMP  AX,[SI].sf_mft
   JNZ  OpenNext
   MOV  AX,WORD PTR ES:[DI].sf_UID
   CMP  AX,WORD PTR [SI].sf_uid
   JNZ  OpenNext
   MOV  AX,WORD PTR ES:[DI].sf_pid
   CMP  AX,WORD PTR [SI].sf_pid
   JZ   OpenFound
OpenNext:
   INC  BX
   JMP  OpenScan
                                        ;--------------------------------------
                                        ; DS:SI points to an sft which is a
                                        ;        duplicate of that found in
                                        ; ES:DI is the older one.
                                        ;
                                        ; We call mftclose to release the
                                        ;   appropriate info.
                                        ;--------------------------------------
OpenFound:
   MOV  [SI].sf_ref_count,0             ; free 'new' sft

   SaveReg <DS,SI,ES,DI,BX>

   Context DS

   LES  DI,ThisSFT

   call MFTClose

   RestoreReg <AX,DI,ES,SI,DS>

   ASSUME DS:NOTHING

   INC  ES:[DI].sf_ref_count            ;   d->refcount++;
   XOR  BX,BX                           ; find jfn with sfn as contents
JFNScan:

   CallInstall pJFNFromHandle,multDOS,32,AX,AX

   JC   UseJFN                          ; ran out of handles?
   CMP  AL,BYTE PTR ES:[DI]             ; does JFN have SFN?
   jz   JFNfound                        ; YES, go return JFN
   INC  BX                              ; no, look at next
   JMP  JFNScan
JFNFound:
   LDS  SI,pJFN
   MOV  BYTE PTR [SI],0FFh              ; free JFN
   MOV  AX,BX                           ; return JFN

   ret

UseJFN:
   MOV  AX,JFN

   ret

   EndProc ShCol

   Break <ShCloseFile - close a particular file for a particular UID/PID>

;******************* START OF SPECIFICATIONS ***********************************
;
;   ShCloseFile - close a particular file for a particular UID/PID
;
;   ShCloseFile - Compatability mode programs will often delete files that
;   they had open.  This was perfectly valid in the 2.0 days, but this
;   presents a reliability problem in the network based operating environment.
;   As a result, both RENAME and DELETE will call us to see if the file is
;   open by is only.  If it is not open or is open by us only, we close it.
;   Note that we will ONLY close compatability SFTs.
;   Otherwise, we signal and error.
;
;   Inputs:     WFT_Start has a DOSDATA offset to the file name
;               DS is DOSData
;   Outputs:    ES:DI contains address of DEL_sft        ; I001
;   Registers Revised: ES,DI                             ; I001
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure ShCloseFile,NEAR

   ASSUME DS:DOSDATA,ES:NOTHING,SS:DOSDATA

;; SaveReg <AX,BX,CX,DX,SI,DI,BP,DS,ES>                        ; I001
   SaveReg <AX,BX,CX,DX,SI,BP,DS>                              ; I001

   EnterCrit critShare

ShCl:
   MOV  SI,WFP_Start
   XOR  AL,AL

   call FNM                             ; attempt to find name in list

   ASSUME DS:NOTHING

   JC   ShCloseDone                     ; can't find, signal success

                                        ;--------------------------------------
                                        ; We have found a file in the MFT.
                                        ;  Walk the open sft list to find
                                        ;  the SFTs for the current UID/PID.
                                        ;--------------------------------------
   MOV  CX,DS
   LDS  SI,[BX].mft_sptr
ShClCheck:
   MOV  AX,Proc_ID
   CMP  [SI].sf_PID,AX
   JNZ  ShCloseDone
   MOV  AX,User_ID
   CMP  [SI].sf_UID,AX
   JNZ  ShCloseDone
   MOV  AX,[SI].sf_mode
   AND  AX,sharing_mask
   CMP  AX,sharing_net_fcb
   jz   ShClNext
   CMP  AX,sharing_compat
   jnz  ShCloseDOne
ShClNext:
   LDS  SI,[SI].sf_chain
   OR   SI,SI
   JNZ  ShClCheck
   MOV  DS,CX
   LDS  SI,[BX].mft_sptr
                                        ;--------------------------------------
                                        ; Everything matches.  Set up ThisSFT
                                        ;  and walk the chain from the beginning.
                                        ;--------------------------------------
   MOV  WORD PTR ThisSFT,SI
   MOV  WORD PTR ThisSFT+2,DS
                                        ;--------------------------------------
                                        ; Close all handles for this SFT
                                        ;--------------------------------------
   call CPS
                                        ;--------------------------------------
                                        ; Close the sft itself.
                                        ;--------------------------------------
   Context DS

   CallInstall DOS_Close,multDos,1
                                        ;--------------------------------------
                                        ; The SFT may be free and we have no
                                        ;  idea where the next is.  Go and loop
                                        ;  all over.
                                        ;--------------------------------------
   JMP  ShCl
                                        ;--------------------------------------
                                        ; There are no more SFTs to close. Leave
                                        ;---------------------------------------
ShCloseDone:

IFDEF VCB_HMA
   MOV  AX,SEG SHARE
ELSE
   MOV  AX,CS                           ; I001
ENDIF
IFDEF VCB_SFT_OPT
   SUB  AX,10H                          ; Define DEL_SFT in SHARE PSP
   MOV  ES,AX                           ;  at offset 80h
   MOV  DI,80H
ELSE
   MOV  ES,AX                           ; I001
   MOV  DI,OFFSET DEL_sft               ; I001
ENDIF

   LeaveCrit critShare

   STC

;; RestoreReg <ES,DS,BP,DI,SI,DX,CX,BX,AX>  ; I001
   RestoreReg <DS,BP,SI,DX,CX,BX,AX>        ; I001

   ret

   EndProc ShCloseFile

   .xall
   Break <ShSU - update all SFTs for a specified change>
;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:           ShSU - update all SFTs for a specified change>
;
;  FUNCTION:       In a shared environment, we want to propogate the SFT
;                  changes for a particular file to all other SFTs for that
;                  file.  The types of things we propogate are:
;
;                  - Time of last write - we only do this on CLOSE and on
;                    FILETIMES.
;
;                  - Size and allocation information - we do this ONLY when
;                    we change sf_size.
;
;                  We achieve this by walking the linked list of SFTs for the
;                  file. See PSEUDOCODE below
;
;  INPUT:          ES.DI  has SFT that was just Revised.
;                  AX = 0 for updating of time from ES:DI into old sfts
;                  AX = 1 for updating of size/allocation for growth from ES:DI
;                  AX = 2 for updating of size/allocation for shrink from ES:DI
;                  AX = 3 for new instance copy into ES:DI
;                  AX = 4 for update of codepage and high attribute
;
;  OUTPUT:         All relevant SFTs are updated.
;
;  REGISTERS USED: All except ES:DI and DS:SI
;  (NOT RESTORED)
;
;  LINKAGE:        DOS Jump Table
;
;  EXTERNAL        Invoke: New_Sft, Call_IFS
;  REFERENCES:     Callinstall
;
;  NORMAL          -
;  EXIT:
;
;  ERROR           -
;  EXIT:
;
;  CHANGE          04/15/87 - Major overhaul and IFS support
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START ShSU
;
;       if not a device and
;       if not a network
;               search
;                       if our SFT
;                               advance to next SFT
;                       endif
;               leave if no more SFT's
;               exitif cx = 3
;                       invoke New_Sft
;               orelse
;                       if cx = 0
;                               update time
;                               update date
;                               if non - FAT file system
;                                       call IFSFUNC
;                               endif
;                       else cx = 1 or 2
;                               update size
;                               if non - FAT file system
;                                       call IFSFUNC
;                               else
;                                       update first cluster
;                                       if cx = 2 or
;                                       if lstclus un-set from create
;                                               update cluster position
;                                               update last cluster
;                                       endif
;                               endif
;                       endif
;                       advance to next SFT
;               endloop
;               endsearch
;       endif
;       return
;
;       END ShSU
;
;******************+  END  OF PSEUDOCODE +**************************************

   Procedure ShSU,near

   ASSUME DS:NOTHING,ES:NOTHING

   nop
;  int 3
   nop

ifs_flag equ 8000h                      ;                                      ;AN000;
                                        ;---------------------------------------
                                        ; Do nothing for device or network
                                        ;---------------------------------------

   mov  bx,es:[di].sf_flags             ; M004: must check sf_flags field
;; mov  bx,es:[di].sf_mode              ; M004: sf_mode

   and  bx,sf_isnet + devid_device

;  $if  z,and,long                      ; if not device and                    ;AC000;
   JZ $$XL1
   JMP $$IF4
$$XL1:

   mov  bx,es:[di].sf_MFT
   or   bx,bx

;  $if  nz,,long                        ; if not network                       ;AC000;
   JNZ $$XL2
   JMP $$IF4
$$XL2:

       EnterCrit critShare
                                        ;---------------------------------------
                                        ; Walk the sft chain for this file and
                                        ;  skip the current SFT (ES:DI)
                                        ;---------------------------------------
       SaveReg <DS,SI>

IFDEF VCB_HMA
       call get_ds
       lds  si,[bx].MFT_SPTR
ELSE
       lds  si,cs:[bx].MFT_SPTR
ENDIF
       mov  cx,ax

;      $search                          ;                                      ;AC000;
$$DO5:

           CallInstall PointComp,multDOS,20 ; pointers different?

;          $if  z                       ; if ourselves                         ;AC000;
           JNZ $$IF6

               lds  si,[si].sf_chain    ; move to next                         ;AC000;

;          $endif                       ; endif - ourselves                    ;AC000;
$$IF6:

           or   si,si

;      $leave z                         ;                                      ;AC000;
       JZ $$EN5

                                        ;---------------------------------------
                                        ; CX = 0 for updating of time
                                        ; CX = 1 for updating of size/allocation
                                        ;          for growth
                                        ; CX = 2 for updating of size/allocation
                                        ;          for shrink
                                        ; CX = 3 for new instance copy.
                                        ;---------------------------------------
           cmp  cx,2                    ;                                      ;AC000;

;      $exitif a                        ;                                      ;AC000;
       JNA $$IF5
                                        ;---------------------------------------
                                        ; CX = 3 for new instance copy.
                                        ; CX = 4 for codepage and high attrib update
                                        ;---------------------------------------
           cmp  cx,3                    ; cx = 3 ?                             ;an000;
;          $if  e                       ; yes                                  ;an000;
           JNE $$IF10
               call New_Sft             ;                                      ;AN000;
;;         $else                        ; cx = 4                               ;an000;
;;             call New_CP_Attrib       ; update codepage and high attrib      ;an000;
;          $endif                       ;                                      ;an000;
$$IF10:

;      $orelse                          ;                                      ;AC000;
       JMP SHORT $$SR5
$$IF5:

           or   cx,cx

;          $if  z                       ; if cx = 0 then                       ;AC000;
           JNZ $$IF13
                                        ;---------------------------------------
                                        ; CX = 0 for updating of time
                                        ;
                                        ; Copy time from ES:DI into DS:SI
                                        ;---------------------------------------
               mov  bx,es:[di].sf_time
               mov  [si].sf_time,bx
               mov  bx,es:[di].sf_date
               mov  [si].sf_date,bx
               test [si].sf_flags,ifs_flag ;                                   ;AN000;

;              $if  nz                  ; if non-FAT                           ;AC003;
               JZ $$IF14

                   call Call_IFS        ; tell IFS of SFT change               ;AN000;

;              $endif                   ; endif non- FAT                       ;AN000;
$$IF14:

;          $else                        ; else - must be >0 and <2             ;AC000;
           JMP SHORT $$EN13
$$IF13:
                                        ;---------------------------------------
                                        ; CX = 1 for updating of size/allocation
                                        ;         for growth
                                        ; CX = 2 for updating of size/allocation
                                        ;         for shrink
                                        ;
                                        ; We always copy size and firclus
                                        ;---------------------------------------
               mov  bx,word ptr es:[di].sf_size
               mov  word ptr [si].sf_size,bx
               mov  bx,word ptr es:[di].sf_size+2
               mov  word ptr [si].sf_size+2,bx
               test [si].sf_flags,ifs_flag ;                                   ;AN000;

;              $if  nz                  ; if non-FAT                           ;AC003;
               JZ $$IF17

                   invoke Call_IFS      ; tell IFS of SFT change               ;AN000;

;              $else                    ; else - its FAT                       ;AN000;
               JMP SHORT $$EN17
$$IF17:

                   mov  bx,es:[di].sf_firclus
                   mov  [si].sf_firclus,bx
                   cmp  cx,2            ;                                      ;AC000;

;                  $if  z,or            ; if SFT is shrinking or               ;AC000;
                   JZ $$LL19

                   cmp  [si].sf_lstclus,0 ; lstclus UN-set from a create?      ;AC000;

;                  $if  z               ; If it is, set lstclus and cluspos too;AC000;
                   JNZ $$IF19
$$LL19:
                                        ;---------------------------------------
                                        ; Shrink the file, move in new cluspos
                                        ;  and lstclus
                                        ;---------------------------------------
                       mov  [si].sf_cluspos,0 ; retrace from start
                       mov  [si].sf_lstclus,bx ; ditto

;                  $endif               ; endif - set lstclus and cluspos      ;AC000;
$$IF19:

;              $endif                   ; endif  FAT                           ;AN000;
$$EN17:

;          $endif                       ; enndif - > 0                         ;AC000;
$$EN13:
                                        ;---------------------------------------
                                        ; Link to next SFT
                                        ;---------------------------------------
           lds  si,[si].sf_chain

;      $endloop                         ;                                      ;AC000;
       JMP SHORT $$DO5
$$EN5:

;      $endsrch                         ;                                      ;AC000;
$$SR5:
                                        ;---------------------------------------
                                        ; All Done
                                        ;---------------------------------------
       RestoreReg <SI,DS>

       LeaveCrit critShare

;  $endif                               ; endif - device and network           ;AC000;
$$IF4:

   ret

   EndProc ShSU

   Break <New_Sft - update a new SFT>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:           New_Sft - update a new SFT
;
;  FUNCTION:       Copy all SFT information into a NEW sft of a SHARED file.
;
;
;  INPUT:          ES.DI  has SFT that was just Revised.
;                  DS:SI  has SFT that is to be updated
;
;  OUTPUT:         SFT is updated.
;
;  REGISTERS USED: AX, BX
;  (NOT RESTORED)
;
;  LINKAGE:        Invoked by: ShSU
;
;  EXTERNAL        Invoke: Call_IFS
;  REFERENCES:
;
;  CHANGE          04/15/87 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START New_Sft
;
;       update time
;       update date
;       update size
;       if   non - FAT file system
;               call IFSFUNC
;       else
;               update first cluster
;               update cluster position
;               update last cluster
;       endif
;       return
;
;       END New_Sft
;
;******************+  END  OF PSEUDOCODE +**************************************

   Procedure New_Sft,near               ;                                      ;AN000;

   mov  bx,[si].sf_time                 ; update time
   mov  es:[di].sf_time,bx
   mov  bx,[si].sf_date                 ; update date
   mov  es:[di].sf_date,bx
   mov  bx,word ptr [si].sf_size        ; update size
   mov  word ptr es:[di].sf_size,bx
   mov  bx,word ptr [si].sf_size+2
   mov  word ptr es:[di].sf_size+2,bx
   test es:[di].sf_flags,ifs_flag       ;                                      ;AN000;

;  $if  nz                              ; if non-FAT                           ;AC003;
   JZ $$IF26

       call Call_IFS                    ; tell IFS of SFT change               ;AN000;

;  $else                                ; else - its FAT                       ;AN000;
;  JMP SHORT $$EN26
   ret
$$IF26:

       mov  bx,[si].sf_firclus          ; update first cluster
       mov  es:[di].sf_firclus,bx
       mov  es:[di].sf_cluspos,0        ; retrace from start
       mov  es:[di].sf_lstclus,bx       ; ditto

;  $endif                               ; endif  FAT                           ;AN000;
$$EN26:

   ret                                  ; we'er done                           ;AN000;

   EndProc New_Sft                      ;                                      ;AN000;

   Break <New_CP_Attrib - update the codepage and attrib in SFT>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:           New_CP_Attrib - Update codepage and attrib in SFT
;
;  FUNCTION:       Copy all codepage and attrib into SFT of a SHARED file.
;
;
;  INPUT:          ES.DI  has SFT that was just Revised.
;                  DS:SI  has SFT that is to be updated
;
;  OUTPUT:         SFT is updated.
;
;  REGISTERS USED: AX, BX
;  (NOT RESTORED)
;
;  LINKAGE:        Invoked by: ShSU
;
;  EXTERNAL        Invoke: Call_IFS
;  REFERENCES:
;
;  CHANGE          10/06/87 - First release     - D. M. Sewell
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START New_CP_Attrib
;
;       Update codepage
;       Update high attribute
;       $if ifs_flag
;               call Call_IFS
;       $endif
;       return
;
;       END New_CP_Attrib
;
;******************+  END  OF PSEUDOCODE +**************************************

;; Procedure New_CP_Attrib,near         ;                                      ;AN000;

;; mov  bx,es:[di].SF_Codepage          ; update codepage                      ;an000;
;; mov  [si].SF_Codepage,bx             ;an000; dms;
;; mov  bl,es:[di].SF_Attr_Hi           ; update high attribute                ;an000;
;; mov  [si].SF_Attr,bl                 ;an000; dms;
;; test es:[di].sf_flags,ifs_flag       ;                                      ;AN000;

;; $if  nz                              ; if non-FAT                           ;AC003;

;;     call Call_IFS                    ; tell IFS of SFT change               ;AN000;

;; $endif                               ; endif  FAT                           ;AN000;

;; ret                                  ; we'er done                           ;AN000;

;; EndProc New_CP_Attrib                ;                                      ;AN000;


   Break <Call_IFS - warn IFS that SFT has changed>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:           Call_IFS - warn IFS that SFT has changed
;
;  FUNCTION:       Call IFS thru 2F interupt.
;
;  INPUT:          DS.SI  points to SFT that was just Revised.
;
;  OUTPUT:         none
;
;  REGISTERS USED: AX
;  (NOT RESTORED)
;
;  LINKAGE:        Invoked by: ShSU, New_SFT
;
;  EXTERNAL        Callinstall
;  REFERENCES:
;
;  CHANGE          04/15/87 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START Call_IFS
;
;       set up for INT
;       INT 2F
;       return
;
;       END Call_IFS
;
;******************+  END  OF PSEUDOCODE +**************************************

   Procedure Call_IFS,near              ;                                      ;AN000;

   CallInstall BlockUpdate,MultIFS,44,CX,CX ;                                  ;AC005;

   ret                                  ;                                      ;AN000;

   EndProc Call_IFS                     ;                                      ;AN000;

   Break <Internal error routines>

;******************* START OF SPECIFICATIONS ***********************************
;
; INTERR - INTernal ERRor routines
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure INTERR,NEAR

   ASSUME DS:NOTHING,ES:NOTHING,SS:NOTHING

IFNDEF VCB_HMA
   SaveReg <BX,SI,DS>                   ; save registers that get clobbered

   push cs                              ; gain addressability
   pop  ds

   call gout
ELSE
patch5:
   mov  si,0                            ; patched if in HMA
   add  si,ax                           ; get message to print

   call gout

patch6:
ENDIF

   off  si,IntErrMsg

   call gout

IFNDEF VCB_HMA
   RestoreReg <ds,si,bx>
ENDIF

INTERRL:jmp INTERRL                     ; hang here - we're sick

IFDEF VCB_HMA
gout: lods byte ptr cs:[si]
ELSE
gout: lodsb
ENDIF
   or   al,al
   retz
   mov  ah,0eh
   int  10h
   jmp  gout


   EndProc INTERR

   Break <INT 2F handler>

   IF   installed

IFDEF VCB_HMA
       extrn INT_2F:near
       extrn OLD2F:dword
ELSE
OLD2F  dd   ?

INT_2F  PROC FAR

        ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:NOTHING
        cmp  ah,multSHARE
        jnz  ContJ

;
;       00h its anyone else  - return 0FFh - loaded
;
        or      al,al           ;
        jnz     ContJ           ;not our function, pass it on

loaded:
        mov     al,0ffh ;indicate that Share is loaded

        iret
ContJ:
        jmp     OLD2F           ;chain on to next handler

INT_2F  ENDP
ENDIF   ; VCB_HMA

       ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:DOSData

IRP    rtn,<MFT_enter, MFTClose, MFTclU, MFTCloseP, MFTCloN, set_mult_block, clr_mult_block>
J&rtn  proc far
       call rtn
       ret
j&rtn  endp
endm

IRP    rtn,<chk_block, MFT_get, ShSave, ShChk, ShCol, ShCloseFile, ShSU>
J&rtn  proc far
       call rtn
       ret
j&rtn  endp
endm

IRP    sect,<critShare>
       Procedure E&sect,NEAR
       PUSH AX
       MOV  AX,8000h+sect
       INT  int_ibm
       POP  AX
       ret
       EndProc E&sect

       Procedure L&sect,NEAR
       PUSH AX
       MOV  AX,8100h+sect
       INT  int_ibm
       POP  AX
       ret
       EndProc L&sect
       ENDM

   ENDIF

;SR;
; The internal error messages are being included here. These have all been
;moved into a single file so that it is easy to internationalize the messages
;

include shmsg.inc



   BREAK <MFT and Lock Record Data Area>

;******************* START OF SPECIFICATIONS ***********************************
;
;       first MFT record
;
;       Note that the name field can have garbage after the trailing
;       00 byte.  This is because the field might be too long, but
;       not long enough (at least 16 extra bytes) to fragment.
;       in this case we copy the length of the string area, not
;       the length of the string and thus may copy tailing garbage.
;
;******************* END OF SPECIFICATIONS *************************************

PoolSize = 2048

   PUBLIC MFT

MFT DB  0                               ; free
   DW   PoolSize                        ; PoolSize bytes long

   IF   not  Installed

       DB   (PoolSize-3) DUP(0)         ; leave rest of record
MEND   DB   -1                          ; END record

lck1   DW   0                           ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck2   DW   OFFSET DOSDATA:lck1        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck3   DW   OFFSET DOSDATA:lck2        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck4   DW   OFFSET DOSData:lck3        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck5   DW   OFFSET DOSDATA:lck4        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck6   DW   OFFSET DOSDATA:lck5        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck7   DW   OFFSET DOSDATA:lck6        ; link
       DB   SIZE RLR_entry-2 DUP(0)
lck8   DW   OFFSET DOSDATA:lck7        ; link
       DB   SIZE RLR_entry-2 DUP(0)

       CODE ENDS

       %out Ignore this END error (blasted assembler)

   ENDIF

IF Installed

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING,SS:NOTHING

   IF1
InitSpace DW PoolSize
   ELSE
       IF   shareinit-MFT LT PoolSize
InitSpace  DW   PoolSize
       ELSE
InitSpace  DW   shareinit-MFT
       ENDIF
   ENDIF
InitLocks DW 20


JTable LABEL BYTE
   DD   ?
   DD   JMFT_Enter                      ;   1   MFT_enter
   DD   JMFTClose                       ;   2   MFTClose
   DD   JMFTclU                         ;   3   MFTclU
   DD   JMFTcloseP                      ;   4   MFTCloseP
   DD   JMFTcloN                        ;   5   MFTCloN
   DD   JSet_Mult_Block                 ;   6   Set_Mult_Block
   DD   JClr_Mult_Block                 ;   7   Clr_Mult_Block
   DD   JChk_Block                      ;   8   Chk_Block
   DD   JMFT_Get                        ;   9   MFT_get
   DD   JShSave                         ;   10  ShSave
   DD   JShChk                          ;   11  ShChk
   DD   JShCol                          ;   12  ShCol
   DD   JShCloseFile                    ;   13  ShCloseFile
   DD   JShSU                           ;   14  ShSU
JTableLen = $ - JTable

;       $SALUT  (4,9,17,36)
                                   ;---------------------------------------
                                   ;  STRUCTURE TO DEFINE ADDITIONAL
                                   ;  COMMAND LINE PARAMETERS
                                   ;---------------------------------------
PARMS   LABEL   DWORD
        DW      OFFSET PARMSX      ; POINTER TO PARMS STRUCTURE
        DB      0                  ; NO DELIMITER LIST FOLLOWS
        DB      0                  ; NUMBER OF ADDITIONAL DELIMITERS

                                   ;---------------------------------------
                                   ;  STRUCTURE TO DEFINE SORT
                                   ;  SYNTAX REQUIREMENTS
                                   ;---------------------------------------
PARMSX  LABEL   BYTE
        DB      0,0                ; THERE ARE NO POSITIONAL PARAMETERS
        DB      2                  ; THERE ARE TWO TYPES OF SWITCH
        DW      OFFSET SW          ; POINTER TO THE SWITCH DEFINITION AREA
        DW      OFFSET SW_OPT      ; POINTER TO THE SWITCH DEFINITION AREA
        DW      0                  ; THERE ARE NO KEYWORDS IN SHARE SYNTAX

                                   ;---------------------------------------
                                   ;  STRUCTURE TO DEFINE THE SWITCHES
                                   ;---------------------------------------

SW      LABEL   WORD
        DW      08001H             ; MUST BE NUMERIC
        DW      0                  ; NO FUNCTION FLAGS
        DW      OFFSET SWITCH_BUFF ; PLACE RESULT IN SWITCH BUFFER
        DW      OFFSET VALUES      ; NEED VALUE LIST
        DB      3                  ; TWO SWITCHES IN FOLLOWING LIST
F_SW    DB      "/F",0             ; /F: INDICATES n FILESPACE REQUESTED
L_SW    DB      "/L",0             ; /L: INDICATES m LOCKS REQUESTED
N_SW    DB      "/NC",0            ; /NC: INDICATES no checking required

        PUBLIC  SW_OPT, ?_SW
SW_OPT  LABEL   WORD
        DW      0                  ; MATCH MASK
        DW      0                  ; FUNCTION MASK
        DW      OFFSET SWITCH_BUFF ; PLACE RESULT IN SWITCH BUFFER
        DW      OFFSET VALUES      ; NEED VALUE LIST
IFDEF VCB_HMA
        DB      2                  ; 2 SWITCHES IN FOLLOWING LIST
NH_SW   DB      "/NOHMA",0
ELSE
        DB      1                  ; 1 SWITCH IN FOLLOWING LIST
ENDIF
?_SW    DB      "/?",0             ; /?   INDICATES give options help

                                   ;---------------------------------------
                                   ;  VALUE LIST DEFINITION FOR n
                                   ;---------------------------------------

VALUES  LABEL   BYTE
        DB      1                  ; ONE VALUE ALLOWED
        DB      1                  ; ONLY ONE RANGE
        DB      FILE_SWITCH        ; IDENTIFY IT AS n
        DD      1,65535            ; USER CAN SPECIFY /+1 THROUGH /+65535

                                   ;---------------------------------------
                                   ;  RETURN BUFFER FOR SWITCH INFORMATION
                                   ;---------------------------------------
;               $SALUT    (4,17,27,36)

SWITCH_BUFF     LABEL     BYTE
SW_TYPE         DB        ?        ; TYPE RETURNED
SW_ITEM_TAG     DB        ?        ; SPACE FOR ITEM TAG
SW_SYN          DW        ?        ; POINTER TO SWITCH LIST ENTRY
SW_VALUE        DD        ?        ; SPACE FOR VALUE

Exit_Msg                db      0       ;flag set if no exit on ShDispMsg ;M006
Fswitch         db      0       ;flag set if /F given ;M006
Lswitch         db      0       ;flag set if /L given ;M006
IFDEF VCB_HMA
nohma_flag      db      0
ENDIF

;  $SALUT (4,4,9,41)

   Break <INIT - INITalization routines>

;******************* START OF SPECIFICATIONS ***********************************
;
; INIT - INITalization routines
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure Init,NEAR

   PUSH CS
   POP  DS

   ASSUME DS:SHARE

   MOV  BX,InitSpace

   SUB  BX,3
   MOV  SI,OFFSET MFT

IFDEF   VCB_HMA
        extrn   hma_end:near
        extrn   get_ds:near
        extrn   patch1:byte
        extrn   patch2:byte
        extrn   patch3:byte
        extrn   patch4:byte
        push    bx                      ;Save BX
        push    es                      ;Save ES
        cmp     nohma_flag,1            ;Was /NOHMA specified ?
        je      @f                      ;Yes, skip
        mov     di,-1                   ;Load -1
        mov     bx,offset mft           ;Load required length
        sub     bx,offset hma_end
        mov     ax,4a02h                ;Allocate HMA function
        int     2fh                     ;Multiplex
        cmp     di,-1                   ;HMA available ?
        je      @f                      ;No
        mov     si,offset hma_end       ;Point to new resident end
        mov     mftptr,si               ;Update MFT pointer
        mov     ax,di                   ;Get relocation factor
        sub     ax,si
        mov     word ptr patch1+3,di    ;Fixup DS_ORG references
        mov     word ptr patch2+3,di
        mov     word ptr patch3+3,di
        add     word ptr patch4+3,ax    ;Fixup CUCA reference
        add     word ptr patch5+1,ax    ;Fixup errmsg references
        add     word ptr patch6+1,ax
        add     word ptr get_ds+3,ax    ;Fixup DSSEG reference
        mov     cx,bx                   ;Load length
        rep     movsb                   ;Copy code to HMA
        mov     di,offset jtable+4      ;Point to jump table
        mov     cl,(jtablelen/4)-1      ;Load table length
fix_loop:
        add     word ptr [di],ax        ;Update offset
        mov     word ptr [di+2],es      ;Update segment
        add     di,4                    ;Point to next entry
        loop    fix_loop                ;Iterate loop
        mov     si,offset hma_end       ;Point to new resident end
@@:     pop     es                      ;Restore ES
        pop     bx                      ;Restore BX
        mov     byte ptr [si],0
ENDIF   ; VCB_HMA

   MOV  WORD PTR [SI+1],BX              ; length of first item
IFNDEF VCB_HMA
   ADD  SI,BX                           ; link to end of structure
   MOV  BYTE PTR [SI],-1                ; signal end
   INC  SI                              ; point to next free byte

   MOV  CX,initlocks                    ; count for loop
   MOV  AX,0

;  $do                                  ;                                      ;AC000;
$$DO48:

       MOV  [SI].RLR_next,AX            ; link in previous
       MOV  AX,SI                       ; this is now previous
       ADD  SI,SIZE RLR_Entry           ; move to next object

;  $enddo loop                          ;                                      ;AC000;
   LOOP $$DO48

   MOV  FreLock,AX                      ; point to beginning of free list

   MOV  DX,CS
   MOV  BX,ES
   SUB  DX,BX
   ADD  SI,15
   RCR  SI,1
   SHR  SI,1
   SHR  SI,1
   SHR  SI,1

   ADD  SI,DX
   PUSH SI                              ; # of paras for share on stack
ENDIF   ; VCB_HMA

   MOV  AX,(Get_Interrupt_Vector SHL 8) + 2Fh
   INT  21h
   MOV  WORD PTR OLD2F,BX
   MOV  WORD PTR OLD2F+2,ES
   MOV  AX,(Set_Interrupt_Vector SHL 8) + 2Fh
   MOV  DX,OFFSET INT_2F
   INT  21h
                                        ;---------------------------------------
                                        ; Notify the DOS that we are around so that
                                        ; the DOS can make expensive calls to us.
                                        ;---------------------------------------
   MOV  AH,Get_In_Vars
   INT  21h

   ASSUME ES:DOSDATA

   MOV  fShare,-1                       ; tell DOS we are here                 ;AC011;
                                        ;---------------------------------------
                                        ; Cram in the new jump table
                                        ;---------------------------------------
   CLI
   MOV  SI,OFFSET JTable
   MOV  DI,OFFSET JShare
   MOV  CX,JTableLen/2
   REP  MOVSW

IFNDEF VCB_HMA
                                        ;---------------------------------------
                                        ; Examine the size of the FCB cache.
                                        ; If it is NOT the system default of 4,0
                                        ; change it (via reallocation) to 16,8.
                                        ; The old table is lost.
                                        ;---------------------------------------
   ASSUME DS:NOTHING

   CMP  KeepCount,0

;  $if  z,and                           ; if the ",0"  part and                ;AC000;
;* JNZ $$IF52
   JMP SHORT $$IF52

   LDS  SI,ES:[BX].SYSI_FCB             ; point to the existing cache
   CMP  [SI].sfCount,4

;  $if  z                               ; if the "4,"  part then               ;AC000;
   JNZ $$IF52

                                        ;---------------------------------------
                                        ; Whammo, we need to allocate 16 * size
                                        ; of SF_entry + size of sfTable.
                                        ; Compute this size in paragraphs
                                        ;---------------------------------------
       MOV  AX,16
       MOV  CX,size sf_entry
       MUL  CX
       ADD  AX,(size sf) - 2
                                        ;---------------------------------------
                                        ; This size is in bytes...
                                        ; Round up to paragraph size
                                        ;---------------------------------------
       ADD  AX,0Fh
       RCR  AX,1
       SHR  AX,1
       SHR  AX,1
       SHR  AX,1
                                        ;---------------------------------------
                                        ; AX is the number of paragraphs to add.
                                        ; Word on stack is current TNR size.
                                        ; Make dos point to new table
                                        ;---------------------------------------
       MOV  WORD PTR ES:[BX].SYSI_FCB,0
       MOV  WORD PTR ES:[BX].SYSI_FCB+2,SS
       POP  SI
       ADD  WORD PTR ES:[BX].SYSI_FCB+2,SI
                                        ;---------------------------------------
                                        ; Initialize table parts, next link
                                        ;   and size
                                        ;---------------------------------------
       MOV  DS,WORD PTR ES:[BX].SYSI_FCB+2
       MOV  WORD PTR DS:[sfLink],-1
       MOV  WORD PTR DS:[sfLink+2],-1
       MOV  DS:[sfcount],16
                                        ;---------------------------------------
                                        ; Set up succeeding LRU size
                                        ;---------------------------------------
       MOV  KeepCount,8

       ADD  SI,AX
       PUSH SI

;  $endif                               ; endif - "4,0"                        ;AC000;
$$IF52:
ENDIF   ; VCB_HMA

                                        ;---------------------------------------
                                        ; Clean out the FCB Cache
                                        ;---------------------------------------
   LES  DI,ES:[BX].SYSI_FCB

   ASSUME ES:Nothing

   MOV  CX,ES:[DI].SFCount
   LEA  DI,[DI].SFTable

;  $do                                  ;                                      ;AC000;
$$DO54:

       MOV  ES:[DI].sf_ref_count,0
       MOV  WORD PTR ES:[DI].sf_position,0
       MOV  WORD PTR ES:[DI].sf_position+2,0
       ADD  DI,SIZE sf_entry

;  $enddo loop                          ;                                      ;AC000;
   LOOP $$DO54

   STI

   ASSUME ES:NOTHING

   XOR  BX,BX
   MOV  CX,5                            ; StdIN,StdOUT,StdERR,StdAUX,StdPRN

;  $do                                  ; Close STD handles before             ;AC000;
$$DO56:
                                        ; keep process
       MOV  AH,CLOSE
       INT  21H
       INC  BX

;  $enddo loop                          ;                                      ;AC000;
   LOOP $$DO56

IFDEF VCB_HMA
        push    cs                      ;Get CS
        pop     ds                      ;Set DS = CS
        push    cs                      ;Get CS
        pop     es                      ;Set ES = CS
nops:   db  18 DUP(90h)
;        mov     si,offset finish        ;Point to finish code
;        mov     di,ds:mftptr            ;Get MFT pointer
;        add     di,3                    ;Add 3
;        push    di                      ;Push offset
;        mov     cx,finish_length        ;Load code length
;        rep     movsb                   ;Copy code
;        ret                             ;Goto finish code

finish:
        mov     si,ds:mftptr            ;Get MFT pointer
        mov     bx,[si+1]               ;Get length
        add     si,bx                   ;Point to end of MFT
        mov     byte ptr [si],-1        ;Indicate end of MFT
        inc     si                      ;Point to lock table
        mov     cx,ds:initlocks         ;Get lock count
        xor     ax,ax                   ;Load 0
@@:     mov     [si].rlr_next,ax        ;Set pointer
        mov     ax,si                   ;Get current address
        add     si,size rlr_entry       ;Point to next entry
        loop    @b                      ;Iterate loop
        mov     ds:frelock,ax           ;Set lock table pointer
        add     si,15                   ;Add 15 for rounding
        rcr     si,1                    ;Divide by 16
        shr     si,1
        shr     si,1
        shr     si,1
        lea     dx,[si+10h]             ;Add 10h for PSP
ELSE
   POP  DX                              ; T+R size in DX
ENDIF   ; VCB_HMA
   MOV  AX,(Keep_Process SHL 8) + 0
   INT  21h
   MOV  AX,(EXIT SHL 8) + 1
   INT  21h                             ; We'er now resident, return to DOS
IFDEF VCB_HMA
finish_length   equ     $-finish
ENDIF

   EndProc Init

   Break <SHAREINIT - Share initialization entry point>

;******************* START OF SPECIFICATIONS ***********************************
;
; SHAREINIT - Share initialization entry point
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure SHAREINIT,NEAR

   ASSUME CS:SHARE,DS:NOTHING,ES:NOTHING

;  int 3
   nop
   nop


   PUSH DS                              ; save PSP segment for later stack     ;AC001;
                                        ;     relocation

                                        ;---------------------------------------
                                        ; Load Messages
                                        ;---------------------------------------
   call ShLoadMsg                       ;                                      ;AN000;
                                        ;---------------------------------------
                                        ; At this point, the DOS version is OK.
                                        ;  (checked by SYSLOADMSG)
                                        ;  Now - Check the DOS data version
                                        ;---------------------------------------
;  $if  c,or                            ; if not same as us                     ;AC009;
   JC $$LL58

   MOV  AH,Get_In_Vars
   INT  21h

   ASSUME ES:DOSDATA

   CMP  DataVersion,ShareDataVersion

   ASSUME ES:NOTHING

;  $if  ne                              ; if not same as us                     ;AC000;
   JE $$IF58
$$LL58:
       mov  ax,(Utility_Msg_CLASS shl 8) + Bad_DOS_Ver ;                        ;AN000;
       call ShDispMsg                   ;                                       ;AN000;
;  $endif                               ; endif - not same as us                ;AC000;
$$IF58:

                                        ;---------------------------------------
                                        ; Deallocate memory if possible
                                        ;---------------------------------------
   mov  ax,ds:[pdb_environ]
   or   ax,ax

;  $if  nz                              ; if > 0 deallocate memory             ;AC000;
   JZ $$IF60
       mov  es,ax
       mov  ah,dealloc
       int  21h
;  $endif                               ; endif - > 0 deallocate memory        ;AC000;
$$IF60:

                                        ;---------------------------------------
                                        ; Parse the command line
                                        ;---------------------------------------
   call ShComndParse                    ;                                      ;AN000;
                                        ;---------------------------------------
                                        ; Check to see if share already installed.
                                        ;---------------------------------------
   mov  ah,multShare                    ;                                      ;AC010;
   xor  al,al
   INT  2Fh                             ;                                      ;AC010;
   CMP  AL,0FFh                         ;                                      ;AC010;
   JNZ $$IF62
                                        ;Share is already loaded
       mov  ax,(UTILITY_MSG_CLASS shl 8) + Sh_Already_Loaded ;                 ;AC010;
       call ShDispMsg                   ;                                      ;AC010;
$$IF62:
;
;M007; Begin changes
; Check to see if we are under the Dosshell. If so, we issue an error
;message and exit
;
        mov     ax,4b02h                ; see if switcher enabled
        xor     bx,bx
        push    es
        mov     es,bx
        mov     di,bx                   ; es:di <- 0 on entry
        int     2fh
        mov     ax,es
        pop     es
        or      ax,di                   ; es:di == 0 =>no switcher
        jz      Sh_noshell              ;switcher not present, continue
        mov     ax,(UTILITY_MSG_CLASS shl 8) + SH_DOSSHELL ;switcher present
        call    ShDispMsg               ;display error message & terminate

Sh_noshell:

                                        ;---------------------------------------
                                        ; All set to initialize the world.
                                        ; Make sure that we have enough memory
                                        ; for everything in our little 64K here.
                                        ; First get avail count of paras.
                                        ;---------------------------------------
   pop  es                              ; recover PSP segment                  ;AC002;
   push es                              ;                                      ;AC002;
   MOV  BX,CS
   MOV  AX,ES:[PDB_Block_Len]
   SUB  AX,BX
                                        ;---------------------------------------
                                        ; AX has the number of paragraphs
                                        ; available to us after the beginning
                                        ; of CS.  Max this out at 64K.
                                        ;---------------------------------------
   CMP  AX,1000h

;  $if  a                               ; if more than we can handle           ;AC000;
   JNA $$IF66
       MOV  AX,1000h                    ;  force it
;  $endif                               ; endif - more than we can handle      ;AC000;
$$IF66:

                                        ;---------------------------------------
                                        ; Take AX paragraphs and convert them
                                        ; into BX:CX bytes.
                                        ;---------------------------------------
   XOR  BX,BX
   SHL  AX,1
   SHL  AX,1
   SHL  AX,1
   SHL  AX,1
   ADC  BX,0
   MOV  CX,AX
                                        ;---------------------------------------
                                        ; compute in DX:AX, the size
                                        ; requested by the user
                                        ;---------------------------------------
   MOV  AX,initlocks
   MOV  SI,size RLR_Entry
   MUL  SI
   ADD  AX,OFFSET MFT
   ADC  DX,0
   ADD  AX,InitSpace
   ADC  DX,0
                                        ;---------------------------------------
                                        ; Compare the 32 bit sizes DX:AX and BX:CX.
                                        ; If BX:CX is smaller, then we
                                        ; are out of memory.
                                        ;---------------------------------------

   CMP  DX,BX                           ; try upper half first

;  $if  a,or                            ; if most significant is bigger or     ;AC000;
   JA $$LL68

;  $if  e,and                           ; if equal and                         ;AC000;
   JNE $$IF68

   CMP  AX,CX                           ;

;  $if  a                               ; if least significant is bigger       ;AC000;
   JNA $$IF68
$$LL68:

       mov  ax,(EXT_ERR_CLASS shl 8) + No_Mem_Error ; issue error message      ;AN000;

       call ShDispMsg                   ;                                      ;AN000;

;  $endif                               ; endif - bigger                       ;AC000;
$$IF68:

;SR;
; Display the installed message here
;
   mov  ax,(UTILITY_MSG_CLASS shl 8) + SH_LOADED
   mov  Exit_Msg,1                      ;do not exit after message ;M006
   call ShDispMsg                       ;will return for this call
   mov  Exit_Msg,0                      ;reset exit flag ;M006


                                        ;--------------------------------------
                                        ; Move stack to PSP area.  Otherwise we
                                        ; will run into problems with growing
                                        ; the stack into the lock records.
                                        ;---------------------------------------
   POP  AX                              ; this is the entry value for DS (PSP) ;AC001;
   MOV  SS,AX                           ;                                      ;AC001;
   MOV  SP,100h                         ;                                      ;AC001;

   ASSUME SS:NOTHING
                                        ;---------------------------------------
                                        ; Continue with rest of initialization
                                        ;---------------------------------------
   JMP  INIT

   EndProc SHAREINIT

   Break <ShLoadMsg  -  Share Load Message>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:        ShLoadMsg  -  Share Load Message
;
;  FUNCTION:    Load the Share messages into the message buffer.
;
;  INPUT:       None
;
;  OUTPUT:      Messages loaded into the message buffer and Message
;               Sevices code initalized
;
;  REGISTERS USED:  DI AX CX DX
;  (NOT RESTORED)
;
;  LINKAGE:     Call near
;
;  NORMAL       CF = O
;  EXIT:
;
;  ERROR        CF = 1
;  EXIT:
;
;  CHANGE       04/15/87 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************

                                        ;---------------------------------------
                                        ; Message Equates
                                        ;---------------------------------------

;                         $SALUT (4,27,34,41)

Bad_DOS_Ver               equ    1      ; Incorrect DOS version                ;AN000;
Sh_Already_Loaded         equ    2      ; SHARE already loaded message number  ;AN000;
No_Mem_Error              equ    8      ; insufficient memory message number   ;AN000;

;SR;
; Share installed messafe

SH_LOADED                 equ    9      ; Share loaded message

SH_DOSSHELL               equ   3       ; Share cannot load under dosshell

;  $SALUT (4,4,9,41)

   Procedure ShLoadMsg,near             ;                                      ;AN000;
                                        ;---------------------------------------
                                        ; Load the Messages
                                        ;---------------------------------------
EXTRN SYSLOADMSG:NEAR                   ;                                      ;AN000;

   call SYSLOADMSG                      ;                                      ;AN000;

;  $IF  C                               ; if we have a MAJOR problem           ;AN000;
   JNC $$IF70
       mov  ah,dh                       ; save the class
       call ShDispMsg                   ;                                      ;AN000;
                                        ; For pre DOS 2.0, we may come back
       xor  ax,ax                       ;   here - so do it the old way
       push ss                          ;   just in case
       push ax                          ;

xxx    proc far                         ;                                      ;AN000;
       ret                              ;                                      ;AN000;
xxx    endp                             ;                                      ;AN000;

;  $ENDIF                               ; endif - we have a MAJOR problem      ;AN000;
$$IF70:


   ret                                  ;                                      ;AN000;

   EndProc ShLoadMsg                    ;

   Break <ShDispMsg  -  Share Display Message>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:        ShDispMsg  -  Share Display Message
;
;  FUNCTION:    Display the messages for share
;
;  INPUT:       AX = message number - AH - Class
;                                     AL - Number
;
;  OUTPUT:      - Messages output to Output Device
;               - Exit to DOS
;
;  REGISTERS USED:  CX DX
;  (NOT RESTORED)
;
;  LINKAGE:     Call near
;
;  NORMAL       CF = O
;  EXIT:
;
;  ERROR        CF = 1
;  EXIT:        CX = 0 - INCORRECT DOS VERSION
;
;  CHANGE       04/15/87 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************

;                         $SALUT (4,27,34,41)

                                        ; The following structure is a
                                        ;   SYSMSG SUBLIST control block.
                                        ;   It is initalized for the "already
                                        ;   installed " message.  The parse
                                        ;   routine will set it up to work
                                        ;   for parseing.
SUBLIST                   LABEL  WORD

                          db     sub_size ; size of sublist
                          db     0      ; reserved
msg_offset                dw     offset SHARE_Name ; insert 'SHARE'

msg_segment               LABEL  WORD

IF                        NOT    INSTALLED

                          dw     CODE

ELSE

                          dw     SHARE

ENDIF

num_ins                   db     1      ; only one insert
                          db     Char_Field_ASCIIZ ; data type flag - ascii z string
max_ins                   db     SHARE_Name_Size ; maximum field size
min_ins                   db     SHARE_Name_Size ; minimum field size
                          db     " "    ; pad character

sub_size                  equ    $ - SUBLIST

SHARE_Name                LABEL  WORD

                          db     "SHARE"

SHARE_Name_Size           equ    $ - Share_Name

                          db     0      ; make it a Z string
;  $SALUT (4,4,9,41)

   Procedure ShDispMsg,near             ;                                      ;AN000;
                                        ;---------------------------------------
                                        ; Set up required parameters
                                        ;--------------------------------------
   MOV  BX,STDERR                       ;display message on STD ERROR          ;AN000;
   XOR  CX,CX                           ;no substitution required              ;AN000;
   XOR  DX,DX                           ;set flags to 0                        ;AN000;
   DEC  DH                              ;and class to utility                  ;AN000;
   cmp  ah,PARSE_ERR_CLASS              ;
;  $if  be,and                          ;                                      ;AC009;
   JNBE $$IF72
   mov  dh,ah                           ;
;  $if  e                               ; set up implied substitution          ;AC009;
   JNE $$IF72

       ASSUME DS:nothing,ES:DOSDATA

       mov  num_ins,cl                  ; set number of inserts to 0           ;AN009;
       mov  BYTE PTR max_ins,030h       ; set maximum size of insert           ;AN009;
       mov  BYTE PTR min_ins,1          ; set minimum size of insert           ;AN009;
       push ds                          ; set up segment                       ;AN009;
       pop  [msg_segment]               ;                                      ;AN009;
       mov  BYTE PTR ds:[si],0          ; turn it into a ASCIIZ string         ;AN009;
       cmp  si,msg_offset               ; is there something there?            ;AN009;
;      $if  a                           ; if it is...                          ;AN009;
       JNA $$IF73
           inc  cx                      ;                                      ;AN009;
;      $endif                           ;                                      ;AN009;
$$IF73:
;  $endif                               ;
$$IF72:
   cmp  al,Sh_Already_Loaded            ; SHARE already loaded message ?       ;AN000;
;  $if  e                               ; if it is...                          ;AN000;
   JNE $$IF76

   mov  num_ins,1                       ;Set inserts to 1 ;M006
   push cs                              ;M006
   pop  msg_segment                     ;Set segment for name ;M006

       inc  cx                          ;
       mov  msg_offset,OFFSET SHARE_name ; ensure the pointer is right         ;AN010;
       jmp  short not_loadmsg
;  $endif                               ;
$$IF76:
;M002;
; Parse error message has the same number. Make sure the message does not
;belong to the parse class.
;
   cmp  dh,PARSE_ERR_CLASS              ;M002
   je   not_loadmsg                     ;M002

;SR;
; If this is the Share Installed message, ensure that pointer is at name
;
   cmp  al, SH_LOADED
   jne  not_loadmsg

   mov  num_ins,1                       ;Set inserts to 1 ;M006
   push cs                              ;M006
   pop  msg_segment                     ;Set segment for name ;M006

   inc  cx
   mov  msg_offset,OFFSET SHARE_name
not_loadmsg:

   push cs                              ; ensure that SYSMSG has proper        ;AC009;
   pop  ds                              ;          addressability              ;AC009;
   lea  si,SUBLIST                      ; point to sublist                     ;AC009;

   push ax                              ;SR; save for later check
   xor  ah,ah                           ;                                      ;AN000;

                                        ;--------------------------------------
                                        ; Output the Message
                                        ;---------------------------------------
EXTRN SYSDISPMSG:NEAR                   ;                                      ;AN000;

   CALL SYSDISPMSG                      ;                                      ;AN000;

   pop  ax                              ;restore ax

;  $IF  C                               ; if error occured                     ;AN000;
   JNC $$IF78

       CALL Get_DOS_Error               ; a DOS extended error occured         ;AN000;
       CALL SYSDISPMSG                  ; try to issue it                      ;AN000;

;  $ENDIF                               ; endif - error occured                ;AN000;
$$IF78:

;M006
; Check if flag for no exit is set. If so, do not exit.
;
   cmp  Exit_Msg,1                      ; should we exit? ;M006
   jnz  doexit                          ; yes
   ret
doexit:

   MOV  AX,(EXIT SHL 8) + 0FFH          ; exit to DOS                          ;AN000;
   INT  21h                             ;                                      ;AN000;

   ret                                  ; may return if pre DOS 2.0            ;AN000;

   EndProc ShDispMsg                    ;                                      ;AN000;

   BREAK < Get_DOS_Error >

;******************* START OF SPECIFICATIONS ***********************************
;Routine name: Get_DOS_Error
;*******************************************************************************
;
;Description:  Call DOS to obtain DOS extended error #
;
;Called Procedures: None
;
;Input:             None
;
;Output:            AX = error number
;                   DH = DOS extended error class
;
;Change History:    Created        5/01/87         FG
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START  Get_DOS_Error
;
;       call DOS for extended error (INT21 GetExtendedError + 00 <5900>)
;       set up registers for return
;       ret
;
;       END  Get_DOS_Error
;
;******************-  END  OF PSEUDOCODE -**************************************

   public Get_DOS_Error

   Get_DOS_Error PROC NEAR

   mov  ax,(GetExtendedError shl 8)     ; DOS ext. error                       ;AN000;
   xor  bx,bx
   push es                              ;                                      ;AN000;
   INT  21h                             ;    GetExtendedError + not_used <5900>;AN000;
   pop  es
   mov  bx,STDERR                       ; fix up bx                            ;AN000;
   xor  cx,cx                           ; fix up cx                            ;AN000;
   mov  dh,EXT_ERR_CLASS                ; set class to dos error

   ret                                  ;                                      ;AN000;

   ENDPROC Get_DOS_Error

   Break <ShComndParse  -  Share Command line Parser>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:        ShComndParse  -  Share Command line Parser
;
;  FUNCTION:    Call the DOS PARSE Service Routines to process the command
;               line. Search for valid switches (/F:n and /L:m) and
;               update the values for file size and number of locks accordingly
;
;  INPUT:       Parameter string from command line in the PSP
;
;  OUTPUT:      INITspace and INITlocks are updated.
;
;  REGISTERS USED: ES DI AX BX CX DX
;  (NOT RESTORED)
;
;  LINKAGE:     Call
;
;  NORMAL       - If /F:n specified, then INITspace is updated.
;  EXIT:        - If /L:m specified, then INITlocks is updated.
;
;  ERROR        If user enters:
;  EXIT:        - any parameter or switch other than /F:n or /L:m
;               - an invalid value for "n" or "m"
;               then this routine will display the "Invalid Parameter"
;               error message and terminate.
;
;  EXTERNAL     - System parse service routines
;  REFERENCES:  - INT21 - GET PSP Function Call 062h
;
;  CHANGE       04/15/87 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************
;******************+ START OF PSEUDOCODE +**************************************
;
;       START
;
;       return
;
;       END
;
;******************-  END  OF PSEUDOCODE -*************************************

;                         $SALUT (4,27,34,41)

                                        ;--------------------------------------
                                        ; Parse Equates
                                        ;--------------------------------------

EOL                       equ    -1     ; Indicator for End-Of-Line            ;AN000;
NOERROR                   equ    0      ; Return Indicator for No Errors       ;AN000;
FILE_SWITCH               equ    1      ; this is a file switch                ;AN000;
LOCK_SWITCH               equ    2      ; this is a lock switch                ;AN000;
Syntax_Error              equ    9      ; maximum PARSE error #                ;AN000;

INV_SWITCH              equ      3      ;invalid switch ( for /NC)
TOOMANYPARMS            equ     1       ;too many parameters ;M006

MSG_OPTIONS_FIRST       equ     300     ; first line of options msg
MSG_OPTIONS_LAST        equ     304     ; last line of options msg

;  $SALUT (4,4,9,41)

   Procedure ShComndParse,near          ;                                      ;AN000;
                                        ;--------------------------------------
                                        ;  Get address of command line
                                        ;--------------------------------------
EXTRN SYSPARSE:NEAR                     ;                                      ;AN000;

   MOV  SI,0081H                        ; OFFSET OF COMMAND LINE IN PSP        ;AN000;
   MOV  AH,62H                          ; AH=GET PSP ADDRESS FUNCTION CALL     ;AN000;
   INT  21H                             ; PSP SEGMENT RETURNED IN BX           ;AN000;
   MOV  DS,BX                           ; PUT PSP SEG IN DS                    ;AN000;
   MOV  CX,0                            ; NUMBER OF PARMS PROCESSED SO FAR     ;AN000;
   PUSH CS                              ;                                      ;AN000;
   POP  ES                              ;                                      ;AN000;

   ASSUME ES:SHARE                      ;                                      ;AN000;

                                        ;--------------------------------------
                                        ;  Loop for each operand at DS:SI
                                        ;--------------------------------------
;  $do                                  ;                                      ;AN000;
$$DO80:

       LEA  DI,PARMS                    ; ADDRESS OF PARSE CONTROLS            ;AN000;
       MOV  DX,0                        ; RESERVED                             ;AN000;
       mov  msg_offset,si               ; save the start scan point            ;AC009;
       CALL SYSPARSE                    ; PARSE IT!                            ;AN000;
       CMP  AX,EOL                      ; ARE WE AT END OF COMMAND LINE ?      ;AN000;

;  $leave e                             ;                                      ;AN000;
   JnE  @f                              ;M006
       jmp      $$EN80                  ;M006
@@:                                     ;M006

       CMP  AX,NOERROR                  ; ANY ERRORS?                          ;AN000;

;      $if  ne,or                       ; if parse says error or               ;AN000;
       JNE $$LL82

       MOV  AX,Syntax_Error             ; Parse syntax error - just in case    ;AN000;
       MOV  BX,DX                       ; PLACE RESULT ADDRESS IN BX           ;AN000;
       CMP  BX,OFFSET SWITCH_BUFF       ;                                      ;AN000;

;      $if  ne                          ; if no pointer                        ;AN000;
       JE $$IF82
$$LL82:

           call PARSE_ERROR             ;   call error routine                 ;AN000;

;      $endif                           ; endif - error                        ;AN000;
$$IF82:

       MOV  AX,WORD PTR SW_VALUE        ; load the value                       ;AN000;
       MOV  BX,SW_SYN                   ; load pointer to synonym              ;AN000;

       ; DS = PSP segment
       ; ES = CS = Parse structures segment

       ; See if the user put /? on the command line.
       ; If so, they're asking for the options help
       ; message.

       CMP      BX, OFFSET ?_SW         ; /? ?
       JNE      PARSE_NOT_OPHELP        ; skip if not
         CALL   DisplayOptions          ; display the user's options

        mov     ax,(EXIT shl 8) + 0             ;normal exit ; M000
        int     21h                     ; M000

PARSE_NOT_OPHELP:
                                        ;--------------------------------------
                                        ;  If user said  /F:n, then
                                        ;--------------------------------------

       CMP  BX,OFFSET F_SW              ; IF USER SPECIFIED /F                 ;AN000;

;      $if  e                           ;                                      ;AN000;
       JNE $$IF84

        cmp     Fswitch,1               ;switch already given? ;M006
        jz      err_too_many            ;yes, flag error ;M006
        mov     Fswitch,1               ;no, indicate /F found ;M006

           CMP  INITspace,AX            ; is default < requested ?             ;AN000;

;          $if  b                       ; if default is <                      ;AN000;
           JNB $$IF85
               MOV  INITspace,AX        ; save the new value                   ;AN000;
;          $endif                       ; endif   (else leave it alone)        ;AN000;
$$IF85:

;      $else                            ; else - CHECK FOR LOCKS               ;AN000;
       JMP SHORT $$EN84

;
;M006; Start block changes
;
err_too_many:
        mov     ax,TOOMANYPARMS         ;too many parameters
        mov     Exit_Msg,1              ;do not exit after msg
        push    ds                      ;save regs
        push    si
        push    es
        push    di
        push    cx
        mov     dl,byte ptr ds:[si]             ;save byte zeroed out by ShDispMsg
        push    dx
        call    Parse_Error             ;display error message
        pop     dx
        pop     cx
        pop     di
        pop     es
        pop     si
        pop     ds                      ;restore regs
        mov     byte ptr ds:[si],dl             ;restore saved byte to continue
        mov     Exit_Msg,0              ;reset exit flag
        jmp     short $$EN84            ;continue

;
;M006; End block changes
;
$$IF84:

                                        ;---------------------------------------
                                        ;  If user said /L:m, then update INITlocks
                                        ;---------------------------------------
           CMP  BX,OFFSET L_SW          ; IF USER SPECIFIED /L                 ;AN000;

;          $if  e                       ; if it is                              ;AN000;
           JNE $$IF88

        cmp     Lswitch,1               ;switch already given? ;M006
        jz      err_too_many            ;yes, flag error ;M006
        mov     Lswitch,1               ;no, indicate /L found ;M006

               CMP  INITlocks,AX        ; is default < requested ?             ;AN000;

;              $if  b                   ; if default is <                      ;AN000;
               JNB $$IF89
                   MOV  INITlocks,AX    ;   save the value                     ;AN000;
;              $endif                   ; endif      (else leave it alone)     ;AN000;
$$IF89:

;          $else                        ; else - CHECK FOR TOGGLE              ;AN010;
           JMP SHORT $$EN88
$$IF88:

;SR;
; /NC switch will not be allowed for DOS 5.0. This was needed only for
;automatic installation of Share. This will not be done in DOS 5.0 and so
;the /NC switch is not needed. Just display an error message and terminate
;

                                        ;---------------------------------------
                                        ; If user said /NC, then ignore it
                                        ;---------------------------------------
               CMP  BX,OFFSET N_SW      ; IF USER SPECIFIED /NC                ;AN010;
               JE $$EN84        ; ignore /NC and continue ;M005

IFDEF VCB_HMA
                cmp     bx,offset nh_sw
                jne     @f
                mov     nohma_flag,1
                jmp     short $$EN84
@@:
ENDIF
                   MOV  AX,INV_SWITCH ; Parse syntax error                     ;AN000;
                   call PARSE_ERROR     ;   call error routine                 ;AN000;

;;;$$IF92:
;;;

;          $endif                       ; endif - CHECK FOR TOGGLE             ;AN010;
$$EN88:

;      $endif                           ; endif - CHECK FOR LOCKS              ;AN000;
$$EN84:

;  $enddo                               ; CHECK FOR NEXT PARM                  ;AN000;
   JMP $$DO80
$$EN80:
ShComndParseExit:

   ret                                  ; NORMAL RETURN TO CALLER              ;AN000;

                                        ;---------------------------------------
                                        ;  If any other parameter specified,
                                        ;  display message and quit
                                        ;---------------------------------------
PARSE_ERROR:                            ;                                      ;AN000;

   cmp  al,Syntax_Error                 ; error 1 to 9 ?                       ;AN000;

;  $if  a                               ; if parse error                       ;AN000;
   JNA $$IF97

       mov  al,Syntax_Error             ; Parse syntax error

;  $endif                               ; endif errors                         ;AN000;
$$IF97:

   lea  bx,Parse_Ret_Code
   xlat cs:[bx]
   mov  ah,PARSE_ERR_CLASS              ; set class to parse error             ;AN000;

   CALL ShDispMsg                       ; display the parse error              ;AN000;

   ret                                  ; this should never be used

Parse_Ret_Code label byte

   db   0                               ; Ret Code 0 -
   db   1                               ; Ret Code 1 - Too many parameters
   db   9                               ; Ret Code 2 - Required parameter missing
   db   3                               ; Ret Code 3 - Invalid switch
   db   9                               ; Ret Code 4 - Invalid keyword
   db   9                               ; Ret Code 5 - (reserved)
   db   6                               ; Ret Code 6 - Parm val out of range
   db   9                               ; Ret Code 7 - Parameter val not allowed
   db   9                               ; Ret Code 8 - Parameter val not allowed
   db   9                               ; Ret Code 9 - Parm format not correct

   EndProc ShComndParse                 ;                                      ;AN000;

   Break <DisplayOptions        -  Display Options Help Message>

;******************* START OF SPECIFICATIONS ***********************************
;
;  NAME:        DisplayOptions  -  Display Options Help Message
;
;  FUNCTION:    Display each of the lines of the options help message
;               on standard output.
;
;  INPUT:       No value passed.
;
;  OUTPUT:      No value returned.
;
;  REGISTERS USED: AX BX CX DX SI
;  (NOT RESTORED)
;
;  LINKAGE:     Call
;
;  NORMAL
;  EXIT:
;
;  ERROR
;  EXIT:
;
;  EXTERNAL
;  REFERENCES:  - SYSDISPMSG
;
;  CHANGE       05/01/90 - First release
;  LOG:
;
;******************* END OF SPECIFICATIONS *************************************

   Procedure DisplayOptions, near

        push    ds                      ; save caller's DS
        mov     ax, cs                  ; set
        mov     ds, ax                  ;  ds = cs

        mov     ax, MSG_OPTIONS_FIRST   ; message to display
        mov     bx, STDOUT              ; output handle
        mov     cx, 0                   ; no substitutions
        mov     dh, UTILITY_MSG_CLASS   ; message class
        mov     dl, NO_INPUT            ; no input wanted
        mov     si, 0                   ; no substitution list
DispOptLoop:
        call    SYSDISPMSG              ; send this message
        cmp     ax, MSG_OPTIONS_LAST    ; last message?
        je      DispOptDone             ;  we're done if so
        inc     ax                      ; else get next message
        jmp     short DispOptLoop       ;  and go do it

DispOptDone:
        pop     ds
        ret

   EndProc DisplayOptions

   include msgdcl.inc

   SHARE ENDS

ENDIF

   END  shareinit
