; ; msgs.s ; ; Message file handling (MDW) ; ; © 1994-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 ;----- External dependencies ------------------------------------------------ GET sapphire:alloc GET sapphire:sapphire GET sapphire:string GET sapphire:res GET sapphire:resources ;----- Main code ------------------------------------------------------------ AREA |Sapphire$$Code|,CODE,READONLY ; --- msgs_load --- ; ; On entry: R0 == pointer to filename ; ; On exit: May return an error ; ; Use: Reads in the given messages file. EXPORT msgs_load msgs_load ROUT STMFD R13!,{R0-R5,R12,R14} ;Stack some registers WSPACE msgs__wSpace ;Find my workspace ; --- How big is the file? --- MOV R1,R0 ;Point to the filename MOV R0,#17 ;File info please SWI XOS_File ;Get the info BVS %99msgs_load ;Make the error if not OK TST R0,#1 ;Is it a file? BEQ %80msgs_load ;No -- ignore it then ; --- Allocate a heap block for it --- ADD R3,R4,#1+8 ;Get file size + 1 +size word MOV R0,R3 ;Get the size BL alloc ;Try to allocate the block BLCS alloc_error ;If failed, find error BCS %99msgs_load ;And handle it MOV R2,R0 ;Get the pointer safely ; --- Remember block position --- LDR R14,msgs__list ;Find old list head STR R14,[R2,#0] ;Save that here STR R2,msgs__list ;Store this block away ADD R3,R2,R3 ;Get pointer to end of block STR R3,[R2,#4] ;And save it ADD R2,R2,#8 ;Point to file space STMFD R13!,{R2,R3} ;Save these registers ; --- Load the messages file into buffer --- MOV R0,#16 ;Load file into memory MOV R3,#0 ;Load into my buffer SWI XOS_File ;Load the file now BVS %98msgs_load ;If error, then free block ; --- Scan through the messages, and NULL terminate them --- LDMFD R13!,{R2,R3} ;Get the start/end of mesgs SUBS R3,R3,R2 ;Get the length MOV R1,#0 ;The NULL byte 10msgs_load LDRB R0,[R2] ;Get a character CMP R0,#' ' ;Is it a control character STRLTB R1,[R2] ;Yes, NULL terminate it SUBS R3,R3,#1 ;Decrement counter ADDGT R2,R2,#1 ;Increase index BGT %10msgs_load ;And keep looping STRB R1,[R2] ;Put NULL at end ; --- Return to the user --- 80msgs_load LDMFD R13!,{R0-R5,R12,R14} ;Get registers BICS PC,R14,#V_flag ;And return without error ; --- Free memory on error --- 98msgs_load MOV R5,R10 ;Keep hold of error pointer LDMFD R13!,{R2,R3} ;Restore old registers LDR R14,[R2,#0] ;Load next link STR R14,msgs__list ;Store back as list head MOV R0,R2 ;Free memory from heap BL free ;Free the block MOV R0,R5 ;Restore the error pointer ; --- Report the error --- 99msgs_load ADD R2,R0,#4 ;Point to error message ADR R0,msgs__loadError ;Point to error skeleton BL msgs_error ;Create the error message ADD R13,R13,#4 ;Don't restore R0 LDMFD R13!,{R1-R5,R12,R14} ;Restore other registers ORRS PC,R14,#V_flag ;And return the error msgs__loadError DCD 1 DCB "msgsMLE:Error loading messages file: %0",0 LTORG ; --- msgs_build --- ; ; On entry: R0 == pointer to a message string ; R1 == pointer to output buffer ; ; On exit: R0 == pointer to buffer (R1 on entry) ; R1 == pointer to terminating null ; ; Use: Builds a message string, by substituting message references ; by their values. Each reference of the form `$tag' (or ; optionally `$(tag)', to avoid having to have a trailing) ; space is replaced by the actual message. A literal `$' sign ; may be represented as `$$'. EXPORT msgs_build msgs_build ROUT STMFD R13!,{R1-R4,R14} ;Save some registers MOV R2,R0 ;Remember this pointer 05msgs_build LDRB R14,[R2],#1 ;Load the next character CMP R14,#'$' ;Is it a message reference? BEQ %f00 ;Yes -- handle it then 10msgs_build CMP R14,#&20 ;Is it the end of the line? MOVCC R14,#0 ;Yes -- store a zero then STRB R14,[R1],#1 ;Store in output buffer BCS %05msgs_build ;And keep on going SUB R1,R1,#1 ;Point back to the null LDMFD R13!,{R0,R2-R4,PC}^ ;And return to caller ; --- Handle a dollar sign --- 00 LDRB R14,[R2],#1 ;Load the next character CMP R14,#'$' ;Is this a literal dollar? CMPNE R14,#&1F ;Or maybe a control character BLS %10msgs_build ;Yes -- then ignore this CMP R14,#'(' ;Is the reference bracketted? MOVEQ R3,#')' ;Yes -- remember this char MOVNE R3,#' ' ;Otherwise, use a space LDREQB R14,[R2],#1 ;Load next char if `(` MOV R4,R1 ;Remember this output place 00 CMP R14,R3 ;Is this the end char? CMPNE R14,#&1F ;Or a control character? STRHIB R14,[R4],#1 ;Write the character out LDRHIB R14,[R2],#1 ;Load the next one maybe BHI %b00 ;And keep going until done MOV R0,#0 ;A nice zero word STRB R0,[R4],#1 ;Store the word away nicely CMP R14,#' ' ;Is this a space character? SUBLS R2,R2,#1 ;Yes -- move back one space MOV R0,R1 ;Point to the tag start BL msgs_lookup ;Translate the message 00 LDRB R14,[R0],#1 ;Load a byte from here CMP R14,#&20 ;Finished here yet? STRCSB R14,[R1],#1 ;No -- store the byte BCS %b00 ;And keep on going B %05msgs_build ;Go back to the main loop LTORG ; --- msgs_error --- ; ; On entry: R0 == pointer to an error skeleton string: ; R0+0 == error number ; R0+4 == message tag-and-default (null-terminated) ; R2-R11 == filler strings (not message tags) ; ; On exit: R0 == pointer to translated error message (in error buffer) ; R1 == pointer to null terminator of message ; ; Use: Performs string sustitution on an error message (as done by ; str_subst), but translating the error string. EXPORT msgs_error msgs_error ROUT STMFD R13!,{R0,R14} ;Save some registers ; --- First, translate the message --- ADD R0,R0,#4 ;Point to the message tag BL msgs_lookup ;Translate the tag ; --- Perform the substitution --- SUB R0,R0,#4 ;Create a dummy error number BL str_error ;So the real work ; --- Now copy the error number over --- LDR R14,[R13],#4 ;Get the initial error ptr LDR R14,[R14,#0] ;Get the user's error number STR R14,[R0,#0] ;Store in substituted error LDMFD R13!,{PC}^ ;Return to caller LTORG ; --- msgs_lookup --- ; ; On entry: R0 == message tag (and default message) ; ; On exit: R0 == pointer to located message ; ; Use: Returns the real message from its tag. If the tag does not ; exist, then the default message is used. If that is not ; supplied, then the tag name itself is returned (ie. R0 ; is preserved). EXPORT msgs_lookup msgs_lookup ROUT STMFD R13!,{R1-R6,R12,R14} ;Stack some registers WSPACE msgs__wSpace ;Load pointer LDR R14,msgs__flags ;Load my flags word TST R14,#msFlag__inited ;Are we initialised? BEQ %60msgs_lookup ;No -- handle specially LDR R6,msgs__list ;Find message block list ; --- Loop through the message lists --- 10msgs_lookup CMP R6,#-1 ;Is this the very end? BEQ %90msgs_lookup ;Yes -- return default then MOVS R4,R6 ;Reached the end yet? ADREQ R14,msgs__global ;Otherwise find shared msgs LDMEQIA R14,{R4,R5} ;Load those out please MOVEQ R6,#-1 ;And stop next time LDMNEIA R4!,{R1,R5} ;Load data from block MOVNE R6,R1 ;Set up the link ; --- Try matching the next message --- 20msgs_lookup MOV R1,R0 ;Remember start of tag CMP R4,R5 ;Finished yet? BCS %10msgs_lookup ;Yes -- move to next block LDRB R2,[R1],#1 ;Load next byte from tag LDRB R3,[R4],#1 ;And one from the message ; --- Handle a comment --- CMP R3,#';' ;Is it a semicolon? CMPNE R3,#'#' ;Or a hash? CMPNE R3,#'|' ;Or a vertical bar? BEQ %50msgs_lookup ;Yes -- skip on to next msg ; --- Main comparison loop --- 00 CMP R2,#0 ;End of tag? CMPNE R2,#':' ;Could have a default CMPNE R3,#'*' ;Or is tag wildcarded? BEQ %f00 ;Yes -- investigate then CMP R3,#0 ;End of message? CMPNE R3,#'/' ;End of alternative? BEQ %20msgs_lookup ;Yes -- retry from here CMPNE R3,#':' ;End of message tags? BEQ %50msgs_lookup ;Move to next message then CMP R2,R3 ;Do the two match at all? CMPNE R3,#'?' ;Allow a wildcard here BNE %30msgs_lookup ;No -- move to next message LDRB R2,[R1],#1 ;Load next byte from tag LDRB R3,[R4],#1 ;And one from the message B %b00 ;And keep on looping ; --- Investigate a possible match --- 00 CMP R3,#':' ;End of message's tag? CMPNE R3,#'/' ;End of this alternative? CMPNE R3,#'*' ;Or just a wildcard? BNE %30msgs_lookup ;No -- try next message 00 CMP R3,#0 ;End of message? SUBEQ R4,R4,#1 ;Yes -- backtrack one then CMPNE R3,#':' ;Found the message text yet? LDRNEB R3,[R4],#1 ;No -- skip on then BNE %b00 ;Loop till we find it MOV R0,R4 ;Point to the message LDMFD R13!,{R1-R6,R12,PC}^ ;Return to caller OK ; --- Skip on to next alternative --- 30msgs_lookup CMP R3,#0 ;End of message? CMPNE R3,#'/' ;Or of the alternative? LDRNEB R3,[R4],#1 ;No -- move on then BNE %b30 ;And loop round B %20msgs_lookup ;Try the next message now ; --- Skip on to next message --- 50msgs_lookup CMP R3,#0 ;End of message? LDRNEB R3,[R4],#1 ;No -- move on then BNE %b50 ;And loop round B %20msgs_lookup ;Try the next message now ; --- Not yet initialised --- ; ; This is a bit of an odd circumstance, but people can have ; errors at all sorts of times. We should try to translate ; the message using the [Sapphire.Resources] DLL, although ; not be overly upset if this isn't possible -- either the ; default message (English) will be used, or maybe 60msgs_lookup MOV R6,R0 ;Look after this for a while MOV R0,#rsType_message ;Request a message resource BL resources_find ;Find the resource please MOVCC R0,R6 ;Failed -- refind tag pointer BCC %90msgs_lookup ;And return tag as MOV R4,R0 ;Point to message block base MOV R5,R1 ;Point to the block limit MOV R0,R6 ;Point to the tag again MOV R6,#-1 ;Stop after scanning please B %20msgs_lookup ;Now search default messages ; --- No luck at all --- 90msgs_lookup MOV R1,R0 ;Look after tag pointer 00 LDRB R14,[R1],#1 ;Load next byte CMP R14,#':' ;Is it a tag separator? MOVEQ R0,R1 ;Yes -- return this string CMPNE R14,#0 ;Or is it the end? BNE %b00 ;No -- keep on going then LDMFD R13!,{R1-R6,R12,PC}^ ;Return to caller with that LTORG ; --- msgs_init --- ; ; On entry: -- ; ; On exit: -- ; ; Use: Initialises the message system. EXPORT msgs_init msgs_init ROUT STMFD R13!,{R0-R5,R12,R14} ;Stack some registers WSPACE msgs__wSpace ;Get workspace (silly billy) ; --- Return if we are already initialised --- LDR R0,msgs__flags ;Are we initialised TST R0,#msFlag__inited ;Test the bit LDMNEFD R13!,{R0-R5,R12,PC}^ ;Yes -- return ORR R0,R0,#msFlag__inited ;Set the initialised bit STR R0,msgs__flags ;Store the flags back ; --- Initialise properly --- LDR R0,[R13] ;Get the app name BL res_init ; --- Set up fallback position --- MOV R0,#rsType_message ;Find message resource BL resources_find ;Find the resource please MOVCC R0,#0 ;Not there -- remember this MOVCC R1,#0 ;We get base and limit ADR R14,msgs__global ;Find the global block STMIA R14,{R0,R1} ;Store them away nicely ; --- Load messages file --- MOV R14,#0 ;Clear the messages list STR R14,msgs__list ;Store that over now SUB R13,R13,#16 ;Make some space available MOV R0,R13 ;Point at this buffer BL res_country ;Read the country name BL %10msgs_init ;Try to load that file ADRCC R0,msgs__ukName ;Failed -- try UK in case BLCC %10msgs_init ;Try that quickly too ADRCC R0,msgs__fileName ;Failed -- use normal name BLCC %10msgs_init ;Try that quickly too ADD R13,R13,#16 ;Restore my buffer now LDMFD R13!,{R0-R5,R12,PC}^ ; --- Look up a name, and load if it is a file --- 10msgs_init STMFD R13!,{R14} ;Save a register MOV R1,R11 ;Point to a buffer BL res_find ;Try to find the file MOV R1,R0 ;Point to the name MOV R0,#17 ;Read file information SWI XOS_File ;Get the info on it MOVVS R0,#0 ;If failed, say not there CMN R0,#0 ;Clear V flag and others MOVS R0,R0,LSR #1 ;Is it a file? MOV R0,R1 ;Point to the name again BLCS msgs_load ;If able, load the file SWIVS OS_GenerateError ;If failed, be unhappy LDMFD R13!,{PC} ;And return C state msgs__fileName DCB "Messages",0 msgs__ukName DCB "UK",0 LTORG msgs__wSpace DCD 0 ;----- Workspace ------------------------------------------------------------ ^ 0,R12 msgs__wStart # 0 msgs__flags # 4 ;Flags word msgs__list # 4 ;Linked list of messages msgs__global # 8 ;Shared resource messages msgs__wSize EQU {VAR}-msgs__wStart msFlag__inited EQU (1<<0) ;Has been initialised AREA |Sapphire$$LibData|,CODE,READONLY DCD msgs__wSize ;Workspace size DCD msgs__wSpace ;Workspace pointer DCD 256 ;Scratchpad size DCD msgs_init ;Initialisation ;----- That's all folks ----------------------------------------------------- END