


                   M2LMC - Modula2 Library-Modul-Converter


                                  © 1994

                             Carsten Ziegeler

                               Version 1.1



                             What does M2LMC ?
                             -----------------

M2LMC usually converts every standard library module for M2Amiga
into an appropriate module which can then be converted into a
shared library using the library linker m2liblink !
M2LMC was created out of the problems which occure creating a
shared library out of a standard library module.
Usually you don't design your library in a way that it can be used
with m2liblink without changing the code.
But if you want to do so, you have to give every procedure register
parameters. If you have done this, you will notice that M2Amiga will
usually not compile the implementation module, because there are
not enough free registers anymore. And now you have to do a lot of
unnecessary work to make the library run !
But don't worry ! Now you have M2LMC which does all of this work for
you ! This means you can develope your module as a normal standard
library module for M2Amiga, then you use M2LMC and (wupp) you have
a shared library !


                             Copyright
                             ---------

COPYRIGHT NOTICE

M2LMC software and documentation are Copyright © 1994 by Carsten Ziegeler.
All rights reserved.

DISCLAIMER

The author is not responsible for any loss of data, damages to software or
hardware that may result directly or indirectly from the use of this
program. The author reserves the right to make changes to the software or
documentation without notice.

PREFACE

This program is freeware, this means that you can copy it freely as long as
you don't ask any more money for it than a nominal fee for copying. If you
want to distribute this program you should keep this document with it. This
program cannot be used for commercial purposes without written permission
from the author.

None of the files of the M2LMC package may be modified or left out without
permission of the author. Crunching or archiving is allowed only if none of
the M2LMC files get modified by it.

CONTENTS

M2LMC          The converter
M2LMCUI        GUI for M2LMC
M2LMC.doc      English documentation
M2LMC.dok      German documentation


                             Installation
                             ------------

Copy the M2LMC and the M2LMCUI files into your M2: drawer and if you
need the documentation copy it to whereever you want.
But notice that M2LMCUI requires at least OS2.04 for the graphical
user interface. (It uses the modula2 linker library version of the
guitools.library !)


                            Starting M2LMC
                            --------------

Usually M2LMC is started from CLI. It knowns the following parameters:

M2LMC [-rFILENAME] [-wFILENAME] [-vVERSION] [-vrREVISION] MODULENAME


 -vVersion   The version of the library, e.g -v37 for a library under
             OS2.04.
             Predefined is your current kickstart version !
 -vrRevision The revision number. Predefined is 1.

 MODULENAME  The module to convert. You have to specify the whole path
             without extensions !
             For example: M2LMC txt/NewLibrary.
             M2LMC would now convert txt/NewLibrary.def into
             txt/NewLibraryLib.def and txt/NewLibrary.mod into
             txt/NewLibraryLib.mod.

 -wFILENAME  With these you can define a temporary data file in which
 -rFILENAME  M2LMC saves the required information about the procedures
             in the new library.
             These values can be changed using a normal ASCII editor
             and if you then use -rFILENAME M2LMC uses these values
             and doesn't scan the modules again !
             Using this option you can control the work of M2LMC !
             (This is exactly what M2LMCUI does for you !)
             You will get more information about the temporary file
             in a few lines...



                            The Conversion
                            --------------

The changes in the definition module:

M2LMC copies the definiton module and concats 'Lib' to the modulename.
It also adds the following lines:
- CONST version = <VERSIONSNR>; (* You can specify this using the -v option*)
- TYPE <modulename>BasePtr = POINTER TO <modulename>;
       <modulename>Base = RECORD
         lib:Library;
         (* store global variables here *)
       END;
- CONST baseSize = SIZE(<modulename>Base);
- The definitions for the procedures LibOpen, LibClose, LibExpunge and
  LibExtFunc which will be set above all other procedure declarations.

Furthermore, M2LMC changes the import lists, so that this module can be
compiled without any further changes by you !
All procedures will get register parameters. For all types except pointers
M2LMC uses the data registers beginning with D0 and for pointers the
address registers are used beginning with A0.
M2LMC chooses automatically the register type, but this can be controlled
if necessary by using the temporary data file.


The changes in the implementation module:

M2LMC copies the implementation module and concats 'Lib' to the modulename.
It also adds the following lines:
- All control code is turned off (e.g. (* NilChk:=FALSE *))
- The import lists are extended
- CONST revision = <REVISIONSNR>; (* Option -vr *)
- VAR myLib : <modulename>BasePtr;
- The procedures LibOpen, LibClose, LibExpunge and LibExtFunc are added.
- After the BEGIN statement of the module the following line is added:
  myLib := CAST(<modulename>BasePtr, dosCmdLen);
- All procedures get (*$ LoadA4:=TRUE *)
- All procedures will get register parameters. In addition to avoid the
  problem with not having enough registers when compiling, M2LMC writes
  an interface procedure for each library function.
  An 'E' is added to the procedure's name and M2LMC generates a new
  procedure with this name which pushes all the registers onto the stack
  and then calls the old procedure !
  But this can only work, if M2LMC knows the size of the data types !
  M2LMC knows the following data types and puts them automatically into
  data registers (the size in bytes is given in brackets):
   - SHORTINT  (1)
   - INTEGER   (2)
   - LONGINT   (4)
   - SHORTCARD (1)
   - CARDINAL  (2)
   - LONGCARD  (4)
   - SHORTSET  (1)
   - BITSET    (2)
   - LONGSET   (4)
   - FFP       (4)
   - REAL      (4)
   - CHAR      (1)
   - BOOLEAN   (1)
  All other types which name doesn't end with <Set> will be put into an
  address register with the size of 4 bytes. Types which end with <Set>
  are stored into data registers with also a size of 4 bytes !



   Changing the procedure declarations using the temporary file
   ------------------------------------------------------------

The temporary file contains all important information about every
procedure, e.g which parameters will put in which register and
what size this type has.
M2LMC knows some types and is so able to give them the right
register type and size, but there can still be some problems, e.g.
with SET types which are not 4 bytes long !
Using the temporary file you have the possibility to change the
register and the size of every parameter of a procedure !
In addition it is possible to tell M2LMC whether it should create
an interface routine for a procedure or not. This routine is
needless if not many parameters are used. Often you have to try
if the routine is necessary or not !

If you have OS2.04 or above, you can use M2LMCUI to change the
temporary file !
For all the other pour users now the description of the temporary file:
The keywort ##PROC= marks a new procedure definition. After the keywort
follows the name of the procedure.
Now these four keyworts follow for each parameter of the procedure:
VAR=     : name of the variable
TYPE=    : type of the variable
LENGTH=  : size of the type in bytes
REG=     : register
After all parameters are specified, the keywort INTERFACE= follows
together with one of the values TRUE or FALSE. With this you can tell
M2LMC to create an interface routine or not !


What have YOU to do ?
---------------------

The only thing you have to take care off is to check that your module
is correct and translatable into a shared library !
The global variables must be plugged into the LibraryBase structure
which M2LMC creates and the implementation module must be modified
in the same way.



                          Using M2LMCUI
                          -------------

The format of the temporary file is not very pretty, so M2LMCUI was
created. It requires OS2.04 for the graphical user interface.
After starting M2LMC from CLI or Workbench, you have to specify
the same parameters as for M2LMC (modulename, version, revision
and a name for the temporary file). In difference to M2LMC you
HAVE to specify EVERY parameter !
Then press <Do it> and M2LMCUI calls M2:M2LMC to create the
temporary file. If this file still exists, M2LMC doesn't scan the
module again and this file is used without any changes !
Then M2LMCUI reads this file and opens a new window with a lot of
gadgets ! On top of the window you see the procedure name.
Next to it is a checkbox gadget for the interface routine.
Below are for every parameter gadgets which contain the size and
the register of this parameter. You can change this.
Using the <++> or <--> gadgets you are able to navigate through
all procedures of this module.
Pressing <OK> will write the new changed temporary file and M2:M2LMC
is called again and the conversion is started !


                             Known Problems
                             --------------

 1. The implementation module MUST have a BEGIN statement. But this
    can be an empty procedure ! If there is no BEGIN statement,
    M2LMC refuses to do the conversion !
 2. TYPE definitions for PROCEDURE statements should be turned into
    (* *) paires, so that they are ignored by M2LMC, because the
    parser is VERY simple. It only scans for the PROCEDURE keyword,
    and thinks than that this is a real PROCEDURE declaration !
    But if this is a TYPE declaration, M2LMC interprets it wrong
    and creates a lot of rubbish.
    You don't have to remark the TYPE declarations of the PROCEDURE
    statement is followed by an open bracket. (e.g. ...PROCEDURE(....)
 3. If a procedure has locale procedure, you have to set the
    (*$ LoadA4:=TRUE *) statement by hand to the appropriate place,
    because M2LMC set it straight after the PROCEDURE declaration.
    This is also a problem of the simle parser.
 4. For the same reason you have to import TYPEs in the implementation
    module in the same way as in the definition module, this means
    the following example is not allowed:

    DEFINITION MODULE ....

    IMPORT I:IntuitionD;

      PROCEDURE OpenAWindow(wptr : I.WindowPtr);

     END ...

     IMPLEMENTATION MODULE ....

       FROM IntuitionD IMPORT WindowPtr;

       PROCEDURE OpenAWindow(wptr : WindowPtr);
     END ...

     M2LMC would now create the following line in the implementation
     module:

       PROCEDURE OpenAWindow(wptr{R.A0} : I.WindowPtr);


But I am sure that you can life with this restrictions (because I can
do it).



                           Possible Error Causes
                           ---------------------

What can you do if the library linker creates happily your library,
you test it and ..whoop... flash..flash..flash - a crash !

During my work with M2LMC I had the following problems:

 1) In any procedure, M2LMC created an interface for, is the size of
    the variable wrong.
    To Do: Usign M2LMCUI you have to check all procedures if the
           size and the register are correct !
 2) A procedure has a locale procedure, so the (*$ LoadA4:=TRUE *)
    statement is at the wrong position.
    To Do: Check the module for all locale procedures and change then
           the place of the (*$ LoadA4:=TRUE *) statement after
           the last locale procedure.

If you module was correct before the conversion and you have done
everything mentioned above, there is no reason that your new shared
library won't function...


                       A Short Example
                       ---------------

If you have a library called test.def/test.mod with the following procedure

  PROCEDURE Wow(a, b : CARDINAL; c : LONGINT):BOOLEAN;

a call to <M2LMC test> would create the following:

In the definition module testlib.def:

  PROCEDURE Wow(a{R.D0}, b{R.D1} : CARDINAL; c{R.D2} : LONGINT):BOOLEAN;

In the implementation module testlib.mod

  PROCEDURE WowE(a, b : CARDINAL; c : LONGINT):BOOLEAN;
  (*$ LoadA4:=TRUE *)
  ....
  END WowE;

  PROCEDURE Wow(a{R.D0}, b{R.D1} : CARDINAL; c{R.D2} : LONGINT):BOOLEAN;
  (*$ EntryExitCode:=FALSE *)
  BEGIN
    ASSEMBLE(MOVE.W D0, -(A7)
             MOVE.W D1, -(A7)
             MOVE.L D2, -(A7)
             BSR    WowE(PC)
             RTS  END);
  END Wow;

If you call <M2LMC -wTEMP test> the TEMP file would look like this:

##PROCEDURE=Wow
VAR=a
TYPE=CARDINAL
LENGTH=2
REG=D0
VAR=b
TYPE=CARDINAL
LENGTH=2
REG=D1
VAR=c
TYPE=LONGINT
LENGTH=4
REG=D2
INTERFACE=TRUE
##ENDOFFILE




Enjoy it !

May-1994, Carsten Ziegeler
          Augustin-Wibbelt-Str.7
          33106 Paderborn

