Initial revision
[ssr] / StraySrc / Libraries / Sapphire / xfer / s / save
1 ;
2 ; xfer.save.s
3 ;
4 ; Saving data to other applications (MDW)
5 ;
6 ; © 1994 Straylight
7 ;
8
9 ;----- Standard header ------------------------------------------------------
10
11 GET libs:header
12 GET libs:swis
13
14 ;----- External dependencies ------------------------------------------------
15
16 GET sapphire:fastMove
17 GET sapphire:msgs
18 GET sapphire:sapphire
19 GET sapphire:string
20 GET sapphire:wimp
21 GET sapphire:win
22
23 ;----- Main code ------------------------------------------------------------
24
25 AREA |Sapphire$$Code|,CODE,READONLY
26
27 ; --- save ---
28 ;
29 ; On entry: R0 == window handle to send to
30 ; R1 == icon handle to send to
31 ; R2 == estimated size of the data
32 ; R3 == file type of data to send and flag:
33 ; bit 31: use R8 as below
34 ; R4 == pointer to name of file (may be full path)
35 ; R5 == address of handler block
36 ; R6 == value to pass handlers in R10
37 ; R7 == value to pass handlers in R12
38 ; R8 == pointer to extra handler block (only if bit 31 of R3)
39 ;
40 ; On exit: --
41 ;
42 ; Use: Starts a save operation to another application. The extra
43 ; handler is used by systems like saveas which need to be
44 ; aware of data transfer start/end conditions without
45 ; interfering with the normal entry table. This will not
46 ; normally concern applications however.
47
48 EXPORT save
49 save ROUT
50
51 STMFD R13!,{R0-R8,R12,R14} ;Save a load of registers
52 WSPACE save__wSpace ;Find my workspace pointer
53
54 ; --- Save some information in workspace ---
55
56 TST R3,#&80000000 ;Is there an extra handler?
57 MOVEQ R8,#0 ;No -- then clear pointer
58 SUBNE R8,R8,#sEntry__success ;Otherwise, pad it out a bit
59 BIC R3,R3,#&FF000000 ;Clear the flag bits
60 ADR R14,save__handler ;Save the handler information
61 STMIA R14,{R5-R8} ;Save them for later
62
63 MOV R14,#0 ;No buffer to send yet
64 STR R14,save__srcSize ;So clear out its size
65 STR R14,save__acc ;And clear RAM transfer acc
66 MOV R14,#sState__safe ;Data is safe at the moment
67 STR R14,save__state ;Clear out any old state info
68
69 ; --- Get the leafname of the file ---
70
71 MOV R5,R4 ;Point to the name start
72 00save LDRB R14,[R5],#1 ;Get a character from it
73 CMP R14,#'.' ;Is it a directory separator?
74 MOVEQ R4,R5 ;Yes -- update pointer
75 CMP R14,#32 ;Is this the name end?
76 BGE %00save ;No -- go round for more
77
78 ; --- Find the mouse position ---
79
80 SUB R13,R13,#36 ;Make way for a pointer block
81 MOV R1,R13 ;Point to the new space
82 SWI Wimp_GetPointerInfo ;Read the mouse position
83 LDMIA R1,{R7,R14} ;Load the mouse coordinates
84 ADD R13,R13,#36 ;Reclaim the stack space
85 LDMIA R13,{R5,R6} ;Load the window and icon
86
87 ; --- Build the message at last ---
88
89 ADD R0,R11,#20 ;Start building msg body
90 STMIA R0!,{R5-R7,R14} ;Save coords and window hnd
91 STMIA R0!,{R2,R3} ;Save estimated size and type
92 MOV R1,R4 ;Point to the filename
93 BL str_cpy ;Copy the name over
94 ADD R0,R0,#4 ;Include the null terminator
95 SUB R0,R0,R11 ;Get the final offset
96 BIC R0,R0,#3 ;Round off to word size
97 STR R0,[R11,#0] ;Save the message size
98 ADD R0,R11,#12 ;Point into message header
99 MOV R1,#0 ;This isn't a reply
100 MOV R2,#1 ;The message code for save
101 STMIA R0,{R1,R2} ;Store them in the message
102
103 ; --- Send the message over ---
104
105 MOV R0,#18 ;I want a bounce if it fails
106 MOV R1,R11 ;Point to message in scratch
107 LDMIA R13,{R2,R3} ;Load the window to send to
108 SWI Wimp_SendMessage ;Send the message to it then
109
110 ; --- Register the unknown handler to fix it all ---
111
112 ADR R0,save__unknown ;Point to my handler
113 MOV R1,#0 ;Nothing interesting in R4
114 MOV R2,#0 ;Nothing interesting in R10
115 MOV R3,R12 ;Pass my workspace pointer
116 BL win_unknownHandler ;Add in the handler nicely
117 LDMFD R13!,{R0-R8,R12,PC}^ ;Restore registers and return
118
119 LTORG
120
121 ; --- save__unknown ---
122 ;
123 ; On entry: R0 == event code
124 ; R1 == pointer to event data
125 ;
126 ; On exit: --
127 ;
128 ; Use: Handles unknown events during a save operation.
129
130 save__unknown ROUT
131
132 CMP R0,#19 ;Is this a message bounce?
133 BEQ %60save__unknown ;Yes -- skip to handle it
134 CMP R0,#17 ;Is this any sort of message?
135 CMPNE R0,#18 ;Check both types
136 MOVNE PC,R14 ;No -- return to caller
137
138 ; --- Check the message codes ---
139
140 STMFD R13!,{R14} ;Save the link to check it
141 LDR R14,[R1,#16] ;Load the message code
142 CMP R14,#6 ;Is it a RamFetch message?
143 BEQ %20save__unknown ;Yes -- get a buffer to send
144 CMP R14,#4 ;Is it a DataLoadAck?
145 BEQ %40save__unknown ;Yes -- wrap scrap xfer up
146 CMP R14,#2 ;Is it a DataSaveAck?
147 LDMNEFD R13!,{PC}^ ;No -- return to caller
148
149 ; --- It's a normal acknowledgement ---
150
151 STMFD R13!,{R0-R2,R10,R12} ;Save some more registers
152 ADD R0,R1,#44 ;Point to the filename
153 LDR R1,[R1,#36] ;Load the estimated size
154 CMP R1,#-1 ;Is it an unsafe file?
155 MOVLE R1,#0 ;Yes if est size < 0
156 MOVGT R1,#1 ;No if est size >= 0
157 STRLE R1,save__state ;Store the state away
158 ADR R14,save__handler ;Point to the handler block
159 LDMIA R14,{R2,R10,R12} ;Load the registers out
160 ADDS R0,R0,#0 ;Clear carry and overflow
161 MOV R14,PC ;Set up the return address
162 ADD PC,R2,#sEntry__save ;Call the save routine
163 WSPACE save__wSpace ;Load workspace pointer again
164 BLVS save__finish ;Wrap everything up here
165 BVS %10save__unknown ;It failed -- skip to the end
166
167 ; --- Send the DataLoad message ---
168
169 MOV R0,R11 ;Copy it to the scratchpad
170 LDR R1,[R13,#4] ;Read from the message block
171 LDR R2,[R1,#0] ;Message size, conveniently
172 BL fastMove ;Copy it over quickly
173 LDR R14,[R1,#8] ;Get his reference number
174 STR R14,[R1,#12] ;Store it so I can reply
175 MOV R14,#3 ;Send a DataLoad message
176 STR R14,[R1,#16] ;Save it in the message code
177 LDR R2,[R1,#4] ;Get his task handle out
178 MOV R0,#18 ;Make sure I get a bounce
179 SWI Wimp_SendMessage ;Send the message to him
180
181 10save__unknown LDMFD R13!,{R0-R2,R10,R12,R14} ;Restore all the registers
182 ORRS PC,R14,#C_flag ;Return with carry set
183
184 ; --- It's a request for memory transfer ---
185
186 20save__unknown STMFD R13!,{R0-R7,R10,R12} ;Save some more registers
187 LDR R14,save__handler ;Load the handlers block
188 LDR R14,[R14,#sEntry__send] ;Get the send entry
189 CMP R14,#0 ;Is it defined properly?
190 BEQ %35save__unknown ;No -- skip to the end
191
192 ; --- Set things up for the main loop ---
193
194 MOV R6,#0 ;No data sent yet
195 LDR R2,[R1,#4] ;Load his task handle
196 ADD R3,R1,#20 ;Point to dest buffer info
197 LDMIA R3,{R3,R5} ;Load his buffer info
198 ADR R1,save__srcBuff ;Point to source buffer info
199 LDMIA R1,{R1,R7} ;Load the information out
200
201 ; --- Now for the main loop then ---
202
203 25save__unknown LDR R14,save__state ;Get the current state
204 CMP R14,#sState__xferred ;Have we finished?
205 BEQ %30save__unknown ;Yes -- skip to the end
206
207 CMP R7,#0 ;Is there any data waiting?
208 BNE %30save__unknown ;Yes -- skip the next bit
209
210 ; --- Find some data from the client ---
211
212 ADR R14,save__handler ;Point to the handler
213 STMFD R13!,{R2} ;Save the old R2 value away
214 LDR R2,save__acc ;Load caller's accumulator
215 LDMIA R14,{R0,R10,R12} ;Get ready to call it
216 ADDS R0,R0,#0 ;Clear lots of flags
217 MOV R14,PC ;Set up the return address
218 ADD PC,R0,#sEntry__send ;Get some data to send
219 WSPACE save__wSpace ;Load my workspace again
220 BLVS save__finish ;It failed -- wrap things up
221 ADDVS R13,R13,#4 ;Don't bother with acc.
222 BVS %35save__unknown ;And skip to the end
223 STRCC R2,save__acc ;Save accumulator back
224 LDMFD R13!,{R2} ;Reload saved R2 value
225 MOVCS R14,#sState__xferred ;If that's the last one...
226 STRCS R14,save__state ;Save the state flag away
227 MOV R7,R1 ;Copy the size and the...
228 MOV R1,R0 ;... buffer pointers away
229
230 ; --- Send another bufferfull ---
231
232 30save__unknown CMP R5,R7 ;Which one is bigger?
233 MOVLT R4,R5 ;Choose the smaller as the...
234 MOVGE R4,R7 ;... buffer size to send
235 BL wimp_taskHandle ;Get my task handle ready
236 SWI Wimp_TransferBlock ;Transfer the data across
237
238 ; --- Set things up for the next go round ---
239
240 ADD R6,R6,R4 ;Bump the amount we've sent
241 SUB R7,R7,R4 ;Decrement the amount to send
242 SUB R5,R5,R4 ;And the destination buffer
243 ADD R1,R1,R4 ;But bump the buffer pointer
244 ADD R3,R3,R4 ;For both sides of the xfer
245
246 ; --- Find out if we need to go again ---
247
248 LDR R14,save__state ;Get my state variable again
249 CMP R14,#sState__xferred ;Is the transfer proceeding?
250 CMPNE R5,#0 ;And is he waiting for more?
251 BNE %25save__unknown ;Yes -- loop back round then
252
253 ; --- Update all the variables ---
254
255 ADR R14,save__srcBuff ;Point to source buff address
256 STMIA R14,{R1,R7} ;Save the updated values back
257
258 ; --- Send the RamTransmit to the other task ---
259
260 MOV R0,#28 ;Size of my message block
261 LDR R1,[R13,#4] ;Get the address of original
262 LDR R3,[R1,#8] ;Get his reference number
263 MOV R4,#7 ;This is a RamTransmit
264 LDR R5,[R1,#20] ;Get his buffer address
265 STMIA R11,{R0-R6} ;Save all the information
266 LDR R7,[R1,#24] ;Get the amount he expected
267 CMP R6,R7 ;Have we filled his buffer?
268 MOVLT R0,#17 ;No -- send as normal message
269 MOVEQ R0,#18 ;Otherwise get bounces nicely
270 LDR R2,[R1,#4] ;Get his task handle ready
271 MOV R1,R11 ;Point to the scratch message
272 SWI Wimp_SendMessage ;Send the message over
273
274 ; --- Now tidy everthing up and leave ---
275
276 CMP R6,R7 ;Did we fill his buffer?
277 BEQ %35save__unknown ;Yes -- skip this next bit
278 CMP R0,#0 ;Clear overflow flag
279 BL save__finish ;Tidy everything up nicely
280
281 35save__unknown LDMFD R13!,{R0-R7,R10,R12,R14} ;Load massive chunk of regs
282 ORRS PC,R14,#C_flag ;I handled the event
283
284 ; --- Handle a DataLoadAck message ---
285
286 40save__unknown CMP R14,#0 ;Clear the overflow flag
287 LDMFD R13!,{R14} ;Load the return address
288 ORR R14,R14,#C_flag ;Set C on eventual exit
289 B save__finish ;Tidy everything up and leave
290
291 ; --- Handle message bounces ---
292
293 60save__unknown STMFD R13!,{R14} ;Save a single register
294 LDR R14,[R1,#16] ;Load the message code
295 CMP R14,#3 ;Is it a bounced DataLoad?
296 BEQ %70save__unknown ;Yes -- handle that properly
297 CMP R14,#7 ;Is it a bounced RamTransit?
298 CMPNE R14,#1 ;Or a bounced DataSave?
299 LDMNEFD R13!,{PC}^ ;No -- return to caller then
300
301 ; --- Receiver failed to reply to RamTransmit or DataSave ---
302 ;
303 ; There's probably a good reason for this, such as it ran
304 ; out of memory, so we'd better just ignore it and tidy up.
305
306 STMFD R13!,{R0} ;Save another register
307 MOV R14,#V_flag ;Get the V flag's bit
308 TEQVCP R14,PC ;If V not set, toggle it!
309 MOV R0,#0 ;Don't pass an error block
310 BL save__finish ;Bring it all to a stop
311 LDMFD R13!,{R0,PC}^ ;Return to caller
312
313 ; --- Failed to reply to a DataLoad ---
314 ;
315 ; There could be a loose temporary file lying around, so
316 ; we'd better nobble it quickly. It also seems to be
317 ; traditional to moan if the DataLoadAck is not received.
318
319 70save__unknown STMFD R13!,{R0-R2} ;Save a few registers
320 ADR R0,save__delScrap ;Point to the command skel
321 ADD R2,R1,#44 ;Point to the filename
322 MOV R1,R11 ;Build it up in the scratch
323 BL str_subst ;Build the command string
324 SWI XOS_CLI ;Perform the command and hope
325 ADR R0,save__dtDead ;Point to an error message
326 BL msgs_error ;Translate it cunningly
327 MOV R14,#V_flag ;Get the V flag's bit
328 TEQVCP R14,PC ;If V not set, toggle it!
329 BL save__finish ;Wrap everything up then
330 LDMFD R13!,{R0-R2,PC}^ ;Return to caller
331
332 save__delScrap DCB "%%Wipe %0 ~c~vfr",0
333 save__dtDead DCD 1
334 DCB "saveDTDEAD",0
335
336 LTORG
337
338 ; --- save__finish ---
339 ;
340 ; On entry: R0 == pointer to error, or 0 if V set
341 ;
342 ; On exit: --
343 ;
344 ; Use: Finishes off a data transfer job nicely
345
346 save__finish ROUT
347
348 STMFD R13!,{R0-R4,R10,R12,R14} ;Save some registers
349
350 ; --- We need to remove the unknown handler first ---
351
352 MOV R10,PC ;Look after entry flags
353 ADR R0,save__unknown ;Point to my handler
354 MOV R1,#0 ;Nothing interesting in R4
355 MOV R2,#0 ;Nothing interesting in R10
356 MOV R3,R12 ;Pass my workspace pointer
357 BL win_removeUnknownHandler ;Kill off the handler
358 TEQP R10,#0 ;Restore the saved flags
359 MOVVS R4,#4 ;If so, offset handlers by 4
360 MOVVC R4,#0 ;Otherwise, don't do it
361
362 LDRVS R0,[R13,#0] ;Yes -- load error pointer
363 MOVVS R1,#1 ;And pass 1 as button count
364 LDRVC R1,save__state ;Load the state value
365 ANDVC R1,R1,#1 ;Leave the safeness flag
366 LDRVC R0,[R13,#4] ;Load the message address
367 ADDVC R0,R0,#44 ;Point to the filename
368
369 ; --- Now call the user routine ---
370
371 ADR R14,save__handler ;Point to the handlers
372 LDMIA R14,{R2,R10,R12,R14} ;Load all the stuff out
373
374 MOVS R3,R14 ;Keep the extra handler
375 ADD R2,R2,R4 ;Offset the handler properly
376 ADDNE R3,R3,R4 ;And offset extra one too
377
378 10save__finish MOV R14,PC ;Set up return address
379 ADD PC,R2,#sEntry__success ;Call the handler as required
380 MOVS R2,R3 ;Copy the real handler over
381 MOVNE R3,#0 ;If it was nonzero, zero it
382 BNE %10save__finish ;And go round again for it
383
384 LDMFD R13!,{R0-R4,R10,R12,PC}^ ;Return to caller
385
386 LTORG
387
388 save__wSpace DCD 0
389
390 ;----- The save handler -----------------------------------------------------
391
392 ^ 0
393 sEntry__save # 4 ;Write to a file
394 ;Entry:
395 ; R0 == pointer to file name
396 ; R1 == 0 if file unsafe,
397 ; non-0 if safe
398 ;Exit:
399 ; --
400
401 sEntry__send # 4 ;Send a block of data
402 ;Entry:
403 ; R2 == 0 for first call,
404 ; or R2 from previous
405 ;Exit:
406 ; R0 == pointer to block
407 ; R1 == size of block
408 ; R2 == value to pass to
409 ; next call
410 ; CS if this is the last one
411
412 sEntry__success # 4 ;Data transfer has finished
413 ;Entry:
414 ; R0 == pointer to filename
415 ; R1 == safeness flag
416 ;Exit:
417 ; --
418
419 sEntry__failed # 4 ;Data transfer failed
420 ;Entry:
421 ; R0 == 0 or ptr to error
422 ; R1 == 1
423 ;Exit:
424 ; --
425
426 ;----- Workspace ------------------------------------------------------------
427
428 ^ 0,R12
429 save__wStart # 0
430
431 ; --- Miscellaneous variables ---
432
433 save__state # 4 ;My current saving state
434
435 ; --- The handler ---
436
437 save__handler # 4 ;Pointer to handler code
438 save__R10 # 4 ;The R10 to pass to it
439 save__R12 # 4 ;The R12 to pass to it
440 save__extra # 4 ;Special extra handler
441
442 ; --- Variables for dealing with RAM transfer ---
443
444 save__srcBuff # 4 ;The source buffer to read
445 save__srcSize # 4 ;The source buffer size
446 save__acc # 4 ;The sender's counter thing
447
448 save__wSize EQU {VAR}-save__wStart
449
450 ; --- Various state indicators ---
451 ;
452 ; These have been carefully arranged so that the safeness
453 ; flag is the bottom bit of the state. The state is changed
454 ; from the default sState__safe when we detect that the file
455 ; is not safe.
456
457 sState__unsafe EQU 0 ;File is unsafe as it is
458 sState__safe EQU 1 ;File is safe
459 sState__xferred EQU 2 ;We've finished all that now
460
461 AREA |Sapphire$$LibData|,CODE,READONLY
462
463 DCD save__wSize
464 DCD save__wSpace
465 DCD 256
466 DCD 0
467
468 ;----- That's all, folks ----------------------------------------------------
469
470 END