        SUBT    > <wini>arm.FileSwitch.FSUtils - Copy

; Bits in the bitset used by utilities: internal defs

util_topconfirm *       1 :SHL: 31 ; Top level confirmation

; Bits in the bitset used by utilities: external defs

util_peekdest   *       1 :SHL: 14 ; Quick peek at dest before loading src ?
util_userbuffer *       1 :SHL: 13 ; Use punter's buffer as well as apl/rma ?
util_newer      *       1 :SHL: 12 ; Copy files if newer (or binary) ?
util_structureonly *    1 :SHL: 11 ; Structure only (no files) ?
util_restamp    *       1 :SHL: 10 ; Restamp datestamped files ?
util_noattr     *       1 :SHL: 9  ; Don't copy attributes over ?
util_printok    *       1 :SHL: 8  ; Allow any printing during operation ?
; If not set then forces ~confirm, ~verbose, ~promptchange
util_deletesrc  *       1 :SHL: 7  ; Delete source after copy ?
util_promptchange *     1 :SHL: 6  ; Prompt for each source/dest switch ?
util_quick      *       1 :SHL: 5  ; Use apl as well as rma/wimp/user ?
util_verbose    *       1 :SHL: 4  ; Print info on objects ?
util_confirm    *       1 :SHL: 3  ; Prompt for each object ?
util_datelimit  *       1 :SHL: 2  ; Apply date range to source files ?
util_force      *       1 :SHL: 1  ; Check for overwriting ?
util_recurse    *       1 :SHL: 0  ; Recurse down directories ?

 [ hascopy
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Copy_UpCallCode
; ===============
;
; Monitor UpCalls during *Copy to see if media change needed

; In    r1 = fs number
;       r2 -> media title, 0
;       wp valid

; !!! NO ERRORS COPIED HERE !!!

Copy_UpCallCode ROUT

; Pass UpCall on to other people in chain to give them first stab at it.

        Push    "r10-r12"               ; Save state of this vector call
        Push    "pc"                    ; Fudge return address,psr = .+12
        MOV     pc, lr                  ; Pass down chain
        NOP                             ; Required for address fudge

; Vector claimer (maybe default) will always return here

        Pull    "r10-r12"               ; Restore state of this vector call

        TEQ     r0, #UpCall_MediaNotPresent
        TEQNE   r0, #UpCall_MediaNotKnown
        Pull    pc, NE                  ; Claim UpCall if it's been claimed
                                        ; or if it's not one of ours.

        Push    "r1-r3"
        SUB     sp, sp, #128

        MOV     r0, #FSControl_ReadFSName
        MOV     r2, sp
        MOV     r3, #128
        SWI     XOS_FSControl
        ADRVC   r0, fsw_Ensure_space
        SWIVC   XOS_Write0
        BVS     %FT40

        LDRB    r14, [sp]
        CMP     r14, #0
        BEQ     %FT30                   ; [no filing system name found]

        MOV     r0, sp
        SWI     XOS_Write0              ; Filing system name
        SWIVC   XOS_WriteI+":"

30      SWIVC   XOS_WriteI+":"
        LDRVC   r0, [sp, #128 + 4]      ; Disc name (r2in)
        BLVC    PromptSpaceBar          ; Doesn't copy errors
        MOVVC   r0, #UpCall_Claimed     ; UpCall processed

40      ADD     sp, sp, #128
        Pull    "r1-r3, pc"             ; Claim vector


fsw_Ensure_space DCB    "Ensure ", 0
                 ALIGN

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;                        W i l d c a r d   C o p y
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyEntry
; =========

; In    r1 -> path to copy from
;       r2 -> path to copy to
;       r3 = bitset for copy
;       r4,r5 = optional time (start)
;       r6,r7 = optional time (end)
;       r8 -> optional copy structure
;         [r8, #0] = buffer address     ; iff util_userbuffer
;         [r8, #4] = buffer size        ; iff util_userbuffer

CopyEntry NewSwiEntry "r0-r10",copy     ; CopyWildObject destroys all regs
                                        ; Seriously large frame for copy
 [ debugcopy
 DLINE "FSControl_Copy: options '",cc
 TST r3, #util_noattr
 SWIEQ XOS_WriteI+"A"
 TST r3, #util_confirm
 SWINE XOS_WriteI+"C"
 TST r3, #util_deletesrc
 SWINE XOS_WriteI+"D"
 TST r3, #util_force
 SWINE XOS_WriteI+"F"
 TST r3, #util_newer
 SWINE XOS_WriteI+"N"
 TST r3, #util_promptchange
 SWINE XOS_WriteI+"P"
 TST r3, #util_quick
 SWINE XOS_WriteI+"Q"
 TST r3, #util_recurse
 SWINE XOS_WriteI+"R"
 TST r3, #util_restamp
 SWINE XOS_WriteI+"S"
 TST r3, #util_structureonly
 SWINE XOS_WriteI+"T"
 TST r3, #util_verbose
 SWINE XOS_WriteI+"V"
 DREG r3,"' "
 ]
        TST     r3, #util_userbuffer
        LDMNEIA r8, {r9, r10}
        MOVEQ   r9, #&4000              ; No user buffer supplied (say &4000
        MOVEQ   r10, #0                 ; so we'll load zero length files in
        STR     r9,  copy_userbuffer    ; it though - don't say &8000 as we
        STR     r10, copy_userbuffersize ; won't release apl >>>a186<<<)

        BL      Util_CommonStart
        BVS     %FA99 ; SwiExit - nothing allocated

        LDR     r2, SpecialField        ; Remove second string set
        STR     r2, SpecialField2
        BL      DelinkLinkedArea        ; from global chain as we will be
        LDR     r2, PassedFilename      ; doing StartUpApplication
        STR     r2, PassedFilename2
        BL      DelinkLinkedArea        ; (Order makes it a little quicker)

        LDR     r1, [fp, #2*4]          ; Molest the second one (r2in)
        BL      TransNameSetFSAndPolice
        BVS     %FT87 ; SwiExit - Deallocate r7 set, second string set

        LDR     r2, SpecialField        ; Remove first string set
        BL      DelinkLinkedArea        ; from global chain as we will be
        LDR     r2, PassedFilename      ; doing StartUpApplication
        BL      DelinkLinkedArea        ; (Order makes it a little quicker)

        BL      Util_MakeFileStrings

        BVS     %FT86 ; SwiExit - Deallocate r7 set, both string sets

        ADR     r8, dst_copy_block
        STR     r0, [r8, #copy_dirprefix]
        STR     r1, [r8, #copy_leafname]
        STR     r2, [r8, #copy_special]
        STR     r3, [r8, #copy_fscb]

        LDR     r14, util_bitset
        TST     r14, #util_quick :OR: util_restamp ; If we want to restamp or
        MOVNE   r0, #14                 ; might use SWI OS_Exit, note time
        ADRNE   r1, copy_startedtime
        MOVNE   r14, #3
        STRNE   r14, [r1]
        SWINE   XOS_Word                ; ReadTime shouldn't give error

        MOV     r14, #0                 ; We don't yet own apl space
        STRB    r14, copy_owns_apl_flag

        MOV     r14, #copy_at_unknown   ; Not at source or dest a ce moment
        STRB    r14, copy_src_dst_flag

        LDR     r14, util_bitset        ; Can't do upcalls if printing not ok
        TST     r14, #util_printok
        BEQ     %FT10

        LDRB    r14, copy_n_upcalls     ; If ~n_upcalls++ then claim
        TEQ     r14, #0
        ADD     r14, r14, #1
        STRB    r14, copy_n_upcalls     ; NB. This is global
        BNE     %FT10

        MOV     r0, #UpCallV            ; Sit on UpCallV                     
        addr    r1, Copy_UpCallCode
        MOV     r2, wp
        SWI     XOS_Claim
        BLVS    CopyError
        BVS     %FT85 ; SwiExit - Deallocate r7,r8 sets, both string sets
10

        BL      CopyWildObject

        LDR     r14, util_bitset        ; Can't do upcalls if printing not ok
        TST     r14, #util_printok
        BEQ     %FT20

        LDRB    r14, copy_n_upcalls     ; If --n_upcalls then release
        SUBS    r14, r14, #1
        STRPLB  r14, copy_n_upcalls     ; NB. This is global. Paranoid PL
        BNE     %FT20

        MOV     r0, #UpCallV            ; Delink from UpCallV
        addr    r1, Copy_UpCallCode
        MOV     r2, wp
        SWI     XOS_Release
        BLVS    CopyError
20

        BL      Util_FreeFileStrings_R8 ; 'Cos it's nice to print verbose bits
        BL      Util_FreeFileStrings_R7 ; Catch errors from these on SwiExit

        BL      SFreePassedFilenameAndSpecial_delinked
        BL      SFreePassedFilename2AndSpecial2_delinked ; second string set

        LDR     r14, globalerror        ; Give 'Not found' if no error below
        CMP     r14, #0                 ; fp is valid, of course ...
        LDREQ   r14, util_ndir          ; and no dirs or files copied
        CMPEQ   r14, #0
        LDR     r0, util_nfiles         ; r0 useful for below - load always !
        CMPEQ   r0, #0
        LDREQ   r14, util_nskipped      ; Only give error if complete wally
        CMPEQ   r14, #0
        BEQ     %FA98

        LDR     r14, util_bitset
        TST     r14, #util_verbose
        BEQ     %FT95

        TST     r14, #util_deletesrc
        ADREQ   r1, fsw_copied_total    ; r0 still ok from above
        ADRNE   r1, fsw_moved_total
        BL      Util_FilesDone          ; eg. '3 files copied, 123456 bytes'

        LDRVC   r0, util_totalsize
        BLVC    Util_PrintFullSize

90      BLVS    CopyError               ; ep for below

95      LDRB    r14, copy_owns_apl_flag ; <> 0 -> apl space corrupted
        TEQ     r14, #0
        BEQ     %FA99 ; SwiExit

        LDR     r0, globalerror         ; Must exit, maybe error ?
        TEQ     r0, #0                  ; fp is valid, of course ...
        BEQ     %FT96

        ADD     r0, r0, #4              ; Point to error message
        SWI     XOS_Write0              ; Z would be dead if VS but see below
        SWIVC   XOS_NewLine             ; Valiantly ignore error + prettify

96 ; Prettify old style supervisor exit handling. Not needed now ?

 [ AssemblingArthur
        LDR     r1, =EnvTime            ; Set EnvTime from time we started copy
 |
        LDR     r1, EnvTimeAddr         ; Set EnvTime from time we started copy
 ]
        LDR     r0, copy_startedtime
        STR     r0, [r1]
        LDRB    r0, copy_startedtime+4
        STRB    r0, [r1, #4]

        MOV     r0, #0                  ; Can't cause error 'cause that'd
        LDR     r1, tutu_abex_string    ; return to Appl with apl trashed !
        MOV     r2, #0                  ; rc = 0. No error on exit
        SWI     OS_Exit                 ; And this sets CAO pointer to be
                                        ; not me no more, so freeing apl


85      BL      Util_FreeFileStrings_R8 ; Early deallocation errors

86      BL      SFreePassedFilenameAndSpecial_delinked ; normal string set

87      BL      Util_FreeFileStrings_R7

        BL      SFreePassedFilename2AndSpecial2_delinked ; second string set
        B       %FA99 ; SwiExit


99      SwiExit



98      addr    r0, ErrorBlock_NothingToCopy
        SETV
        B       %BT90                   ; Might have corrupt apl, so not simple


fsw_copied_total DCB    " copied, total ", 0
fsw_moved_total  DCB    " moved, total ", 0

        ALIGN

tutu_abex_string DCB    "ABEX"          ; Picked up as a word

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyWildObject
; ==============

; src x, dst -: CopyObject single object                  eg. fred    jim
;                                                             *       jim
; src *, dst *: CopyObject on all that match              eg. fred.a* jim.*
;             : Bad copy (no substitution done)               fred.a* jim.b*
; src -, dst *: CopyObject on all that match              eg. fred    *
;             : Bad copy (must be single rhs *)               fred    b*

; Out   Only r7, r8, wp preserved

CopyWildObject ENTRY

 [ debugcopy
 DREG sp,"Entering CopyWildObject; sp = "
 ]
        LDR     r9, [r7, #copy_leafname] ; Hold onto existing leafname pointers
        LDR     r10, [r8, #copy_leafname]

        MOV     r1, r10
        BL      Util_CheckWildName
        BNE     %FT90                   ; Dest not wild, so try CopyObject
                                        ; (src type irrelevant)

; ...................... Wild object spec for copy ............................

        LDRB    r0, [r10]               ; No replace, so must have '*' on rhs
        TEQ     r0, #"*"
        LDREQB  r0, [r10, #1]
        TEQEQ   r0, #0
        BNE     %FA80

        MOV     r14, #0
        STR     r14, util_direntry      ; Start at the beginning of dir
        STR     r14, [r7, #copy_leafname] ; 'Free' leaves !
        STR     r14, [r8, #copy_leafname]
        Push    "r9, r10"               ; Save leafname pointers

10 ; Loop over source names, match wildcard bits. Leaves are NewString'ed each
   ; time round, but fullnames are always explicitly made and freed in loop

        BL      STestEscape             ; Util grade, not copied
        BLVS    CopyError
        BLVC    Copy_PromptSource
        BLVC    Util_ReadDirEntry       ; Get a name. Uses + updates util_diren
        BVS     %FT60                   ; Deallocate new leafnames, put old
                                        ; leafnames back, exit

        CMP     r3, #0                  ; No name xferred ?
        BEQ     %FT60                   ; Means eod

        ADR     r4, util_objectname     ; What we read just now
        BL      Util_TryMatch
        BNE     %BT10                   ; Loop - try another name
        BL      Copy_MakeNewLeaves      ; Deallocate old ones, make new ones
        BVS     %FA70                   ; Will have deallocated old ones if VS

        MOV     r0, #-1                 ; Use both given leafnames
        BL      Copy_MakeFullnames      ; Deallocate new leafnames, put old
        BVS     %FT60                   ; leafnames back, exit

        Push    r9                      ; Preserve wild pattern round call
        BL      CopyObject
        Pull    r9
        BL      Copy_FreeFullnames      ; Accumulate V
        BVC     %BT10                   ; Loop - try another name

60      BL      Copy_FreeLeafnames      ; Deallocate leaves

70      Pull    "r9, r10"               ; Had to stack these
        STR     r9,  [r7, #copy_leafname] ; Put old leaves back
        STR     r10, [r8, #copy_leafname]
 [ debugcopy
 DREG sp,"Leaving CopyWildObject; sp = "
 ]
        EXIT


80      addr    r0, ErrorBlock_BadCopy
81      BL      CopyError
        EXIT


; ............ Single object copy. Must read object info ourselves ............

; NB. Don't call CopyObject - if copying dir, just recurse one level unless
; punter wants more than that

90      MOV     r0, #-1                 ; Use both leafnames in fullname build
        BL      Copy_MakeFullnames
        EXIT    VS

        BL      Copy_PromptSource
        BLVC    Util_SingleObjectSetup  ; Error if not found
        BVS     %FT95                   ; Deallocate error
        BHI     %FT96                   ; Is it a dir ?
        BLEQ    CopyFile                ; If it's a file

95      BL      Copy_FreeFullnames      ; Preserves V if set
        EXIT


96      BL      CopyDirectory
        B       %BT95

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Copy_MakeNewLeaves
; ==================

; Replace wildcard bits and make two new leafnames in r7, r8 records

; In    r9 -> source wild leafname
;       r10 -> dest wild leafname
;       util_objectname = name read

; Out   VS: error; all strings deallocated, old + new

Copy_MakeNewLeaves ENTRY "r0-r2"

 [ debugcopy
 ADR r1, util_objectname
 DSTRING r1, "Copy_MakeNewLeaves with "
 ]
; pltb assume match, no replace yet !

        ADD     r0, r7, #copy_leafname
        ADR     r1, util_objectname
        BL      SNewString
        EXIT    VS

        ADD     r0, r8, #copy_leafname
        ADR     r1, util_objectname
        BL      SNewString

        LDRVS   r2,  [r7, #copy_leafname] ; Deallocate first one if second fail
        MOVVS   r14, #0
        STRVS   r14, [r7, #copy_leafname]
        BLVS    SFreeArea               ; Accumulate V
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Copy_MakeFullnames
; ==================

; Append leaf to dir for source and dest

; In    r0  = 0: use src leafname when making dst fullname
;          <> 0: use dst leafname when making dst fullname

; Out   VS: error - both strings deallocated (no such thing as old fullnames)

Copy_MakeFullnames ENTRY "r0-r2, r4"

 [ debugcopy
 DLINE "Copy_MakeFullnames"
 ]
        MOV     r0, r7                  ; Make source fullname
        BL      Util_AppendLeafToDir
        EXIT    VS

        LDR     r0, [sp, #0]
        TEQ     r0, #0
        LDREQ   r1, [r7, #copy_leafname]
        LDRNE   r1, [r8, #copy_leafname]
        MOV     r0, r8                  ; Make dst fullname with given leafname
        BL      Util_AppendGivenLeafToDir

        LDRVS   r2, [r7, #copy_name]    ; Deallocate source fullname
        BLVS    SFreeArea               ; Accumulate V
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Copy_FreeFullnames
; ==================

; Out   VS: error - both strings deallocated, else V preserved (snazzy)

Copy_FreeFullnames ENTRY "r0, r2-r3"

 [ debugcopy
 DLINE "Copy_FreeFullnames"
 ]
        MOV     r3, #copy_name

10      LDR     r2,  [r7, r3]           ; Deallocate source name
        BL      SFreeArea               ; Accumulate V

        LDR     r2,  [r8, r3]           ; Deallocate dest name
        BL      SFreeArea               ; Accumulate V
        EXIT

; .............................................................................

Copy_FreeLeafnames ALTENTRY

 [ debugcopy
 DLINE "Copy_FreeLeafnames"
 ]
        MOV     r3, #copy_leafname
        B       %BT10

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyObject
; ==========
;
; Copy object from A to B, recursing as necessary
; Dirnames set up for this level
; Leafnames already set up after possible wildcard match
; Fullnames already set up

; In    r7 = source file desc^
;       r8 = dest file desc^

; Out   r0-r5 corrupted by calls
;       VC: object copied, skipped, or was dir & ~recurse
;       VS: failed in copying object, or aborted

CopyObject ENTRY

 [ debugcopy
 DLINE "CopyObject"
 ]
        LDR     r14, util_objecttype    ; What the source ?
        TEQ     r14, #object_directory
        BEQ     %FT50                   ; [is a dir]

; Copy existing file (if doing files !)

        LDR     r14, util_bitset
        TST     r14, #util_structureonly
        BLEQ    CopyFile
        EXIT


50 ; It's a directory. Are we recursing ?

        LDR     r14, util_bitset        ; Recurse set ?
        TST     r14, #util_recurse
        BEQ     %FT70                   ; [no - we've got r14 ok]

; Copy this dir, recursing

        BL      CopyDirectory           ; dir & recurse
        EXIT


70      TST     r14, #util_verbose      ; dir & ~recurse. No need to INC skippd
        EXIT    EQ

        MOV     r0, r7                  ; src
        BL      Util_PrintName
        ADRVC   r0, fsw_space_is_a_dir
        SWIVC   XOS_Write0
        BLVS    CopyError
        CMPVC   r0, r0                  ; EQ -> not copied
        EXIT


fsw_space_is_a_dir
        DCB     " is a directory", LF,CR, 0
        ALIGN

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyFile
; ========
;
; Copy single file (which exists) from A to B, preserving attributes
; Fullnames set up in desc^.name; source info read

; In    r7 = source file desc^, source exists !
;       r8 = dest file desc^

; Out   Much corruption
;       VC: file copied or skipped
;       VS: failed to copy file

CopyFile ENTRY

 [ debugcopy
 DLINE "CopyFile"
 ]
        BL      CopyFile_Confirm        ; Check before trying anything
        EXIT    VS
        BLNE    Util_IncrementSkipped
        EXIT    NE                      ; [no copy wanted, nothing allocated]

        ADR     r14, util_load          ; Copy these away to a safe place
        LDMIA   r14, {r0, r1}           ; so looking at restamp won't alter
        ADR     r14, copy_realload      ; (Used in date cmp routine)
        STMIA   r14, {r0, r1}

        LDR     r14, util_bitset        ; Restamping ?
        TST     r14, #util_restamp
        BEQ     %FT01

        CMN     r0, #&00100000          ; If not dated, don't alter addresses
        MOVCS   r14, r0, ASR #8         ; &FFFFFttt
        LDRCSB  r0, copy_startedtime+4
        ORRCS   r14, r0, r14, LSL #8    ; &FFFtttdd
        STRCS   r14, util_load
        LDRCS   r14, copy_startedtime
        STRCS   r14, util_exec
 [ debugcopy
 BCC %FT00
 DLINE "setting new stamp for copy load/exec"
00
 ]

01      LDR     r14, util_bitset
        TST     r14, #util_peekdest
        BEQ     %FT02

        BL      CopyFile_EnsureDestFileWriteable
        EXIT    VS
        EXIT    NE                      ; [no copy wanted, nothing allocated]

02      BL      Copy_PromptSource
        EXIT    VS


; Claim appropriate area of memory to do the copy: user > wimp > rma > apl.
; NB. Memory remapping can't be done under interrupt, so we're reasonably safe.

        LDR     r4, util_length         ; Size of file we are copying
 [ debugcopy
 DREG r4, "FileSize = "
 ]

        LDR     r1, copy_userbuffersize ; Try punter's buffer first
 [ debugcopy
 DREG r1, "UserSize = "
 ]
        CMP     r1, r4
        LDRHS   r2, copy_userbuffer
        BHS     %FT15                   ; [do whole file in user buffer]

        MOV     r0, #0
        STR     r0, copy_wimpfreearea   ; For eventual deallocation
        STR     r0, copy_wimpfreesize
        STR     r0, copy_rmasize
        STR     r0, copy_aplsize

        MOV     r0, #1                  ; Then the Window Manager
        MOV     r1, #1
 [ debugcopy
 DREG r0,"Wimp_ClaimFreeMemory: r0 = ",cc
 DREG r1,", r1 = "
 ]
        SWI     XWimp_ClaimFreeMemory
        BVS     %FT03                   ; [no wimp]
 [ debugcopy
 DREG r2, "WimpAddr = "
 DREG r1, "WimpSize = "
 ]
        CMP     r2, #0
        BEQ     %FT03                   ; [someone else's claimed; can't move]
        STR     r1, copy_wimpfreesize   ; Remember this anyway
        CMP     r1, r4
        STRHS   r2, copy_wimpfreearea
        BHS     %FT15                   ; [do whole file in wimp buffer]

        MOV     r0, #0                  ; Must free it again
 [ debugcopy
 DREG r0,"Wimp_ClaimFreeMemory: r0 = ",cc
 DREG r1,", r1 = "
 ]
        SWI     XWimp_ClaimFreeMemory   ; Can't give error or fail


03      BL      SDescribeRMA
        CMP     r2, r4
        BLO     %FT04

        MOV     r3, r4                  ; Only claim right amount
        BL      SGetRMA
        EXIT    VS
        BNE     %FT15                   ; [claim ok; do whole file in RMA]

; RMA claim failed, maybe due to IRQ

04      LDR     r14, util_bitset
        TST     r14, #util_quick
        BEQ     %FT50                   ; [no way we can do whole file in RMA]

        BL      SClaimAPL               ; Out: r2 -> apl, r1 = apl size

        CMP     r1, r4
        BLO     %FT50                   ; [no way we can do whole file in apl]

        BL      SClaimAPL               ; Out: r2 -> apl

15 ; ++++++++++++++++++ Copy file by Load/Save/WriteAttr ++++++++++++++++++++++

 [ debugcopy
 DREG r2, "Got area for whole file copy: "
 ]
        STR     r2, copy_area

; ***^  LDR     r2, copy_area
        MOV     r0, #fsfile_Load
        BL      CallFSFile_Given_R7     ; Will load at r2
        BVS     %FT95                   ; Deallocate block

        LDR     r14, util_bitset
        TST     r14, #util_peekdest
        BNE     %FT17                   ; Already got dest into suitable state

        BL      CopyFile_EnsureDestFileWriteable ; Get to dest; maybe unlock
        BVS     %FT95                   ; Deallocate block
        BNE     %FT95                   ; [don't copy: deallocate block]
        B       %FT18

17      BL      Copy_PromptDest         ; Still need to get to dest though

18
 [ debugcopy
 DLINE "ok - writing dest file"
 ]
        LDMVCIA r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        ADRVC   r14, util_load          ; Preserve load and exec addresses
        LDMVCIA r14, {r2, r3, r5}       ; from the source file. NB r5 := length
        LDRVC   r4, copy_area           ; So that we can save a word here
        ADDVC   r5, r4, r5              ; r5 = end address in core (order)
                                        ; r4 = start address in core
        MOVVC   r0, #fsfile_Save
        BLVC    CallFSFile_Given        ; Must be on dest
        BVS     %FT95                   ; Deallocate block

        LDR     r14, util_bitset        ; Copying attributes ?
        TST     r14, #util_noattr
        LDREQ   r5, util_attr
        MOVEQ   r0, #fsfile_WriteAttr   ; Write correct attributes
        BLEQ    CallFSFile_Given        ; Still on dest

40 ; ................ Common end for both copy mechanisms .....................

        BLVC    Copy_DeleteSourceAfterCopy ; r5 = source attributes

        BLVC    CopyFile_Verbose        ; Tell them copy action is complete

95      LDR     r2, copy_area           ; Free the used block
        BL      SFreeCopy               ; Accumulates V
        EXIT


50 ; ++++++++++ Copy file by OpenIn/Create/OpenUp/GBPB/Close/WriteInfo ++++++++

51 ; Loop till we get some workspace - IRQ processes may be altering RMA size

; Clip request against largest source so far
; Some sources won't alter size under interrupt

        LDR     r4, copy_userbuffersize
        LDR     r14, copy_wimpfreesize
        CMP     r4, r14
        MOVLO   r4, r14
        LDR     r14, copy_rmasize
        CMP     r4, r14
        MOVLO   r4, r14
        LDR     r14, copy_aplsize
        CMP     r4, r14
        MOVLO   r4, r14

; Most efficient now to round our request down to 1K bdy if possible to get
; the best out of buffering whole sectors on D format discs

        CMP     r4, #1024
        BICHI   r4, r4, #(1024-1) :AND: &FF00
        BICHI   r4, r4, #(1024-1) :AND: &00FF
 [ debugcopy
 DREG r4, "initial max block after rounding = "
 ]

        CMP     r4, #0                  ; Now failed totally? >>>a186<<<
        MOVEQ   r0, #ModHandReason_Claim ; VClear
        MOVEQ   r3, #32*1024*1024       ; So make ludicrous claim to get
        SWIEQ   XOS_Module              ; a reasonable error message
        BLVS    CopyError
        EXIT    VS

        LDR     r14, copy_userbuffersize
        CMP     r14, r4
        LDRHS   r14, copy_userbuffer
        BHS     %FT60                   ; [use punter's buffer]
        
        LDR     r14, copy_wimpfreesize
        CMP     r14, r4
        BLO     %FT52

        MOV     r0, #1
        MOV     r1, r4
 [ debugcopy
 DREG r0,"Wimp_ClaimFreeMemory: r0 = ",cc
 DREG r1,", r1 = "
 ]
        SWI     XWimp_ClaimFreeMemory
 [ debugcopy
 DREG r2, "WimpAddr = "
 DREG r1, "WimpSize = "
 ]
        STR     r2, copy_wimpfreearea
        CMP     r2, #0
        BNE     %FT60                   ; [use wimp buffer]

        MOV     r14, #0                 ; The bastard's changed his mind:
        STR     r14, copy_wimpfreesize  ; Don't reconsider this source


52      LDR     r14, copy_rmasize
        CMP     r14, r4
        BLO     %FT55

        MOV     r3, r4
 [ debugcopy
 DREG r3, "Trying to get space for GBPB buffer: "
 ]
        BL      SGetRMA
        EXIT    VS
        BNE     %FT60                   ; [block claimed; use rma]

        BL      SDescribeRMA            ; Recompute amount of rma left

55      LDR     r14, copy_aplsize       ; Will be zero if ~Q or unable to claim
        CMP     r14, r4
        BLO     %BT51                   ; [can't fit, so loop]

        BL      SClaimAPL               ; Out: r2 -> apl


60 ; Why is it so hard ???

 [ debugcopy
 DREG r2, "Got area for GBPB copy: ",cc
 DREG r3, ", "
 ]
        STR     r2, copy_area
        STR     r4, copy_blocksize

        MOV     r0, #open_read          ; Open source for read
        LDMIA   r7, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        BL      OpenFileForCopy
        BVS     %BT95                   ; Deallocate block
        STRB    r0, copy_srchandle

        LDR     r14, util_bitset        ; >>>a186<<< addition
        TST     r14, #util_peekdest
        BNE     %FT61                   ; Already got dest into suitable state

        BL      CopyFile_EnsureDestFileWriteable ; Get to dest; maybe unlock
        BVS     %FT91                   ; Close source       >>>a186<<< fix vvv
        BNE     %FT91                   ; [don't copy: close source]
        B       %FT62

61      BL      Copy_PromptDest         ; Still need to get to dest though

62
 [ debugcopy
 DLINE "ok - writing dest file"
 ]
        LDMVCIA r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        MOVVC   r0, #fsfile_Create      ; Create new file with wrong load,exec
        LDRVC   r2, DeadMeat            ; so that if copy breaks down (eg.
        MOVVC   r3, r2                  ; no fucking reply, we can restart a
        MOVVC   r4, #0                  ; copy newer. Use right length though
        LDRVC   r5, util_length         ; r4,r5 = pseudo-start,end addresses
        BLVC    CallFSFile_Given        ; Still on dest.
        BVS     %FT91                   ; Close source

; Both source and dest are now files

        MOV     r0, #open_write + open_read ; Open dest for update
; ***^  LDMIA   r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        BL      OpenFileForCopy
        BVS     %FT91                   ; Close source
        STRB    r0, copy_dsthandle

        ADR     r9, gbpb_memadr         ; Prepare for loop
        LDR     r5, util_length         ; n_left := size(src)

; Loop copying from one to t'other. NEVER have the r5 = 0 case, always OSFiled

; n_left := size(src)
; WHILE n_left > 0 DO
;   n_to_do := min(nleft, ?buffer)
;   readatptr(buffer, n_to_do)
;   writeatptr(buffer, n_to_do)
;   n_left -:= n_to_do
; OD

70      CMP     r5, #0                  ; Bored shitless ? Well, I am. VClear
        BEQ     %FT86                   ; [close dest only, src already closed]

        LDR     r14, copy_blocksize
        CMP     r5, r14                 ; Is n_left > ?buffer
        MOVLS   r3, r5
        MOVHI   r3, r14
        SUB     r5, r5, r3              ; n_left -:= n_to_do (Exactly 0 if end)

        MOV     r10, r3
        LDRB    r1, copy_srchandle
        LDR     r2, copy_area
        STMIA   r9, {r2, r3}

        BL      Copy_PromptSource
        MOVVC   r0, #OSGBPB_ReadFromPTR
        BLVC    Xfer_ReadBytes
        BVS     %FT85                   ; [close both files]

        CMP     r5, #0                  ; No more to do after this xfer? VClear
        BLEQ    Copy_CloseSrc
        BVS     %FT86                   ; [close dest only, src already closed]

        MOV     r3, r10                 ; Restore n_to_do
        LDRB    r1, copy_dsthandle
        LDR     r2, copy_area
        STMIA   r9, {r2, r3}

        BL      Copy_PromptDest
        MOVVC   r0, #OSGBPB_WriteAtPTR
        BLVC    Xfer_WriteBytes
        BVC     %BT70                   ; Loop 'till bored
                                        ; else drop thru to close both


85      BL      Copy_CloseSrc           ; Accumulate V (src may be closed here
                                        ; if we got error in saving last bytes)

86      BL      Copy_CloseDst
        BVS     %BT95                   ; Deallocate block

; Note that we are now on the dest, unlike before !!! >>>a816<<< fix

        LDR     r14, util_bitset        ; Copying attributes ?
        TST     r14, #util_noattr
        LDMIA   r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        BNE     %FT88                   ; in any case (still on dest)

        MOV     r0, #fsfile_WriteInfo   ; Write correct attributes + load/exec
        ADR     r14, util_load
        LDMIA   r14, {r2, r3, r4, r5}   ; util_load,_exec,dummy(_len),_attr
        B       %FT89                   ; Write then exit. VClear


88      MOV     r0, #fsfile_WriteExec
        LDR     r3, util_exec           ; Always copy over load,exec in reverse
        BL      CallFSFile_Given        ; order so that load addr DeadMeat
        MOVVC   r0, #fsfile_WriteLoad   ; until this final op -> file ok
        LDRVC   r2, util_load

89      BLVC    CallFSFile_Given
        B       %BT40                   ; Common exit


91      BL      Copy_CloseSrc           ; Close source, accumulating V
        B       %BT95                   ; Deallocate block >>>a186<<< fix


; >>>a186<<< removed 3 spurious instructions

DeadMeat
        DCD     &DEADDEAD               ; Picked up as word

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Out   V preserved or set

Copy_CloseSrc ENTRY "r0-r2"

        LDRB    r1, copy_srchandle      ; Already closed ?
        TEQ     r1, #0
        EXITS   EQ                      ; Accumulates V

        MOV     r14, #0
        STRB    r14, copy_srchandle     ; Now closed

        BL      Copy_PromptSource       ; Accumulates V, preserves r1

10      MOV     r2, psr
        MOV     r0, #0
        SWI     XOS_Find                ; Don't call internal routine as we
        BLVS    CopyError               ; may have globalerror set, and the
        TEQVCP  r2, #0                  ; flushing code sets V if globalerror
        EXIT                            ; was set at all

; .............................................................................
; Don't need to do same trick with file handle for CloseDest

Copy_CloseDst ALTENTRY

        BL      Copy_PromptDest         ; Accumulates V

        LDRB    r1, copy_dsthandle      ; Close dest
        B       %BT10

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyDirectory
; =============

; Copy whole directory contents
; Fullnames of dirs set up in desc^.name; info read

; In    r7 = dir desc^, directory exists

; Out   Only r7, r8, wp preserved
;       VC: directory copied, or skipped
;       VS: failed to copy directory, or aborted

CopyDirectory ENTRY

 [ debugcopy
 DLINE "CopyDirectory"
 ]
        BL      CopyDirectory_Confirm
        EXIT    VS
        BLNE    Util_IncrementSkipped
        EXIT    NE

; First, create your directory !

        LDMIA   r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        BL      Util_SpecialDir         ; If special, don't create: waste of
        BEQ     %FT50                   ; time and just looks plain silly
                                        ; Don't change access either. Dubious

        MOV     r0, #fsfile_ReadInfo    ; Exists already ?
        BL      Copy_PromptDest
        BLVC    CallFSFile_Given
        EXIT    VS

        CMP     r0, #object_file
        BHI     %FT20                   ; If a dir, don't ask to recreate
        BEQ     %FA99                   ; Error if dest is a file

        MOV     r0, #fsfile_CreateDir   ; No error if already exists
        MOV     r4, #35                 ; Sensible n entries (not random !)
                                        ; Will give &400 dirs on Net
                                        ; Ignored by ADFS
        BL      Copy_PromptDest
        BLVC    CallFSFile_Given        ; Doesn't corrupt util_attr
        BLVC    CopyDirectory_VerboseCDir
        EXIT    VS

20 ; Copy attr of source dir to dest dir iff access copying

        LDR     r14, util_bitset        ; Copying attributes ?
        TST     r14, #util_noattr
        LDREQ   r5, util_attr
        MOVEQ   r0, #fsfile_WriteAttr   ; Write correct attributes
        BLEQ    CallFSFile_Given        ; Still on dest
        EXIT    VS


50 ; Copy contents of dir, saving info on stack

        LDR     r1, util_totalsize      ; Save total so far this level
        Push    r1

        LDR     r0, [r7, #copy_dirprefix] ; Push names
        LDR     r1, [r7, #copy_leafname]
        LDR     r2, [r7, #copy_name]
        LDR     r3, util_direntry       ; Push position in dir
        LDR     r4, util_bitset         ; Push flags
        LDR     r5, util_attr           ; Push srclocked state in case deleting
        LDR     r6, [r8, #copy_dirprefix]
        LDR     r9, [r8, #copy_leafname]
        LDR     r10, [r8, #copy_name]
        LDR     r14, util_nskipped
        Push    "r0-r6, r9-r10, r14"

        LDR     r14, [r7, #copy_name]   ; Use fullname as dirprefix
        STR     r14, [r7, #copy_dirprefix]
        LDR     r14, [r8, #copy_name]
        STR     r14, [r8, #copy_dirprefix]
        addr    r14, fsw_wildstar       ; Leafname := '*'

; Might be nice at some stage to pass in some other leafname. Suggestions ?
; Roger wants to be able to do o.* ... seems difficult though
; Easy to do recursive wipe of m2dump etc.

        STR     r14, [r7, #copy_leafname]
        STR     r14, [r8, #copy_leafname]
        MOV     r14, #0
        STR     r14, util_nskipped      ; Nothing skipped at this level
        STR     r14, util_totalsize     ; Nothing copied at this level

 [ debugcopy
 DREG sp, "Leaving CopyDirectory; sp = "
 ]
        BL      CopyWildObject

 [ debugcopy
 DREG sp, "Back in CopyDirectory; sp = "
 ]
        Pull    "r0-r6, r9-r10, r14"    ; Restore names, locked state (to r5)
        STR     r0, [r7, #copy_dirprefix]
        STR     r1, [r7, #copy_leafname]
        STR     r2, [r7, #copy_name]
        STR     r3, util_direntry
        STR     r4, util_bitset
; r5 is source dir attributes
        STR     r6, [r8, #copy_dirprefix]
        STR     r9, [r8, #copy_leafname]
        STR     r10, [r8, #copy_name]

        LDR     r0, util_nskipped       ; Remember nskipped at that level
        STR     r14, util_nskipped

        LDR     r14, util_totalsize     ; Remember size copied at that level
        STR     r14, util_length

        Pull    r1                      ; Restore size copied at this level
        STR     r1, util_totalsize
        ADDVS   r1, r1, r14             ; add here if error
        STRVS   r1, util_totalsize
        EXIT    VS

; Contents copied. Shall we (or can we) delete the source ?

        CMP     r0, #0                  ; Did we skip any in there ? VClear
        BLNE    Util_IncrementSkipped   ; Note that we've skipped this dir del!

        BLEQ    Copy_DeleteSourceAfterCopy

        BLVC    CopyDirectory_Verbose   ; Tell them copy dir complete
        EXIT


; Destination is a file. Always an error

99      addr    r0, ErrorBlock_CopyDirOntoFile
        BL      CopyError
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; See if the destination file already exists or is a dir

; Out   Much corruption
;       r1, r6, fscb set up for dest

;       VS: error copied
;       VC, EQ: copy file
;       VC, NE: don't copy file

CopyFile_EnsureDestFileWriteable ENTRY

 [ debugcopy
 BL %FT00
 DLINE "EnsureDestFileWriteable returns ",cc
 ADRVS r0, %FT03
 BVS %FT04
 ADREQ r0, %FT01
 ADRNE r0, %FT02
04
 BL Tutu_PrintString
 EXIT
01
 DCB "EQ: copy file", LF,CR,0
02
 DCB "NE: don't copy file", LF,CR,0
03
 DCB "error", LF,CR,0
 ALIGN


00
 ENTRY
 DLINE "Copy_EnsureDestFileWriteable"
 ]
        LDMIA   r8, {r1, r6, fscb}      ; copy_name, copy_special, copy_fscb
        MOV     r0, #fsfile_ReadInfoNoLen ; Allow better NetFS performance
        BL      Copy_PromptDest         ; when FileServer feels up to it
        BLVC    CallFSFile_Given
        EXIT    VS

        TEQ     r0, #object_nothing     ; No possible objection to copy !
        EXIT    EQ                      ; EQ -> do it

        TEQ     r0, #object_file
        BEQ     %FT20                   ; File may be locked, or not forcing

; Destination is a directory. Always an error

        addr    r0, ErrorBlock_CopyFileOntoDir

10      BL      CopyError
        EXIT                            ; VSet always



20 ; Destination is a file

        LDR     r14, util_bitset        ; Is source newer than dest ?
        TST     r14, #util_newer
        BEQ     %FT65

 [ debugcopy
 DLINE "Copy if newer"
 ]
        ADR     r14, fileblock_load     ; Read load/exec of dest file
        LDMIA   r14, {r0, r4}           ; r0 = load, r4 = exec
        CMN     r0, #&00100000          ; Is dest dated ? CSet if so
 [ debugcopy
 BCS %FT00
 DLINE "destination file undated"
00
 ]
        BCC     %FT65                   ; Copy if not

        ADR     r14, copy_realload      ; Read load/exec of source file
        LDMIA   r14, {r2, r3}           ; r2 = load, r3 = exec
        CMN     r2, #&00100000          ; Is source dated ? CSet if so
 [ debugcopy
 BCS %FT00
 DLINE "source file undated"
00
 ]
        BCC     %FT65                   ; Copy if not

        AND     r0, r0, #&FF            ; Mask out crap from load addresses
        AND     r2, r2, #&FF            ; Comparison must be done unsigned !

 [ debugcopy
 DREG r2,"source datestamp is: ",cc,Byte
 DREG r3
 DREG r0,"destin datestamp is: ",cc,Byte
 DREG r4
 ]
        SUBS    r3, r3, r4              ; Another careful date comparison
        MOVNE   r3, #Z_bit              ; lo words first
        SBCS    r2, r2, r0              ; hi words next
        TEQEQP  r3, pc

        BHI     %FT65                   ; [yes, do copy]

        ADRLO   r2, fsw_is_less_recent
        ADREQ   r2, fsw_is_same_age     ; [equal datestamps]

; Destination is newer than (or same age as) source:
 [ False ; >>>a186<<<
;   If (c ~v) or (c v) then prompt + get input.
;   If (~c ~v) then tough luck; no info output
;   If (~c v) then print file blurb
 ]

        LDR     r14, util_bitset
 [ True ; >>>a186<<< see below
        TST     r14, #util_verbose
 |
        TST     r14, #util_verbose :OR: util_topconfirm
 ]
        BEQ     %FT70                   ; Tough if neither set ! Don't copy

        ADR     r0, fsw_File_space      ; 'File '
        SWI     XOS_Write0
        MOVVC   r0, r7                  ; src
        BLVC    Util_PrintName
        MOVVC   r0, r2                  ; ' is the same age as ' or
                                        ; ' is more recent than '
        SWIVC   XOS_Write0
        MOVVC   r0, r8                  ; dst
        BLVC    Util_PrintName
 [ True ; >>>a186<<< Don't ask the punter if datecmp fails. Sam request
        SWIVC   XOS_NewLine             ; message ends
        BVS     %BT10
        B       %FT70                   ; Don't copy
 |
        BVS     %BT10

        LDR     r14, util_bitset
        TST     r14, #util_topconfirm   ; Shall we prompt the user ?
        BNE     %FT60

        SWI     XOS_NewLine             ; [no. message ends]
        BVS     %BT10
        B       %FT70                   ; Don't copy

60      ADR     r0, fsw_Overwrite
        SWI     XOS_Write0
        BL      Util_GetConfirmYN       ; EQ -> do it
        BVS     %BT10
        EXIT    NE                      ; NE -> don't copy
        B       %FT85                   ; Override force, the punter has spoken
 ]

fsw_is_same_age    DCB " has the same datestamp as ", 0
fsw_is_less_recent DCB " has an earlier datestamp than ", 0
fsw_already_exists DCB " already exists", 0
fsw_and_is_locked  DCB " and is locked", 0
fsw_Overwrite      DCB ". Overwrite", 0

        ALIGN


65      LDR     r14, util_bitset        ; Forcing copy ?
        TST     r14, #util_force
        BNE     %FT85                   ; [yes]

 [ debugcopy
 DLINE "Not forcing"
 ]
; Not forcing:
;   If (c ~v) or (c v) then prompt + get input.
;   If (~c ~v) then tough luck; no info output
;   If (~c v) then print file blurb

        TST     r14, #util_verbose :OR: util_topconfirm
        BEQ     %FT70                   ; Tough if neither set ! Don't copy

        ADR     r0, fsw_File_space      ; 'File '
        SWI     XOS_Write0
        MOVVC   r0, r8                  ; dst
        BLVC    Util_PrintName
        ADRVC   r0, fsw_already_exists  ; ' already exists'
        SWIVC   XOS_Write0
        BVS     %BT10

        LDR     r5, fileblock_attr
        TST     r5, #locked_attribute   ; Locked ?
        ADRNE   r0, fsw_and_is_locked
        SWINE   XOS_Write0
        BVS     %BT10

        LDR     r14, util_bitset        ; Shall we prompt the user ?
        TST     r14, #util_topconfirm
        BNE     %FT80

        SWI     XOS_NewLine             ; [no. message ends]
        BVS     %BT10

70      BL      Util_IncrementSkipped
        CMP     pc, #0                  ; VClear
        EXIT                            ; NE -> don't copy

80      ADR     r0, fsw_Overwrite
        SWI     XOS_Write0
        BL      Util_GetConfirmYN       ; EQ -> do it
        BVS     %BT10
 [ True ; >>>a186<<< SKS just spotted bug, could give 'Nothing to copy' error
        BNE     %BT70                   ; [don't copy]
 |
        EXIT    NE                      ; NE -> don't copy
 ]


; The man from DelMonte, he say 'Yeh' ! - so ensure attributes ok for the copy

85      LDR     r5, fileblock_attr      ; Need to have WR~L to copy to file
 [ debugcopy
 DREG r5, "dest attributes are ",,Byte
 ]
        TST     r5, #locked_attribute   ; Locked ?
        BNE     %FT90                   ; If so, must force access

        AND     r14, r5, #(read_attribute+write_attribute) ; Already got wr ?
        TEQ     r14, #(read_attribute+write_attribute)
        EXIT    EQ                      ; If so, don't need to do access
                                        ; EQ -> do it

90      MOV     r5, #(read_attribute+write_attribute)
        MOV     r0, #fsfile_WriteAttr
        BL      CallFSFile_Given        ; Got to dest already
        CMPVC   r0, r0                  ; EQ -> do it
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r5 = source object attributes

Copy_DeleteSourceAfterCopy ENTRY "r1"

 [ debugcopy
 DLINE "Copy_DeleteSourceAfterCopy"
 ]
        LDR     r14, util_bitset        ; Deleting source ?
        TST     r14, #util_deletesrc
        EXIT    EQ

        LDR     r1, [r7, #copy_name]
        BL      Util_SpecialDir
        EXIT    EQ                      ; VClear. Don't try to delete $ etc.

        BL      Copy_PromptSource
        EXIT    VS

        TST     r5, #locked_attribute   ; Is source locked ?
        MOVNE   r5, #0                  ; Take out all attributes, esp L
        MOVNE   r0, #fsfile_WriteAttr
        BLNE    CallFSFile_Given_R7     ; Only if neccessary

        MOVVC   r0, #fsfile_Delete
        BLVC    CallFSFile_Given_R7     ; Still on source

        BLVC    Util_DecrementDirEntry  ; Must go back one in the dir, 'cos
        EXIT                            ; we've just deleted the one we read

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyFile_Confirm
; ================

; Ask the punter if he wants to do it (if dates allow)

; Out   VS: error
;       VC, EQ -> do it
;       VC, NE -> don't do it

CopyFile_Confirm ENTRY "r0, r1"

        BL      Util_DateRange          ; See if dates allow it
        EXIT    NE

        ADR     r1, fsw_file_space


10      LDR     r14, util_bitset        ; Entered from below
        TST     r14, #util_confirm      ; Use this level's confirm bit here
        EXIT    EQ

        TST     r14, #util_deletesrc
        ADREQ   r0, fsw_copy_space
        ADRNE   r0, fsw_move_space
        SWI     XOS_Write0

        MOVVC   r0, r1
        SWIVC   XOS_Write0

        MOVVC   r0, r7                  ; src
        BLVC    Util_PrintName

        ADRVC   r0, fsw_space_as_space  ; ' as '
        SWIVC   XOS_Write0
        MOVVC   r0, r8                  ; dst
        BLVC    Util_PrintName

        BLVC    Util_GetConfirm
        BLVS    CopyError
        EXIT


fsw_copy_space  DCB     "Copy ", 0
fsw_move_space  DCB     "Move ", 0
fsw_file_space  DCB     "file ", 0
                ALIGN

; .............................................................................

CopyDirectory_Confirm ALTENTRY

        ADR     r1, fsw_directory_space
        B       %BT10

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyFile_Verbose
; ================

; Copied the file, so print copied info if being verbose. nfiles++

; In    util_length = size of file copied. To be added to totalsize

; Out   VS: error

CopyFile_Verbose ENTRY "r0, r9"

        BL      Util_IncrementFiles_TestVerbose

        ADR     r0, fsw_File_space      ; 'File '

30      LDR     r9, util_length         ; Always increment size copied
        LDR     r14, util_totalsize
        ADD     r14, r14, r9
        STR     r14, util_totalsize

        EXIT    EQ                      ; EQ -> ~verbose, so leave

        SWI     XOS_Write0
        MOVVC   r0, r7                  ; src
        BLVC    Util_PrintName
        BVS     %FT99

        LDR     r14, util_bitset
        TST     r14, #util_deletesrc
        ADREQ   r0, fsw_space_copied_as_space ; ' copied as '
        ADRNE   r0, fsw_space_moved_as_space  ; ' moved as '
        SWI     XOS_Write0

        MOVVC   r0, r8                  ; dst
        BLVC    Util_PrintName

        SWIVC   XOS_WriteI+","          ; Does save space !
        SWIVC   XOS_WriteI+space

        MOVVC   r0, r9
        BLVC    Util_PrintSize          ; 'xxx bytes', NL

99      BLVS    CopyError
        EXIT


fsw_File_space            DCB   "File ", 0

fsw_space_copied_as_space DCB   " copied"       ; Share with ...
fsw_space_as_space        DCB   " as ", 0
fsw_space_moved_as_space  DCB   " moved as ", 0

fsw_Directory_space       DCB   "Directory ", 0

fsw_Created_directory_space DCB "Created "      ; Share with ...
fsw_directory_space       DCB   "directory ", 0

        ALIGN

; .............................................................................
;
; CopyDirectory_Verbose
; =====================

; Copied the directory, so print

; In    util_length = size of dir copied. To be added to totalsize

; Out   VS: error

CopyDirectory_Verbose ALTENTRY

        BL      Util_IncrementDir_TestVerbose

        ADR     r0, fsw_Directory_space ; 'Directory '
        B       %BT30

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CopyDirectory_VerboseCDir
; =========================

; Created the directory, so print

; Out   VS: error

CopyDirectory_VerboseCDir ENTRY "r0"

        LDR     r14, util_bitset
        TST     r14, #util_verbose
        EXIT    EQ                      ; EQ -> ~verbose

        addr    r0, fsw_Created_directory_space ; 'Created directory '
        SWI     XOS_Write0

        MOVVC   r0, r8                  ; dst.
        BLVC    Util_PrintName
        SWIVC   XOS_NewLine

        BLVS    CopyError
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Copy_PromptSource
; =================

; Out   VC: ok
;       VS: error copied, or VSet on entry

Copy_PromptSource ENTRY "r0, r1"

        MOV     r1, #copy_at_source

10      LDRB    r14, copy_src_dst_flag
        CMP     r14, r1                 ; VClear
        LDRNEB  r14, util_bitset
        TSTNE   r14, #util_promptchange
        BEQ     %FT99
        TEQ     r1, #copy_at_source
        ADREQ   r0, fsw_EnsureSourceMedia
        ADRNE   r0, fsw_EnsureDestMedia
        BL      PromptSpaceBar

        BLVS    CopyError

99      STRVCB  r1, copy_src_dst_flag
        EXITS   VC                      ; Accumulate V
        EXIT

; .............................................................................
;
; Copy_PromptDest
; ===============

Copy_PromptDest ALTENTRY

        MOV     r1, #copy_at_dest
        B       %BT10


fsw_EnsureSourceMedia   DCB     "Ensure source media", 0
fsw_EnsureDestMedia     DCB     "Ensure destination media", 0
fsw_HitSpaceBar         DCB     " present then press SPACE bar", LF,CR, 0

        ALIGN

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r0 -> string to print

; Out   VC: r0 corrupt
;       VS: r0 -> error, not copied

PromptSpaceBar ENTRY

        SWI     XOS_Write0
        ADRVC   r0, fsw_HitSpaceBar
        SWIVC   XOS_Write0
        BLVC    ReadC_Escape
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; ReadC_Escape
; ============

; Out   VC: r0 = char
;       VS: r0 -> error, not copied

ReadC_Escape ENTRY "r1, r2"

        MOV     r0, #15                 ; Flush current input buffer
        MOV     r1, #1
        SWI     XOS_Byte

        SWIVC   XOS_ReadC
        EXIT    VS
        BLCS    SAckEscape
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Out   r2 = size of largest block in rma that we can/ought to claim

SDescribeRMA ENTRY "r0, r3"

        MOV     r0, #ModHandReason_RMADesc ; Try RMA now
        SWI     XOS_Module              ; r2 := maxblocksize; r3 := totalsize
        BLVS    CopyError
        EXIT    VS

        TEQ     r2, #0                  ; Can get r2 = -4 >>>a186<<<
        MOVMI   r2, #0

        CMP     r2, #4096 + 1024        ; If rma reasonably big, don't use all:
        SUBHI   r2, r2, #1024           ; leave some for filing systems
        BICHI   r2, r2, #(4096-1) :AND: &FF00
        BICHI   r2, r2, #(4096-1) :AND: &00FF
 [ debugcopy
 DREG r2, "rmaSize = "
 ]
        STR     r2, copy_rmasize        ; Remember this anyway
        EXITS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Out   r1 = apl size
;       r2 -> apl

SClaimAPL ENTRY "r0, r3"

        LDRB    r14, copy_owns_apl_flag
        TEQ     r14, #0
        BNE     %FT90                   ; [already own it, just resize]

        MOV     r14, #1                 ; apl is now dead meat and ALL mine!
        STRB    r14, copy_owns_apl_flag

        MOV     r0, #FSControl_StartApplication ; Start myself up
        addr    r1, anull               ; command tail
        addr    r2, Module_BaseAddr     ; CAO pointer
        addr    r3, FileSwitch_Title    ; command name
        SWI     XOS_FSControl

90      SWI     XOS_GetEnv              ; Where can we use up to ?
        MOV     r2, #&8000
        SUB     r1, r1, r2
 [ debugcopy
 DREG r1, "aplSize = "
 ]
        STR     r1, copy_aplsize        ; Remember this anyway
        EXITS

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; SFreeCopy
; =========

; In    r2 = pointer to space (user, wimp, rma, or apl)

; Out   V accumulated, block freed to appropriate owner

SFreeCopy ENTRY "r0-r2"

 [ debugcopy
 DREG r2, "SFreeCopy "
 ]
        LDR     r14, copy_wimpfreearea  ; Can be at &8000, but we MUST free it
        TEQ     r14, r2
        BNE     %FT50                   ; [must be RMA that we used then]

        MOV     r0, #0
 [ debugcopy
 DREG r0,"Wimp_ClaimFreeMemory: r0 = ",cc
 DREG r1,", r1 = "
 ]
        SWI     XWimp_ClaimFreeMemory   ; Can't give error
        EXITS                           ; Restore caller V

50      LDR     r14, copy_userbuffer    ; User buffer ?
        TEQ     r14, r2
        EXITS   EQ                      ; Restore caller V

        TEQ     r2, #&8000              ; apl after all ?
        EXITS   EQ                      ; Keep apl claimed, it'll be 'freed'
                                        ; when we OS_Exit

        BL      SFreeArea               ; Accumulates V
        EXITS   VC                      ; Restore caller V
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 ] ; hascopy

        LNK     $fileprefix.FSUtils2
