; Copyright 1999 Pace Micro Technology plc
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; Title:   s.ddeutils
; Purpose: Assembler source for DDEUtils module
; Author:
; History: Used to live on Aquarius SrcFiler
;
                GET     VersionASM

                ^    0,r12
chain           #     4
fname_buffer    #     4
cli_buffer      #     4
cli_size        #     4
receiver_id     #     4
workspace_end   #     0

; JRF: Debugging
                GBLL    DEBUG ; turn this off for ROMing
DEBUG           SETL    {FALSE}

; JRF: Don't make it work on pre-RO4
                GBLL    RO4Only
RO4Only         SETL    {FALSE}

; JRF: Switch added to allow longer filenames to be 'handled'. This may
;      not necessarily fix all the problems that DDEUtils has with them,
;      but will alleviate the majority. Problems may still lie in the
;      throwback handler.
                GBLL    LongFilenames
LongFilenames   SETL    {TRUE}

; JRF: Set this to the length of filenames that is the maximum you wish
;      to handle
 [ LongFilenames
FilenameLength    EQU    1024
 |
FilenameLength    EQU     256
 ]

; JRF: Turn this on and all prefixes passed will be canonicalised for you
                  GBLL    CanonicalisePath
CanonicalisePath  SETL    {TRUE}

; JRF: We should /really/ be checking the strings fit our CL buffer!
                  GBLL    CheckBufferSize
CheckBufferSize   SETL    {TRUE}

                        GBLL   AllowDirectoryChanging
AllowDirectoryChanging  SETL   {TRUE}

; JRF: Allow a lot of the later image file extensions
;      This has NOT been tested and it's a little too late to add them
                        GBLL   HandleImages
HandleImages            SETL   {FALSE}

os_writec       EQU     0
os_writes       EQU     1
os_write0       EQU     2
os_newline      EQU     3

xos_module      EQU     &2001e
xos_claim       EQU     &2001f
xos_release     EQU     &20020
xos_fscontrol   EQU     &20029
xos_file        EQU     &20008
xos_changeenvironment EQU &20040
xos_readsysinfo EQU     &20058
xos_enteros     EQU     &20016
os_exit         EQU     &11
os_generateerror EQU    &2b
xwimp_readsysinfo EQU   &600f2
xwimp_sendmessage EQU   &600e7
xmessagetrans_errorlookup EQU &61506
xos_setvarval   EQU     &20024
xos_word        EQU     &20007
os_converthex8  EQU     &d4

zp_wimpdomain   EQU     &ff8

n_module_claim  EQU     6
n_module_free   EQU     7

n_filev         EQU     &08
n_gbpbv         EQU     &0c
n_findv         EQU     &0d
n_fscontrolv    EQU     &0f

n_error_h       EQU     6
n_exit_h        EQU     11

ddeutils_swibase             EQU    &42580
xddeutils_swibase            EQU    &62580
ddeutils_prefix              EQU    0               ; + ddeutils_swibase
ddeutils_setclsize           EQU    1
ddeutils_setcl               EQU    2
ddeutils_getclsize           EQU    3
ddeutils_getcl               EQU    4
ddeutils_throwbackregister   EQU    5
ddeutils_throwbackunregister EQU    6
ddeutils_throwbackstart      EQU    7
ddeutils_throwbacksend       EQU    8
ddeutils_throwbackend        EQU    9
ddeutils_readprefix          EQU    10

reason_processing            EQU    0
reason_errordetails          EQU    1
reason_infodetails           EQU    2

overflow        EQU     &10000000
carry           EQU     &20000000

ddeutils_errbase    EQU &20600
unk_swi_error       EQU ddeutils_errbase + 0
no_cli_buffer_error EQU ddeutils_errbase + 1
not_desktop_error   EQU ddeutils_errbase + 2
no_task_error       EQU ddeutils_errbase + 3
already_reg_error   EQU ddeutils_errbase + 4
not_reg_error       EQU ddeutils_errbase + 5
buffer_too_short    EQU ddeutils_errbase + 6

ddeutils_msgbase             EQU ddeutils_swibase
ddeutils_msgbase_h           EQU &42000
ddeutils_msgbase_l           EQU &580
msg_throwback_start          EQU 0               ; + ddeutils_msgbase
msg_throwback_processingfile EQU 1
msg_throwback_errorsin       EQU 2
msg_throwback_errordetails   EQU 3
msg_throwback_end            EQU 4
msg_throwback_infoforfile    EQU 5
msg_throwback_infodetails    EQU 6

service_reset         EQU &27
service_wimpclosedown EQU &53

o_next          EQU     &00
                ASSERT :INDEX: o_next = 0
o_wimpdomain    EQU     &04
o_prefix        EQU     &08

                IMPORT  |__RelocCode|

                AREA    |!|, CODE, READONLY

module_start    EQU     .

                DCD     0                         ; Run
                DCD     init - module_start       ; Init
                DCD     finish - module_start     ; Finish
                DCD     service - module_start    ; Service call
                DCD     title - module_start      ; Title
                DCD     help - module_start       ; Help
                DCD     cmd_table - module_start  ; *commands
                DCD     ddeutils_swibase          ; SWI Base
                DCD     do_swi - module_start     ; SWI Handler
                DCD     swi_table - module_start  ; SWI Table
                DCD     0                         ; SWI Decoder
                DCD     0                         ; Messages filename
                DCD     flags - module_start      ; Module flags


help            DCB     "DDEUtils", 9
                DCB     Module_MajorVersion, " (", Module_Date, ")", 0
        [ Module_MinorVersion <> ""
                DCB     " ", Module_MinorVersion
        |
        ]
                DCB     0

title           ; DCB     "DDEUtils", 0
swi_table       DCB     "DDEUtils", 0
                DCB     "Prefix", 0
                DCB     "SetCLSize", 0
                DCB     "SetCL", 0
                DCB     "GetCLSize", 0
                DCB     "GetCl", 0
                DCB     "ThrowbackRegister", 0
                DCB     "ThrowbackUnRegister", 0
                DCB     "ThrowbackStart", 0
                DCB     "ThrowbackSend", 0
                DCB     "ThrowbackEnd", 0
                DCB     "ReadPrefix", 0
                DCB     0

cmd_table       DCB     "Prefix", 0
                ALIGN
                DCD     prefix_cmd - module_start
                DCB     0                          ; Min. parameters
                DCB     1                          ; GSTrans map
                DCB     1                          ; Max. parameters
                DCB     0                          ; Flags
                DCD     prefix_syn - module_start  ; Syntax message
                DCD     prefix_help - module_start ; Help message
                DCD     0                          ; End of command table

prefix_help     DCB     "*Prefix selects a directory as the current directory unique to the currently executing task. *Prefix with no arguments sets the current directory back to the systemwide default (as set with *Dir).", 13

prefix_syn      DCB     "Syntax: *Prefix [<directory>]", 0
                ALIGN

flags           DCD     1                          ; 32-bit compatible

;Ursula format
;
                ASSERT  service_reset < service_wimpclosedown
;
UServTab
                DCD     0                              ;flags
                DCD     UService - module_start
                DCD     service_reset
                DCD     service_wimpclosedown
                DCD     0                              ;terminator
                DCD     UServTab - module_start        ;anchor
service
 [ RO4Only
                MOV     r0,r0                          ;magic instruction
                TEQNE   r1,#service_reset
                TEQNE   r1,#service_wimpclosedown
                MOVNE   pc,lr
                B       service
 |
                MOV     r0,r0                          ;magic instruction
                TEQ     r1, #service_reset
                TEQNE   r1, #service_wimpclosedown
                MOVNE   pc,lr
 ]
UService
                TEQ     r1,#service_reset
                LDREQ   r12,[r12]
                BEQ     reset
                CMP     r0, #0
                MOVNE   pc, lr
                STMFD   sp!, {r0, lr}
                MOV     r0, #0
                SWI     xddeutils_swibase + ddeutils_prefix
                LDMFD   sp!, {r0, pc}

; Really should clear the chain here...
reset
                STMFD   sp!, {r0, lr}
                BL      claimvectors
                LDMFD   sp!, {r0, pc}

filetype_fd3    DCB     "File$Type_FD3", 0
debimage        DCB     "DebImage", 0
runtype_fd3     DCB     "Alias$@RunType_FD3", 0
debugaif        DCB     "DebugAIF %*0", 0
loadtype_fd3    DCB     "Alias$@LoadType_FD3", 0
loadaif         DCB     "Load %0 8000", 0
filetype_fe1    DCB     "File$Type_FE1", 0
makefile        DCB     "Makefile", 0
runtype_fe1     DCB     "Alias$@RunType_FE1", 0
make            DCB     "DDE:!Make %*0", 0
prefix_dir      DCB     "Prefix$Dir", 0
                ALIGN
n_vartype_code  EQU     16

init            STMFD   sp!, {r7, r8, r9, r10, r11, lr}
  [ RO4Only
                MOV     r0,#9
                MOV     r1,#0
                SWI     xos_readsysinfo
                MOVVS   pc,#0
  ]
                ADR     r0, filetype_fd3
                ADR     r1, debimage
                BL      initvar
                ADR     r0, runtype_fd3
                ADR     r1, debugaif
                BL      initvar
                ADR     r0, loadtype_fd3
                ADR     r1, loadaif
                BL      initvar
                ADR     r0, filetype_fe1
                ADR     r1, makefile
                BL      initvar
                ADR     r0, runtype_fe1
                ADR     r1, make
                BL      initvar

                MOV     r0, #n_module_claim
                MOV     r3, #:INDEX: workspace_end
                SWI     xos_module            ; claim our module workspace
                STRVC   r2,[r12]
                MOVVC   r12,r2

                MOVVC   r0,#0
                STRVC   r0, chain
                STRVC   r0, cli_buffer
                STRVC   r0, cli_size
                STRVC   r0, receiver_id

                BLVC    claimvectors
;                MOVVC   r2, r12
                MOVVC   r0, #n_module_claim
                MOVVC   r3, #FilenameLength * 2
                SWIVC   xos_module
                STRVC   r2, fname_buffer
                ADRVC   r0, prefix_dir
                ADRVC   r1, prefix_dir_code
                MOVVC   r2, #prefix_dir_code_end - prefix_dir_code
                MOVVC   r3, #0
                MOVVC   r4, #n_vartype_code
                SWIVC   xos_setvarval
                LDMFD   sp!, {r7, r8, r9, r10, r11, lr}
xferv           TEQ     pc, pc
                MOVEQ   pc, lr
                ORRVS   lr, lr, #overflow
                MOVS    pc, lr

xfervc          TEQ     pc, pc
                MOVEQ   pc, lr
                BIC     lr, lr, #carry
                ORRCS   lr, lr, #carry
                ORRVS   lr, lr, #overflow
                MOVS    pc, lr

claimvectors
                STMFD   sp!, {r2,r3,lr}
                MOV     r2,r12
                MOV     r0, #n_filev
                TEQ     pc, pc
                ADREQL  r1, file_handler_32
                ADRNEL  r1, file_handler_26
                SWI     xos_claim
                MOVVS   r3, r0
                BVS     %FT01
                MOV     r0, #n_gbpbv
                TEQ     pc, pc
                ADREQL  r1, gbpb_handler_32
                ADRNEL  r1, gbpb_handler_26
                SWI     xos_claim
                MOVVS   r3, r0
                BVS     %FT02
                MOV     r0, #n_findv
                TEQ     pc, pc
                ADREQL  r1, find_handler_32
                ADRNEL  r1, find_handler_26
                SWI     xos_claim
                MOVVS   r3, r0
                BVS     %FT03
                MOV     r0, #n_fscontrolv
                TEQ     pc, pc
                ADREQL  r1, fscontrol_handler_32
                ADRNEL  r1, fscontrol_handler_26
                SWI     xos_claim
                MOVVS   r3, r0
                BVS     %FT04
                LDMFD   sp!, {r2,r3,pc}

; these are the failure cases
04
                MOV     r0, #n_findv
                TEQ     pc, pc
                ADREQL  r1, find_handler_32
                ADRNEL  r1, find_handler_26
                SWI     xos_release
03
                MOV     r0, #n_gbpbv
                TEQ     pc, pc
                ADREQL  r1, gbpb_handler_32
                ADRNEL  r1, gbpb_handler_26
                SWI     xos_release
02
                MOV     r0, #n_filev
                TEQ     pc, pc
                ADREQL  r1, file_handler_32
                ADRNEL  r1, file_handler_26
                SWI     xos_release
01
                LDMFD   sp!, {r2,r3,lr}
                MOV     r0,r3
                TEQ     pc, pc
                ORRNES  pc,lr,#overflow
                MSR     CPSR_f, #overflow
                MOV     pc, lr



prefix_dir_code B       dir_code_write
; prefix_dir read code
; <= r0-> value
                STMFD   sp!, {lr}
                MOV     r0,#0
                SWI     xddeutils_swibase + ddeutils_readprefix
                MOVVS   r0,#0
                CMP     r0,#0     ; was it invalid ?
                MOVEQ   r0,#0
                MOVEQ   r2,#0
                LDMEQFD sp!, {pc} ; yes
; now we need to find the length of the directory
                MOV     r1,r0
01
                LDRB    r2,[r1],#1
                CMP     r2,#31
                BGT     %BT01
                SUB     r2,r1,r0
                SUB     r2,r2,#1 ; and we increased over the terminator
                LDMFD   sp!, {pc}

dir_code_write  STMFD   sp!, {r0, lr}
                MOV     r0, r1
                SWI     xddeutils_swibase + ddeutils_prefix
                ADDS    r0, r0, #0 ; clear V
                LDMFD   sp!, {r0, pc}
prefix_dir_code_end

finish          MOV     r6, lr
                LDR     r12, [r12]
                MOV     r0, #n_module_free
                LDR     r2, fname_buffer
                CMP     r2, #0
                SWINE   xos_module

                LDR     r2, cli_buffer
                CMP     r2, #0
                SWINE   xos_module

                LDR     r2, chain
                MOV     r1, #0
                STR     r1, chain
                STR     r1, fname_buffer
                STR     r1, cli_buffer
                STR     r1, cli_size
                STR     r1, receiver_id

finish1         CMP     r2, #0
                BEQ     finish2
                LDR     r5, [r2,#o_next]
                MOV     r0, #n_module_free
                SWI     xos_module
                MOV     r2, r5
                BVC     finish1

finish2         MOV     r2, r12
                MOV     r0, #n_filev
                TEQ     pc, pc
                ADREQL  r1, file_handler_32
                ADRNEL  r1, file_handler_26
                SWI     xos_release
                MOV     r0, #n_gbpbv
                TEQ     pc, pc
                ADREQ   r1, gbpb_handler_32
                ADRNE   r1, gbpb_handler_26
                SWI     xos_release
                MOV     r0, #n_findv
                TEQ     pc, pc
                ADREQ   r1, find_handler_32
                ADRNE   r1, find_handler_26
                SWI     xos_release
                MOV     r0, #n_fscontrolv
                TEQ     pc, pc
                ADREQL  r1, fscontrol_handler_32
                ADRNEL  r1, fscontrol_handler_26
                SWI     xos_release
                MOV     r2, r12               ; free our main workspace
                MOV     r0, #n_module_free
                SWI     xos_module
                MOVS    pc, r6

; Input: R0: task handle or 0 for current task
; Output: R0: pointer to prefix dir for that task or 0 if none.
doswi_readprefix
		MOVS	r11, r0, lsl #16
		LDREQ	r11, [r11, #zp_wimpdomain]
		MOVEQ	r11, r11, ror #16
		MOV	r0, #0
		STMFD	sp!, {r1, r2, r3, r8, lr}
		LDR     r8, chain
doswi_readprefix1
		CMP	r8, #0
		LDMEQFD	sp!, {r1, r2, r3, r8, pc}
		LDR	r2, [r8,#o_next]
		LDR	r1, [r8, #o_wimpdomain]
		CMP	r11, r1, ror #16
		ADDEQ	r0, r8, #o_prefix
		LDMEQFD	sp!, {r1, r2, r3, r8, pc}
		MOV	r8, r2
		B	doswi_readprefix1

do_swi
   STR     lr,[sp,#-4]!
   LDR     r12,[r12] ; read workspace pointer
   BL      do_swi_orig
   TEQ     pc, pc
   LDREQ   pc,[sp],#4 ; 32-bit return corrupting flags
   LDMVCFD sp!,{pc}^  ; 26-bit return without error
   LDR     lr,[sp],#4 ; 26-bit return with error
   ORRS    pc,lr,#overflow

do_swi_orig
   CMP     r11,#11
   ADDLT   pc,pc,r11,LSL #2
   B       module_swierror
; ***** SWI jump table
   B       doswi_prefix
   B       doswi_setclsize
   B       doswi_setcl
   B       doswi_getclsize
   B       doswi_getcl
   B       doswi_throwbackregister
   B       doswi_throwbackunregister
   B       doswi_throwbackstart
   B       doswi_throwbacksend
   B       doswi_throwbackend
   B       doswi_readprefix

module_swierror
   STMFD   sp!,{r1-r4,lr}
   ADR     r0,msg_swierror
   MOV     r1,#0
   MOV     r2,#0
   ADRL    r4,title
   SWI     xmessagetrans_errorlookup
   LDMFD   sp!,{r1-r4,pc}

msg_swierror
   DCD     &1E6
   DCB     "BadSWI",0
   ALIGN


doswi_prefix
                MOV     r10, r0
                STMFD   sp!, {r1, r2, r3, r8, lr}
                TEQ     r0,#0
                BEQ     %FT01       ; they gave 0
                LDRB    r0,[r10]
                CMP     r0,#32
                BLO     %FT01       ; it was a null command

  [ CanonicalisePath
                STMFD   sp!, { r4, r5 }
                MOV     r0,#37
                MOV     r1,r10
                LDR     r2,fname_buffer
                MOV     r3,#0 ; no path var
                MOV     r4,#0 ; 0
                MOV     r5,#FilenameLength
                SWI     xos_fscontrol ; canonicalise it!
                LDRVC   r10,fname_buffer
                LDMFD   sp!, { r4, r5 }
01
  ]

  [ DEBUG
                STMFD   sp!,{r0,r2}            ; Stack registers
                SWI     os_writes
                DCB     4, "attempting to set prefix: ", 0
                MOV     r2, r10
01              LDRB    r0, [r2], #1
                CMP     r0, #' '+1
                SWICS   os_writec
                CMP     r0, #' '+1
                BCS     %BT01
                SWI     os_newline
                LDMFD   sp!,{r0,r2}            ; Unstack registers
  ]

                ASSERT  ddeutils_prefix = 0
                LDR     r11, [r11, #zp_wimpdomain]
                ADR     r8, chain
                LDR     r2, chain
do_swi1         TEQ     r2, #0
                BEQ     do_swi2
                LDR     r1, [r2, #o_wimpdomain]
                TEQ     r1, r11
                ADDNE   r8, r2, #o_next       ; r8 = last next pointer addr
                LDRNE   r2, [r2, #o_next]     ; r2 = this pointer
                BNE     do_swi1
                LDR     r3, [r2, #o_next]     ; read this next
                STR     r3, [r8]              ; store as last next
                MOV     r0, #n_module_free
                SWI     xos_module
                MOVVC   r2,r3
                BVC     do_swi1
                LDMFD   sp!, {r1, r2, r3, r8, pc} ; V set

do_swi2         ADDS    r0, r10, #0
                LDMEQFD sp!, {r1, r2, r3, r8, pc} ; V clear
                LDRB    r1, [r0]
                CMP     r1, #' ' + 1
                LDMLOFD sp!, {r1, r2, r3, r8, pc} ; V clear
                MOV     r3, #0
do_swi3         LDRB    r1, [r0], #1
                ADD     r3, r3, #1
                CMP     r1, #' ' + 1
                BCS     do_swi3
                ADD     r3, r3, #o_prefix
                MOV     r0, #n_module_claim
                SWI     xos_module
                LDMVSFD sp!, {r1, r2, r3, r8, pc} ; V set
                STR     r2, [r8]      ; store over last next pointer (!)
                MOV     r0, #0
                STR     r0, [r2], #4  ; next
                STR     r11, [r2], #4 ; domain
                                      ; prefix follows
                MOV     r0, r10
do_swi4         LDRB    r1, [r10], #1
                STRB    r1, [r2], #1
                CMP     r1, #' ' + 1
                MOVHS   r3, r1
                BHS     do_swi4
                CMP     r3, #'.'
                STREQB  r1, [r2, #-2]
                MOV     r3,#0
                STRB    r3, [r2, #-1] ; store it as terminated
                LDMFD   sp!, {r1, r2, r3, r8, pc} ; V clear

strip_hats      SUBS    r0, r0, #0 ; set carry
                B       strip_hats0

; Entry: VC
;        R1  = Filename
;        R11 = Filename buffer
;        R8 = Task block
; Exit:  R11, LR = ???
;        R1  = Preserved
;        R11 = Preserved
;        R8 = New Filename (R1 or R11 on entry)
;        CS => No prefix added (filename contained root char)
add_prefix      SUBS    r0, r0, #0      ; set C
add_prefix0     STMFD   sp!, {r0, r1, r2, r3, r4, r5, lr}       ; r5 is placeholder
                MRS     lr, CPSR        ; NOP on old machine
                STR     lr, [sp, #20]
  [ DEBUG
                STMFD   sp!, {r0-r2}
                SWI     os_writes
                DCB     "Before add_prefix: ", 0
                MOV     r2, r1
write_name0     LDRB    r0, [r2], #1
                CMP     r0, #' '+1
                SWICS   os_writec
                CMP     r0, #' '+1
                BCS     write_name0
                SWI     os_newline
                LDMFD   sp!,{r0-r2}
  ]
                MOV     r2, r1
add_prefix1     LDRB    r0, [r2], #1
                CMP     r0, #':'
                CMPNE   r0, #'$'
                CMPNE   r0, #'&'
                CMPNE   r0, #'%'
                CMPNE   r0, #'<'
                MOVEQ   r8, r1
                BEQ     add_prefix5
                CMP     r0, #' ' + 1
                BCS     add_prefix1
                MOV     r2, r1
                LDRB    r0, [r2]
                CMP     r0, #'@'
                BNE     add_prefix2
                LDRB    r0, [r2, #1]!
                CMP     r0, #'.'
                ADDEQ   r2, r2, #1
add_prefix2     MOV     r3, r11
                ADD     r8, r8, #o_prefix
add_prefix3     LDRB    r0, [r8], #1
                CMP     r0, #' ' + 1
                STRCSB  r0, [r3], #1
                BCS     add_prefix3
                LDRB    r0, [r2]
                CMP     r0, #' ' + 1
                MOVCS   r0, #'.'
                STRCSB  r0, [r3], #1
add_prefix4     LDRB    r0, [r2], #1
                CMP     r0, #' ' + 1
                MOVCC   r0, #0
                STRB    r0, [r3], #1
                BCS     add_prefix4
                MOV     r8, r11

  [ DEBUG
                SWI     os_writes
                DCB     4, "After add_prefix: ", 0
                MOV     r2, r8
01              LDRB    r0, [r2], #1
                CMP     r0, #' '+1
                SWICS   os_writec
                CMP     r0, #' '+1
                BCS     %BT01
                SWI     os_newline
  ]
                LDMFD   sp, {r0, r1, r2, r3, r4, lr}
                BIC     lr, lr, #carry
                STR     lr, [sp, #20]
                B       add_prefix5

strip_hats0     STMFD   sp!, {r0, r1, r2, r3, r4, r5, lr}
                MRS     lr, CPSR        ; NOP on old machine
                STR     lr, [sp, #20]
add_prefix5     MOV     r2, r8
                MOV     r1, r11
                MOV     r3, r1
                MOV     r4, r3
add_prefix6     LDRB    r0, [r2], #1
                STRB    r0, [r1], #1
                CMP     r0, #'.'
                LDREQB  lr, [r2]
                CMPEQ   lr, #'^'
                BNE     add_prefix9
                LDRB    lr, [r3]
                CMP     lr, #'$'
                CMPNE   lr, #'@'
                CMPNE   lr, #'%'
                CMPNE   lr, #'&'
                CMPNE   lr, #'<'
                CMPNE   lr, #'^'
                MOVEQ   r0, #'!'        ; R0 > ' ' and != '.'
                BEQ     add_prefix9
add_prefix7     LDRB    lr, [r2], #1
                CMP     lr, #'.'
                CMPNE   lr, #' '
                BHI     add_prefix7
                SUB     r2, r2, #1
                CMP     r3, r4
                STREQB  lr, [r3]
add_prefix8     LDRB    lr, [r2], #1
                STRNEB  lr, [r3], #1
                CMP     lr, #' '
                BHI     add_prefix8
                MOV     r8, r11
                LDR     r2, [sp, #20]
                BIC     r2, r2, #carry
                STR     r2, [sp, #20]
                B       add_prefix5
add_prefix9     CMP     r0, #':'
                MOVEQ   r4, r1
                MOVEQ   r3, r1
                CMP     r0, #'.'
                SUBEQ   r3, r1, #1
                CMP     r0, #' '
                BHI     add_prefix6
  [ DEBUG
                SWI     os_writes
                DCB     4, "After stripping ^s ", 0
                SWI     os_newline
                MOV     r2, r8
write_name1     LDRB    r0, [r2], #1
                CMP     r0, #' '+1
                SWICS   os_writec
                CMP     r0, #' '+1
                BCS     write_name1
                SWI     os_newline
  ]
                LDMFD   sp!, {r0, r1, r2, r3, r4, lr}
                TEQ     pc, pc
                BNE     add_prefix_ret_26
                MSR     CPSR_f, lr
                LDR     pc, [sp], #4

add_prefix_ret_26
                TEQP    pc, lr
                LDR     pc, [sp], #4

find_handler_26
                STR     lr, [sp, #-4]!
                STR     pc, [sp, #-4]!
                BL      find_handler_32
                NOP
                ADD     sp, sp, #4
                LDMVCFD sp!, {pc}^
                LDR     lr, [sp], #4
                ORRS    pc, lr, #overflow

find_handler_32 CMP     r0, #&40
                BHS     file_handler_external_entry
                CMP     r0, #0 ; clear V
                MOV     pc, lr

gbpb_handler_26
                STR     lr, [sp, #-4]!
                STR     pc, [sp, #-4]!
                BL      gbpb_handler_32
                NOP
                ADD     sp, sp, #4
                LDMVCFD sp!, {pc}^
                LDR     lr, [sp], #4
                ORRS    pc, lr, #overflow

gbpb_handler_32 CMP     r0, #9
                MOVLO   pc, lr          ; V clear
                CMP     r0, #13
                BLO     file_handler_external_entry
                CMP     r0, #0          ; V clear
                MOV     pc, lr

file_handler_26
                STR     lr, [sp, #-4]!
                STR     pc, [sp, #-4]!
                BL      file_handler_32
                NOP
                ADD     sp, sp, #4
                LDMVCFD sp!, {pc}^
                LDR     lr, [sp], #4
                ORRS    pc, lr, #overflow

  [ DEBUG
file_handler_external_entry
                STMFD   sp!, {r8, r11, lr}
                B       %FT02
file_handler_32
                STMFD   sp!, {r8, r11, lr}
                STMFD   sp!, {r0,r1}
                SWI     os_writes
                DCB     4, "file_handler: ", 0
01              LDRB    r0, [r1], #1
                CMP     r0, #' '+1
                SWICS   os_writec
                CMP     r0, #' '+1
                BHS     %BT01
                SWI     os_newline
                LDMFD   sp!, {r0,r1}
02
  |
file_handler_external_entry
file_handler_32
                STMFD   sp!, {r8, r11, lr}
  ]
                LDR     r8, chain
                MOV     lr, #0
                LDR     lr, [lr, #zp_wimpdomain]    ; lr = domainid
file_handler1   CMP     r8, #0
                BEQ     file_handler2
                LDR     r11, [r8, #o_wimpdomain]
                CMP     r11, lr
                LDRNE   r8, [r8, #o_next]
                BNE     file_handler1
                LDR     r11, fname_buffer
                BL      add_prefix
file_handler3   MOV     r12,r8 ; hold dir block otherwise this gets very icky
                LDMFD   sp!, {r8, r11, lr}
                MOVCS   pc, lr
                TEQ     pc, pc
                LDRNE   lr, [sp, #8]     ;get real pass-on address from 26-bit veneer
                TEQNEP  pc, lr
                STR     r1, [sp, #-4]!
                MOV     r1, r12
                STR     pc, [sp, #-4]!   ;store PC+8 (Architecture 4) or PC+12
                MOV     pc, lr
                NOP                      ;so that PC+8 is ok

file_upcall     LDMFD   sp!, {r1, lr}    ;target of stored PC
                B       xfervc

file_handler2   LDR     r11, fname_buffer
                MOV     r8, r1
                BL      strip_hats
                B       file_handler3

fscontrol_handler_26
                STR     lr, [sp, #-4]!
                STR     pc, [sp, #-4]!
                BL      fscontrol_handler_32
                NOP
                ADD     sp, sp, #4
                LDMVCFD sp!, {pc}^
                LDR     lr, [sp], #4
                ORRS    pc, lr, #overflow

fscontrol_handler_32
                CMP     r0, #25             ; Rename objects
                BLO     fscontrol_handler1
                CMP     r0, #27             ; Copy objects
                BLO     copy_or_rename
                CMPNE   r0, #28             ; Count objects
                CMPNE   r0, #32             ; *FileInfo
                CMPNE   r0, #37             ; Canonicalise
  [ HandleImages
                CMPNE   r0, #41             ; return defects for image
                CMPNE   r0, #42             ; map out defects for image
                CMPNE   r0, #46             ; return used space map for image
                CMPNE   r0, #47             ; read boot for disc/image
                CMPNE   r0, #48             ; write boot for disc/image
                CMPNE   r0, #49             ; read free space for disc/image
                CMPNE   r0, #50             ; rename disc/image
; (should already be canonical, I think - JRF)
;                CMPNE   r0, #51             ; update stamp
                CMPNE   r0, #52             ; find object at offset
                CMPNE   r0, #55             ; read freespace (large)
                CMPNE   r0, #56             ; read defects (large)
                CMPNE   r0, #57             ; map out defect (large)
  ]
                BEQ     file_handler_external_entry
  [ AllowDirectoryChanging
                CMP     r0, #53
                BEQ     set_given_dir
                CMP     r0, #43
                BEQ     unset_dir
  ]
                CMP     r0, r0
                MOV     pc, lr

fscontrol_handler1
                CMP     r0, #5              ; *.
                CMPNE   r0, #6              ; *Ex
                CMPNE   r0, #9              ; *Info
                CMPNE   r0, #24             ; *Access
                BEQ     file_handler_external_entry
  [ AllowDirectoryChanging
                CMP     r0, #0
                BEQ     change_dir
  ]
                CMP     r0, r0
                MOV     pc, lr

  [ AllowDirectoryChanging
unset_dir
                STMFD   sp!, {r0,lr}
                MOV     r0,#0
                SWI     xddeutils_swibase + ddeutils_readprefix ;read context
                BVS     %FT01
                TEQ     r0,#0
                LDMEQFD sp!, {r0,pc}
                MOV     r0,#0
                SWI     xddeutils_swibase + ddeutils_prefix
01
                LDMVCFD sp!, {r0,lr,pc}
                ADDVS   sp,sp,#4
                LDMFD   sp!, {lr,pc}

set_given_dir
                CMP     r2,#0
                MOVNE   pc,lr  ; only process if 'set CSD'

                STMFD   sp!, {r0,lr}
                MOV     r0,#0
                SWI     xddeutils_swibase + ddeutils_readprefix ;read context
                BVS     %FT01
                CMP     r0,#0
                LDMEQFD sp!, {r0,pc}
                MOV     r0,r1
                SWI     xddeutils_swibase + ddeutils_prefix
01
                LDMVCFD sp!, {r0,lr,pc}
                ADDVS   sp,sp,#4
                LDMFD   sp!, {lr,pc}

change_dir
                STMFD   sp!, {r0-r5,lr}
                MOV     r0,#0
                SWI     xddeutils_swibase + ddeutils_readprefix ;read context
                BVS     %FT01
                TEQ     r0,#0
                LDMEQFD sp!, {r0-r5,pc}
                MOV     r0,#5
                SWI     xos_file
                TST     r0,#2
                BEQ     %FT02
                MOV     r0,r1
                SWI     xddeutils_swibase + ddeutils_prefix
01
                LDMVCFD sp!, {r0-r5,lr,pc}
                ADDVS   sp,sp,#4
                LDMFD   sp!, {r1-r5,lr,pc}
02
                MOV     r0,#19
                MOV     r2,#&100 ; Directory 'wibble' not found
                SWI     xos_file
                ADD     sp,sp,#4 ; skip r0
                LDMFD   sp!, {r1-r5,lr,pc}

  ]

copy_or_rename  STMFD   sp!, {r1, r2}
                STMFD   sp!, {r8, r9, r10, r11, lr, pc} ;store PC+8 or PC+12
                B       copy_or_rename1
                NOP                                  ;so that PC+8 is ok

copy_or_rename_upcall                                ;target of stored PC
                LDMFD   sp!, {r1, r2, lr}
                B       xfervc

copy_or_rename1
;   [ DEBUG
;                 STMFD   sp!, {r0,r1}
;                 SWI     os_writes
;                 DCB     4, "copy_or_rename1: ", 0
; 01              LDRB    r0, [r1], #1
;                 CMP     r0, #' '+1
;                 SWICS   os_writec
;                 CMP     r0, #' '+1
;                 BCS     %BT01
;                 SWI     os_newline
;                 LDMFD   sp!, {r0,r1}
;   ]
                ADR     r8, chain
copy_or_rename1b LDR    r8, [r8]
                CMP     r8, #0
                BEQ     copy_or_rename2
                MOV     lr, #0
                LDR     lr, [lr, #zp_wimpdomain]
                LDR     r11, [r8, #o_wimpdomain]
                CMP     r11, lr
                BNE     copy_or_rename1b
                LDR     r11, fname_buffer
                MOV     r9, r8
                BL      add_prefix
                MOV     r10, r8
                MOV     r8, r9
                ADD     r11, r11, #FilenameLength
                MOV     r9, r1
                MOV     r1, r2
                BL      add_prefix0
copy_or_rename3 MOV     r1, r9
                MOVCC   r2, r8
                MOVCC   r1, r10
                LDMFD   sp!, {r8, r9, r10, r11, lr}
                ADDCS   sp, sp, #12
                MOVCS   pc, lr
                TEQ     pc, pc
                LDRNE   lr, [sp, #16]     ;get real pass-on address from 26-bit veneer
                MOVNES  pc, lr
                MOV     pc, lr

copy_or_rename2 LDR     r11, fname_buffer
                MOV     r8, r1
                BL      strip_hats
                MOV     r10, r8
                ADD     r11, r11, #FilenameLength
                MOV     r9, r1
                MOV     r8, r2
                BL      strip_hats0
                B       copy_or_rename3

; SWI DDEUtils_GetClSize
doswi_getclsize LDR     r0, cli_size
                MOV     pc, lr


; SWI DDEUtils_GetCl
doswi_getcl     LDR     r11, cli_buffer
                CMP     r11, #0
                MOVEQ   r12, #0
                STREQB  r12, [r0]
                MOVEQ   pc, lr
                STMFD   sp!, {r2, r8, lr}
                MOV     r8, #0
                STR     r8, cli_buffer
                STR     r8, cli_size
                MOV     r2, r11
                MOV     r8, r0
getcl1          LDRB    r10, [r11], #1
                STRB    r10, [r0], #1
                CMP     r10, #' '
                BHS     getcl1
                MOV     r10, #0
                STRB    r10, [r0, #-1]
                MOV     r0, #n_module_free
                SWI     xos_module
                MOVVC   r0, r8
                LDMFD   sp!, {r2, r8, lr}
                B       xferv


; SWI DDEUtils_SetClSize
doswi_setclsize STMFD   sp!, {r1, r2, r3, lr}
                MOV     r3, r0
                LDR     r2, cli_buffer
                CMP     r2, #0
                MOVNE   r0, #n_module_free
                SWINE   xos_module
                LDMVSFD sp!, {r1, r2, r3, pc}
  [ 0 = 1
                CMP     r3, #0
                LDMEQFD sp!, {r1, r2, r3, pc}
  ]
                MOV     r0, #n_module_claim
                SWI     xos_module
                MOVVS   r1, #0
                STRVS   r1, cli_buffer
                STRVS   r1, cli_size
                STRVC   r2, cli_buffer
                STRVC   r3, cli_size
                MOVVC   r0, r2
                LDMFD   sp!, {r1, r2, r3, lr}
                B       xferv

no_cli_buffer_msg
                DCD     no_cli_buffer_error
                DCB     "CLI buffer not set", 0
                ALIGN

do_no_cli_buffer
                ADR     r0, no_cli_buffer_msg
                TEQ     pc, pc
                ORRNES  pc, lr, #overflow
                MSR     CPSR_f, #overflow
                MOV     pc, lr


; SWI DDEUtils_SetCl
doswi_setcl     LDR     r11, cli_buffer
                CMP     r11, #0
                BEQ     do_no_cli_buffer
                STMFD   sp!, {r0, r1, lr}
                LDR     r1, cli_size
setcl1          LDRB    r10, [r0], #1
                STRB    r10, [r11], #1
  [ CheckBufferSize
                SUBS    r1,r1,#1
                BMI     do_buffer_too_short
  ]
                CMP     r10, #' '
                BCS     setcl1
                LDMFD   sp!, {r0, r1, pc}
  [ CheckBufferSize
do_buffer_too_short
                LDMFD   sp!, {r0, r1, lr}
                ADR     r0, buffer_too_short_msg
                TEQ     pc, pc
                ORRNES  pc, lr, #overflow
                MSR     CPSR_f, #overflow
                MOV     pc, lr

buffer_too_short_msg
                DCD     buffer_too_short
                DCB     "CLI buffer too short", 0
  ]

prefix_cmd      MOV     r6, lr
                SWI     xddeutils_swibase + ddeutils_prefix
                MOV     pc, r6



not_desktop_msg DCD     not_desktop_error
                DCB     "Throwback not available outside the desktop", 0
                ALIGN

no_task_msg     DCD     no_task_error
                DCB     "No task registered for throwback", 0
                ALIGN

already_reg_msg DCD     already_reg_error
                DCB     "Another task is registered for throwback", 0
                ALIGN

not_reg_msg     DCD     not_reg_error
                DCB     "Task not registered for throwback", 0
                ALIGN



; check if we're in the desktop or not
checkactivetasks
                STMFD   sp!, {r0, lr}
                MOV     r0, #0
                SWI     xwimp_readsysinfo
                MOVVS   r0, #0
                CMP     r0, #0
                LDMFD   sp!, {r0, lr}
                MOVNE   pc, lr
                ADR     r0, not_desktop_msg
                TEQ     pc, pc
                ORRNES  pc, lr, #overflow
                MSR     CPSR_f, #overflow
                MOV     pc, lr

do_no_task
                ADR     r0, no_task_msg
return_setv     TEQ     pc, pc
                ORRNES  pc, lr, #overflow
                MSR     CPSR_f, #overflow
                MOV     pc, lr

; SWI DDEUtils_ThrowbackEnd
doswi_throwbackend
                STMFD   sp!, {r0-r4, r9, lr}
                BL      checkactivetasks
                ADDVS   sp,sp,#4
                LDMVSFD sp!, {r1-r4, r9, pc}
                LDR     r9, receiver_id
                CMP     r9, #0
                LDMEQFD sp!, {r0-r4, r9, lr}
                BEQ     do_no_task

                MOV     r0, #msg_throwback_end
startorendmsg   MOV     r1, #0                  ; No string
stringonlymsg1  MVN     r3, #0                  ; No line no.
                MVN     r4, #0                  ; No error level
                BL      sendmessage
throwback_vsret ADDVS   sp, sp, #4
                LDRVC   r0, [sp], #4
                LDMFD   sp!, {r1-r4, r9, lr}
                B       xferv


stringonlymsg
                STMFD   sp!, {r0-r4, r9, lr}
                B       stringonlymsg1

throwback_err   DCB     "Throwback error", 13, 10, 0
                ALIGN


; SWI DDEUtils_ThrowbackRegister
doswi_throwbackregister
                STMFD   sp!, {r0, r9, lr}
                BL      checkactivetasks
                ADDVS   sp,sp,#4
                LDMVSFD sp!, {r9, pc}
                LDR     r9, receiver_id
                CMP     r9, #0
                LDMFD   sp!, {r0, r9, lr}
                ADRNE   r0, already_reg_msg
                BNE     return_setv
                STR     r0, receiver_id
                MOVS    pc, lr

; SWI DDEUtils_ThrowbackUnregister
doswi_throwbackunregister
                STMFD   sp!, {r0, r9, lr}
                BL      checkactivetasks
                ADDVS   sp,sp,#4
                LDMVSFD sp!, {r9, pc}
                LDR     r9, receiver_id
                CMP     r9, r0
                MOVEQ   r0, #0
                STREQ   r0, receiver_id
                LDMFD   sp!, {r0, r9, lr}
                ADRNE   r0, not_reg_msg
                BNE     return_setv
                MOV     pc, lr

; SWI DDEUtils_ThrowbackStart
doswi_throwbackstart
                STMFD   sp!, {r0-r4, r9, lr}
                BL      checkactivetasks
                ADDVS   sp,sp,#4
                LDMVSFD sp!, {r1-r4, r9, pc}
                LDR     r9, receiver_id
                CMP     r9, #0
                LDMEQFD sp!, {r0-r4, r9, lr}
                BEQ     do_no_task

                MOV     r0, #msg_throwback_start
                B       startorendmsg

; support for ThrowbackSend
throwback_add_prefix
                STMFD   sp!, {lr}
                MOV     r1, r2
                BL      file_handler_external_entry
                STMFD   sp!, {r0, r3, r4}
                MOV     lr, r0
                CMP     lr, #reason_infodetails
                MOVEQ   r0, #msg_throwback_infoforfile
                CMP     lr, #reason_processing
                MOVEQ   r0, #msg_throwback_processingfile
                CMP     lr, #reason_errordetails
                MOVEQ   r0, #msg_throwback_errorsin
                BL      stringonlymsg
                LDRVC   r0, [sp], #4
                ADDVS   sp, sp, #4
                LDMFD   sp!, {r3, r4}
                BVS     throwback_add_prefix1
                CMP     r0, #reason_processing
                LDMEQFD sp!, {pc}
                CMP     r0, #reason_infodetails
                MOVEQ   r0, #msg_throwback_infodetails
                MOVNE   r0, #msg_throwback_errordetails
                MOV     r1, r5
                BL      sendmessage
throwback_add_prefix1
                LDMFD   sp!, {lr}
                B       xferv


; DDEUtils_ThrowbackSend
doswi_throwbacksend
                STMFD   sp!, {r0-r4, r9, lr}
                BL      checkactivetasks
                ADDVS   sp,sp,#4
                LDMVSFD sp!, {r1-r4, r9, pc}
                LDR     r9, receiver_id
                CMP     r9, #0
                LDMEQFD sp!, {r0-r4, r9, lr}
                BEQ     do_no_task

                BL      throwback_add_prefix

                B       throwback_vsret


; R0 = message id
; R1 = string       0 => no string
; R3 = line no     -1 => no line no
; R4 = error level -1 => no errorlevel
sendmessage     STMFD   sp!, {lr}
  [ DEBUG
                STMFD   sp!, {r0, r1, r2, r3}
                MOV     r3, r1
                SWI     os_writes
                DCB     4, "Message id = ", 0
                ADR     r1, hbuff
                MOV     r2, #12
                SWI     os_converthex8
                SWI     os_write0
                SWI     os_writes
                DCB     13, 10, 0
                MOV     r0, r3
                SWI     os_write0
                SWI     os_writes
                DCB     13, 10, 5, 0
                LDMFD   sp!, {r0, r1, r2, r3}
                B       %FT01
hbuff
                %       256
01
  ]
                MOV     r2, r1
                MOVS    lr, r1
                BEQ     sendmessage2
sendmessage1    LDRB    r2, [lr], #1
                CMP     r2, #0
                BNE     sendmessage1
                SUB     r2, lr, r1
sendmessage2    ADD     r2, r2, #31
                BIC     r2, r2, #3
                MOV     lr, sp
                SUB     sp, sp, r2
                STR     r2, [sp]
                ADD     r2, sp, #12
                STMFD   sp!, {lr}
                MOV     lr, #0
                STR     lr, [r2], #4
                ADD     r0, r0, #ddeutils_msgbase_l
                ADD     r0, r0, #ddeutils_msgbase_h
                STR     r0, [r2], #4
                CMN     r3, #1
                STRNE   r3, [r2], #4
                CMN     r4, #1
                STRNE   r4, [r2], #4
                CMP     r1, #0
                BEQ     sendmessage4
sendmessage3    LDRB    lr, [r1], #1
                STRB    lr, [r2], #1
                CMP     lr, #0
                BNE     sendmessage3
sendmessage4    MOV     r0, #17
                ADD     r1, sp, #4
                MOV     r2, r9
;               IDJ/NK 4-Jan-95: AQU-00756 - truncate if message text too long
                LDR     lr, [r1]   ; length of msg
                CMP     lr, #256
                MOVGT   lr, #256
                STRGT   lr, [r1]   ; 256 is max size of msg
                MOVGT   lr, #0
                STRGTB  lr, [r1, #255]
                SWI     xwimp_sendmessage
                LDR     sp, [sp]
                LDMFD   sp!, {lr}
                B       xferv

initvar         STMFD   sp!, {r4, lr}
                MOV     r3, r1
initvar1        LDRB    r2, [r3], #1
                CMP     r2, #' '
                BCS     initvar1
                SUB     r2, r3, r1
                MOV     r3, #0
                MOV     r4, #0
                SWI     xos_setvarval
                LDMFD   sp!, {r4, pc}

                END