Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / chunk
1 ;
2 ; chunk.s
3 ;
4 ; Loading and management of options chunks (MDW)
5 ;
6 ; © 1995-1998 Straylight
7 ;
8
9 ;----- Licensing note -------------------------------------------------------
10 ;
11 ; This file is part of Straylight's Sapphire library.
12 ;
13 ; Sapphire is free software; you can redistribute it and/or modify
14 ; it under the terms of the GNU General Public License as published by
15 ; the Free Software Foundation; either version 2, or (at your option)
16 ; any later version.
17 ;
18 ; Sapphire is distributed in the hope that it will be useful,
19 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ; GNU General Public License for more details.
22 ;
23 ; You should have received a copy of the GNU General Public License
24 ; along with Sapphire. If not, write to the Free Software Foundation,
25 ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26
27 ;----- Standard header ------------------------------------------------------
28
29 GET libs:header
30 GET libs:swis
31
32 GET libs:stream
33
34 ;----- External dependencies ------------------------------------------------
35
36 GET sapphire:alloc
37 GET sapphire:fastMove
38 GET sapphire:flex
39 GET sapphire:string
40
41 GET sapphire:xfer.xsave
42
43 ;----- Main code ------------------------------------------------------------
44
45 AREA |Sapphire$$Code|,CODE,READONLY
46
47 ; --- chunk_create ---
48 ;
49 ; On entry: --
50 ;
51 ; On exit: R0 == chunk file handle
52 ; May return an error
53 ;
54 ; Use: Creates a new chunk file structure and returns a handle to
55 ; it.
56
57 EXPORT chunk_create
58 chunk_create ROUT
59
60 STMFD R13!,{R14} ;Save a register
61 MOV R0,#cBase__size ;Get the size of the block
62 BL alloc ;Try to allocate the block
63 BLCS alloc_error ;If it failed, get error
64 MOVCC R14,#0 ;Otherwise make list empty
65 STRCC R14,[R0,#cBase__list] ;By clearing the link
66 LDMFD R13!,{R14} ;Restore link register
67 BICCCS PC,R14,#V_flag ;If OK, return without error
68 ORRCSS PC,R14,#V_flag ;Else return the error
69
70 LTORG
71
72 ; --- chunk_destroy ---
73 ;
74 ; On entry: R0 == chunk file handle
75 ;
76 ; On exit: --
77 ;
78 ; Use: Removes a chunk file structure from memory. Chunk data in
79 ; flex blocks is freed; chunk claimers who free flex blocks
80 ; should clear the anchors to 0.
81
82 EXPORT chunk_destroy
83 chunk_destroy ROUT
84
85 STMFD R13!,{R0-R2,R14} ;Save some registers
86 MOV R2,R0 ;Look after the chunk base
87 LDR R1,[R2,#0] ;Load the first chunk block
88
89 00chunk_destroy MOVS R0,R1 ;Is this the end of the list?
90 BEQ %f00chunk_destroy ;Yes -- stop the loop
91 LDR R14,[R0,#0] ;Load the flex anchor
92 CMP R14,#0 ;Is there a block here?
93 BLNE flex_free ;Yes -- free it then
94 LDR R1,[R0,#cLink__next] ;Load the next block
95 BL free ;Free this block
96 B %b00chunk_destroy ;And loop back
97
98 00chunk_destroy MOV R0,R2 ;Point to the chunk base
99 BL free ;Don't need that any more
100 LDMFD R13!,{R0-R2,PC}^ ;Return to caller
101
102 LTORG
103
104 ; --- chunk_claim ---
105 ;
106 ; On entry: R0 == chunk file handle
107 ; R1 == pointer to chunk name
108 ; R2 == pointer to saver routine, or 0 for none, or -1 for no
109 ; change
110 ; R3 == R10 value to pass to saver
111 ; R4 == R12 value to pass to saver
112 ;
113 ; On exit: R1 == chunk handle/anchor
114 ; CS if the chunk already existed
115 ; May return an error
116 ;
117 ; Use: Claims a chunk, installing a save handler for it. The chunk
118 ; handle returned is actually the address of a flex anchor for
119 ; the chunk's data (use flex_size to find the block's size).
120 ; If the save handle is 0, the data in the flex block (which
121 ; may be modified) is saved directly from the block. Otherwise
122 ; the save routine is expected to save its data, using xsave.
123 ;
124 ; The anchor is followed by 3 unused words -- you can use them
125 ; for whatever you want.
126 ;
127 ; Warning: this routine may move flex blocks.
128
129 EXPORT chunk_claim
130 chunk_claim ROUT
131
132 BIC R14,R14,#V_flag ;Clear V and hope...
133 STMFD R13!,{R0,R5,R6,R14} ;Save some registers
134 SUB R5,R0,#cLink__next ;Look after the handle
135
136 00chunk_claim LDR R6,[R5,#cLink__next] ;Load the next pointer
137 CMP R6,#0 ;Is this the very end?
138 BEQ %f00chunk_claim ;Yes -- create a new chunk
139 ADD R0,R6,#cLink__name ;Point to the chunk's name
140 BL str_icmp ;Compare the names
141 MOVNE R5,R6 ;No match -- move on
142 BNE %b00chunk_claim ;Loop back to start
143
144 ; --- Found a matching chunk ---
145
146 CMP R2,#-1 ;Do we change the saver?
147 ADDNE R14,R6,#cLink__saver ;No -- point to saver info
148 STMNEIA R14,{R2-R4} ;And stuff the values in
149 MOV R1,R6 ;Point to the anchor
150 LDMFD R13!,{R0,R5,R6,R14} ;Restore registers
151 ORRS PC,R14,#C_flag ;And return to caller
152
153 ; --- No match -- create a new chunk ---
154
155 00chunk_claim MOV R0,#cLink__size ;Get the block size I need
156 BL alloc ;Try to allocate the memory
157 BLCS alloc_error ;If it failed, get error
158 BCS %99chunk_claim ;And return the failure
159 MOV R6,R0 ;Get the chunk handle
160 ADD R0,R6,#cLink__name ;Point to the name field
161 BL str_cpy ;Fill in the new name
162
163 ; --- Allocate an empty flex block for it ---
164
165 MOV R1,#0 ;Allocate no memory
166 MOV R0,R6 ;Point to the anchor
167 BL flex_alloc ;Allocate the block
168 BLCS alloc_error ;If it failed, get error
169 BCS %98chunk_claim ;And tidy up on the way out
170
171 ; --- Fill in the rest of the chunk ---
172
173 MOV R14,#0 ;Fill in the next field
174 STR R14,[R6,#cLink__next] ;Clear the next pointer
175 STR R6,[R5,#cLink__next] ;And link in the new chunk
176 STR R14,[R6,#cLink__flags] ;Clear flags initially
177 CMP R2,#-1 ;Do we change the saver?
178 MOVEQ R2,#0 ;No -- then leave none there
179 ADD R14,R6,#cLink__saver ;Point to saver info
180 STMIA R14,{R2-R4} ;And stuff the values in
181
182 MOV R1,R6 ;Point to the anchor
183 LDMFD R13!,{R0,R5,R6,R14} ;Restore registers
184 BICS PC,R14,#C_flag ;And return to caller
185
186 ; --- Tidy up on the way out ---
187
188 98chunk_claim MOV R5,R0 ;Look after the error
189 MOV R0,R6 ;Point to new chunk block
190 BL free ;Free the block
191 MOV R0,R5 ;Get the error pointer back
192
193 99chunk_claim ADD R13,R13,#4 ;Don't restore R0 on exit
194 LDMFD R13!,{R5,R6,R14} ;Restore registers
195 ORRS PC,R14,#V_flag ;And return the error
196
197 LTORG
198
199 ; --- chunk_makeBinary ---
200 ;
201 ; On entry: R0 == chunk file handle
202 ; R1 == chunk handle
203 ;
204 ; On exit: --
205 ;
206 ; Use: Marks a given chunk as containing binary data.
207
208 EXPORT chunk_makeBinary
209 chunk_makeBinary ROUT
210
211 STMFD R13!,{R14} ;Save a register
212 LDR R14,[R1,#cLink__flags] ;Load the flags word
213 ORR R14,R14,#clFlag__binary ;Set the binary flag
214 STR R14,[R1,#cLink__flags] ;Save the flags back again
215 LDMFD R13!,{PC}^ ;And return to caller
216
217 LTORG
218
219 ; --- chunk_read ---
220 ;
221 ; On entry: R0 == chunk file handle
222 ; R1 == address of a flex anchor
223 ;
224 ; On exit: May return an error
225 ;
226 ; Use: Merges the data contained in the flex block with that already
227 ; in the chunk file. If the chunk file is empty, this is
228 ; equivalent to a load. Data from the flex block is appended
229 ; to chunks already loaded where appropriate.
230 ;
231 ; Warning: this routine may move flex blocks.
232
233 EXPORT chunk_read
234 chunk_read ROUT
235
236 STMFD R13!,{R0-R9,R14} ;Save some registers
237 LDR R8,[R1,#0] ;Load the block address
238 MOV R7,R0 ;Look after the chunk handle
239 MOV R0,R1 ;Point to the anchor
240 BL flex_size ;Read the block's size
241 ADD R9,R8,R0 ;And find the limit pointer
242
243 ; --- Find the first chunk ---
244 ;
245 ; There'll probably be some comments at the top -- we don't
246 ; care about them.
247
248 10chunk_read MOV R2,#&0A ;Say this is a new line
249 00chunk_read CMP R8,R9 ;Have we reached the end?
250 BCS %90chunk_read ;Yes -- nothing to read
251 LDRB R1,[R8],#1 ;Load the next byte
252 CMP R2,#&0A ;Is this a new line?
253 CMPEQ R1,#'[' ;And is this a chunk start?
254 MOVNE R2,R1 ;No -- stash previous char
255 BNE %b00chunk_read ;And skip back for more
256
257 ; --- Read the next chunk ---
258
259 MOV R2,R11 ;Copy name to scratchpad
260 00chunk_read CMP R8,R9 ;Reached the end yet?
261 BCS %90chunk_read ;Yes -- ignore bogus header
262 LDRB R1,[R8],#1 ;Get a byte of name
263 CMP R1,#']' ;Is it the end of it?
264 MOVEQ R1,#0 ;Yes -- terminate the name
265 STRB R1,[R2],#1 ;Store this byte away
266 BNE %b00chunk_read ;Keep on going to the end
267 STRB R1,[R11,#19] ;Make sure name's <12 chars
268
269 ; --- Ignore the rest of this line ---
270
271 MOV R3,#0 ;Clear size just in case
272 00chunk_read CMP R8,R9 ;Reached the end yet?
273 BCS %f05chunk_read ;Yes -- stop here then
274 LDRB R1,[R8],#1 ;Load the next byte out
275 CMP R1,#&0A ;Is this the end of the line?
276 BNE %b00chunk_read ;No -- skip back then
277
278 ; --- Work out how big the chunk is ---
279
280 AND R0,R8,#3 ;Get the non-word-alignedness
281 BIC R1,R8,#3 ;And round down nicely
282 LDMIA R1,{R2-R4} ;Load next two fullwords
283 MOVS R0,R0,LSL #3 ;Turn bytes into bits
284 RSB R14,R0,#32 ;And work out other shift
285 MOVNE R2,R2,LSR R0 ;Shift down lowest word
286 ORRNE R2,R2,R3,LSL R14 ;Copy in bottom of next word
287 MOVNE R3,R3,LSR R0 ;Shift rest of this one down
288 ORRNE R3,R3,R4,LSL R14 ;Copy in bottom of top word
289
290 LDR R14,=chunk__binMark ;Is this the binary marker?
291 CMP R2,R14 ;Is this a binary chunk?
292 MOVNE R5,#0 ;No -- don't set any flags
293 MOVEQ R5,#clFlag__binary ;Yes -- set the binary flag
294 BNE %f00chunk_read ;No -- search for next chunk
295
296 ADD R8,R8,#8 ;Skip past those two words
297 ADD R8,R8,R3 ;And move on to end of chunk
298 B %f05chunk_read ;And skip on (size in R3)
299
300 ; --- Now search for a new chunk ---
301
302 00chunk_read MOV R3,#0 ;No bytes counted so far
303 00chunk_read CMP R8,R9 ;Reached the end yet?
304 BCS %f05chunk_read ;Yes -- stop here then
305 LDRB R0,[R8],#1 ;Load the next byte
306 CMP R1,#&0A ;Is this a new line?
307 CMPEQ R0,#'[' ;And is this a new chunk?
308 ADDNE R3,R3,#1 ;No -- bump the counter
309 MOVNE R1,R0 ;Remember the last character
310 BNE %b00chunk_read ;And go back found
311
312 SUB R8,R8,#1 ;Go back to the newline char
313
314 ; --- Now claim a chunk for us ---
315
316 05chunk_read MOV R0,R7 ;Get the chunk handle
317 MOV R1,R11 ;Point to the chunk's name
318 MOV R2,#-1 ;Don't care about savers
319 FSAVE "R8,R9" ;Stash flex pointers
320 BL chunk_claim ;Claim this block please
321 BVS %99chunk_read ;It failed -- tidy up
322 MOV R6,R1 ;Look after the link block
323
324 LDR R14,[R6,#cLink__flags] ;Load the flags word
325 ORR R14,R14,R5 ;Set any flags we need
326 STR R14,[R6,#cLink__flags] ;Save the flags back again
327
328 ; --- Grow the flex block and copy ---
329
330 MOV R0,R6 ;Point to the anchor
331 BL flex_size ;Read the block's size
332 MOV R5,R0 ;Look after this
333 ADD R1,R0,R3 ;Add on a little size
334 MOV R0,R6 ;Point to the anchor again
335 BL flex_extend ;Make the block bigger
336 BLCS alloc_error ;If it failed, moan a lot
337 BCS %99chunk_read ;And go off in a huff
338
339 LDR R0,[R6,#0] ;Load the block base
340 ADD R0,R0,R5 ;Find the destination addr
341 FLOAD "R8,R9" ;Reload my saved pointers
342 SUB R1,R8,R3 ;Reclaim my data
343 MOV R2,R3 ;Set the amount to copy
344 BL fastMove ;And copy it all across
345
346 ; --- That's done -- now do the rest ---
347
348 B %10chunk_read ;Go back to the top again
349
350 ; --- We made it -- huzzah! ---
351
352 90chunk_read LDMFD R13!,{R0-R9,R14} ;Restore registers
353 BICS PC,R14,#V_flag ;And return with no error
354
355 ; --- Something went awry ---
356
357 99chunk_read
358 FLOAD "R8,R9" ;Restore regs from flex stack
359 ADD R13,R13,#4 ;Don't restore R0 on exit
360 LDMFD R13!,{R1-R9,R14} ;Restore registers
361 ORRS PC,R14,#V_flag ;And return the error
362
363 LTORG
364
365 ; --- chunk_enum ---
366 ;
367 ; On entry: R0 == chunk file handle
368 ; R1 == 0 for first call or continuation value
369 ;
370 ; On exit: CC if this isn't over yet, and
371 ; R1 == continuation value for next call
372 ; R2 == pointer to chunk name
373 ; else CS and
374 ; R1 == 0
375 ; R2 preserved
376 ;
377 ; Use: Allows you to enumerate the chunks in a chunk file structure.
378
379 EXPORT chunk_enum
380 chunk_enum ROUT
381
382 CMP R1,#0 ;Is this a new call?
383 SUBEQ R1,R0,#cLink__next ;Yes -- set up continuation
384 LDR R1,[R1,#cLink__next] ;Move onto the next block
385 CMP R1,#0 ;Is this at the end?
386 ADDNE R2,R1,#cLink__name ;No -- point to the name
387 BICNES PC,R14,#C_flag ;And return OK
388 ORREQS PC,R14,#C_flag ;Otherwise say it's over
389
390 LTORG
391
392 ; --- chunk_save ---
393 ;
394 ; On entry: R0 == chunk file handle
395 ;
396 ; On exit: May return an error
397 ;
398 ; Use: Saves a chunk file to xsave's current output.
399
400 EXPORT chunk_save
401 chunk_save ROUT
402
403 STMFD R13!,{R0-R4,R10,R12,R14} ;Save a few registers
404 LDR R4,[R0,#0] ;Load the list base
405 05chunk_save CMP R4,#0 ;Is there nothing to do?
406 BEQ %90chunk_save ;That's OK -- do nothing then
407
408 ; --- Write out this chunk's name ---
409
410 MOV R0,#'[' ;Output a `[' character
411 BL xsave_byte ;Write that OK
412 BVS %99chunk_save ;Die if that went wrong
413
414 ADD R1,R4,#cLink__name ;Point to the name
415 00chunk_save LDRB R0,[R1],#1 ;Load the next byte
416 CMP R0,#0 ;Is this the end yet?
417 MOVEQ R0,#']' ;Yes -- write terminator
418 BL xsave_byte ;Write that out
419 BVS %99chunk_save ;Die if that went wrong
420 BNE %b00chunk_save ;And if there's more, do it
421
422 ; --- Write any necessary preamble ---
423
424 MOV R0,#&0A ;Start a new line
425 BL xsave_byte ;Write the newline byte
426 BVS %99chunk_save ;Die if that went wrong
427
428 LDR R14,[R4,#cLink__flags] ;Load the flags word
429 TST R14,#clFlag__binary ;Is this block binary?
430 LDRNE R0,=chunk__binMark ;Yes -- write a bin marker
431 BLNE xsave_word ;Yes -- write a whole word
432 BVS %99chunk_save ;Die if that went wrong
433
434 ; --- Now work out how to write this block ---
435
436 ADD R14,R4,#cLink__saver ;Point to saver info
437 LDMIA R14,{R2,R10,R12} ;Load that lot out
438 CMP R2,#0 ;Is this a real saver?
439 BEQ %10chunk_save ;No -- skip on then
440 MOV R0,R4 ;Point to the anchor
441 MOV R14,PC ;Set up return address
442 MOV PC,R2 ;And call the saver
443 LDRVC R4,[R4,#cLink__next] ;Find the next block
444 BVC %05chunk_save ;And loop back to the start
445 BVS %99chunk_save ;Die if that went wrong
446
447 ; --- We must save the chunk ourselves ---
448
449 10chunk_save LDR R14,[R4,#cLink__flags] ;Load the flags word
450 TST R14,#clFlag__binary ;Is this block binary?
451
452 MOV R0,R4 ;If OK, get flex anchor
453 BL flex_size ;Find the block's size
454 BLNE xsave_word ;If binary, write that out
455 MOVVC R1,R0 ;Look after that
456 LDRVC R0,[R4,#0] ;Load the flex base address
457 BLVC xsave_block ;And write out the whole lot
458 BVS %99chunk_save ;Die if anything went wrong
459 MOVNE R0,#&0A ;Write a final line end
460 BLNE xsave_byte ;Just to make sure
461 BLNE xsave_byte ;Leave blank line under bin
462 LDRVC R4,[R4,#cLink__next] ;Find the next block
463 BVC %05chunk_save ;And loop back to the start
464 BVS %99chunk_save ;Die if anything went wrong
465
466 ; --- Finished writing the file ---
467
468 90chunk_save LDMFD R13!,{R0-R4,R10,R12,R14} ;Restore registers
469 BICS PC,R14,#V_flag ;Return error-free
470
471 ; --- Something got messed up ---
472
473 99chunk_save ADD R13,R13,#4 ;Don't restore R0
474 LDMFD R13!,{R1-R4,R10,R12,R14} ;Restore other registers
475 ORRS PC,R14,#V_flag ;And return the error
476
477 LTORG
478
479 ;----- Data structures ------------------------------------------------------
480
481 ; --- Chunk base ---
482
483 ^ 0
484 cBase__list # 4 ;List of chunks
485 cBase__size # 0
486
487 ; --- Chunk link blocks ---
488
489 ^ 0
490 cLink__anchor # 4 ;Anchor for flex block
491 cLink__userData # 12 ;12 bytes of user data
492 cLink__next # 4 ;Link to next block
493 cLink__flags # 4 ;Interesting things
494 cLink__name # 20 ;Name of this chunk
495 cLink__saver # 12 ;Saver routine for chunk
496 cLink__size # 0
497
498 ; --- Flags ---
499
500 clFlag__binary EQU (1<<0) ;Chunk contains binary data
501
502 ; --- Other magic values ---
503
504 chunk__binMark EQU &6E694200 ;Magic word for binary data
505
506 ;----- That's all, folks ----------------------------------------------------
507
508 END