; ; chunk.s ; ; Loading and management of options chunks (MDW) ; ; © 1995-1998 Straylight ; ;----- Licensing note ------------------------------------------------------- ; ; This file is part of Straylight's Sapphire library. ; ; Sapphire is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2, or (at your option) ; any later version. ; ; Sapphire is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with Sapphire. If not, write to the Free Software Foundation, ; 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ;----- Standard header ------------------------------------------------------ GET libs:header GET libs:swis GET libs:stream ;----- External dependencies ------------------------------------------------ GET sapphire:alloc GET sapphire:fastMove GET sapphire:flex GET sapphire:string GET sapphire:xfer.xsave ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ; --- chunk_create --- ; ; On entry: -- ; ; On exit: R0 == chunk file handle ; May return an error ; ; Use: Creates a new chunk file structure and returns a handle to ; it. EXPORT chunk_create chunk_create ROUT STMFD R13!,{R14} ;Save a register MOV R0,#cBase__size ;Get the size of the block BL alloc ;Try to allocate the block BLCS alloc_error ;If it failed, get error MOVCC R14,#0 ;Otherwise make list empty STRCC R14,[R0,#cBase__list] ;By clearing the link LDMFD R13!,{R14} ;Restore link register BICCCS PC,R14,#V_flag ;If OK, return without error ORRCSS PC,R14,#V_flag ;Else return the error LTORG ; --- chunk_destroy --- ; ; On entry: R0 == chunk file handle ; ; On exit: -- ; ; Use: Removes a chunk file structure from memory. Chunk data in ; flex blocks is freed; chunk claimers who free flex blocks ; should clear the anchors to 0. EXPORT chunk_destroy chunk_destroy ROUT STMFD R13!,{R0-R2,R14} ;Save some registers MOV R2,R0 ;Look after the chunk base LDR R1,[R2,#0] ;Load the first chunk block 00chunk_destroy MOVS R0,R1 ;Is this the end of the list? BEQ %f00chunk_destroy ;Yes -- stop the loop LDR R14,[R0,#0] ;Load the flex anchor CMP R14,#0 ;Is there a block here? BLNE flex_free ;Yes -- free it then LDR R1,[R0,#cLink__next] ;Load the next block BL free ;Free this block B %b00chunk_destroy ;And loop back 00chunk_destroy MOV R0,R2 ;Point to the chunk base BL free ;Don't need that any more LDMFD R13!,{R0-R2,PC}^ ;Return to caller LTORG ; --- chunk_claim --- ; ; On entry: R0 == chunk file handle ; R1 == pointer to chunk name ; R2 == pointer to saver routine, or 0 for none, or -1 for no ; change ; R3 == R10 value to pass to saver ; R4 == R12 value to pass to saver ; ; On exit: R1 == chunk handle/anchor ; CS if the chunk already existed ; May return an error ; ; Use: Claims a chunk, installing a save handler for it. The chunk ; handle returned is actually the address of a flex anchor for ; the chunk's data (use flex_size to find the block's size). ; If the save handle is 0, the data in the flex block (which ; may be modified) is saved directly from the block. Otherwise ; the save routine is expected to save its data, using xsave. ; ; The anchor is followed by 3 unused words -- you can use them ; for whatever you want. ; ; Warning: this routine may move flex blocks. EXPORT chunk_claim chunk_claim ROUT BIC R14,R14,#V_flag ;Clear V and hope... STMFD R13!,{R0,R5,R6,R14} ;Save some registers SUB R5,R0,#cLink__next ;Look after the handle 00chunk_claim LDR R6,[R5,#cLink__next] ;Load the next pointer CMP R6,#0 ;Is this the very end? BEQ %f00chunk_claim ;Yes -- create a new chunk ADD R0,R6,#cLink__name ;Point to the chunk's name BL str_icmp ;Compare the names MOVNE R5,R6 ;No match -- move on BNE %b00chunk_claim ;Loop back to start ; --- Found a matching chunk --- CMP R2,#-1 ;Do we change the saver? ADDNE R14,R6,#cLink__saver ;No -- point to saver info STMNEIA R14,{R2-R4} ;And stuff the values in MOV R1,R6 ;Point to the anchor LDMFD R13!,{R0,R5,R6,R14} ;Restore registers ORRS PC,R14,#C_flag ;And return to caller ; --- No match -- create a new chunk --- 00chunk_claim MOV R0,#cLink__size ;Get the block size I need BL alloc ;Try to allocate the memory BLCS alloc_error ;If it failed, get error BCS %99chunk_claim ;And return the failure MOV R6,R0 ;Get the chunk handle ADD R0,R6,#cLink__name ;Point to the name field BL str_cpy ;Fill in the new name ; --- Allocate an empty flex block for it --- MOV R1,#0 ;Allocate no memory MOV R0,R6 ;Point to the anchor BL flex_alloc ;Allocate the block BLCS alloc_error ;If it failed, get error BCS %98chunk_claim ;And tidy up on the way out ; --- Fill in the rest of the chunk --- MOV R14,#0 ;Fill in the next field STR R14,[R6,#cLink__next] ;Clear the next pointer STR R6,[R5,#cLink__next] ;And link in the new chunk STR R14,[R6,#cLink__flags] ;Clear flags initially CMP R2,#-1 ;Do we change the saver? MOVEQ R2,#0 ;No -- then leave none there ADD R14,R6,#cLink__saver ;Point to saver info STMIA R14,{R2-R4} ;And stuff the values in MOV R1,R6 ;Point to the anchor LDMFD R13!,{R0,R5,R6,R14} ;Restore registers BICS PC,R14,#C_flag ;And return to caller ; --- Tidy up on the way out --- 98chunk_claim MOV R5,R0 ;Look after the error MOV R0,R6 ;Point to new chunk block BL free ;Free the block MOV R0,R5 ;Get the error pointer back 99chunk_claim ADD R13,R13,#4 ;Don't restore R0 on exit LDMFD R13!,{R5,R6,R14} ;Restore registers ORRS PC,R14,#V_flag ;And return the error LTORG ; --- chunk_makeBinary --- ; ; On entry: R0 == chunk file handle ; R1 == chunk handle ; ; On exit: -- ; ; Use: Marks a given chunk as containing binary data. EXPORT chunk_makeBinary chunk_makeBinary ROUT STMFD R13!,{R14} ;Save a register LDR R14,[R1,#cLink__flags] ;Load the flags word ORR R14,R14,#clFlag__binary ;Set the binary flag STR R14,[R1,#cLink__flags] ;Save the flags back again LDMFD R13!,{PC}^ ;And return to caller LTORG ; --- chunk_read --- ; ; On entry: R0 == chunk file handle ; R1 == address of a flex anchor ; ; On exit: May return an error ; ; Use: Merges the data contained in the flex block with that already ; in the chunk file. If the chunk file is empty, this is ; equivalent to a load. Data from the flex block is appended ; to chunks already loaded where appropriate. ; ; Warning: this routine may move flex blocks. EXPORT chunk_read chunk_read ROUT STMFD R13!,{R0-R9,R14} ;Save some registers LDR R8,[R1,#0] ;Load the block address MOV R7,R0 ;Look after the chunk handle MOV R0,R1 ;Point to the anchor BL flex_size ;Read the block's size ADD R9,R8,R0 ;And find the limit pointer ; --- Find the first chunk --- ; ; There'll probably be some comments at the top -- we don't ; care about them. 10chunk_read MOV R2,#&0A ;Say this is a new line 00chunk_read CMP R8,R9 ;Have we reached the end? BCS %90chunk_read ;Yes -- nothing to read LDRB R1,[R8],#1 ;Load the next byte CMP R2,#&0A ;Is this a new line? CMPEQ R1,#'[' ;And is this a chunk start? MOVNE R2,R1 ;No -- stash previous char BNE %b00chunk_read ;And skip back for more ; --- Read the next chunk --- MOV R2,R11 ;Copy name to scratchpad 00chunk_read CMP R8,R9 ;Reached the end yet? BCS %90chunk_read ;Yes -- ignore bogus header LDRB R1,[R8],#1 ;Get a byte of name CMP R1,#']' ;Is it the end of it? MOVEQ R1,#0 ;Yes -- terminate the name STRB R1,[R2],#1 ;Store this byte away BNE %b00chunk_read ;Keep on going to the end STRB R1,[R11,#19] ;Make sure name's <12 chars ; --- Ignore the rest of this line --- MOV R3,#0 ;Clear size just in case 00chunk_read CMP R8,R9 ;Reached the end yet? BCS %f05chunk_read ;Yes -- stop here then LDRB R1,[R8],#1 ;Load the next byte out CMP R1,#&0A ;Is this the end of the line? BNE %b00chunk_read ;No -- skip back then ; --- Work out how big the chunk is --- AND R0,R8,#3 ;Get the non-word-alignedness BIC R1,R8,#3 ;And round down nicely LDMIA R1,{R2-R4} ;Load next two fullwords MOVS R0,R0,LSL #3 ;Turn bytes into bits RSB R14,R0,#32 ;And work out other shift MOVNE R2,R2,LSR R0 ;Shift down lowest word ORRNE R2,R2,R3,LSL R14 ;Copy in bottom of next word MOVNE R3,R3,LSR R0 ;Shift rest of this one down ORRNE R3,R3,R4,LSL R14 ;Copy in bottom of top word LDR R14,=chunk__binMark ;Is this the binary marker? CMP R2,R14 ;Is this a binary chunk? MOVNE R5,#0 ;No -- don't set any flags MOVEQ R5,#clFlag__binary ;Yes -- set the binary flag BNE %f00chunk_read ;No -- search for next chunk ADD R8,R8,#8 ;Skip past those two words ADD R8,R8,R3 ;And move on to end of chunk B %f05chunk_read ;And skip on (size in R3) ; --- Now search for a new chunk --- 00chunk_read MOV R3,#0 ;No bytes counted so far 00chunk_read CMP R8,R9 ;Reached the end yet? BCS %f05chunk_read ;Yes -- stop here then LDRB R0,[R8],#1 ;Load the next byte CMP R1,#&0A ;Is this a new line? CMPEQ R0,#'[' ;And is this a new chunk? ADDNE R3,R3,#1 ;No -- bump the counter MOVNE R1,R0 ;Remember the last character BNE %b00chunk_read ;And go back found SUB R8,R8,#1 ;Go back to the newline char ; --- Now claim a chunk for us --- 05chunk_read MOV R0,R7 ;Get the chunk handle MOV R1,R11 ;Point to the chunk's name MOV R2,#-1 ;Don't care about savers FSAVE "R8,R9" ;Stash flex pointers BL chunk_claim ;Claim this block please BVS %99chunk_read ;It failed -- tidy up MOV R6,R1 ;Look after the link block LDR R14,[R6,#cLink__flags] ;Load the flags word ORR R14,R14,R5 ;Set any flags we need STR R14,[R6,#cLink__flags] ;Save the flags back again ; --- Grow the flex block and copy --- MOV R0,R6 ;Point to the anchor BL flex_size ;Read the block's size MOV R5,R0 ;Look after this ADD R1,R0,R3 ;Add on a little size MOV R0,R6 ;Point to the anchor again BL flex_extend ;Make the block bigger BLCS alloc_error ;If it failed, moan a lot BCS %99chunk_read ;And go off in a huff LDR R0,[R6,#0] ;Load the block base ADD R0,R0,R5 ;Find the destination addr FLOAD "R8,R9" ;Reload my saved pointers SUB R1,R8,R3 ;Reclaim my data MOV R2,R3 ;Set the amount to copy BL fastMove ;And copy it all across ; --- That's done -- now do the rest --- B %10chunk_read ;Go back to the top again ; --- We made it -- huzzah! --- 90chunk_read LDMFD R13!,{R0-R9,R14} ;Restore registers BICS PC,R14,#V_flag ;And return with no error ; --- Something went awry --- 99chunk_read FLOAD "R8,R9" ;Restore regs from flex stack ADD R13,R13,#4 ;Don't restore R0 on exit LDMFD R13!,{R1-R9,R14} ;Restore registers ORRS PC,R14,#V_flag ;And return the error LTORG ; --- chunk_enum --- ; ; On entry: R0 == chunk file handle ; R1 == 0 for first call or continuation value ; ; On exit: CC if this isn't over yet, and ; R1 == continuation value for next call ; R2 == pointer to chunk name ; else CS and ; R1 == 0 ; R2 preserved ; ; Use: Allows you to enumerate the chunks in a chunk file structure. EXPORT chunk_enum chunk_enum ROUT CMP R1,#0 ;Is this a new call? SUBEQ R1,R0,#cLink__next ;Yes -- set up continuation LDR R1,[R1,#cLink__next] ;Move onto the next block CMP R1,#0 ;Is this at the end? ADDNE R2,R1,#cLink__name ;No -- point to the name BICNES PC,R14,#C_flag ;And return OK ORREQS PC,R14,#C_flag ;Otherwise say it's over LTORG ; --- chunk_save --- ; ; On entry: R0 == chunk file handle ; ; On exit: May return an error ; ; Use: Saves a chunk file to xsave's current output. EXPORT chunk_save chunk_save ROUT STMFD R13!,{R0-R4,R10,R12,R14} ;Save a few registers LDR R4,[R0,#0] ;Load the list base 05chunk_save CMP R4,#0 ;Is there nothing to do? BEQ %90chunk_save ;That's OK -- do nothing then ; --- Write out this chunk's name --- MOV R0,#'[' ;Output a `[' character BL xsave_byte ;Write that OK BVS %99chunk_save ;Die if that went wrong ADD R1,R4,#cLink__name ;Point to the name 00chunk_save LDRB R0,[R1],#1 ;Load the next byte CMP R0,#0 ;Is this the end yet? MOVEQ R0,#']' ;Yes -- write terminator BL xsave_byte ;Write that out BVS %99chunk_save ;Die if that went wrong BNE %b00chunk_save ;And if there's more, do it ; --- Write any necessary preamble --- MOV R0,#&0A ;Start a new line BL xsave_byte ;Write the newline byte BVS %99chunk_save ;Die if that went wrong LDR R14,[R4,#cLink__flags] ;Load the flags word TST R14,#clFlag__binary ;Is this block binary? LDRNE R0,=chunk__binMark ;Yes -- write a bin marker BLNE xsave_word ;Yes -- write a whole word BVS %99chunk_save ;Die if that went wrong ; --- Now work out how to write this block --- ADD R14,R4,#cLink__saver ;Point to saver info LDMIA R14,{R2,R10,R12} ;Load that lot out CMP R2,#0 ;Is this a real saver? BEQ %10chunk_save ;No -- skip on then MOV R0,R4 ;Point to the anchor MOV R14,PC ;Set up return address MOV PC,R2 ;And call the saver LDRVC R4,[R4,#cLink__next] ;Find the next block BVC %05chunk_save ;And loop back to the start BVS %99chunk_save ;Die if that went wrong ; --- We must save the chunk ourselves --- 10chunk_save LDR R14,[R4,#cLink__flags] ;Load the flags word TST R14,#clFlag__binary ;Is this block binary? MOV R0,R4 ;If OK, get flex anchor BL flex_size ;Find the block's size BLNE xsave_word ;If binary, write that out MOVVC R1,R0 ;Look after that LDRVC R0,[R4,#0] ;Load the flex base address BLVC xsave_block ;And write out the whole lot BVS %99chunk_save ;Die if anything went wrong MOVNE R0,#&0A ;Write a final line end BLNE xsave_byte ;Just to make sure BLNE xsave_byte ;Leave blank line under bin LDRVC R4,[R4,#cLink__next] ;Find the next block BVC %05chunk_save ;And loop back to the start BVS %99chunk_save ;Die if anything went wrong ; --- Finished writing the file --- 90chunk_save LDMFD R13!,{R0-R4,R10,R12,R14} ;Restore registers BICS PC,R14,#V_flag ;Return error-free ; --- Something got messed up --- 99chunk_save ADD R13,R13,#4 ;Don't restore R0 LDMFD R13!,{R1-R4,R10,R12,R14} ;Restore other registers ORRS PC,R14,#V_flag ;And return the error LTORG ;----- Data structures ------------------------------------------------------ ; --- Chunk base --- ^ 0 cBase__list # 4 ;List of chunks cBase__size # 0 ; --- Chunk link blocks --- ^ 0 cLink__anchor # 4 ;Anchor for flex block cLink__userData # 12 ;12 bytes of user data cLink__next # 4 ;Link to next block cLink__flags # 4 ;Interesting things cLink__name # 20 ;Name of this chunk cLink__saver # 12 ;Saver routine for chunk cLink__size # 0 ; --- Flags --- clFlag__binary EQU (1<<0) ;Chunk contains binary data ; --- Other magic values --- chunk__binMark EQU &6E694200 ;Magic word for binary data ;----- That's all, folks ---------------------------------------------------- END