chiark / gitweb /
JPEG support and other fixes from Nick Clark
[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