> net#arf:$.a500.RiscOS+.doc.MsgTrans

Author: Neil Raine
Status: Description of module in RISC OS+
History:
         2-Nov-89  0.01  NDR  First draft.
         3-Nov-89  0.02  NDR  Name changed to MessageTrans, parameters altered.
         6-Nov-89  0.03  NDR  Assembler header file section added.
         6-Nov-89  0.04  NDR  Added bit about Service_Reset
         7-Nov-89  0.05  NDR  Fixed typo in BASIC example of MessageTrans_OpenFile
         8-Nov-89  0.06  NDR  Updated info on OpenFile and Lookup
        22-Nov-89  0.07  NDR  Updated info on MessageTrans_MakeMenus
         7-Aug-90  0.08  NDR  Removed references to DeskFS/ResourceFS

        27-Jan-92  0.17  BC   Added new SWI CopyError, formatted, corrected
                              spelling, fixed the number of buffers

        29-Jan-92  0.18  BC   Added missing section on EnumerateTokens, put
                              SWIs in numerical order.

Overview
--------

This document describes the SWI interface to the MessageTrans module, which
provides message translation services, and the format of the message files
that it uses.


SWI MessageTrans_FileInfo ; &041500

    In  R1 -> filename
    Out R0 =  flag word:
              bit 0 set => file is held in memory (can be accessed directly)
              bits 1..31 reserved (ignore them)
        R2 =  size of buffer required to hold file
              if R0 bit 0 set, the buffer is not required for read-only access


SWI MessageTrans_OpenFile ; &041501

    In  R0 -> 4-word data structure
              must be held in the RMA if R2=0 on entry
        R1 -> filename, held in the RMA if R2=0 on entry
        R2 -> buffer to hold file data
              0 => allocate some space in the RMA,
                   or use the file directly if possible
        Error: "Message file already open" if R0 points to a structure
               already known to MessageTrans (ie. already open).

  An application may decide that it would like to buffer the file in its own
workspace (rather than the RMA) if it needs to be loaded, or use the file
directly if it is already in memory.  To do this:

            SYS "MessageTrans_FileInfo",,filename$ TO flags%,,size%
            IF flags% AND 1 THEN buffer%=0 ELSE buffer%=FNalloc(size%)
            SYS "OS_Module",6,,,17+LENfilename$ TO ,,filedesc%
            $(filedesc%+16)=filename$
            SYS "MessageTrans_OpenFile",filedesc%,filedesc%+16,buffer%

  Where FNalloc() allocates a buffer of a given size, by using the
Wimp_SlotSize or "END=" command.  Note that in fact the filename and file
descriptor only need to be in the RMA if R2=0 on entry to
MessageTrans_OpenFile.

  Note: If R2=0 on entry to this SWI, and the application uses direct
pointers into the file (rather than copying the messages out) or uses
MessageTrans_MakeMenus, it should also trap Service_MessageFileClosed, in
case the file is unloaded.


SWI MessageTrans_Lookup ; &041502

    In  R0 -> 4-word data structure passed to MessageTrans_LoadFile
        R1 -> token, terminated by any char <= 32, or "," or ")"
        R2 -> buffer to hold result (0 => don't copy it)
        R3 =  buffer size (if R2 non-0)
        R4 -> parameter 0 (0 => don't substitute for "%0")
        R5 -> parameter 1 (0 => don't substitute for "%1")
        R6 -> parameter 2 (0 => don't substitute for "%2")
        R7 -> parameter 3 (0 => don't substitute for "%3")
    Out R1 -> terminator of token
        R2 -> result string (read-only with no substitution if R2=0 on entry)
        R3 =  size of result before terminator
              (terminator = 10 if R2=0 on entry, else 0)

  This SWI allows a message token to be translated into a string, with
optional parameter substitution.

  The application must have called MessageTrans_OpenFile beforehand in order
to use this SWI, although you can still call it if the file has been
automatically closed by the system, because it will automatically re-open it
as well.

  See the "File format" section for further details.

SWI MessageTrans_MakeMenus ; &041503

    In  R0 -> 4-word data structure passed to MessageTrans_OpenFile
        R1 -> menu definition (see below)
        R2 -> RAM buffer to hold menu structure
        R3 =  size of RAM buffer
    Out [R1..] = menu data
        R3 =  bytes remaining in buffer (should be 0 if you got it right)
        "Buffer overflow" error if buffer is too small

  Menu structure:
        +0 (n)  Token for menu title, terminated by any char <= 32, or "," or ")"
                null => no more menus, otherwise:
        +n (1)  menu title foreground and frame colour
           (1)  menu title background colour
           (1)  menu work area foreground colour
           (1)  menu work area background colour
           (1)  height of menu items
           (1)  gap between items
  Menu items:
           (n)  Token for menu item, terminated by any char <= 32, or "," or ")"
           Word-align to here (addr := (addr+3) AND (NOT 3))
           (4)  Menu flags (bit 7 set => last item)
           (4)  Offset from RAM menu start to RAM submenu start
                0 => no submenu
           (4)  Icon flags

  This SWI allows a menu structure to be set up from a structure containing
references to tokens, and sets up menu widths.  Parameter substitution is
not allowed.

  The application must have called MessageTrans_OpenFile beforehand in order
to use this SWI, although you can still call it if the file has been
automatically closed by the system, because it will automatically re-open it
as well.

  If the icon flags have bit 8 clear (ie. they are not indirected), the
message text for the icon will be read into the 12-byte block that forms the
icon data, otherwise the icon data will be set up to point to the message
text inside the file data.  In the latter case they are read-only.

  If the menu item flags bit 2 is set (writable) and the icon is indirected,
the 3 words of the icondata in the RAM buffer are assumed to have already
been set up by the calling program.  The result of looking up the message
token is copied into the buffer indicated by the first word of the icon data
(truncated if it gets bigger than the buffer size indicated in
[icondata,#8]).


SWI MessageTrans_CloseFile ; &041504

    In  R0 -> 4-word data structure passed to MessageTrans_OpenFile


SWI MessageTrans_EnumerateTokens ; &041505

    In  R0 -> 4-word data structure passed to MessageTrans_OpenFile
        R1 -> token, terminated by 0, 10, 13 or ":"
              wildcards: ? = match 1 char, * = match 0 or more chars
        R2 -> buffer to hold result
        R3 =  buffer size
        R4 =  place marker (0 for first call)
    Out R2 -> buffer, containing next token if found, with terminator copied from input
              R2=0 => no more tokens found (we've finished)
        R3 =  length of result excluding terminator (if R2<>0)
        R4 =  place marker for next call (non-0)


SWI MessageTrans_ErrorLookup ; &041506

    In  R0 -> Error block (Word aligned) containing error number , token, terminated
              by 0 or error number , "token:default" terminated by 0.
        R1 -> 4-word data structure passed to MessageTrans_LoadFile
        R2 -> buffer to hold result (0 => Use internal buffer)
        R3 =  buffer size (if R2 non-0)
        R4 -> parameter 0 (0 => don't substitute for "%0")
        R5 -> parameter 1 (0 => don't substitute for "%1")
        R6 -> parameter 2 (0 => don't substitute for "%2")
        R7 -> parameter 3 (0 => don't substitute for "%3")
    Out R0 -> Error buffer used
        V Set

  This is like MessageTrans_Lookup, but is used for error messages, the
error number is copied into the destination buffer and then a lookup is done
on the token and the result put after the error number in the destination
buffer.

  If R2 is 0 on entry, MessageTrans will use one of its internal buffers for
the result. There are 10 buffers for foreground processes and 2 for calls
made from within IRQ processes. MessageTrans will cycle through these
buffers. 


SWI MessageTrans_GSLookup ; &041507

    In  R0 -> 4-word data structure passed to MessageTrans_LoadFile
        R1 -> token, terminated by 0, 10 or 13, or "token:default"
        R2 -> buffer to hold result (0 => don't copy it)
        R3 =  buffer size (if R2 non-0)
        R4 -> parameter 0 (0 => don't substitute for "%0")
        R5 -> parameter 1 (0 => don't substitute for "%1")
        R6 -> parameter 2 (0 => don't substitute for "%2")
        R7 -> parameter 3 (0 => don't substitute for "%3")
    Out R0 -> preserved.
        R1 -> preserved.
        R2 -> result string (read-only with no parameter substitution if
              R2=0 on entry)
        R3 =  size of result before terminator (character 10 if R2=0 on
              entry, else 0)

  Same as MessageTrans_Lookup, only string is GSTrans'd before you get it
back, but after the parameters are substituted This needs an intermediate
buffer, and so will fail if one cannot be allocated  from the RMA.

  Calling this SWI with R2=0 is exactly equivalent to MessageTrans_Lookup
with R2=0


SWI MessageTrans_CopyError ; &041508

    In  R0 -> Error block (Word aligned) containing error number, text (may
              be zero length), terminating zero.
    Out R0 -> Error buffer used

  MessageTrans will copy an error to one of its internal buffers for the
result. There are 10 buffers for foreground processes and 2 for calls made
from within IRQ processes. MessageTrans will cycle through these buffers. 


  *************************************************************************

Service_MessageFileClosed

    In  R0 -> 4-word data structure passed to MessageTrans_OpenFile
    Out If the application recognises the value of R0 passed in, and it has
        any direct pointers into the message data that it relates to, it
        should re-initialise itself by calling MessageTrans_OpenFile again
        to re-open the file, and recache its pointers.  If it has used
        MessageTrans_MakeMenus, it should call Wimp_GetMenuState to see if
        its menu tree it open, and delete it using Wimp_CreateMenu(-1) if
        so.

  This service call is only ever issued if the file is not held in the
user's own buffer.  It tells the application that its file data has been
thrown away, for example if the file is held inside a module which is then
reloaded.

  It is only necessary to trap this service call if direct pointers into the
file data are being used.  Otherwise, the MessageTrans module will make a
note in the file descriptor that the file has been closed, and simply
re-open it when MessageTrans_Lookup or MessageTrans_MakeMenus is next called
on that file.

  It is recommended that applications that cannot trap service calls do not
use direct pointers into the file data (eg. indirected icons with
MessageTrans_MakeMenus).  They can still use such indirected icons, if they
provide a buffer pointer in R2 on entry to MessageTrans_OpenFile (so that
the message file data is copied into the buffer).


Service_Reset

  Since MessageTrans does not close message files on a soft reset,
applications that do not wish their message files to be open once they leave
the desktop should call MessageTrans_CloseFile for all their open files at
this point.  However, it is perfectly legal for message files to be left
open over soft reset.


File format
-----------

  Message files contain a series of one-line token / value pairs, terminated
by character 10 (linefeed).

        <file> ::= { <line> }*
        <line> ::= <tokline> | "#" <comment><nl> | <nl>
     <tokline> ::= <token> { "/"<token> | <nl><token> }* : <value><nl>
       <token> ::= <tokchar> { <tokchar> }*
     <tokchar> ::= <char> | <wildcard>
        <char> ::= any character > " " except ",", ")", ":", "?" or "/"
    <wildcard> ::= "?"      (matches any character)
     <comment> ::= { <anychar> }*
     <anychar> ::= any character except <nl>
          <nl> ::= character code 10
       <value> ::= { <anychar> | "%0" | "%1" | "%2" | "%3" | "%%" }*

  Note that the spaces in the above description are purely to improve
readability - in fact spaces are significant inside tokens, so should only
really appear in <comment> and <value>.

  Alternative tokens are separated by "/" or <nl>.  If any of the
alternative tokens before the next ":" match the supplied token, the value
after the next ":" up to the following <nl> is returned.  The "?" character
in a token in the file matches any character in the supplied match token. 
Case is significant.

  If R2 is not 0 on entry to MessageTrans_Lookup, "%0", "%1", "%2" and "%3"
are substituted with the parameters supplied in R4..R7, except where the
relevant register is 0, in which case the text is left alone.  "%%" is
converted to "%" - otherwise if no parameter substitution occurs the text is
left alone.  No other substitution is performed on the string.

  For example:

        # This is an example message file

        TOK1:This value is obtained only for "TOK1".
        TOK2
        TOK3/TOK4:This value is obtained for "TOK2","TOK3" or "TOK4"
        TOK?:This value is obtained for "TOK<not 1,2,3 or 4>"

        ANOTHER:Parameter in R4 = %0, parameter in R5 = %1.

  If the message token does not match, the error "Message token not found"
is returned.  This error is also given if the value to be returned is on the
last line of the file, and does not have a terminating CHR$(10).


Assembler header files
----------------------

  There are two header files for the MessageTrans module:

        Hdr.MsgTrans            ; SWI numbers and names
        Hdr.MsgMenus            ; macros for use with MessageTrans_MakeMenus

  The latter file defines two macros for setting up the data structures for
use with MessageTrans_MakeMenus.  It is used as follows:

        GET     &.Hdr.WimpSpace
        GET     &.Hdr.MsgTrans
        GET     &.Hdr.MsgMenus

        ...

        ^       0, R12          ; set up workspace (R12-relative)

m_start #       0
m_main  #       m_headersize + 3 * mi_size
m_sub   #       m_headersize + 3 * mi_size
m_end   #       0

        ...

        ADR     r0, filedesc            ; open message file
        ADR     r1, filename
        SWI     XMessageTrans_OpenFile
        BVS     Error

        ...

        ADR     r0, filedesc            ; construct menus
        ADR     r1, rom_menus
        ADR     r2, m_start
        MOV     r3, m_end-m_start
        SWI     XMessageTrans_MakeMenus
        BVS     Error_close_messagefile

        ...

        ADR     r0, filedesc            ; close message file
        SWI     XMessageTrans_CloseFile

        ...

rom_menus
m_main  Menu    T00             ; T00 = token for title of main menu
mo_01   Item    M01             ; M01 = token for item 0 of main menu
mo_02   Item    M02,m_sub       ; submenu pointer to m_sub
mo_03   Item    M03

m_sub   Menu    T02
mo_12   Item    M12             ; M12 = token for item 1 of submenu 2
mo_22   Item    M22

        DCB     0               ; terminator of menu structure
        ALIGN

Error_close_messagefile
        MOV     r1, r0
        MOV     r2, pc
        ADR     r0, filedesc
        SWI     XMessageTrans_CloseFile
        MOVVC   r0, r1
        TEQVCP  r2, #0
Error
        <report error and abort>

  The 'Menu' macro sets up the header for the menu, and remembers the name
of the menu being defined.  It also calculates how many Items will follow,
based on the size of the buffer reserved for the RAM menu.

  The 'Item' macro sets up the data for a menu item.  It allows a submenu to
be referenced, and automatically converts this into an offset from the
current menu header to the required submenu.  It also allows the item to be
specified as writable, have a dotted line underneath it, and be indirected
(the default) or not.  See Hdr.MsgMenus for further details.

