        SUBT    > <wini>arm.FileSwitch.LowLevel - Calls to the real Filing Systems

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;           L O W   L E V E L   F I L I N G   S Y S T E M   C A L L S
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

; I have now foolishly guaranteed that Filing Systems may use registers r0-r12
; for their own purposes within their code without having to restore them when
; returning to me - ie. it would be nice if they kept the stack flat and
; remembered the lr I passed them !
; This means they only have to keep track of which are parms for the operation
; and which should be returned. SKS 05-Feb-87

; NB. Restore wp immediately after they return - it's stacked (somewhere) !

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSFile
; ==========
;
; Do an OSFILE type operation
; fsforthisop must be set up already
; Monitor messages are printed according to the osfile op at this level

; In    r0 = OSFILE action to perform
;       r1 -> filename to use
;       fileblock contains parms to use (load, exec, length, attr)

; Out   VC: r0 and fileblock updated
;       VS: failed

CallFSFile ENTRY "r0-r12" ; Never (ever) trust lower level routines

        LDR     r6, SpecialField

        LDR     fscb, fsforthisop       ; Need a valid fscb set up

        ADR     r14, fileblock_base     ; Get parms from fileblock
        LDMIA   r14, {r2-r5}
 [ debugframe
 DREG r14, "Thinks fileblock_base at "
 ]

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

01      BL      CheckNullName           ; Reject null names unless fscb^.nullok
        EXIT    VS                      ; Also checks fscb^ valid

        LDRB    r14, [fscb, #fscb_opt1] ; Entered from below, r0-r6, fscb valid
        STRB    r14, lowfile_opt1       ; Remember OPT 1 state for after op

        LDRB    r14, [r6]               ; Convert zero length special fields
        CMP     r14, #0                 ; to zero for filing system
        MOVEQ   r6, #0

        TEQ     r0, #fsfile_Load        ; Must only load at r2 at this level
        MOVEQ   r3, #0                  ; Use r2 please ! Much depends on this

        TEQ     r0, #fsfile_CreateDir   ; Always datestamp directories
        LDREQ   r2, =&00000FFD          ; Type nibble = 'Data'
        BLEQ    SReadTime               ; Get datestamp in r2,r3

        TEQ     r0, #fsfile_ReadInfoNoLen
        LDREQ   r14, [fscb, #fscb_info]
        TSTEQ   r14, #fsinfo_fsfilereadinfonolen ; If fs doesn't support it
        MOVEQ   r0, #fsfile_ReadInfo    ; use standard ReadInfo call

; Enter Filing System with :
;    r0 = file op
;    r1 -> filename
;    r2 = load addr
;    r3 = exec addr
;    r4 = data start
;    r5 = data end / file attributes
;    r6 -> special field (if present) or 0
;   r12 -> module workspace

        TEQ     r0, #fsfile_Load        ; These are the only two that
        TEQNE   r0, #fsfile_ReadInfo    ; don't modify file structure or info !
        TEQNE   r0, #fsfile_ReadInfoNoLen
        BEQ     %FT10

        Push    "r0-r12"                ; Protect myself from idiots
        LDR     r8, [fscb, #fscb_info]  ; Filing system info word
        MOV     r9, r0                  ; fsfile operation (0xx)
        MOV     r0, #UpCall_ModifyingFile
  [ debuglowfile
  DREG r9, "UpCalling from FileSwitch: r9 = ",cc
  DREG r8, ", r8 = "
  ]
        SWI     XOS_UpCall              ; Just a notify op pltb.
        Pull    "r0-r12"
10

 [ debuglowfile
 DREG r0,"FSFile: calling rc ",cc,Byte
 TEQ r0,#fsfile_ReadInfo
 BEQ %FT05
 DREG r2,", parms ",cc
 DREG r3,,cc
 TEQ r0,#fsfile_Load
 BEQ %FT05
 DREG r4,,cc
 DREG r5
05
 DSTRING r6,", special ",cc
 DSTRING r1,", filename "
 ]
        MOV     r8, #fscb_file
        BL      CallFSEntryChecked

; Filing System returns with :
;    r0 = object type
;    r2 = load addr
;    r3 = exec addr
;    r4 = length
;    r5 = file attributes
;    r6 -> unwildcarded filename of low lifetime - copy away immediately
;         so that spooling etc. don't kill it

 [ debuglowfile
 BVS %FT42
 DREG r0,"FSFile: returned type ",cc
 DREG r2,", info ",cc
 DREG r3,,cc
 DREG r4,,cc
 DREG r5
 B %FT45
42
 DLINE "Error in FSFile"
45
 ]
        ADD     fp, sp, #4*(11-0)       ; Restore fp, wp in all cases
        LDMIA   fp, {fp, wp}

        BLVS    CopyError
        EXIT    VS

; Only Load/ReadInfo/Delete return object type (cat info returned to fileblock)

        LDRB    r1, [sp]                ; What was the op ?
        TEQ     r1, #fsfile_Load
        TEQNE   r1, #fsfile_ReadInfo
        TEQNE   r1, #fsfile_Delete
        TEQNE   r1, #fsfile_ReadInfoNoLen
        STREQ   r0, [sp]                ; Update object type
        ADREQ   r14, fileblock_base     ; Update object info
        STMEQIA r14, {r2-r5}
 [ debugframe
 BNE %FT00
 DREG r14, "Thinks fileblock_base at "
00
 ]


; Only Load/Save/Create give monitor messages from OPT 1

        LDRB    r7, lowfile_opt1        ; Nothing to do if OPT 1, 0
        CMP     r7, #0
        EXIT    EQ                      ; VClear

        CMP     r1, #fsfile_Save        ; Print data that was used in save
        CMPNE   r1, #fsfile_Create      ; or create, not what comes back
        ADREQ   r14, fileblock_base
        LDMEQIA r14, {r2-r5}            ; Get original parms in r2-r5
        SUBEQ   r4, r5, r4              ; Form length, you dead grey elf pillok
        CMPNE   r1, #fsfile_Load        ; Order !
        EXIT    NE                      ; VClear


; Must copy name away in case of reentrancy (very low lifetime object anyway)

        Push    "r2, r3"
        ADR     r0, OptFilenameString
        MOV     r1, r6
        BL      SGetLinkedString_excludingspaces ; Stop on CtrlChar/space
        Pull    "r2, r3"                        ; >>>a186<<<
        EXIT    VS

; Always print name. r1 -> copy of filename. r7 = OPT 1 value

        MOV     r8, #0                  ; Print name in field of 10
20      LDRB    r0, [r1], #1
        CMP     r0, #0                  ; Now zero terminated
        ADDNE   r8, r8, #1              ; Another one bites the dust
        SWINE   XOS_WriteC              ; WriteC preserves Z
        BVS     %FT95
        BNE     %BT20                   ; Loop over all of name

; OPT 1, 2 or higher ?

        CMP     r7, #1                  ; OPT 1,1 -> just filename, no trailers
        BEQ     %FT85


; Must now pad out in field of 10, 'cos here comes the info

26      CMP     r8, #10                 ; Must allow for name overflowing !
        ADDLO   r8, r8, #1              ; Finished spacing yet ?
        SWILO   XOS_WriteI+space
        BVS     %FT95
        BLO     %BT26

27      SWIVC   XOS_WriteI+space        ; Two spaces please in any case
        SWIVC   XOS_WriteI+space
        BVS     %FT95


        CMP     r7, #2                  ; OPT 1, 2 -> Hex Load/Exec/Length
        BNE     %FT50                   ; OPT 1, 4 and above identical to 3

30      MOV     r0, r2                  ; Load address in hex. Entry from below
        BL      HexR0LongWord
        SWIVC   XOS_WriteI+space

        MOVVC   r0, r3                  ; Exec address in hex
        BLVC    HexR0LongWord
        B       %FT80                   ; Print the length as well


50 ; Interpret the load and exec addresses suitably

        CMP     r2, r3                  ; Load = exec -> BBC utility
        BEQ     %BT30
        CMN     r2, #&000100000         ; Undated ones are given in hex
        BCC     %BT30

        Push    "r2, r3"
        MOV     r2, r2, LSR #8          ; File type in bottom 12 bits
        BL      DecodeFileType
        MOV     r0, r2
        BL      PrintR0Chars
        MOVVC   r0, r3
        BLVC    PrintR0Chars
        Pull    "r2, r3"

        SUB     sp, sp, #64
        SWIVC   XOS_WriteI+space
        MOVVC   r0, sp
        STRVC   r3, [sp]
        STRVCB  r2, [sp, #4]
        ADDVC   r1, sp, #8              ; rv^
        MOVVC   r2, #64-8
        SWIVC   XOS_ConvertStandardDateAndTime
        ADDVC   r0, sp, #8
        SWIVC   XOS_Write0
        ADD     sp, sp, #64

; Exit for OPT 1, 2 and above - print a space, then the length

80      SWIVC   XOS_WriteI+space
        MOVVC   r0, r4                  ; Length in hex
        BLVC    HexR0LongWord


; Exit for OPT 1, 1

85      SWIVC   XOS_NewLine             ; Tidy up the output line

95      BLVS    CopyError

        ADR     r0, OptFilenameString   ; Always deallocate string
        BL      SFreeLinkedArea
        EXIT

; .............................................................................
; In    r0-r6 parms for OSFile, fscb^ valid (checked by CheckNullName too)

CallFSFile_Given ALTENTRY

        CMP     r0, #fsfile_Save        ; Save in case of monitor info
        CMPNE   r0, #fsfile_Create
        ADREQ   r14, fileblock_base
        STMEQIA r14, {r2-r5}

        B       %BT01

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSFunc
; ==========
;
; Lots of miscellaneous Filing System functions

; In    r0 reason code, various parms

; Out   VC: ok, r0-r5 may (or may not) be modified, but don't trust 'em
;       VS: fail

CallFSFunc ENTRY "r6-r12" ; Never (ever) trust lower level routines

        LDR     r6, SpecialField
        LDR     fscb, fsforthisop

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

01 ; Entered from below

        LDRB    r14, [r6]               ; Convert zero length special fields
        CMP     r14, #0                 ; to zero for filing system
        MOVEQ   r6, #0

        TEQ     r0, #fsfunc_FileInfo
        LDREQ   r14, [fscb, #fscb_info]
        TSTEQ   r14, #fsinfo_fileinfo   ; If filing system doesn't support it
        MOVEQ   r0, #fsfunc_Info        ; use standard info call

 [ debuglowfunc
 DREG r0,"FSFunc: rc ",cc
 DREG r1," arg ",cc
 DREG r2," arg2 ",cc
 DSTRING r6,", special "
 ]
; Enter Filing System with :
;    r0 = reason code
;    r1 = arg1 .. r5 = arg5
;    r6 -> special field (if present) or 0
;    r7 -> second special field (if present) or 0 for rename
;   r12 -> module workspace

        CMP     r0, #fsfunc_Rename
        BNE     %FT30

        Push    r1
        MOV     r1, r2
        BL      CheckNullName
        Pull    r1
        BLVC    CheckNullName
        BVC     %FA31                   ; send upcall, then do op
        EXIT


30      CMP     r0, #fsfunc_Info        ; VClear
        CMPNE   r0, #fsfunc_Access
        BLEQ    CheckNullName
        EXIT    VS

        TEQ     r0, #fsfunc_Access      ; These are the only two that
; ***^  TEQNE   r0, #fsfunc_Rename      ; modify file structure or info
        BNE     %FT35

31      Push    "r0-r12"                ; Protect myself from idiots
        LDR     r8, [fscb, #fscb_info]  ; Filing system info word
        ORR     r9, r0, #&200           ; fsfunc operation :OR: a bit (2xx)
        MOV     r0, #UpCall_ModifyingFile
  [ debuglowfunc
  DREG r9, "UpCalling from FileSwitch: r9 = ",cc
  DREG r8, ", r8 = "
  ]
        SWI     XOS_UpCall              ; Just a notify op pltb.
        Pull    "r0-r12"
35

40      MOV     r8, #fscb_func
        BL      CallFSWithCheck

 [ debuglowfunc
 EXIT VC
 DLINE "Error in FSFunc"
 ]
        ADDVS   fp, sp, #4*(11-6)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError
        EXIT

; .............................................................................
; In    fscb^ valid

CallFSFunc_Given ALTENTRY

        B       %BT01

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSOpen
; ==========
;
; Try to open the file pointed to by r1 in mode r0. fsforthisop set up already

; In    r0 =  &40: open for read
;             &80: create and open for update
;             &C0: open for update
;       r1 -> filename, 0
;       r3 =  FileSwitch handle allocated to the embryo stream

; NB. r0 = 0 is NOT a valid parm for CallFSOpen ! Use CallFSClose instead

; Out   VC: r0  = bits 7..0 = Filing System number, bits 29..8 = FS device
;                 (normally ALL zero - only need this in the fuschia !)
;                 bits 31, 30, 29 = write/read/dir attributes of file
;           r1 <> 0: 32 bit Filing System handle. NB. not r0 !!!
;                 0: not found
;           r2  = buffer chunk size to use with this file. 0 -> unbuffered
;           r3  = file extent (for buffered files only)
;           r4  = initial allocated size on disc (for buffered files only)
;                                                 (for writeable files only)
;       VS: fail. handle = 0

CallFSOpen ENTRY "r5-r12" ; Never (ever) trust lowel level routines

        LDR     r6, osfind_specialptr
       
        LDR     fscb, fsforthisop

        BL      CheckNullName           ; Reject null names unless fscb^.nullok
        EXIT    VS                      ; Also checks fscb^ valid

        MOV     r0, r0, LSR #(8-2)      ; 0 -> 0, &C0 -> 3. Get RC and shift
        SUB     r0, r0, #1              ; Open mode in 0..2 now
        MOV     r2, r3                  ; Put handle where File System expects

        LDRB    r14, [r6]               ; Convert zero length special fields
        CMP     r14, #0                 ; to zero for filing system
        MOVEQ   r6, #0

; Enter Filing System with :
;    r0 =  file open mode 0..2 (old) or 3 (new)
;    r1 -> filename
;    r2 = FileSwitch handle for this proto-stream
;    r6 -> special field (if present) or 0
;   r12 -> module workspace

        TEQ     r0, #fsopen_CreateUpdate
        BNE     %FT10

        Push    "r0-r12"                ; Protect myself from idiots
        LDR     r8, [fscb, #fscb_info]  ; Filing system info word
        ORR     r9, r0, #&100           ; fsopen operation :OR: a bit(100..102)
        MOV     r0, #UpCall_ModifyingFile
  [ debugosfind
  DREG r9, "UpCalling from FileSwitch: r9 = ",cc
  DREG r8, ", r8 = "
  ]
        SWI     XOS_UpCall
        Pull    "r0-r12"
10

 [ debugosfind
 DREG r0,"FSOpen: rc ",cc
 DREG r2,", FileSwitch handle ",cc
 DSTRING r6,", special ",cc
 DSTRING r1,", filename "
 ]
        MOV     r8, #fscb_open
        BL      CallFSEntryChecked

 [ debugosfind
 BVS %FT90
 DREG r1,"FSOpen: handle ",cc
 TEQ r1,#0
 BEQ %FT42
 DREG r2,", buffer size to use ",cc
 DREG r3,", file extent is ",cc
 DREG r4,", allocated space is ",cc
 AND r14,r0,#fsopen_DeviceIdentity
 DREG r14,", fs/dev ",cc
 STRIM ", attr "
 TST r0,#fsopen_WritePermission
 SWIEQ XOS_WriteI+"w"
 SWINE XOS_WriteI+"W"
 TST r0,#fsopen_ReadPermission
 SWIEQ XOS_WriteI+"r"
 SWINE XOS_WriteI+"R"
 TST r0,#fsopen_IsDirectory
 SWIEQ XOS_WriteI+"d"
 SWINE XOS_WriteI+"D"
 TST r0,#fsopen_UnbufferedGBPB
 SWIEQ XOS_WriteI+"g"
 SWINE XOS_WriteI+"G"
42
 SWI XOS_NewLine
 EXIT
90
 DLINE "Error in FSOpen"
 ]
        ADDVS   fp, sp, #4*(11-5)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError
        EXIT

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Some more macros to stop nasty reentrancy problems

        MACRO
        MakeCritical
        LDR     r14, scb_status
        ORR     r14, r14, #scb_critical
        STR     r14, scb_status
        MEND

        MACRO
        ClearCritical
        LDR     r14, scb_status
        BIC     r14, r14, #scb_critical
        STR     r14, scb_status
        MEND

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSBGet
; ==========
;
; Get a byte from an unbuffered stream

; In    scb^ valid

; Out   VC: ok, r0 = char and flags as set by Filing System
;       VS: fail

CallFSBGet_Guts ENTRY "r1-r12" ; Never (ever) trust lower level routines

        MOV     r8, #fscb_get
        BL      CallFSCommon

        ADDVS   fp, sp, #4*(11-1)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError
        EXIT

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

CallFSBGet ENTRY

        MakeCritical
        BL      CallFSBGet_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSGetBuffer
; ===============
;
; Ask Filing System to get me a new buffer of data

; In    scb^, bufmask and bcb^ valid

; Out   VC: ok
;       VS: fail

CallFSGetBuffer_Guts ENTRY "r0-r12" ; Never (ever) trust lower level routines

        ADR     r2, bcb_bufferdata      ; Memory to be loaded
        ADD     r3, bufmask, #1         ; Correct size to use
        LDR     r4, bcb_bufferbase

 [ debuglowxfer
 DREG r2,"CallFSGetBuffer: to ",cc
 DREG r3,", ",cc
 DREG r4," bytes <- from PTR# "
 ]

10 ; Entered from below too

; Enter Filing System with :
;    r1 = Filing System handle
;    r2 = memory address
;    r3 = number of bytes to read (guaranteed to be a multiple of bufsize)
;    r4 = file address
;   r12 -> module workspace

        MOV     r8, #fscb_get
        BL      CallFSCommon

 [ debugosgbpbirq
 Push "r0, lr"
 MOV r0, psr
 TST r0, #I_bit
 MOVEQ r0, #"1"
 MOVNE r0, #"a"
 SWI XOS_WriteC
 Pull "r0, lr"
 ]
        EXIT    VC

        ADD     fp, sp, #4*(11-0)
        LDMIA   fp, {fp, wp}
        BL      CopyError
        EXIT

; .............................................................................
;
; CallFSGetData
; =============
;
; Ask Filing System to get data for the punter

; In    scb^ valid
;       r2 -> destination
;       r3 = number of bytes
;       r4 = file address

; Out   VC: ok
;       VS: fail

CallFSGetData_Guts ALTENTRY

 [ debuglowxfer
 DREG r2,"CallFSGetData: to ",cc
 DREG r3,", ",cc
 DREG r4," bytes <- from PTR# "
 ]
        B       %BT10

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

CallFSGetBuffer ENTRY

        MakeCritical
        BL      CallFSGetBuffer_Guts
        ClearCritical
 [ debugosgbpbirq
 Push "r0, lr"
 MOV r0, psr
 TST r0, #I_bit
 MOVEQ r0, #"2"
 MOVNE r0, #"b"
 SWI XOS_WriteC
 Pull "r0, lr"
 ]
        EXIT

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

CallFSGetData ENTRY

        MakeCritical
        BL      CallFSGetData_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSBPut
; ==========
;
; Put a byte to an unbuffered stream

; In    r0b = byte to put, scb^ valid

; Out   VC: ok
;       VS: fail

CallFSBPut_Guts ENTRY "r0-r12" ; Never (ever) trust lower level routines

        AND     r0, r0, #&FF            ; Just in case people don't like it
        MOV     r2, #-1                 ; Doing BPut not Multiple
        MOV     r8, #fscb_put
        BL      CallFSCommon

        ADDVS   fp, sp, #4*(11-0)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError
        EXIT

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

CallFSBPut ENTRY

        MakeCritical
        BL      CallFSBPut_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSPutBuffer
; ===============
;
; Give Filing System a buffer of data

; May need to write under mask for Net W only files - to be sussed at leisure !

; In    scb^, bufmask and bcb^ valid

; Out   VC: ok
;       VS: fail

CallFSPutBuffer_Guts ENTRY "r0-r12" ; Never (ever) trust lower level routines

        ADR     r2, bcb_bufferdata      ; Memory to be loaded
        ADD     r3, bufmask, #1         ; Correct size to use
        LDR     r4, bcb_bufferbase

 [ debuglowxfer
 DREG r2,"CallFSPutBuffer: from ",cc
 DREG r3,", ",cc
 DREG r4," bytes -> to PTR# "
 ]

10 ; Entered from below too

; Enter Filing System with :
;    r1 = Filing System handle
;    r2 = memory address
;    r3 = number of bytes to read (guaranteed to be a multiple of bufsize)
;    r4 = file address
;   r12 -> module workspace

        MOV     r8, #fscb_put
        BL      CallFSCommon
        EXIT    VC

        ADD     fp, sp, #4*(11-0)
        LDMIA   fp, {fp, wp}
        BL      CopyError
        EXIT

; .............................................................................
;
; CallFSPutData
; =============
;
; Ask Filing System to save data for the punter

; In    scb^ valid
;       r2 -> source
;       r3 = number of bytes
;       r4 = file address

; Out   VC: ok
;       VS: fail

CallFSPutData_Guts ALTENTRY

 [ debuglowxfer
 DREG r2,"CallFSPutData: from ",cc
 DREG r3,", ",cc
 DREG r4," bytes -> to PTR# "
 ]
        B       %BT10

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

CallFSPutBuffer ENTRY

        MakeCritical
        BL      CallFSPutBuffer_Guts
        ClearCritical
        EXIT    VC

        LDR     r14, scb_status         ; Sorry, we botched it
        ORR     r14, r14, #scb_datalost
        STR     r14, scb_status
        EXIT

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

CallFSPutData ENTRY

        MakeCritical
        BL      CallFSPutData_Guts
        ClearCritical
        EXIT    VC

        LDR     r14, scb_status         ; Sorry, we botched it
        ORR     r14, r14, #scb_datalost
        STR     r14, scb_status
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSMultiple
; ==============
;
; Get many / Put many bytes from / to an fast unbuffered stream

; In    scb^ valid
;       r0 = GBPB op
;       gbpb block = r2-r4 data

; Out   VC: ok, gbpb block updated here !!!
;       VS: fail

CallFSMultiple_Guts ENTRY "r0-r12" ; Never (ever) trust lower level routines

        ADR     r14, gbpb_memadr
        LDMIA   r14, {memadr, nbytes, fileptr}

 [ debuglowxfer
 DREG r2,"CallFSMultiple: from ",cc
 DREG r3,", ",cc
 DREG r4," bytes -> to PTR# "
 ]
        MOV     r8, #fscb_gbpb
        BL      CallFSCommon

        ADD     fp, sp, #4*(11-0)       ; Restore fp, wp in all cases
        LDMIA   fp, {fp, wp}

        ADRVC   r14, gbpb_memadr
        STMVCIA r14, {memadr, nbytes, fileptr}

        BLVS    CopyError
        EXIT

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

CallFSMultiple ENTRY

        MakeCritical
        BL      CallFSMultiple_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSArgs
; ==========
;
; Lots of miscellaneous file control which require open streams

; In    r0 reason code, scb^ valid, various parms

; Out   VC: ok, r2 may be modified according to r0
;       VS: fail

CallFSArgs_Guts ENTRY "r0-r1, r3-r12" ; Never (ever) trust lower level routines

 [ debugosargs
 DREG r0,"FSArgs: rc ",cc
 DREG r2,", r2 ",cc
 DREG r3,", r3 ",cc
 ]
        MOV     r8, #fscb_args
        BL      CallFSCommon
 [ debugosargs
 DREG r2,"FSArgs: r2 := "
 ]

 [ debugosargs
 EXIT VC
 DLINE "Error in FSArgs"
 ]
        ADDVS   fp, sp, #4*(11-3+1-0+1)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError
        EXIT

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

CallFSArgs ENTRY

        MakeCritical
        BL      CallFSArgs_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSClose
; ===========
;
; Close a given file on the Filing System

; In    scb^ valid
;       r2, r3 are load,exec pair to DateStamp stream with
;       Both zero -> don't set DateStamp

; Out   VC: ok
;       VS: fail

CallFSClose_Guts ENTRY "r0-r12" ; Never (ever) trust lower level routines

 [ debugosfind
 WRLN "FSClose called"
 ]
        LDR     r14, scb_status         ; Only tell punter about modified
        TST     r14, #scb_modified      ; files that are being closed
        BEQ     %FT10

        Push    "r0-r12"                ; Protect myself from idiots
        LDR     r8, [fscb, #fscb_info]  ; Filing system info word
        MOV     r9, #&100               ; fsclose operation (103)
        ADD     r9, r9, #&003
        MOV     r0, #UpCall_ModifyingFile
  [ debugosfind
  DREG r9, "UpCalling from FileSwitch: r9 = ",cc
  DREG r8, ", r8 = "
  ]
        SWI     XOS_UpCall
        Pull    "r0-r12"
10

        MOV     r8, #fscb_close
        BL      CallFSCommon

 [ debugosfind
 EXIT VC
 DLINE "Error in FSClose"
 ]
        ADDVS   fp, sp, #4*(11-0)
        LDMVSIA fp, {fp, wp}
        BLVS    CopyError               ; Deallocation done always by hilevel
        EXIT

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

CallFSClose ENTRY

        MakeCritical
        BL      CallFSClose_Guts
        ClearCritical
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CallFSCommon
; ============
;
; For CallFSxxx that pass Filing System handles to the underlying Filing System

; In    scb^ to be checked, r8 = routine offset in scb^.fscb to call

; Out   r1, fscb and r12 definitely trashed

CallFSCommon ROUT

 [ False ; Who ever gets this far if scb invalid ???
        TEQ     scb, #Nowt              ; Paranoia !
        MOVEQS  pc, lr                  ; Skip op if no stream (VClear)
 ]

 assert scb_fscb = scb_fshandle + 4
        ADR     r1, scb_fshandle
        LDMIA   r1, {r1, fscb}          ; Get real FS handle and fscb^

; .............................................................................
;
; CallFSWithCheck
; ===============
;
; For CallFSxxx that don't use streams, eg. File, Open, Func

; In    fscb^ to be checked, r8 = routine offset in fscb to call

CallFSWithCheck

        TEQ     fscb, #Nowt                     ; Got a valid Filing System ?
        BEQ     Lowlevel_NoFilingSystemsActive  ; Nope !

; ............................................................................
;
; CallFSEntryChecked
; ==================
;
; For CallFSxxx that have already validated fscb^. Sets up r12 for modules too

; No checking of FS entries is needed as all routines have a default

; In    fscb^ valid, r8 = routine offset in fscb to be called

; Out   r12 definitely trashed, and as many others as the Filing System saw fit

CallFSEntryChecked

        MOV     r12, sp, LSR #20                ; Stack base on 1M boundary
        SUB     r12, sp, r12, LSL #20           ; Amount of stack left
        CMP     r12, #&400                      ; Must have at least 1K left
        BMI     Lowlevel_NotEnoughStackForFSEntry ; VClear in PSR

        LDR     r12, [fscb, #fscb_privwordptr]  ; Get their private word^
        BIC     lr, lr, #V_bit :OR: I_bit       ; VClear, IClear in lr

 [ anyfiledebug :LAND: False
 DREG sp, "sp on entry to fs = "
 ]
        LDR     pc, [fscb, r8]                  ; So go for it !

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; CheckNullName
; =============
;
; Common routine for CallFSFile, CallFSOpen and CallFSFunc to check null names

; In    r1 -> filename to pass to Filing System
;       fscb^ valid

; Out   VC: ok
;       VS: naff name (null)

CheckNullName ENTRY

        CMP     fscb, #Nowt             ; Must do a quick check here to
        BEQ     %FT90                   ; prevent ye olde address extinctions

        LDRB    r14, [r1]               ; Just look at first char of name !
        CMP     r14, #0                 ; Is it a null string ? - VClear
        LDREQ   r14, [fscb, #fscb_info] ; If so, does the Filing System
        TSTEQ   r14, #fsinfo_nullnameok ; support null filenames ?
        BLEQ    SetMagicBadFileName     ; Error if not. VSet too
        EXIT

90      BL      SetErrorNoSelectedFilingSystem
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

        LTORG


; ++++ Keep all common/changeable stuff together away from sensitive ADRs +++++

 [ anyfiledebug
        InsertDebugRoutines
 ]

 [ debugstream
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    scb, status, fileptr, extent, bufmask ok

DebugStreamInfo ENTRY "r0, bcb"

 DREG scb,"Stream info: scb ",cc
 DLINE " status ",cc
 TST status, #scb_unallocated
 SWIEQ XOS_WriteI+"u"
 SWINE XOS_WriteI+"U"
 SWINE XOS_NewLine
 EXITS NE ; No more info
 TST status, #scb_write
 SWIEQ XOS_WriteI+"w"
 SWINE XOS_WriteI+"W"
 TST status, #scb_read
 SWIEQ XOS_WriteI+"r"
 SWINE XOS_WriteI+"R"
 TST status, #scb_directory
 SWIEQ XOS_WriteI+"d"
 SWINE XOS_WriteI+"D"
 TST status, #scb_modified
 SWIEQ XOS_WriteI+"m"
 SWINE XOS_WriteI+"M"
 TST status, #scb_interactive
 SWIEQ XOS_WriteI+"i"
 SWINE XOS_WriteI+"I"
 TST status, #scb_EOF_pending
 SWIEQ XOS_WriteI+"e"
 SWINE XOS_WriteI+"E"
 TST status, #scb_critical
 SWIEQ XOS_WriteI+"c"
 SWINE XOS_WriteI+"C"
 TST status, #scb_datalost
 SWIEQ XOS_WriteI+"l"
 SWINE XOS_WriteI+"L"
 TST status, #scb_unbuffered
 BEQ %FT10
 TST status, #scb_unbuffgbpb
 SWIEQ XOS_WriteI+"g"
 SWINE XOS_WriteI+"G"
 DLINE " unbuffered "
 EXITS

10 ; buffered stream
 DREG fileptr," fileptr ",cc
 DREG extent," extent ",cc
 LDR r14,scb_allocsize
 DREG r14,", size "
 LDR bcb,scb_bcb ; may not have been loaded
 CMP bcb, #Nowt; Got first ptr
 ADREQ r0,%FT49
 SWIEQ XOS_Write0
 BEQ %FT40
 LDR r0, bcb_bufferbase
 DREG r0,"Buffer on stream at ",cc
 LDRB r0, bcb_status
 TST r0, #bcb_modified
 SWIEQ XOS_WriteI+"m"
 SWINE XOS_WriteI+"M"
 TST r0, #bcb_valid
 SWIEQ XOS_WriteI+"v"
 SWINE XOS_WriteI+"V"
40
 SWI XOS_NewLine
 EXITS

49
 DCB "No buffer on stream",0
 ALIGN
 ]

        LTORG

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; This is the end, my friend

        GBLS    whattodonow

 [ :LNOT: AssemblingArthur
whattodonow SETS " LNK FSShared"
 |
FileSwitch_ModuleEnd

        DCD     0               ; Next module is the end of module chain now

NextModuleInImage               ; Sam's BasProg will patch this as appropriate

whattodonow SETS " END"
 ]

$whattodonow
