Initial revision
[ssr] / StraySrc / Libraries / Sapphire / xfer / s / load
1 ;
2 ; xfer.load.s
3 ;
4 ; Loading and importing of files (MDW)
5 ;
6 ; © 1994 Straylight
7 ;
8
9 ;----- Standard header ------------------------------------------------------
10
11 GET libs:swis
12 GET libs:header
13
14 ;----- External dependencies ------------------------------------------------
15
16 GET sapphire:alloc
17 GET sapphire:event
18 GET sapphire:fastMove
19 GET sapphire:flex
20 GET sapphire:msgs
21 GET sapphire:sapphire
22 GET sapphire:string
23 GET sapphire:wimp
24 GET sapphire:win
25
26 ;----- Main code ------------------------------------------------------------
27
28 AREA |Sapphire$$Code|,CODE,READONLY
29
30 ; --- load ---
31 ;
32 ; On entry: R0 == pointer to entry point block
33 ; R1 == value of R10 to pass to entry points
34 ; R2 == value of R12 to pass to entry points
35 ;
36 ; On exit: --
37 ;
38 ; Use: Attempts to load a file after receipt of a Message_DataSave,
39 ; Message_DataLoad or Message_DataOpen. If user entries for
40 ; RAM transfer are provided, this is attempted, although the
41 ; entries must also be aware that file transfer may be
42 ; required.
43
44 EXPORT load
45 load ROUT
46
47 STMFD R13!,{R0-R6,R10,R12,R14} ;Save a load of registers
48 WSPACE load__wSpace ;Locate my workspace address
49
50 ; --- Save the handler information ---
51
52 ADR R14,load__entries ;Point to my entry info
53 STMIA R14,{R0-R2} ;And save the handler info
54
55 ; --- Read the current message ---
56
57 BL event_last ;Read the actual last event
58 CMP R0,#17 ;Is it a normal message?
59 CMPNE R0,#18 ;Or a bouncy one?
60 BNE %90load ;Neither -- ignore it then
61
62 LDR R0,[R1,#16] ;Load the message action
63 CMP R0,#1 ;Is it a Message_DataSave?
64 BEQ %20load ;Yes -- handle it then
65 CMP R0,#3 ;Is it a Message_DataLoad?
66 BEQ %50load ;Yes -- deal with that
67 CMP R0,#5 ;Is it a Message_DataOpen?
68 BEQ %60load ;Yes -- deal with that too
69 B %90load ;Otherwise ignore it
70
71 ; --- Deal with a Message_DataSave ---
72 ;
73 ; First, set up all the data in my workspace.
74
75 20load MOV R6,R1 ;Keep the message pointer
76 ADR R0,load__message ;Point to my message buffer
77 LDR R2,[R6,#0] ;Get the message block size
78 BL fastMove ;Copy it over nicely
79
80 ; --- Find out if he can do RAM transfer ---
81
82 LDR R5,load__entries ;Find his handler block
83 LDR R14,[R5,#lEntry__initBuf] ;Point to his initBuf entry
84 CMP R14,#0 ;Is it defined?
85 BEQ %40load ;No -- just do scrap xfer
86
87 ; --- Set up for RAM transfer ---
88
89 ADR R0,load__name ;Point to the leafname
90 LDR R1,[R6,#36] ;Load the estimated size
91 MOV R2,#0 ;Pass a zero buffer handle
92 ADR R14,load__R10 ;Point to his R10/R12 values
93 LDMIA R14,{R10,R12} ;Load them out ready
94 ADDS R0,R0,#0 ;Clear lots of flags
95 MOV R14,PC ;Set up a return address
96 ADD PC,R5,#lEntry__initBuf ;Make him give me a buffer
97 WSPACE load__wSpace ;Get my workspace back again
98 STR R10,load__R10 ;Save his returned R10 value
99 BLVS load__finish ;If it failed, tidy it up
100 BVS %90load ;And return right now
101 ADR R14,load__buffStart ;Point to the buffer info
102 STMIA R14,{R0-R2} ;And save the buffer stuff
103 MOV R14,#0 ;We've not read any data yet
104 STR R14,load__totalSize ;So zero the total size
105
106 ; --- Build the Message_RAMFetch ---
107
108 MOV R14,#28 ;Size of a RAMFetch message
109 STR R14,[R11,#0] ;Store it in the scratchpad
110 ADD R14,R11,#12 ;Point to your_ref word
111 MOV R2,R0 ;Point to the buffer start
112 MOV R3,R1 ;And get the buffer size
113 LDR R0,[R6,#8] ;Load his reference number
114 MOV R1,#6 ;The RAMFetch message code
115 STMIA R14,{R0-R3} ;Save all that lot away
116 MOV R0,#18 ;Make it bounce if ignored
117 MOV R1,R11 ;Point to my message block
118 LDR R2,[R6,#4] ;Load his task handle
119 SWI Wimp_SendMessage ;And send along his message
120
121 ; --- Set everything up for the acknowledgement ---
122
123 MOV R14,#lState__test ;We're seeing if he'll cope
124 STR R14,load__state ;So save this state info
125
126 ADR R0,load__unknown ;Point to my unknown handler
127 MOV R1,#0 ;Nothing interesting in R4
128 MOV R2,#0 ;Nothing interesting in R10
129 MOV R3,R12 ;Pass workspace in R12
130 BL win_unknownHandler ;Register my unknown handler
131 B %90load ;And finish everything off
132
133 ; --- Set up scrap transfer ---
134
135 40load BL load__doScrap ;Start scrap transfer going
136 B %90load ;And finish everything off
137
138 ; --- Handle a Message_DataLoad ---
139 ;
140 ; If this is *not* a reply to a Message_DataSaveAck then we
141 ; should clear all the associated data from out message
142 ; cache.
143
144 50load LDR R14,[R1,#12] ;Load message's your_ref
145 CMP R14,#0 ;Is this a new message?
146 BNE %70load ;No -- don't do setting up
147
148 ; --- Handle a new Message_DataLoad or Message_DataOpen ---
149 ;
150 ; First, copy all the message data over
151
152 60load ADR R0,load__message ;Point to my message buffer
153 LDR R2,[R1,#0] ;Get the message block size
154 BL fastMove ;Copy it over nicely
155
156 ; --- Remember we're doing file transfer ---
157
158 MOV R14,#lState__file ;This is file transfer
159 STR R14,load__state ;Save this state value
160
161 ; --- Send an immediate acknowledgement ---
162 ;
163 ; For a Message_DataOpen, this is very important -- if we
164 ; don't, and the application dies, we then get started all
165 ; over again from the command line, and probably die again
166 ; if it's a duff file. For a Message_DataLoad it doesn't
167 ; matter too much, although I suspect we should really send
168 ; the acknowledgement after we loaded the file.
169
170 70load MOV R6,R1 ;Keep the message pointer
171 ADD R0,R11,#20 ;Copy to the scratchpad
172 ADD R1,R6,#20 ;Point to the message data
173 LDR R2,[R6,#0] ;Get the message block size
174 SUB R2,R2,#20 ;Subtract the bit not copied
175 BL fastMove ;Copy it over nicely
176
177 LDR R14,[R6,#0] ;Load the message size word
178 STR R14,[R11,#0] ;Save it in my dummy message
179 LDR R0,[R6,#8] ;Load his my_ref field
180 MOV R1,#4 ;This is Message_DataLoadAck
181 ADD R14,R11,#12 ;Point to the your_ref field
182 STMIA R14,{R0,R1} ;Save them in there
183
184 MOV R0,#17 ;Don't want acknowledgement
185 MOV R1,R11 ;Point to the message block
186 LDR R2,[R6,#4] ;Get his task handle ready
187 SWI Wimp_SendMessage ;And acknowledge his message
188
189 ; --- Tell the client to load the file ---
190
191 ADR R0,load__name ;Point to apparent filename
192 ADD R1,R6,#44 ;Point to filename to load
193 LDR R2,load__state ;Load state (safeness flag)
194 ADR R14,load__entries ;Point to the entry data
195 LDMIA R14,{R5,R10,R12} ;Load the important stuff
196 ADDS R0,R0,#0 ;Clear C and V flags
197 MOV R14,PC ;Set up his return address
198 ADD PC,R5,#lEntry__file ;Tell him to load the file
199 WSPACE load__wSpace ;Find my workspace again
200 STR R10,load__R10 ;Save the new R10 value
201 BL load__finish ;Send a completed message
202
203 ; --- Now delete the Wimp$Scrap file if we need to ---
204
205 CMP R2,#0 ;Is the file `safe'?
206 BNE %90load ;Yes -- then do nothing
207 MOV R0,#27 ;Wipe files please
208 ADD R1,R6,#44 ;Point to the filename
209 MOV R3,#&3 ;No confirm, recurse
210 SWI XOS_FSControl ;Do the Wipe job
211
212 ; --- We finished at last! ---
213
214 90load LDMFD R13!,{R0-R6,R10,R12,PC}^ ;Return to caller
215
216 LTORG
217
218 ; --- load__doScrap ---
219 ;
220 ; On entry: --
221 ;
222 ; On exit: --
223 ;
224 ; Use: Sets everything up for Wimp$Scrap-type data transfer.
225
226 load__doScrap ROUT
227
228 STMFD R13!,{R0-R4,R14} ;Save some registers
229
230 ; --- First, ensure the variable <Wimp$Scrap> exists ---
231
232 ADR R0,load__wimpScrap ;Point to my variable name
233 MOV R1,R11 ;Point to a convenient buffer
234 MOV R2,#256 ;Get the buffer size
235 MOV R3,#0 ;This is the first call
236 MOV R4,#0 ;Don't expand or anything
237 SWI XOS_ReadVarVal ;Read the variable value
238 BLVS load__finish ;If it failed, abort now
239 BVS %90load__doScrap ;And return to caller
240
241 ; --- Build the message and send it ---
242
243 ADD R0,R11,#20 ;Point at scratch msg data
244 ADR R1,load__message+20 ;And the saved bits of data
245 MOV R2,#24 ;All up to the filename
246 BL fastMove ;Copy all that lot over
247
248 MOV R14,#60 ;The size of this message
249 STR R14,[R11,#0] ;Store it in the right place
250 LDR R0,load__message+8 ;Load the message's my_ref
251 MOV R1,#2 ;This is Message_DataSaveAck
252 ADD R14,R11,#12 ;Point to your_ref
253 STMIA R14,{R0,R1} ;Save your_ref and action
254
255 ADD R0,R11,#44 ;Point to the filename area
256 ADR R1,load__scrapVar ;Point to the variable name
257 BL str_cpy ;Copy the string over
258
259 MOV R14,#-1 ;Say that the data's not safe
260 STR R14,[R11,#36] ;Save -1 as estimated size
261 MOV R0,#17 ;This should be send normal
262 MOV R1,R11 ;Point at my message
263 LDR R2,load__message+4 ;Load his task handle
264 SWI Wimp_SendMessage ;Send the message back
265
266 ; --- Now remember we're doing scrap transfer ---
267
268 MOV R14,#lState__scrap ;Get the right state number
269 STR R14,load__state ;And save it away nicely
270
271 ; --- That's it -- we're done ---
272
273 90load__doScrap LDMFD R13!,{R0-R4,PC}^ ;Return to caller
274
275 load__wimpScrap DCB "Wimp$Scrap",0
276 load__scrapVar DCB "<Wimp$Scrap>",0
277
278 LTORG
279
280 ; --- load__unknown ---
281 ;
282 ; On entry: R0 == an event code
283 ; R1 == pointer to event data
284 ;
285 ; On exit: CS if we handled the event, CC otherwise
286 ;
287 ; Use: Handles unknown events (i.e. user messages) during a RAM
288 ; transfer.
289
290 load__unknown ROUT
291
292 CMP R0,#17 ;Is it a user message?
293 CMPNE R0,#18 ;Or a bouncy user message?
294 BEQ %00load__unknown ;Yes -- handle it then
295 CMP R0,#19 ;Is it a bounced message?
296 BEQ %60load__unknown ;Yes -- deal with that
297 MOVS PC,R14 ;Nothing we could do about it
298
299 ; --- Deal with a message ---
300
301 00load__unknown STMFD R13!,{R14} ;Save a register
302 LDR R14,[R1,#16] ;Load the message code
303 CMP R14,#7 ;Is it a Message_RAMTransmit?
304 LDMNEFD R13!,{PC}^ ;No -- ignore it then
305
306 ; --- Data transfer is go ---
307
308 STMFD R13!,{R0-R6,R10} ;Save loads of registers
309 MOV R6,R1 ;Look after the message ptr
310 MOV R14,#lState__ram ;We're doing RAM transfer now
311 STR R14,load__state ;So save this state away
312
313 ; --- Have we finished data transfer yet? ---
314
315 ADR R14,load__buffStart ;Point to the buffer info
316 LDMIA R14,{R0-R2} ;Load all the buffer stuff
317 LDR R3,[R6,#24] ;How much has he sent?
318 LDR R4,load__totalSize ;Load the total so far
319 ADD R4,R4,R3 ;Add on this new size
320 STR R4,load__totalSize ;And save back the new total
321 CMP R1,R3 ;Has he sent enough data?
322 BNE %30load__unknown ;No -- then it's all over
323
324 ; --- Get some more buffer space ---
325
326 ADR R14,load__entries ;Point at his entry info
327 LDMIA R14,{R5,R10,R12} ;Load all his info out
328 ADDS R0,R0,#0 ;Clear C and V flags
329 MOV R14,PC ;Set up the return address
330 ADD PC,R5,#lEntry__extend ;Extend your buffer please
331 WSPACE load__wSpace ;Find my workspace again
332 BVS %40load__unknown ;If it failed, kill buffer
333 ADR R14,load__buffStart ;Point to the buffer info
334 STMIA R14,{R0-R2} ;Save the buffer info again
335
336 ; --- Send another RAMFetch along ---
337
338 MOV R14,#28 ;Size of a RAMFetch message
339 STR R14,[R11,#0] ;Store it in the scratchpad
340 ADD R14,R11,#12 ;Point to your_ref word
341 MOV R2,R0 ;Point to the buffer start
342 MOV R3,R1 ;And get the buffer size
343 LDR R0,[R6,#8] ;Load his reference number
344 MOV R1,#6 ;The RAMFetch message code
345 STMIA R14,{R0-R3} ;Save all that lot away
346 MOV R0,#18 ;Make it bounce if ignored
347 MOV R1,R11 ;Point to my message block
348 LDR R2,[R6,#4] ;Load his task handle
349 SWI Wimp_SendMessage ;And send along his message
350 B %50load__unknown ;Finish off everything
351
352 ; --- Tell the client to wrap things up ---
353
354 30load__unknown ADR R0,load__name ;Point to the `filename'
355 MOV R1,R4 ;Get the total data size
356 ADR R14,load__entries ;Point at his entry info
357 LDMIA R14,{R5,R10,R12} ;Load all his info out
358 ADDS R0,R0,#0 ;Clear C and V flags
359 MOV R14,PC ;Set up the return address
360 ADD PC,R5,#lEntry__doneBuf ;Tidy up your buffer please
361 WSPACE load__wSpace ;Find my workspace again
362 BVS %40load__unknown ;If it failed, tidy up
363 BL load__finish ;It's all over now
364
365 ; --- Unattach this unknown handler ---
366
367 ADR R0,load__unknown ;Point to my unknown handler
368 MOV R1,#0 ;Nothing interesting in R4
369 MOV R2,#0 ;Nothing interesting in R10
370 MOV R3,R12 ;Pass workspace in R12
371 BL win_removeUnknownHandler ;Unattach the handler
372 B %50load__unknown ;And return nicely
373
374 ; --- Tidy up after buffer extension failed ---
375
376 40load__unknown MOV R4,R0 ;Look after the error pointer
377 ADR R14,load__buffStart ;Point to the buffer info
378 LDMIA R14,{R0-R2} ;Load it all out
379 LDR R12,load__R12 ;Find the client's R12
380 MOV R14,PC ;Set up a return address
381 ADD PC,R5,#lEntry__killBuf ;Destroy the buffer
382 WSPACE load__wSpace ;Find my workspace again
383 MOV R14,#V_flag ;Get the V bit position
384 TEQVCP R14,PC ;If clear, set it again
385 MOV R0,R4 ;Point at the error again
386 BL load__finish ;Report the error
387
388 ; --- We don't need the unknown handler any more ---
389
390 ADR R0,load__unknown ;Point to my unknown handler
391 MOV R1,#0 ;Nothing interesting in R4
392 MOV R2,#0 ;Nothing interesting in R10
393 MOV R3,R12 ;Pass workspace in R12
394 BL win_removeUnknownHandler ;Unattach the handler
395
396 ; --- Return to caller ---
397
398 50load__unknown LDMFD R13!,{R0-R6,R10,R14} ;Unstack all the registers
399 ORRS PC,R14,#C_flag ;And claim the event
400
401 ; --- Handle a bounced message ---
402
403 60load__unknown STMFD R13!,{R14} ;Save a register
404 LDR R14,[R1,#16] ;Load the message action
405 CMP R14,#6 ;Is it one of my RAMFetches?
406 LDMNEFD R13!,{PC}^ ;No -- ignore it then
407
408 ; --- My RAMFetch bounced! ---
409
410 LDR R14,load__state ;Get my current state?
411 CMP R14,#lState__test ;Was I just testing the water
412 BLEQ load__doScrap ;Yes -- set up for scrap xfer
413
414 ; --- Shut down the data transfer ---
415
416 STMFD R13!,{R0-R3,R10} ;Save some more registers
417 ADR R14,load__buffStart ;Point to the buffer info
418 LDMIA R14,{R0-R2} ;Load it all out
419 ADR R14,load__entries ;Point to entry information
420 LDMIA R14,{R3,R10,R12} ;Load all the stuff out
421 MOV R14,PC ;Set up a return address
422 ADD PC,R3,#lEntry__killBuf ;Destroy the buffer
423 WSPACE load__wSpace ;Find my workspace again
424 MOV R14,#V_flag ;Get the V bit position
425 TEQVCP R14,PC ;If clear, set it again
426 MOV R0,#0 ;Don't report any errors
427 BL load__finish ;Report the error
428
429 ; --- We don't need the unknown handler any more ---
430
431 ADR R0,load__unknown ;Point to my unknown handler
432 MOV R1,#0 ;Nothing interesting in R4
433 MOV R2,#0 ;Nothing interesting in R10
434 MOV R3,R12 ;Pass workspace in R12
435 BL win_removeUnknownHandler ;Unattach the handler
436
437 LDMFD R13!,{R0-R3,R10,R14} ;Unstack all the registers
438 ORRS PC,R14,#C_flag ;And return with C set
439
440 LTORG
441
442 ; --- load__finish ---
443 ;
444 ; On entry: VS and R0 points to error, or VC
445 ;
446 ; On exit: R10 corrupted
447 ;
448 ; Use: Calls the appropriate client routine for finishing off
449 ; a load operation.
450
451 load__finish ROUT
452
453 STMFD R13!,{R0-R2,R12,R14} ;Save some registers
454 MOVVS R1,#1 ;If error, set button count
455 ADRVC R0,load__name ;Point to apparent name
456 LDRVC R1,load__state ;And load my state
457 AND R1,R1,#1 ;Leave only safeness flag
458 ADR R14,load__entries ;Point to the entry points
459 LDMIA R14,{R2,R10,R12} ;Load the entry info
460 ADDVS R2,R2,#4 ;If error, call fail entry
461 MOV R14,PC ;Set up the return address
462 ADD PC,R2,#lEntry__done ;Call the correct entry pt
463 LDMFD R13!,{R0-R2,R12,PC}^ ;Return to caller
464
465 LTORG
466
467 ; --- load_initBuf ---
468 ;
469 ; On entry: R1 == estimated file size
470 ; R2 == pointer to flex anchor (unallocated)
471 ;
472 ; On exit: R0 == pointer to buffer start
473 ; R1 == buffer size
474 ; May return an error
475 ;
476 ; Use: Initialises a flex block for use as a RAM transfer buffer.
477 ; This routine is suitable for use as the initBuf routine for
478 ; RAM transfer loading.
479
480 EXPORT load_initBuf
481 load_initBuf ROUT
482
483 STMFD R13!,{R14} ;Save some registers
484 MOV R0,R2 ;Point to caller's anchor
485 BL flex_alloc ;Try to allocate the buffer
486 MOVCS R1,#4096 ;Otherwise assume 4K size
487 BLCS flex_alloc ;And try again...
488 BLCS alloc_error ;If it failed, get an error
489 LDRCC R0,[R0,#0] ;Otherwise load buffer start
490 LDMFD R13!,{R14} ;Restore the link register
491 BICCCS PC,R14,#V_flag ;If no error, clear V on exit
492 ORRCSS PC,R14,#V_flag ;Otherwise set it
493
494 LTORG
495
496 ; --- load_killBuf ---
497 ;
498 ; On entry: R2 == pointer to flex anchor
499 ;
500 ; On exit: --
501 ;
502 ; Use: Frees a flex block. This routine should be used to free
503 ; the buffer used for RAM transfer.
504
505 EXPORT load_killBuf
506 load_killBuf ROUT
507
508 STMFD R13!,{R0,R14} ;Save some registers
509 MOV R0,R2 ;Point to the flex anchor
510 BL flex_free ;Free the block
511 MOV R14,#0 ;Get a zero word
512 STR R14,[R2,#0] ;Write this over the anchor
513 LDMFD R13!,{R0,PC}^ ;Return to caller
514
515 LTORG
516
517 ; --- load_extendBuf ---
518 ;
519 ; On entry: R0 == pointer to previous buffer
520 ; R1 == size of previous buffer
521 ; R2 == pointer to flex anchor
522 ;
523 ; On exit: R0 == pointer to a new buffer
524 ; R1 == size of the new buffer
525 ; May return an error
526 ;
527 ; Use: Extends the flex block if it was initially too small.
528 ; This routine is designed to be used as the extend routine
529 ; during RAM transfer.
530
531 EXPORT load_extendBuf
532 load_extendBuf ROUT
533
534 STMFD R13!,{R3,R14} ;Save some registers
535 MOV R0,R2 ;Point to the flex anchor
536 BL flex_size ;Read the block's size
537 MOV R3,R0 ;Look after the size
538 MOV R0,R2 ;Point to the flex anchor
539 ADD R1,R3,#&1000 ;Extend buffer by 4K
540 BL flex_extend ;Make more space for loading
541 BLCS alloc_error ;If it failed, get an error
542 LDRCC R0,[R2,#0] ;Otherwise load the anchor
543 ADDCC R0,R0,R3 ;And add the old size
544 MOVCC R1,#&1000 ;Get the buffer size
545 LDMFD R13!,{R3,R14} ;Restore the registers
546 BICCCS PC,R14,#V_flag ;If no error, clear V on exit
547 ORRCSS PC,R14,#V_flag ;Otherwise set it
548
549 LTORG
550
551 ; --- load_doneBuf ---
552 ;
553 ; On entry: R1 == actual size of data
554 ; R2 == pointer to flex anchor
555 ;
556 ; On exit: --
557 ;
558 ; Use: Sets the block into which the data has been loaded to the
559 ; correct exact size.
560
561 EXPORT load_doneBuf
562 load_doneBuf ROUT
563
564 STMFD R13!,{R0,R14} ;Save some registers
565 MOV R0,R2 ;Point to the anchor
566 BL flex_extend ;Set the block's correct size
567 LDMFD R13!,{R0,PC}^ ;Return to caller
568
569 LTORG
570
571 ; --- load_file ---
572 ;
573 ; On entry: R1 == pointer to filename to load
574 ; R2 == pointer to flex anchor
575 ;
576 ; On exit: R0 == size of file loaded
577 ; May return an error
578 ;
579 ; Use: Loads a named file into a flex block for your delectation.
580
581 EXPORT load_file
582 load_file ROUT
583
584 STMFD R13!,{R0-R6,R14} ;Save some registers
585 MOV R6,R2 ;Keep the flex anchor safe
586
587 ; --- Find the file information ---
588
589 MOV R0,#17 ;Read file information
590 SWI XOS_File ;Find the file's size
591 BVS %90load_file ;If it failed, handle error
592 TST R0,#1 ;Is the object a file?
593 BEQ %80load_file ;No -- get an error for it
594 STR R4,[R13,#0] ;Save the file size in R0
595
596 ; --- Allocate the flex block ---
597
598 MOV R1,R4 ;Get the object size in R1
599 MOV R0,R6 ;Point to caller's anchor
600 BL flex_alloc ;Try to allocate the block
601 BLCS alloc_error ;No memory -- get the message
602 BCS %90load_file ;If it failed, handle error
603
604 ; --- Load file into the flex block ---
605
606 MOV R0,#16 ;Load the file
607 LDR R1,[R13,#4] ;Load the filename address
608 LDR R2,[R6,#0] ;Load the flex anchor
609 MOV R3,#0 ;Load into my buffer please
610 SWI XOS_File ;Try to do the load op
611 BVS %85load_file ;If it failed, tidy up
612 LDMFD R13!,{R0-R6,R14} ;Unstack registers
613 BICS PC,R14,#V_flag ;And return with no error
614
615 ; --- We found a bad object type ---
616
617 80load_file MOV R2,R0 ;Get object type in R2
618 MOV R0,#19 ;Get the error message
619 SWI XOS_File ;Return pointer in R0
620 B %90load_file ;Handle error in usual way
621
622 ; --- Tidy up after various errors ---
623
624 85load_file MOV R1,R0 ;Look after the error pointer
625 MOV R0,R6 ;Point to the flex anchor
626 BL flex_free ;Free up all tht memory
627 MOV R14,#0 ;Get a zero word
628 STR R14,[R6,#0] ;And zero out the anchor
629 MOV R0,R1 ;Restore the error pointer
630
631 90load_file ADD R13,R13,#4 ;Don't restore R0 on exit
632 LDMFD R13!,{R1-R6,R14} ;Unstack registers
633 ORRS PC,R14,#V_flag ;And return with the error
634
635 LTORG
636
637 load__wSpace DCD 0
638
639 ;----- User entry points ----------------------------------------------------
640
641 ^ 0
642
643 lEntry__initBuf # 4 ;Create a load buffer
644 ;On entry:
645 ; R0 == ptr to `filename'
646 ; R1 == estimated file size
647 ; R2 == 0
648 ;On exit:
649 ; R0 == ptr to buffer start
650 ; R1 == ptr to buffer end
651 ; R2 == buffer `handle'
652 ; R10 may be updated
653
654 lEntry__killBuf # 4 ;Destroy the load buffer
655 ;On entry:
656 ; R0 == ptr to buffer start
657 ; R1 == ptr to buffer end
658 ; R2 == buffer `handle'
659 ;On exit:
660 ; --
661
662 lEntry__extend # 4 ;Extend the load buffer
663 ;On entry:
664 ; R0 == ptr to buffer start
665 ; R1 == ptr to buffer end
666 ; R2 == buffer `handle'
667 ;On exit:
668 ; R0-R2 updated
669
670 lEntry__doneBuf # 4 ;All data is now loaded
671 ;On entry:
672 ; R0 == ptr to `filename'
673 ; R1 == total size of data
674 ; R2 == buffer `handle'
675 ;On exit:
676 ; --
677
678 lEntry__file # 4 ;Load data from a file
679 ;On entry:
680 ; R0 == ptr to `filename'
681 ; R1 == file to load
682 ; R2 == 0 if file unsafe
683 ;On exit:
684 ; R10 may be updated
685
686 lEntry__done # 4 ;Completed loading
687 ;On entry:
688 ; R0 == ptr to `filename'
689 ; R1 == safeness indicator
690 ;On exit:
691 ; --
692
693 lEntry__failed # 4 ;Failed to load file
694 ;On entry:
695 ; R0 == pointer to error
696 ; R1 == 1
697 ;On exit:
698 ; --
699
700 ; --- Explanation ---
701 ;
702 ; Loading is several orders of magnitude harder than saving, at a guess.
703 ; I've tried to make it fairly straightforward here -- there are a few
704 ; standard routines provided for simple things like loading into a flex
705 ; block, and a coroutine-based system for unified RAM/file transfer is
706 ; available.
707 ;
708 ; Like saving, loading is based around a table of branch instructions which
709 ; perform application-specific actions during the load operation. All the
710 ; message passing protocol is hidden away, and all you have to do is write
711 ; the entries for the table.
712 ;
713 ; If you want to support RAM-transfer, you must provide three buffer
714 ; handling routines:
715 ;
716 ; * initBuf is called when load is attempting to start a RAM transfer with
717 ; the saving application. It should create a buffer of appropriate size
718 ; (possibly based on the estimated file size already given). You can
719 ; declare a buffer handle at this point, which is passed to all other
720 ; routines that need to deal with the buffer. It may return an error.
721 ;
722 ; If you can't handle RAM transfer, you should replace the branch
723 ; instruction here with a null word.
724 ;
725 ; * extend is called if the previous buffer was filled and there is more
726 ; data to come. The address of the previous buffer is returned to you,
727 ; so either you can process it there and then, or extend the buffer in
728 ; some way. You just have to return a new area of memory to fill with
729 ; data. It may return an error.
730 ;
731 ; * doneBuf is called when all the data has been loaded, so that the buffer
732 ; can be set to the exact right size.
733 ;
734 ; * killBuf is called if the attempt to load via RAM transfer failed and
735 ; the buffer has to be destroyed. It is always called whenever there is
736 ; a fault during RAM transfer, even if one of your other entry points
737 ; raised the error.
738 ;
739 ; * file is called if you have to load a file from the filing system, either
740 ; because RAM transfer failed or because you received a direct load from
741 ; the Filer. It may return an error.
742 ;
743 ; * done is called when the data transfer is successfully completed.
744 ;
745 ; * failed is called when the data transfer fails due to an error.
746
747 ;----- Workspace ------------------------------------------------------------
748
749 ^ 0,R12
750 load__wStart # 0
751
752 load__state # 4 ;The current state (1 byte)
753
754 load__entries # 4 ;Pointer to entry pt block
755 load__R10 # 4 ;Client's R10 value
756 load__R12 # 4 ;Client's R12 value
757
758 load__buffStart # 4 ;The buffer's start address
759 load__buffSize # 4 ;And its size
760 load__buffHnd # 4 ;Client's buffer handle
761
762 load__totalSize # 4 ;How much data we've received
763
764 load__message # 44 ;The original load/save msg
765 load__name # 212 ;The file's apparent name
766
767 load__wSize EQU {VAR}-load__wStart
768
769 ; --- States ---
770 ;
771 ; These have been carefully arranged so that we can return
772 ; the safeness flag to various routines. If we only
773 ; consider files, then the state /is/ the safeness flag.
774 ; Otherwise we only use the bottom bit of the state.
775
776 lState__scrap EQU 0 ;We're doing scrap transfer
777 lState__file EQU 1 ;We're loading from a file
778 lState__test EQU 2 ;We're testing RAM transfer
779 lState__ram EQU 4 ;We're doing RAM transfer
780
781 AREA |Sapphire$$LibData|,CODE,READONLY
782
783 DCD load__wSize
784 DCD load__wSpace
785 DCD 256
786 DCD 0
787
788 ;----- That's all, folks ----------------------------------------------------
789
790 END