;
; 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
