        TITLE   'Copy - RxDOS Command Shell Copy'
        PAGE 59, 132
        .LALL

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell Copy                                     ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Real Time Dos                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  This material  was created as a published version  of a DOS  ;
        ;  equivalent product.   This program  logically  functions in  ;
        ;  the same way as  MSDOS functions and it  is  internal  data  ;
        ;  structure compliant with MSDOS 6.0                           ;
        ;                                                               ;
        ;  This product is distributed  AS IS and contains no warranty  ;
        ;  whatsoever,   including  warranty  of   merchantability  or  ;
        ;  fitness for a particular purpose.                            ;
        ;                                                               ;
        ;                                                               ;
        ;  (c) Copyright 1990, 1997. Api Software and Mike Podanoffsky  ;
        ;      All Rights Reserved Worldwide.                           ;
        ;                                                               ;
        ;  This product is protected under copyright laws and  may not  ;
        ;  be reproduced  in whole  or in part, in any form  or media,  ;
        ;  included but not limited to source listing, facsimile, data  ;
        ;  transmission, cd-rom, or  floppy disk without the expressed  ;
        ;  written consent of the author.                               ;
        ;                                                               ;
        ;  License  for  distribution  for commercial  use  or  resale  ;
        ;  required from:                                               ;
        ;                                                               ;
        ;  Api Software                                                 ;
        ;  12 South Walker Street                                       ;
        ;  Lowell,  MA   01851                                          ;
        ;                                                               ;
        ;  internet: mikep@world.std.com                                ;
        ;                                                               ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;  Compile with MASM 5.1                                        ;
        ;...............................................................;

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Programmer's Notes:                                          ;
        ;                                                               ;
        ;  Command Shell consists of  two parts bound  together into a  ;
        ;  single executable load.  There  exists  a  single  resident  ;
        ;  command shell which is accessible by an Int 2Eh.             ;
        ;                                                               ;
        ;...............................................................;

        include rxdosmac.asm
        include rxdosdef.asm
        include rxdoscin.asm

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  RxDOS Command Shell                                          ;
        ;...............................................................;

RxDOSCMD SEGMENT PUBLIC 'CODE'
         assume cs:RxDOSCMD, ds:RxDOSCMD, es:RxDOSCMD, ss:RxDOSCMD

        public _Copy

        extrn CmndError_BadSwitch                       : near
        extrn CmndError_CannotCopyUntoSelf              : near
        extrn CmndError_CannotCreateFile                : near
        extrn CmndError_ContentsLostBeforeCopy          : near
        extrn CmndError_InvalidNumberArguments          : near
        extrn CmndError_FileNotFound                    : near
        extrn _Copy_FilesCopied                         : near
        extrn CountArgs                                 : near
        extrn CRLF                                      : near
        extrn deleteArg                                 : near
        extrn DisplayErrorMessage                       : near
        extrn DisplayLine                               : near
        extrn RxDOS_DTA                                 : near
        extrn RxDOS_AllFiles                            : near

        extrn _AppendPathName                           : near
        extrn _CopyString                               : near
        extrn _Copy_FilesCopied                         : near
        extrn _CmndParse_SeparatorCheck                 : near
        extrn _makePath                                 : near
        extrn _lowerCase                                : near
        extrn _SwitchChar                               : near
        extrn _splitpath                                : near
        extrn _sprintf                                  : near

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Copy filenameA+filenameB+filenameC filenameDest              ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   ss:di  Arg Array                                            ;
        ;   ax     Number of arguments in array                         ;
        ;...............................................................;

_Copy:

        Entry
        def __argarray, di                              ; args array
        def __numArgs, ax                               ; # args
        def __Mode, 0000                                ; non-z if ascii/ z if binary
        def _overide, FALSE                             ; no automatic overide
        def __AddMode                                   ; 0000 not add mode
        def __NextAddMode                               ; 0000 next is add mode
        def __bytesRead                                 ; bytes actually read

        def _destfilenameSameAsSource, FALSE            ; if take names from source
        def _filesCopied, 0000
        def _srcHandle  , -1
        def _destHandle , -1
        ddef _destCluster
        ddef _srcCluster

        defbytes _destFilename  , 130
        defbytes _createFilename, 130
        defbytes _copyFilename  , 130
        defbytes _buffer, 128

        _tempFilename = _copyFilename                   ; equate temp filename

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  get/test destination filename
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

        mov dx, offset CmndError_InvalidNumberArguments
        cmp ax, 2                                       ; must have at least two args
        ifc _copyDisplayError                           ; any less means error -->

        dec ax
        add ax, ax                                      ; args offset in words
        add di, ax                                      ; point to last arg
        push word ptr [ di ]                            ; get last arg address
        call deleteArg

        pop si
        lea di, offset [ _tempFilename ][ bp ]
        call _copyArgument                              ; copy argument

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  see if dest is just a directory name
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
        mov cx, ATTR_DIRECTORY
        lea dx, offset [ _tempFilename ][ bp ]
        Int21 FindFirstFile                             ; locate file with name
        jc _Copy_18                                     ; not a directory -->

    ;  if . or .. handle special

_Copy_08:
        test byte ptr [ RxDOS_DTA. findFileAttribute ], ATTR_DIRECTORY
        jz _Copy_18                                     ; if not a dir entry -->

        cmp byte ptr [ RxDOS_DTA. findFileName ], '.'
        jnz _Copy_24                                    ; if dir and not . or .. -->

        Int21 FindNextFile                              ; locate next file
        jnc _Copy_08                                    ; see if also a dir -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  scan name for just directory
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_18:
        lea di, offset [ _tempFilename ][ bp ]

_Copy_20:
        cmp byte ptr [ di ], 00                         ; null ?
        jz _Copy_26                                     ; yes, done -->
        inc di
        cmp byte ptr [ di-1 ], ':'                      ; only drive /colon entered ?
        jnz _Copy_20                                    ; no -->
        cmp byte ptr [ di ], 00                         ; 
        jnz _Copy_26

_Copy_24:
        mov si, offset RxDOS_AllFiles                   ; dummy path 
        call _AppendPathName                            ; append all files
        storarg _destfilenameSameAsSource, TRUE         ; \*.*

_Copy_26:
        lea si, offset [ _tempFilename ][ bp ]
        lea di, offset [ _destFilename ][ bp ]          ; expansion area
        mov byte ptr [ di ], '\'                        ; (in case no output generated)
        Int21 GetActualFileName                         ; expand name
        ifc _copyDisplayError                           ; destination doesn't exist -->

        xor ax, ax
        mov cx, 4
        lea di, offset [ _destCluster ][ bp ]           ; clusters
        rep stosw                                       ; clear clusters

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  main loop through all args
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_30:
        mov word ptr [ __AddMode  ][ bp ], 0000         ; not add mode
        mov word ptr [ __NextAddMode  ][ bp ], 0000     ; next is not add mode

_Copy_32:
        mov di, word ptr [ __argarray ][ bp ]           ; get arg pointer to next arg
        mov si, word ptr [ di ]                         ; point to text 
        or si, si                                       ; null entry ?
        ifz _Copy_Return                                ; yes, return -->

        add word ptr [ __argarray ][ bp ], 2            ; skip this argument next time

        mov al, byte ptr [ si ]
        cmp al, byte ptr [ _SwitchChar ]                ; switch ?
        ifz _Copy_TestSwitch                            ; yes, go test switch -->

        cmp al, '+'
        ifz _Copy_AddMode                               ; set add mode -->

        lea di, offset [ _copyFilename ][ bp ]
        call _copyArgument

        call _scanForwardArgArray                       ; see if followed by +
        mov word ptr [ __NextAddMode  ][ bp ], ax       ; next add mode

        mov dx, di                                      ; copy filename
        mov cx, ATTR_NORMAL   
        Int21 FindFirstFile                             ; locate file with name
        jnc _Copy_36                                    ; if file found -->

        mov dx, offset CmndError_FileNotFound
        call DisplayLine
        jmp _copyErrorCleanUp

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  open source file
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_36:
        lea di, offset [ _copyFilename ][ bp ]
        call _replaceWithRealName

        Int21 OpenFile, OPEN_ACCESS_READONLY            ; open source file
        ifc _copyDisplayError                           ; can't, display error -->

        mov bx, ax
        storarg _srcHandle, ax
        call GetClusterValue                            ; src cluster
        mov word ptr [ _srcCluster. _low  ][ bp ], ax   ; (cluster)
        mov word ptr [ _srcCluster. _high ][ bp ], dx   ; (drive )
        jz _Copy_38                                     ; if not a file -->

        call _compareClusters                           ; compare src and dest Clusters
        jnz _Copy_38                                    ; no -->

    ; error: file destroyed

        mov dx, offset CmndError_ContentsLostBeforeCopy
        call DisplayErrorMessage                        ; dest file same as source
        jmp _copyErrorCleanUp

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  attempt create file
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_38:
        getarg bx, _destHandle
        cmp bx, -1                                      ; any dest file ?
        jz _Copy_40                                     ; no, MUST create -->
        cmp word ptr [ __AddMode  ][ bp ], 0000         ; add mode ?
        ifnz _Copy_56                                   ; yes, append to existing file -->

_Copy_40:
        lea si, offset [ _destFilename ][ bp ]          ; destination filename
        lea di, offset [ _createFilename ][ bp ]        ; make destination name
        call _CopyString                                ; copy string

        cmp word ptr [ _destfilenameSameAsSource ][ bp ], TRUE
        jnz _Copy_48                                    ; name available -->

        lea si, offset [ _destFilename ][ bp ]          ; destination filename
        lea di, offset [ _createFilename ][ bp ]        ; make destination name
        mov byte ptr [ di ], '\'                        ; (in case no output generated)
        Int21 GetActualFileName                         ; expand name
        ifc _copyDisplayError                           ; destination doesn't exist -->

        lea di, offset [ _copyFilename ][ bp ]
        call _PtrTo_Filename                            ; get pointer to filename
        push di

        lea di, offset [ _createFilename ][ bp ]        ; make destination name
        call _PtrTo_Filename                            ; get pointer to filename

        pop si                                          ; source name
        call _CopyString                                ; copy string

_Copy_48:
        lea di, offset [ _createFilename ][ bp ]        ; make destination name
        call _makeUniqueName                            ; make unique name

        lea dx, offset [ _createFilename ][ bp ]        ; destination filename
        Int21 OpenFile, OPEN_ACCESS_READONLY            ; we'll try open first
        jc _Copy_52                                     ; MUST create -->

        mov bx, ax
        call GetClusterValue                            ; cluster of dest
        mov word ptr [ _destCluster. _low  ][ bp ], ax  ; (cluster)
        mov word ptr [ _destCluster. _high ][ bp ], dx  ; (drive )
        Int21 CloseFile                                 ; release file

        call _compareClusters                           ; compare src and dest Clusters
        ifz _copyCannotCopyOverSelf                     ; camnnot copy over self -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  create file
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_52:
        getarg ax, _overide                             ; previous overide
        lea dx, offset [ _createFilename ][ bp ]        ; destination filename
      ; call _copyOverideCheck                          ; see if overide is ok
      ; storarg _overide, ax                            ; store for future reference

        mov cx, ATTR_NORMAL
        Int21 CreateFile                                ; creates NULL file (after open try above)
        ifc _copyCannotCreateError                      ; if cannot be created or nulled -->

        mov bx, ax
        storarg _destHandle, ax
        call GetClusterValue                            ; cluster of dest
        mov word ptr [ _destCluster. _low  ][ bp ], ax  ; (cluster)
        mov word ptr [ _destCluster. _high ][ bp ], dx  ; (drive )

        call _compareClusters                           ; compare src and dest Clusters
        ifz _copyCannotCopyOverSelf                     ; camnnot copy over self -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  display filename
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_56:
        getarg bx, _srcHandle
        Int21 IoControl, 00                             ; is source a char device ?
        test dx, sftIsDevice                            ; test device flag
        jnz _Copy_66                                    ; if device, skip display filename -->

        mov dx, offset [ RxDOS_DTA. findFileName ]
        call DisplayLine                                ; display line
        call CRLF                                       ; cr/lf

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  copy loop
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_66:
        mov cx, 128
        getarg bx, _srcHandle
        lea dx, offset [ _buffer ][ bp ]
        Int21 ReadFile                                  ; read 
        ifc _copyDisplayError                           ; if error -->

        mov cx, ax                                      ; bytes read
        or cx, cx                                       ; null chars returned ?
        jz _Copy_82                                     ; must be end of file -->

        getarg bx, _destHandle
        lea dx, offset [ _buffer ][ bp ]
        Int21 WriteFile                                 ; write
        jmp _Copy_66                                    ; read more -->

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  close source file
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_Copy_82:
        getarg bx, _srcHandle
        call _CopyCloseFile
        storarg _srcHandle, -1                          ; change handle to reflect this

        cmp word ptr [ __NextAddMode  ][ bp ], 0000     ; is next add mode ?
        jnz _Copy_92                                    ; yes, go to next -->

        getarg bx, _destHandle
        call _CopyCloseFile                             ; if no adds left ...
        storarg _destHandle, -1
        inc word ptr [ _filesCopied ][ bp ]             ; # files copied.

        Int21 FindNextFile                              ; see if more files to copy
        ifnc _Copy_36                                   ; if file found -->

_Copy_92:
        jmp _Copy_30

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_Copy_Return:
        getarg bx, _destHandle
        cmp bx, -1                                      ; destination still open ?
        jz _Copy_ReturnClose_08                         ; no, don't close -->
        call _CopyCloseFile
        storarg _destHandle, -1
        inc word ptr [ _filesCopied ][ bp ]             ; # files copied.

_Copy_ReturnClose_08:
        lea di, offset [ _filesCopied ][ bp ]
        push di                                         ; first arg encountered

        mov di, offset _Copy_FilesCopied
        push di
        lea di, offset [ _buffer ][ bp ]
        push di
        call _sprintf
        add sp, ax                                      ; # args passed
        call DisplayLine

        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  add mode
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_Copy_AddMode:
        mov word ptr [ __AddMode  ][ bp ], -1           ; set add mode
        jmp _Copy_32

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  test switches
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_Copy_TestSwitch:
        mov al, byte ptr [ si+1 ]
        call _lowerCase                                 ; test switch option

        goto 'a', _copyAsciiSwitch
        goto 'b', _copyBinarySwitch

        push ax
        mov dx, offset CmndError_BadSwitch
        call DisplayLine                                ; show error message

        pop dx
        call DisplayLine                                ; show arg
        Return

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if ascii switch
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_copyAsciiSwitch:
        storarg __Mode, 01                              ; ascii mode
        jmp _Copy_32

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  if binary switch
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_copyBinarySwitch:
        storarg __Mode, 00                              ; binary mode
        jmp _Copy_32

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
;  error in rename command
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

_copyCannotCopyOverSelf:
        mov dx, offset CmndError_CannotCopyUntoSelf
        jmp short _copyDisplayError

_copyCannotCreateError:
        mov dx, offset CmndError_CannotCreateFile
      ; jmp short _copyDisplayError

_copyDisplayError:
        call DisplayErrorMessage
      ; jmp short _copyErrorCleanUp

_copyErrorCleanUp:
        getarg bx, _destHandle
        cmp bx, -1                                      ; if not assigned, 
        jz _copyErrorCleanUp_08                         ; don't delete -->
        call _CopyCloseFile

_copyErrorCleanUp_08:
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Do Not Close Device                                          ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Inputs:                                                      ;
        ;   bx     file Handle                                          ;
        ;                                                               ;
        ;...............................................................;

_CopyCloseFile:
        cmp bx, -1                                      ; if not assigned, 
        jz _CopyClose_Exit                              ; exit -->
        or bx, bx
        jz _CopyClose_Exit                              ; exit -->

        Int21 IoControl, 00                             ; is source a char device ?
        test dx, sftIsDevice                            ; test device flag
        jnz _CopyClose_Exit                             ; if device, skip close -->

        Int21 CloseFile                                 ; close source file

_CopyClose_Exit:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Get ptrto filename after drive and path info                 ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Inputs:                                                      ;
        ;   ss:di  pointer to null terminated path                      ;
        ;                                                               ;
        ;  Outputs:                                                     ;
        ;   di     returns pointer within name                          ;
        ;   cy     set if no filename found                             ;
        ;                                                               ;
        ;...............................................................;

_PtrTo_Filename:

        xor ax, ax
        mov cx, -1
        repnz scasb                                     ; scan for null terminator

        neg cx                                          ; actual size in cx

_PtrTo_Filename_08:
        cmp byte ptr ss:[ di - 1 ], '\'                 ; previous char a '\' ?
        jz _PtrTo_Filename_12                           ; if found -->

        dec di                                          ; scan prev
        loop _PtrTo_Filename_08                         ; continue until start -->

        stc

_PtrTo_Filename_12:
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Insure OK to overwrite file                                  ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Inputs:                                                      ;
        ;   ax     previous overide                                     ;
        ;   dx     filename pointer                                     ;
        ;                                                               ;
        ;  Outputs:                                                     ;
        ;   dx     filename pointer                                     ;
        ;   ax     action code                                          ;
        ;          'A'  overide all                                     ;
        ;          0000 no                                              ;
        ;          0001 yes                                             ;
        ;                                                               ;
        ;...............................................................;

_copyOverideCheck:
        cmp al, 'A'                                     ; all ?
        jnz _copyOverideCheck_06                        ; no -->
        ret

_copyOverideCheck_06:
        push dx

        mov cx, ATTR_NORMAL                             ; normal
        Int21 FindFirstFile                             ; see if file exists
        ifc _copyOverideCheck_OK                        ; doesn't, so exit with OK to overide


      ; display message, get overide ..  





_copyOverideCheck_OK:
        mov ax, TRUE

_copyOverideCheck_Exit:
        pop dx
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Copy Argument                                                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   si     points to argument start                             ;
        ;   di     points to destination                                ;
        ;...............................................................;

_copyArgument:

        push di

_copyArgument_06:
        lodsb                                           ; get character 
        stosb
        cmp al, ' '+1                                   ; space or control character ?
        jc _copyArgument_10                             ; yes -->

        cmp al, byte ptr [ _SwitchChar ]                ; switch character ?
        jz _copyArgument_10                             ; yes -->
        call _CmndParse_SeparatorCheck                  ; parse break ?
        jnz _copyArgument_06                            ; no, go to next char -->

_copyArgument_10:
        mov byte ptr [ di-1 ], 0                        ; place null terminator
        pop di
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  LookAhead Add Mode                                           ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   si     points to argument start                             ;
        ;   di     points to destination                                ;
        ;...............................................................;

_scanForwardArgArray:

        push di
        mov di, word ptr [ __argarray ][ bp ]           ; get arg pointer to next arg
        xor ax, ax                                      ; next is NOT add

_scanForwardArgArray_10:
        mov si, word ptr [ di ]                         ; point to text 
        or si, si                                       ; null entry ?
        jz _scanForwardArgArray_12                      ; yes, return -->

        add di, 2
        cmp byte ptr [ si ], '/'
        jz _scanForwardArgArray_10
        cmp byte ptr [ si ], '+'
        jnz _scanForwardArgArray_12
        mov ax, -1                                      ; next IS add

_scanForwardArgArray_12:
        pop di
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Get Starting Cluster Value for a given Handle                ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Input:                                                       ;
        ;   bx     file handle                                          ;
        ;                                                               ;
        ;  Output:                                                      ;
        ;   ax     starting cluster value                               ;
        ;...............................................................;

GetClusterValue:

        push es
        push di
        push bx
        Int21 GetPSPAddress                             ; returns bx with segment
        mov es, bx                                      ; set PSP address

        pop si                                          ; restore handle offset
        push si                                         ; (save handle)
        les bx, dword ptr es:[ pspFileHandlePtr ]       ; point to file handles
        mov bl, byte ptr es:[ bx + si ]                 ; get real sft offset
        xor bh, bh
        push bx                                         ; save real SFT handle

        Int21 GetDosDataTablePtr                        ; UNDOCUMENTED DOS CALL

        pop ax                                          ; restore real SFT handle
        les si, dword ptr es:[ bx + 4 ]                 ; get address of FT start 

GetClusterValue_08:
        sub ax, word ptr es:[ numberSFTEntries ][ si ]
        jc GetClusterValue_14                           ; if in current FT -->
        cmp word ptr es:[ nextFTPointer. _pointer ][ si ], -1
        jz GetClusterValue_22                           ; if error -->

        les si, dword ptr es:[ nextFTPointer ][ si ]    ; get address of FT start 
        jmp GetClusterValue_08                          ; got to next FT -->
        
GetClusterValue_14:
        add ax, word ptr es:[ numberSFTEntries ][ si ]  ; restore offset
        mov cx, sizeSFT
        mul cx                                          ; offset times size of entries
                
        add si, sizeFT                                  ; move past header
        add si, ax                                      ; position at sft

        xor ax, ax
        xor dx, dx
        test word ptr es:[ sftDevInfo    ][ si ], sftIsDevice
        jnz GetClusterValue_18                          ; if device -->

        mov ax, word ptr es:[ sftBegCluster ][ si ]     ; if file
        mov dx, word ptr es:[ sftDevInfo    ][ si ]
        and dx, sftDrivemask

GetClusterValue_18:
        mov cx, ax
        or cx, dx                                       ; if all zeroes
        jmp short GetClusterValue_26                    ; exit -->

GetClusterValue_22:
        xor ax, ax
        xor dx, dx
        stc

GetClusterValue_26:
        pop bx
        pop di
        pop es
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Compare Drive/Cluster Info                                   ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  NZ if not equal                                              ;
        ;...............................................................;

_compareClusters:

        cmp word ptr [ _destCluster. _low  ][ bp ], 0000
        jz _compareClusters_NotEqual
        cmp word ptr [ _srcCluster. _low  ][ bp ], 0000
        jz _compareClusters_NotEqual

        mov ax, word ptr [ _destCluster. _low  ][ bp ]  ; (cluster)
        cmp ax, word ptr [ _srcCluster. _low ][ bp ]
        jnz _compareClusters_NotEqual

        mov ax, word ptr [ _destCluster. _high ][ bp ]  ; (drive )
        cmp ax, word ptr [ _srcCluster. _high ][ bp ]
        jnz _compareClusters_NotEqual
        ret

_compareClusters_NotEqual:
        mov ax, -1
        or ax, ax
        ret

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Make Unique Name                                             ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   di     name expected with wild characters                   ;
        ;...............................................................;

_makeUniqueName:

        Entry
        def _name, di
        defbytes _expandedname, sizeExpandedName

        push di

        mov si, di
        lea di, offset [ _expandedname ][ bp ]
        call _splitpath

        mov cx, sizefnName
        mov si, offset [ RxDOS_DTA. findFileName ]
        lea di, offset [ _expandedname. expFilename ][ bp ]
        call _makeReplacement

        inc si
        mov cx, sizefnExtension
        lea di, offset [ _expandedname. expExtension + 1 ][ bp ]
        call _makeReplacement

        lea si, offset [ _expandedname ][ bp ]
        getarg di, _name
        call _makePath

        pop di
        mov dx, di
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Make Replacement                                             ;
        ;...............................................................;

_makeReplacement:

        Entry
        defbytes _tempName, sizeFILENAME

        push cx
        push di
        lea  di, offset _tempName [ bp ]

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
;  make blank filled copy
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
_makeReplacement_04:
        mov al, byte ptr [ si ]
        mov byte ptr [ di ], al                         ; copy byte
        cmp al, '.'
        jz _makeReplacement_08
        or al, al
        jz _makeReplacement_08

        inc si
        inc di
        loop _makeReplacement_04

_makeReplacement_08:
        or cx, cx
        jz _makeReplacement_12
        mov byte ptr [ di ], ' '
        inc di
        loop _makeReplacement_08

;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
;  copy with wild character replacement
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
_makeReplacement_12:
        pop di                                          ; real destination
        pop cx                                          ; real count
        push si                                         ; save this pointer
        lea  si, offset _tempName [ bp ]                ; new source

_makeReplacement_18:
        cmp byte ptr [ di ], '?'
        jnz _makeReplacement_22

        mov al, byte ptr [ si ]                         ; get character
        mov byte ptr [ di ], al                         ; replace wild character

_makeReplacement_22:
        inc di
        inc si
        loop _makeReplacement_18

        mov byte ptr [ di ], 00
        pop si
        Return

        ;''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''';
        ;  Replace with Real Name                                       ;
        ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;
        ;                                                               ;
        ;  Usage:                                                       ;
        ;   di     full expanded name expected                          ;
        ;...............................................................;

_replaceWithRealName:

        push di
        mov dx, di

_replaceWithRealName_04:
        cmp byte ptr [ di ], 0                          ; find end of string
        jz _replaceWithRealName_08
        inc di
        jmp _replaceWithRealName_04

_replaceWithRealName_08:
        cmp dx, di
        jz _replaceWithRealName_12

        mov al, byte ptr [ di-1 ]
        cmp al, ':'
        jz _replaceWithRealName_12
        cmp al, '\'
        jz _replaceWithRealName_12
        cmp al, '/'
        jz _replaceWithRealName_12

        dec di
        jmp _replaceWithRealName_08

_replaceWithRealName_12:
        mov si, offset [ RxDOS_DTA. findFileName ]      ; expanded name
        call _CopyString

        pop di
        mov dx, di
        ret

RxDOSCMD                        ENDS
                                END
