; ; xfer.save.s ; ; Saving data to other applications (MDW) ; ; © 1994 Straylight ; ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis ;----- External dependencies ------------------------------------------------ GET sapphire:fastMove GET sapphire:msgs GET sapphire:sapphire GET sapphire:string GET sapphire:wimp GET sapphire:win ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ; --- save --- ; ; On entry: R0 == window handle to send to ; R1 == icon handle to send to ; R2 == estimated size of the data ; R3 == file type of data to send and flag: ; bit 31: use R8 as below ; R4 == pointer to name of file (may be full path) ; R5 == address of handler block ; R6 == value to pass handlers in R10 ; R7 == value to pass handlers in R12 ; R8 == pointer to extra handler block (only if bit 31 of R3) ; ; On exit: -- ; ; Use: Starts a save operation to another application. The extra ; handler is used by systems like saveas which need to be ; aware of data transfer start/end conditions without ; interfering with the normal entry table. This will not ; normally concern applications however. EXPORT save save ROUT STMFD R13!,{R0-R8,R12,R14} ;Save a load of registers WSPACE save__wSpace ;Find my workspace pointer ; --- Save some information in workspace --- TST R3,#&80000000 ;Is there an extra handler? MOVEQ R8,#0 ;No -- then clear pointer SUBNE R8,R8,#sEntry__success ;Otherwise, pad it out a bit BIC R3,R3,#&FF000000 ;Clear the flag bits ADR R14,save__handler ;Save the handler information STMIA R14,{R5-R8} ;Save them for later MOV R14,#0 ;No buffer to send yet STR R14,save__srcSize ;So clear out its size STR R14,save__acc ;And clear RAM transfer acc MOV R14,#sState__safe ;Data is safe at the moment STR R14,save__state ;Clear out any old state info ; --- Get the leafname of the file --- MOV R5,R4 ;Point to the name start 00save LDRB R14,[R5],#1 ;Get a character from it CMP R14,#'.' ;Is it a directory separator? MOVEQ R4,R5 ;Yes -- update pointer CMP R14,#32 ;Is this the name end? BGE %00save ;No -- go round for more ; --- Find the mouse position --- SUB R13,R13,#36 ;Make way for a pointer block MOV R1,R13 ;Point to the new space SWI Wimp_GetPointerInfo ;Read the mouse position LDMIA R1,{R7,R14} ;Load the mouse coordinates ADD R13,R13,#36 ;Reclaim the stack space LDMIA R13,{R5,R6} ;Load the window and icon ; --- Build the message at last --- ADD R0,R11,#20 ;Start building msg body STMIA R0!,{R5-R7,R14} ;Save coords and window hnd STMIA R0!,{R2,R3} ;Save estimated size and type MOV R1,R4 ;Point to the filename BL str_cpy ;Copy the name over ADD R0,R0,#4 ;Include the null terminator SUB R0,R0,R11 ;Get the final offset BIC R0,R0,#3 ;Round off to word size STR R0,[R11,#0] ;Save the message size ADD R0,R11,#12 ;Point into message header MOV R1,#0 ;This isn't a reply MOV R2,#1 ;The message code for save STMIA R0,{R1,R2} ;Store them in the message ; --- Send the message over --- MOV R0,#18 ;I want a bounce if it fails MOV R1,R11 ;Point to message in scratch LDMIA R13,{R2,R3} ;Load the window to send to SWI Wimp_SendMessage ;Send the message to it then ; --- Register the unknown handler to fix it all --- ADR R0,save__unknown ;Point to my handler MOV R1,#0 ;Nothing interesting in R4 MOV R2,#0 ;Nothing interesting in R10 MOV R3,R12 ;Pass my workspace pointer BL win_unknownHandler ;Add in the handler nicely LDMFD R13!,{R0-R8,R12,PC}^ ;Restore registers and return LTORG ; --- save__unknown --- ; ; On entry: R0 == event code ; R1 == pointer to event data ; ; On exit: -- ; ; Use: Handles unknown events during a save operation. save__unknown ROUT CMP R0,#19 ;Is this a message bounce? BEQ %60save__unknown ;Yes -- skip to handle it CMP R0,#17 ;Is this any sort of message? CMPNE R0,#18 ;Check both types MOVNE PC,R14 ;No -- return to caller ; --- Check the message codes --- STMFD R13!,{R14} ;Save the link to check it LDR R14,[R1,#16] ;Load the message code CMP R14,#6 ;Is it a RamFetch message? BEQ %20save__unknown ;Yes -- get a buffer to send CMP R14,#4 ;Is it a DataLoadAck? BEQ %40save__unknown ;Yes -- wrap scrap xfer up CMP R14,#2 ;Is it a DataSaveAck? LDMNEFD R13!,{PC}^ ;No -- return to caller ; --- It's a normal acknowledgement --- STMFD R13!,{R0-R2,R10,R12} ;Save some more registers ADD R0,R1,#44 ;Point to the filename LDR R1,[R1,#36] ;Load the estimated size CMP R1,#-1 ;Is it an unsafe file? MOVLE R1,#0 ;Yes if est size < 0 MOVGT R1,#1 ;No if est size >= 0 STRLE R1,save__state ;Store the state away ADR R14,save__handler ;Point to the handler block LDMIA R14,{R2,R10,R12} ;Load the registers out ADDS R0,R0,#0 ;Clear carry and overflow MOV R14,PC ;Set up the return address ADD PC,R2,#sEntry__save ;Call the save routine WSPACE save__wSpace ;Load workspace pointer again BLVS save__finish ;Wrap everything up here BVS %10save__unknown ;It failed -- skip to the end ; --- Send the DataLoad message --- MOV R0,R11 ;Copy it to the scratchpad LDR R1,[R13,#4] ;Read from the message block LDR R2,[R1,#0] ;Message size, conveniently BL fastMove ;Copy it over quickly LDR R14,[R1,#8] ;Get his reference number STR R14,[R1,#12] ;Store it so I can reply MOV R14,#3 ;Send a DataLoad message STR R14,[R1,#16] ;Save it in the message code LDR R2,[R1,#4] ;Get his task handle out MOV R0,#18 ;Make sure I get a bounce SWI Wimp_SendMessage ;Send the message to him 10save__unknown LDMFD R13!,{R0-R2,R10,R12,R14} ;Restore all the registers ORRS PC,R14,#C_flag ;Return with carry set ; --- It's a request for memory transfer --- 20save__unknown STMFD R13!,{R0-R7,R10,R12} ;Save some more registers LDR R14,save__handler ;Load the handlers block LDR R14,[R14,#sEntry__send] ;Get the send entry CMP R14,#0 ;Is it defined properly? BEQ %35save__unknown ;No -- skip to the end ; --- Set things up for the main loop --- MOV R6,#0 ;No data sent yet LDR R2,[R1,#4] ;Load his task handle ADD R3,R1,#20 ;Point to dest buffer info LDMIA R3,{R3,R5} ;Load his buffer info ADR R1,save__srcBuff ;Point to source buffer info LDMIA R1,{R1,R7} ;Load the information out ; --- Now for the main loop then --- 25save__unknown LDR R14,save__state ;Get the current state CMP R14,#sState__xferred ;Have we finished? BEQ %30save__unknown ;Yes -- skip to the end CMP R7,#0 ;Is there any data waiting? BNE %30save__unknown ;Yes -- skip the next bit ; --- Find some data from the client --- ADR R14,save__handler ;Point to the handler STMFD R13!,{R2} ;Save the old R2 value away LDR R2,save__acc ;Load caller's accumulator LDMIA R14,{R0,R10,R12} ;Get ready to call it ADDS R0,R0,#0 ;Clear lots of flags MOV R14,PC ;Set up the return address ADD PC,R0,#sEntry__send ;Get some data to send WSPACE save__wSpace ;Load my workspace again BLVS save__finish ;It failed -- wrap things up ADDVS R13,R13,#4 ;Don't bother with acc. BVS %35save__unknown ;And skip to the end STRCC R2,save__acc ;Save accumulator back LDMFD R13!,{R2} ;Reload saved R2 value MOVCS R14,#sState__xferred ;If that's the last one... STRCS R14,save__state ;Save the state flag away MOV R7,R1 ;Copy the size and the... MOV R1,R0 ;... buffer pointers away ; --- Send another bufferfull --- 30save__unknown CMP R5,R7 ;Which one is bigger? MOVLT R4,R5 ;Choose the smaller as the... MOVGE R4,R7 ;... buffer size to send BL wimp_taskHandle ;Get my task handle ready SWI Wimp_TransferBlock ;Transfer the data across ; --- Set things up for the next go round --- ADD R6,R6,R4 ;Bump the amount we've sent SUB R7,R7,R4 ;Decrement the amount to send SUB R5,R5,R4 ;And the destination buffer ADD R1,R1,R4 ;But bump the buffer pointer ADD R3,R3,R4 ;For both sides of the xfer ; --- Find out if we need to go again --- LDR R14,save__state ;Get my state variable again CMP R14,#sState__xferred ;Is the transfer proceeding? CMPNE R5,#0 ;And is he waiting for more? BNE %25save__unknown ;Yes -- loop back round then ; --- Update all the variables --- ADR R14,save__srcBuff ;Point to source buff address STMIA R14,{R1,R7} ;Save the updated values back ; --- Send the RamTransmit to the other task --- MOV R0,#28 ;Size of my message block LDR R1,[R13,#4] ;Get the address of original LDR R3,[R1,#8] ;Get his reference number MOV R4,#7 ;This is a RamTransmit LDR R5,[R1,#20] ;Get his buffer address STMIA R11,{R0-R6} ;Save all the information LDR R7,[R1,#24] ;Get the amount he expected CMP R6,R7 ;Have we filled his buffer? MOVLT R0,#17 ;No -- send as normal message MOVEQ R0,#18 ;Otherwise get bounces nicely LDR R2,[R1,#4] ;Get his task handle ready MOV R1,R11 ;Point to the scratch message SWI Wimp_SendMessage ;Send the message over ; --- Now tidy everthing up and leave --- CMP R6,R7 ;Did we fill his buffer? BEQ %35save__unknown ;Yes -- skip this next bit CMP R0,#0 ;Clear overflow flag BL save__finish ;Tidy everything up nicely 35save__unknown LDMFD R13!,{R0-R7,R10,R12,R14} ;Load massive chunk of regs ORRS PC,R14,#C_flag ;I handled the event ; --- Handle a DataLoadAck message --- 40save__unknown CMP R14,#0 ;Clear the overflow flag LDMFD R13!,{R14} ;Load the return address ORR R14,R14,#C_flag ;Set C on eventual exit B save__finish ;Tidy everything up and leave ; --- Handle message bounces --- 60save__unknown STMFD R13!,{R14} ;Save a single register LDR R14,[R1,#16] ;Load the message code CMP R14,#3 ;Is it a bounced DataLoad? BEQ %70save__unknown ;Yes -- handle that properly CMP R14,#7 ;Is it a bounced RamTransit? CMPNE R14,#1 ;Or a bounced DataSave? LDMNEFD R13!,{PC}^ ;No -- return to caller then ; --- Receiver failed to reply to RamTransmit or DataSave --- ; ; There's probably a good reason for this, such as it ran ; out of memory, so we'd better just ignore it and tidy up. STMFD R13!,{R0} ;Save another register MOV R14,#V_flag ;Get the V flag's bit TEQVCP R14,PC ;If V not set, toggle it! MOV R0,#0 ;Don't pass an error block BL save__finish ;Bring it all to a stop LDMFD R13!,{R0,PC}^ ;Return to caller ; --- Failed to reply to a DataLoad --- ; ; There could be a loose temporary file lying around, so ; we'd better nobble it quickly. It also seems to be ; traditional to moan if the DataLoadAck is not received. 70save__unknown STMFD R13!,{R0-R2} ;Save a few registers ADR R0,save__delScrap ;Point to the command skel ADD R2,R1,#44 ;Point to the filename MOV R1,R11 ;Build it up in the scratch BL str_subst ;Build the command string SWI XOS_CLI ;Perform the command and hope ADR R0,save__dtDead ;Point to an error message BL msgs_error ;Translate it cunningly MOV R14,#V_flag ;Get the V flag's bit TEQVCP R14,PC ;If V not set, toggle it! BL save__finish ;Wrap everything up then LDMFD R13!,{R0-R2,PC}^ ;Return to caller save__delScrap DCB "%%Wipe %0 ~c~vfr",0 save__dtDead DCD 1 DCB "saveDTDEAD",0 LTORG ; --- save__finish --- ; ; On entry: R0 == pointer to error, or 0 if V set ; ; On exit: -- ; ; Use: Finishes off a data transfer job nicely save__finish ROUT STMFD R13!,{R0-R4,R10,R12,R14} ;Save some registers ; --- We need to remove the unknown handler first --- MOV R10,PC ;Look after entry flags ADR R0,save__unknown ;Point to my handler MOV R1,#0 ;Nothing interesting in R4 MOV R2,#0 ;Nothing interesting in R10 MOV R3,R12 ;Pass my workspace pointer BL win_removeUnknownHandler ;Kill off the handler TEQP R10,#0 ;Restore the saved flags MOVVS R4,#4 ;If so, offset handlers by 4 MOVVC R4,#0 ;Otherwise, don't do it LDRVS R0,[R13,#0] ;Yes -- load error pointer MOVVS R1,#1 ;And pass 1 as button count LDRVC R1,save__state ;Load the state value ANDVC R1,R1,#1 ;Leave the safeness flag LDRVC R0,[R13,#4] ;Load the message address ADDVC R0,R0,#44 ;Point to the filename ; --- Now call the user routine --- ADR R14,save__handler ;Point to the handlers LDMIA R14,{R2,R10,R12,R14} ;Load all the stuff out MOVS R3,R14 ;Keep the extra handler ADD R2,R2,R4 ;Offset the handler properly ADDNE R3,R3,R4 ;And offset extra one too 10save__finish MOV R14,PC ;Set up return address ADD PC,R2,#sEntry__success ;Call the handler as required MOVS R2,R3 ;Copy the real handler over MOVNE R3,#0 ;If it was nonzero, zero it BNE %10save__finish ;And go round again for it LDMFD R13!,{R0-R4,R10,R12,PC}^ ;Return to caller LTORG save__wSpace DCD 0 ;----- The save handler ----------------------------------------------------- ^ 0 sEntry__save # 4 ;Write to a file ;Entry: ; R0 == pointer to file name ; R1 == 0 if file unsafe, ; non-0 if safe ;Exit: ; -- sEntry__send # 4 ;Send a block of data ;Entry: ; R2 == 0 for first call, ; or R2 from previous ;Exit: ; R0 == pointer to block ; R1 == size of block ; R2 == value to pass to ; next call ; CS if this is the last one sEntry__success # 4 ;Data transfer has finished ;Entry: ; R0 == pointer to filename ; R1 == safeness flag ;Exit: ; -- sEntry__failed # 4 ;Data transfer failed ;Entry: ; R0 == 0 or ptr to error ; R1 == 1 ;Exit: ; -- ;----- Workspace ------------------------------------------------------------ ^ 0,R12 save__wStart # 0 ; --- Miscellaneous variables --- save__state # 4 ;My current saving state ; --- The handler --- save__handler # 4 ;Pointer to handler code save__R10 # 4 ;The R10 to pass to it save__R12 # 4 ;The R12 to pass to it save__extra # 4 ;Special extra handler ; --- Variables for dealing with RAM transfer --- save__srcBuff # 4 ;The source buffer to read save__srcSize # 4 ;The source buffer size save__acc # 4 ;The sender's counter thing save__wSize EQU {VAR}-save__wStart ; --- Various state indicators --- ; ; These have been carefully arranged so that the safeness ; flag is the bottom bit of the state. The state is changed ; from the default sState__safe when we detect that the file ; is not safe. sState__unsafe EQU 0 ;File is unsafe as it is sState__safe EQU 1 ;File is safe sState__xferred EQU 2 ;We've finished all that now AREA |Sapphire$$LibData|,CODE,READONLY DCD save__wSize DCD save__wSpace DCD 256 DCD 0 ;----- That's all, folks ---------------------------------------------------- END