[comp.sys.acorn] MessageTrans

maumg@warwick.ac.uk (Pop Mobility Freak) (03/11/91)

Here is some information which I have worked out about the very useful
MessageTrans module. This comes with the new printer drivers (ie versions
2.44 or later) in the !System directory. This module makes the use of Message
files very easy. This is similar to the facility provided by C but allows
parameter passing as well. There also appears to be an interface for creating
menus but I cannot work out how this works.

Before I explain the SWI's provided by these modules I will give an example
of a message file

---------------------------- EXAMPLE MESSAGE FILE ----------------------------
NONE:This message take no parameters
ONE:This message takes %0 as a parameter
TWO:This message takes %0 and %1 as parameters
THREE:This message has three parameters %0, %1 and %2
FOUR:The maximum number of parameters allowed is four %0, %1, %2, and %3
------------------------- END OF EXAMPLE MESSAGE FILE ------------------------

As can be seen from the example above a message file consists of several
lines each of which starts with a token followed by a colon and then the
message. The %0, %1, %2 and %3 denote parameters which will be substituted
for at the appropriate time. (They are similar to the %<number> values in
system variables. A parameter may be be used more than once in the same
message.

The SWI's provide by the module are

&41500  MessageTrans_FileInfo
&41501  MessageTrans_OpenFile
&41502  MessageTrans_Lookup
&41503  MessageTrans_MakeMenus
&41504  MessageTrans_CloseFile

I will now give a description of each SWI. The descriptions are in no way
guarenteed as they are what I can have gained from experimenting with the
module.

MessageTrans_FileInfo (&41500)
------------------------------

Entry   r1 -> filename of message file

Exit    r1 preserved
        r2 length of file + 4

Use     All I can see that this SWI does is set r2 as shown above
        There may be some side effects I am not sure

MessageTrans_OpenFile (&41501)
------------------------------

Entry   r0 -> buffer of sixteen bytes
        r1 -> filename of message file

Exit    r0 preserved
        r1 preserved

Use     Loads the file into memory (probably the RMA) ready for use by
        MessageTrans_Lookup. The buffer is needed to be passed to the
        following SWI's. The final word in the buffer contains the pointer to
        filename passed in r1. So the filename may need to remain unchanged
        while the file is open. Things appear to work fine when the memory
        which contained the filename is changed but I would keep it unchanged
        for safety.

MessageTrans_Lookup (&41502)
----------------------------

Entry   r0 -> buffer passed to MessageTrans_OpenFile
        r1 -> token (eg pointer to "NONE")  in the example above
              the tokens ARE case conscious
        r2 -> buffer for result
        r3 =  length of buffer
        r4 -> first parameter  \
        r5 -> second parameter  \  these are optional depending
        r6 -> third parameter   /  upon how many are required
        r7 -> forth parameter  /

Exit    r2 -> the message after parameter substitution
              (assuming the token could be matched)
              the message is zero terminated
        r3 =  length of message after substitution excluding
              the terminating zero

Use     Lookup a message from the message file. If a message matching the
        token is found then parameter substitution is performed on it and the
        result put into the buffer passed in r2. If a parameter is expected
        and the pointer is zero then the %<number> is LEFT IN the message. So
        to not use a parameter the pointer must pointer to "".

MessageTrans_MakeMenus (&41503)
-------------------------------

Use     I have no idea how to use this SWI.

MessageTrans_CloseFile (&41504)
-------------------------------

Entry   r0 -> buffer passed to MessageTrans_OpenFile

Exit    None

Use     Free the memory used to store the message file.



Finally here is an example program as how to use the module. To load it into
Basic cut the file out and Load it from the supervisor prompt by doing Load
<filename> of Basic -load <filename>. The program will be automatically given
those annoying line numbers (long live TWINO8). The MessageTrans module must
be loaded for the program to work (fairly obvious eh?) and the example
message file shown above must be saved in the current directory under the
filename Messages.

------------------------------- EXAMPLE PROGRAM ------------------------------
REM > MessageTst

DIM space% 16, buffer% 256

SYS "MessageTrans_OpenFile",space%,"Messages"

PRINT FNmessage0("NONE")
PRINT FNmessage1("ONE"  ,"Howard")
PRINT FNmessage2("TWO"  ,"Peter","Jane")
PRINT FNmessage3("THREE","Pop","Mobility","Freak")
PRINT FNmessage4("FOUR" ,"Joanne","Emma","Mary","Helen")

SYS "MessageTrans_CloseFile",space%
END

DEF FNmessage0(token$)
=FNmessage4(token$,"","","","")

DEF FNmessage1(token$,param1$)
=FNmessage4(token$,param1$,"","","")

DEF FNmessage2(token$,param1$,param2$)
=FNmessage4(token$,param1$,param2$,"","")

DEF FNmessage3(token$,param1$,param2$,param3$)
=FNmessage4(token$,param1$,param2$,param3$,"")

DEF FNmessage4(token$,param1$,param2$,param3$,param4$)
LOCAL length%
SYS "MessageTrans_Lookup",space%,token$,buffer%,256,param1$,param2$,param3$,param4$ TO ,,,length%
buffer%?length%=13
=$buffer%
--------------------------- END OF EXAMPLE PROGRAM ---------------------------

Yours

PMF

P.S.    Perhaps someone in Acorn would like to fill in the blanks and correct
        any errors I made in the above.

Stewart Brodie (03/12/91)

I have fiddled around with the MessageTrans module as well (put it
through disassemblers, dumping the SWI tables etc.) and I still haven't
found out the answer to one small problem:

  WHY can my programs never read the last message in the messages file?
In my applications, I have to stick a dummy message on the eg.
Messages:End
or something similar.  Any explanations?

Stewart Brodie
(snb90@uk.ac.soton.ecs)
(University of Southampton)

Stewart Brodie (03/12/91)

  The menus bit seems to be set up to suit Acorn's own menu shorthand.
I just read my menu item text in from the messages file, and settle for
doing it like that.  I have my own shorthand which I particularly like,
and so I don't use the MessageTrans_MakeMenus SWI at all.

(IDEA: If MessageTrans comes with the Printer Drivers, try looking at
the !RunImage files in the printer drivers. )

Stewart Brodie (University of Southampton) (snb90@uk.ac.soton.ecs)

RMokady@acorn.co.uk (Ran Mokady) (03/14/91)

In article <+GG&9-$@warwick.ac.uk> maumg@warwick.ac.uk (Pop Mobility Freak) writes:

>
>P.S.    Perhaps someone in Acorn would like to fill in the blanks and correct
>        any errors I made in the above.


We do read this group here at Acorn you know...

                        Ran.




As requested here is the MessageTrans documentation. 


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
   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
   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   
                        (NOTE: FILENAME MUST REMAIN UNCHANGED FOR THE DURATION OG THE FILE BEING OPEN)
        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
   In   R0 -> 4-word data structure passed to MessageTrans_OpenFile
        R1 -> token, terminated by any char <= 32, or "," or ")"
              or token:default message terminated by 0 char.
        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 sustitution 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.

   If the message token does not match, the error "Message token not found"
   is returned unless the token was followed by ":default value", in which
   case the default value is returned (I.E. either copied to the buffer or
   pointed at).  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).


   See the "File format" section for further details.



SWI MessageTrans_MakeMenus
   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 (writeable) 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
   In   R0 -> 4-word data structure passed to MessageTrans_OpenFile


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 subsitituted 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.





 
-----
"We're children, Needing other children
 And yet letting our grown up pride
 Hide all the need inside
 Acting more like children than children" 

Julian.Wright@comp.vuw.ac.nz (John Julian Wright) (03/14/91)

In article <7114@ecs.soton.ac.uk> you write:

|> I just read my menu item text in from the messages file, and settle for
|> doing it like that.  I have my own shorthand which I particularly like,
|> and so I don't use the MessageTrans_MakeMenus SWI at all.
|> 
|> (IDEA: If MessageTrans comes with the Printer Drivers, try looking at
|> the !RunImage files in the printer drivers. )

I have looked inside the PrinterDM !RunImage, only to find that Acorn
are doing exactly the same thing as you! I can not find any reference to
MessageTrans_MakeMenus or it's decimal numeric equivalent with a LIST
IF, so I assume it is not there. The menu is in fact read from the file
like any other, and parsed by a BASIC function to produce the final menu
block.

I have always used quite a radically different method of creating menu blocks:
use the assembler with EQUD statements for data values and labels to
point to the
various submenus. I have refined it somewhat by using macro assembly,
such that I
don't actually need to worry about EQUDs any more:
  eg
	.mainmenu
	FNmenu_start("Grapevine",menu_width%)
	FNmenu_item(&00,infow%  ,&21,"Info")
	FNmenu_item(&00,def_menu,&21,"Defaults")
	FNmenu_item(&80,-1      ,&21,"Quit")
	.def_menu
	FNmenu_start("Defaults",72)
	FNmenu_item(&00,-1,&21,"Load")
	FNmenu_item(&80,-1,&21,"Save")

It has the advantage that you need never worry about having to tick or
untick an item, for example because a ticked item can de defined as:
	FNmenu_item(-reverse%,-1,&21,"Reverse Sort")
and the tick will be set or cleared depending on the state of variable
'reverse%'.

Unfortunately this technique doesn't work very well with compilers,
which seem to have hernias over anything assembled :-(

    Cheers, Julian.

RMokady@acorn.co.uk (Ran Mokady) (03/18/91)

As noted by maumg@cu.warwick.ac.uk (Pop Mobility Freak), the number for
Service_MessageFileClosed was missing from my documentation on MessageTrans.
The service call number is &5E.

      Ran.


-----
"We're children, Needing other children
 And yet letting our grown up pride
 Hide all the need inside
 Acting more like children than children"