Initial revision
[ssr] / StraySrc / Libraries / Sapphire / s / msgs
1 ;
2 ; msgs.s
3 ;
4 ; Message file handling (MDW)
5 ;
6 ; © 1994-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 ;----- External dependencies ------------------------------------------------
33
34 GET sapphire:alloc
35 GET sapphire:sapphire
36 GET sapphire:string
37 GET sapphire:res
38 GET sapphire:resources
39
40 ;----- Main code ------------------------------------------------------------
41
42 AREA |Sapphire$$Code|,CODE,READONLY
43
44 ; --- msgs_load ---
45 ;
46 ; On entry: R0 == pointer to filename
47 ;
48 ; On exit: May return an error
49 ;
50 ; Use: Reads in the given messages file.
51
52 EXPORT msgs_load
53 msgs_load ROUT
54
55 STMFD R13!,{R0-R5,R12,R14} ;Stack some registers
56 WSPACE msgs__wSpace ;Find my workspace
57
58 ; --- How big is the file? ---
59
60 MOV R1,R0 ;Point to the filename
61 MOV R0,#17 ;File info please
62 SWI XOS_File ;Get the info
63 BVS %99msgs_load ;Make the error if not OK
64 TST R0,#1 ;Is it a file?
65 BEQ %80msgs_load ;No -- ignore it then
66
67 ; --- Allocate a heap block for it ---
68
69 ADD R3,R4,#1+8 ;Get file size + 1 +size word
70 MOV R0,R3 ;Get the size
71 BL alloc ;Try to allocate the block
72 BLCS alloc_error ;If failed, find error
73 BCS %99msgs_load ;And handle it
74 MOV R2,R0 ;Get the pointer safely
75
76 ; --- Remember block position ---
77
78 LDR R14,msgs__list ;Find old list head
79 STR R14,[R2,#0] ;Save that here
80 STR R2,msgs__list ;Store this block away
81 ADD R3,R2,R3 ;Get pointer to end of block
82 STR R3,[R2,#4] ;And save it
83 ADD R2,R2,#8 ;Point to file space
84 STMFD R13!,{R2,R3} ;Save these registers
85
86 ; --- Load the messages file into buffer ---
87
88 MOV R0,#16 ;Load file into memory
89 MOV R3,#0 ;Load into my buffer
90 SWI XOS_File ;Load the file now
91 BVS %98msgs_load ;If error, then free block
92
93 ; --- Scan through the messages, and NULL terminate them ---
94
95 LDMFD R13!,{R2,R3} ;Get the start/end of mesgs
96 SUBS R3,R3,R2 ;Get the length
97 MOV R1,#0 ;The NULL byte
98 10msgs_load LDRB R0,[R2] ;Get a character
99 CMP R0,#' ' ;Is it a control character
100 STRLTB R1,[R2] ;Yes, NULL terminate it
101 SUBS R3,R3,#1 ;Decrement counter
102 ADDGT R2,R2,#1 ;Increase index
103 BGT %10msgs_load ;And keep looping
104 STRB R1,[R2] ;Put NULL at end
105
106 ; --- Return to the user ---
107
108 80msgs_load LDMFD R13!,{R0-R5,R12,R14} ;Get registers
109 BICS PC,R14,#V_flag ;And return without error
110
111 ; --- Free memory on error ---
112
113 98msgs_load MOV R5,R10 ;Keep hold of error pointer
114 LDMFD R13!,{R2,R3} ;Restore old registers
115 LDR R14,[R2,#0] ;Load next link
116 STR R14,msgs__list ;Store back as list head
117 MOV R0,R2 ;Free memory from heap
118 BL free ;Free the block
119 MOV R0,R5 ;Restore the error pointer
120
121 ; --- Report the error ---
122
123 99msgs_load ADD R2,R0,#4 ;Point to error message
124 ADR R0,msgs__loadError ;Point to error skeleton
125 BL msgs_error ;Create the error message
126 ADD R13,R13,#4 ;Don't restore R0
127 LDMFD R13!,{R1-R5,R12,R14} ;Restore other registers
128 ORRS PC,R14,#V_flag ;And return the error
129
130 msgs__loadError DCD 1
131 DCB "msgsMLE:Error loading messages file: %0",0
132
133 LTORG
134
135 ; --- msgs_build ---
136 ;
137 ; On entry: R0 == pointer to a message string
138 ; R1 == pointer to output buffer
139 ;
140 ; On exit: R0 == pointer to buffer (R1 on entry)
141 ; R1 == pointer to terminating null
142 ;
143 ; Use: Builds a message string, by substituting message references
144 ; by their values. Each reference of the form `$tag' (or
145 ; optionally `$(tag)', to avoid having to have a trailing)
146 ; space is replaced by the actual message. A literal `$' sign
147 ; may be represented as `$$'.
148
149 EXPORT msgs_build
150 msgs_build ROUT
151
152 STMFD R13!,{R1-R4,R14} ;Save some registers
153 MOV R2,R0 ;Remember this pointer
154
155 05msgs_build LDRB R14,[R2],#1 ;Load the next character
156 CMP R14,#'$' ;Is it a message reference?
157 BEQ %f00 ;Yes -- handle it then
158 10msgs_build CMP R14,#&20 ;Is it the end of the line?
159 MOVCC R14,#0 ;Yes -- store a zero then
160 STRB R14,[R1],#1 ;Store in output buffer
161 BCS %05msgs_build ;And keep on going
162 SUB R1,R1,#1 ;Point back to the null
163 LDMFD R13!,{R0,R2-R4,PC}^ ;And return to caller
164
165 ; --- Handle a dollar sign ---
166
167 00 LDRB R14,[R2],#1 ;Load the next character
168 CMP R14,#'$' ;Is this a literal dollar?
169 CMPNE R14,#&1F ;Or maybe a control character
170 BLS %10msgs_build ;Yes -- then ignore this
171 CMP R14,#'(' ;Is the reference bracketted?
172 MOVEQ R3,#')' ;Yes -- remember this char
173 MOVNE R3,#' ' ;Otherwise, use a space
174 LDREQB R14,[R2],#1 ;Load next char if `(`
175 MOV R4,R1 ;Remember this output place
176
177 00 CMP R14,R3 ;Is this the end char?
178 CMPNE R14,#&1F ;Or a control character?
179 STRHIB R14,[R4],#1 ;Write the character out
180 LDRHIB R14,[R2],#1 ;Load the next one maybe
181 BHI %b00 ;And keep going until done
182
183 MOV R0,#0 ;A nice zero word
184 STRB R0,[R4],#1 ;Store the word away nicely
185 CMP R14,#' ' ;Is this a space character?
186 SUBLS R2,R2,#1 ;Yes -- move back one space
187
188 MOV R0,R1 ;Point to the tag start
189 BL msgs_lookup ;Translate the message
190 00 LDRB R14,[R0],#1 ;Load a byte from here
191 CMP R14,#&20 ;Finished here yet?
192 STRCSB R14,[R1],#1 ;No -- store the byte
193 BCS %b00 ;And keep on going
194 B %05msgs_build ;Go back to the main loop
195
196 LTORG
197
198 ; --- msgs_error ---
199 ;
200 ; On entry: R0 == pointer to an error skeleton string:
201 ; R0+0 == error number
202 ; R0+4 == message tag-and-default (null-terminated)
203 ; R2-R11 == filler strings (not message tags)
204 ;
205 ; On exit: R0 == pointer to translated error message (in error buffer)
206 ; R1 == pointer to null terminator of message
207 ;
208 ; Use: Performs string sustitution on an error message (as done by
209 ; str_subst), but translating the error string.
210
211 EXPORT msgs_error
212 msgs_error ROUT
213
214 STMFD R13!,{R0,R14} ;Save some registers
215
216 ; --- First, translate the message ---
217
218 ADD R0,R0,#4 ;Point to the message tag
219 BL msgs_lookup ;Translate the tag
220
221 ; --- Perform the substitution ---
222
223 SUB R0,R0,#4 ;Create a dummy error number
224 BL str_error ;So the real work
225
226 ; --- Now copy the error number over ---
227
228 LDR R14,[R13],#4 ;Get the initial error ptr
229 LDR R14,[R14,#0] ;Get the user's error number
230 STR R14,[R0,#0] ;Store in substituted error
231 LDMFD R13!,{PC}^ ;Return to caller
232
233 LTORG
234
235 ; --- msgs_lookup ---
236 ;
237 ; On entry: R0 == message tag (and default message)
238 ;
239 ; On exit: R0 == pointer to located message
240 ;
241 ; Use: Returns the real message from its tag. If the tag does not
242 ; exist, then the default message is used. If that is not
243 ; supplied, then the tag name itself is returned (ie. R0
244 ; is preserved).
245
246 EXPORT msgs_lookup
247 msgs_lookup ROUT
248
249 STMFD R13!,{R1-R6,R12,R14} ;Stack some registers
250 WSPACE msgs__wSpace ;Load pointer
251
252 LDR R14,msgs__flags ;Load my flags word
253 TST R14,#msFlag__inited ;Are we initialised?
254 BEQ %60msgs_lookup ;No -- handle specially
255
256 LDR R6,msgs__list ;Find message block list
257
258 ; --- Loop through the message lists ---
259
260 10msgs_lookup CMP R6,#-1 ;Is this the very end?
261 BEQ %90msgs_lookup ;Yes -- return default then
262 MOVS R4,R6 ;Reached the end yet?
263 ADREQ R14,msgs__global ;Otherwise find shared msgs
264 LDMEQIA R14,{R4,R5} ;Load those out please
265 MOVEQ R6,#-1 ;And stop next time
266 LDMNEIA R4!,{R1,R5} ;Load data from block
267 MOVNE R6,R1 ;Set up the link
268
269 ; --- Try matching the next message ---
270
271 20msgs_lookup MOV R1,R0 ;Remember start of tag
272 CMP R4,R5 ;Finished yet?
273 BCS %10msgs_lookup ;Yes -- move to next block
274 LDRB R2,[R1],#1 ;Load next byte from tag
275 LDRB R3,[R4],#1 ;And one from the message
276
277 ; --- Handle a comment ---
278
279 CMP R3,#';' ;Is it a semicolon?
280 CMPNE R3,#'#' ;Or a hash?
281 CMPNE R3,#'|' ;Or a vertical bar?
282 BEQ %50msgs_lookup ;Yes -- skip on to next msg
283
284 ; --- Main comparison loop ---
285
286 00 CMP R2,#0 ;End of tag?
287 CMPNE R2,#':' ;Could have a default
288 CMPNE R3,#'*' ;Or is tag wildcarded?
289 BEQ %f00 ;Yes -- investigate then
290 CMP R3,#0 ;End of message?
291 CMPNE R3,#'/' ;End of alternative?
292 BEQ %20msgs_lookup ;Yes -- retry from here
293 CMPNE R3,#':' ;End of message tags?
294 BEQ %50msgs_lookup ;Move to next message then
295 CMP R2,R3 ;Do the two match at all?
296 CMPNE R3,#'?' ;Allow a wildcard here
297 BNE %30msgs_lookup ;No -- move to next message
298 LDRB R2,[R1],#1 ;Load next byte from tag
299 LDRB R3,[R4],#1 ;And one from the message
300 B %b00 ;And keep on looping
301
302 ; --- Investigate a possible match ---
303
304 00 CMP R3,#':' ;End of message's tag?
305 CMPNE R3,#'/' ;End of this alternative?
306 CMPNE R3,#'*' ;Or just a wildcard?
307 BNE %30msgs_lookup ;No -- try next message
308
309 00 CMP R3,#0 ;End of message?
310 SUBEQ R4,R4,#1 ;Yes -- backtrack one then
311 CMPNE R3,#':' ;Found the message text yet?
312 LDRNEB R3,[R4],#1 ;No -- skip on then
313 BNE %b00 ;Loop till we find it
314 MOV R0,R4 ;Point to the message
315 LDMFD R13!,{R1-R6,R12,PC}^ ;Return to caller OK
316
317 ; --- Skip on to next alternative ---
318
319 30msgs_lookup CMP R3,#0 ;End of message?
320 CMPNE R3,#'/' ;Or of the alternative?
321 LDRNEB R3,[R4],#1 ;No -- move on then
322 BNE %b30 ;And loop round
323
324 B %20msgs_lookup ;Try the next message now
325
326 ; --- Skip on to next message ---
327
328 50msgs_lookup CMP R3,#0 ;End of message?
329 LDRNEB R3,[R4],#1 ;No -- move on then
330 BNE %b50 ;And loop round
331
332 B %20msgs_lookup ;Try the next message now
333
334 ; --- Not yet initialised ---
335 ;
336 ; This is a bit of an odd circumstance, but people can have
337 ; errors at all sorts of times. We should try to translate
338 ; the message using the [Sapphire.Resources] DLL, although
339 ; not be overly upset if this isn't possible -- either the
340 ; default message (English) will be used, or maybe
341
342 60msgs_lookup MOV R6,R0 ;Look after this for a while
343 MOV R0,#rsType_message ;Request a message resource
344 BL resources_find ;Find the resource please
345 MOVCC R0,R6 ;Failed -- refind tag pointer
346 BCC %90msgs_lookup ;And return tag as
347 MOV R4,R0 ;Point to message block base
348 MOV R5,R1 ;Point to the block limit
349 MOV R0,R6 ;Point to the tag again
350 MOV R6,#-1 ;Stop after scanning please
351 B %20msgs_lookup ;Now search default messages
352
353 ; --- No luck at all ---
354
355 90msgs_lookup MOV R1,R0 ;Look after tag pointer
356 00 LDRB R14,[R1],#1 ;Load next byte
357 CMP R14,#':' ;Is it a tag separator?
358 MOVEQ R0,R1 ;Yes -- return this string
359 CMPNE R14,#0 ;Or is it the end?
360 BNE %b00 ;No -- keep on going then
361
362 LDMFD R13!,{R1-R6,R12,PC}^ ;Return to caller with that
363
364 LTORG
365
366 ; --- msgs_init ---
367 ;
368 ; On entry: --
369 ;
370 ; On exit: --
371 ;
372 ; Use: Initialises the message system.
373
374 EXPORT msgs_init
375 msgs_init ROUT
376
377 STMFD R13!,{R0-R5,R12,R14} ;Stack some registers
378 WSPACE msgs__wSpace ;Get workspace (silly billy)
379
380 ; --- Return if we are already initialised ---
381
382 LDR R0,msgs__flags ;Are we initialised
383 TST R0,#msFlag__inited ;Test the bit
384 LDMNEFD R13!,{R0-R5,R12,PC}^ ;Yes -- return
385
386 ORR R0,R0,#msFlag__inited ;Set the initialised bit
387 STR R0,msgs__flags ;Store the flags back
388
389 ; --- Initialise properly ---
390
391 LDR R0,[R13] ;Get the app name
392 BL res_init
393
394 ; --- Set up fallback position ---
395
396 MOV R0,#rsType_message ;Find message resource
397 BL resources_find ;Find the resource please
398 MOVCC R0,#0 ;Not there -- remember this
399 MOVCC R1,#0 ;We get base and limit
400 ADR R14,msgs__global ;Find the global block
401 STMIA R14,{R0,R1} ;Store them away nicely
402
403 ; --- Load messages file ---
404
405 MOV R14,#0 ;Clear the messages list
406 STR R14,msgs__list ;Store that over now
407
408 SUB R13,R13,#16 ;Make some space available
409 MOV R0,R13 ;Point at this buffer
410 BL res_country ;Read the country name
411 BL %10msgs_init ;Try to load that file
412 ADRCC R0,msgs__ukName ;Failed -- try UK in case
413 BLCC %10msgs_init ;Try that quickly too
414 ADRCC R0,msgs__fileName ;Failed -- use normal name
415 BLCC %10msgs_init ;Try that quickly too
416 ADD R13,R13,#16 ;Restore my buffer now
417 LDMFD R13!,{R0-R5,R12,PC}^
418
419 ; --- Look up a name, and load if it is a file ---
420
421 10msgs_init STMFD R13!,{R14} ;Save a register
422 MOV R1,R11 ;Point to a buffer
423 BL res_find ;Try to find the file
424 MOV R1,R0 ;Point to the name
425 MOV R0,#17 ;Read file information
426 SWI XOS_File ;Get the info on it
427 MOVVS R0,#0 ;If failed, say not there
428 CMN R0,#0 ;Clear V flag and others
429 MOVS R0,R0,LSR #1 ;Is it a file?
430 MOV R0,R1 ;Point to the name again
431 BLCS msgs_load ;If able, load the file
432 SWIVS OS_GenerateError ;If failed, be unhappy
433 LDMFD R13!,{PC} ;And return C state
434
435 msgs__fileName DCB "Messages",0
436 msgs__ukName DCB "UK",0
437
438 LTORG
439
440 msgs__wSpace DCD 0
441
442 ;----- Workspace ------------------------------------------------------------
443
444 ^ 0,R12
445 msgs__wStart # 0
446
447 msgs__flags # 4 ;Flags word
448 msgs__list # 4 ;Linked list of messages
449 msgs__global # 8 ;Shared resource messages
450
451 msgs__wSize EQU {VAR}-msgs__wStart
452
453 msFlag__inited EQU (1<<0) ;Has been initialised
454
455 AREA |Sapphire$$LibData|,CODE,READONLY
456
457 DCD msgs__wSize ;Workspace size
458 DCD msgs__wSpace ;Workspace pointer
459 DCD 256 ;Scratchpad size
460 DCD msgs_init ;Initialisation
461
462 ;----- That's all folks -----------------------------------------------------
463
464 END
465
466