Initializing help system before first use

The initialization function

Once a module is loaded in core memory, the Module Manager calls a special function: the initialization function. Through this function, the constant symbols (Section Table of constants), subroutines (Section Table of functions), types (Section Table of types), and services (Section Table of services) that are provided by the module are passed on to Mosel. The control parameters of the module are not communicated in this way, they require the definition of a dedicated service function (Section Service ``Find Parameter'') and the implementation of two specific library functions (Section Table of functions).

In order for Mosel to find this initialization function, it must be named modulename_init (where modulename is the name given to the module) and have the following signature:

DSO_INIT modulename_init(XPRMnifct nifct, int *interver, int *libver,
                         XPRMdsointer **interf)

The parameters are used to exchange information about version numbers and the functionality provided by the module.

  • nifct is a table of functions provided by Mosel that can be called from the module during its processing. They are used to access the data of the running model (see Section Functions of the Native Interface) and is usually saved in a global variable for later use
  • interver is used to tell Mosel which version of the Native Interface is employed for the implementation of this module. This parameter must always be assigned the value XPRM_NIVERS. By default, the interface version is the one of the current Mosel version but it is possible to select an older release (such that the generated module can be used with this release) by defining the macro XPRM_NICOMPAT before including the "xprm_ni.h" header file. This macro must refer to the Mosel target version. For instance:
    #define XPRM_NICOMPAT 3000000
    #include "xprm_ni.h"
    will use the API version of Mosel 3.0.0 (functions introduced after this release are disabled)
  • libver is the version number of the module: it is generated using the macro XPRM_MKVER(M,n,r) where (M,n,r) stands for (major version number, minor version number, release number). Each number must be an integer between 0 and 999.
  • interf is a structure composed of 4 tables (and their respective sizes) describing the constants, the functions, the types and the services implemented by the module

The format of the main interface structure XPRMdsointer is the following:

{
 int sizec; XPRMdsoconst *tabconst;
 int sizef; XPRMdsofct *tabfct;
 int sizet; XPRMdsotyp *tabtyp;
 int sizes; XPRMdsoserv *tabserv;
}

Every table in this structure (constants, subroutines, types, and services) is preceded by its size. The four tables are described in detail in the following sections.

Example:

static XPRMnifct mm;

DSO_INIT mymodule_init(XPRMnifct nifct, int *interver, int *libver,
                       XPRMdsointer **interf)
{
 mm=nifct;                  /* Save the table of NI functions */
 *interver=XPRM_NIVERS;     /* Mosel NI version */
 *libver=XPRM_MKVER(0,0,1); /* Module version */
 *interf=&dsointer;         /* Pass info about module contents to Mosel */
 return 0;
}

Table of constants

Each entry of the table of constants is a pair ( constant name, constant value ). If a constant is to be declared as part of a namespace its name must be fully qualified (e.g. "mynamspc∼mycst"). A module can define integer, real, Boolean and string constants. The initialization of the table can be done using the following macros:

XPRM_CST_INT(char *name, int value)
XPRM_CST_BOOL(char *name, int value)
XPRM_CST_STRING(char *name, char *value)
XPRM_CST_REAL(char *name, static const double value)

Note that for real constants, a static variable has to be provided instead of a constant number.

static const double myreal=12.456;

static XPRMdsoconst tabconst[]=
    {
     XPRM_CST_INT("MYINT", 10),
     XPRM_CST_BOOL("MYBOOL", XPRM_TRUE),
     XPRM_CST_STRING("MYSTR", "text"),
     XPRM_CST_REAL("MYREAL", myreal)
    };

The information provided by the table of constants is used only during the compilation phase of the model: constants are immediatly replaced by their values. As a consequence, a module that only defines constants is only required for the compilation of a model using it; at execution time it is not loaded again.

Table of functions

The table of functions describes the functions, procedures, and operators that will be available in the Mosel language. Each entry of the function table is of the following structure:

{
 char *name;
 int code;
 int type;
 int nbpar;
 char *parstr;
 int (*fct)(XPRMcontext ctx, void *libctx);
}
name:
The name that will be used in the Mosel language. If the subroutine is to be declared as part of a namespace its name must be fully qualified ( e.g. "mynamspc∼myfct").
Note that different subroutines (or operators) may have the same name as long as they are not expecting the same parameters ( overloading). It is also possible to overload a predefined function or procedure with the same restriction as for user defined symbols. Overloading cannot apply between function and procedure ( i.e. a procedure cannot overload a function and vice versa).
code:
An internal code for the subroutine or operator.
This code must be either an integer value ≥1000 or a predefined code. Note that the entries in the table of functions must be sorted in ascending order of their internal code.
type:
The type returned by the routine.
For a function, the possible values are: XPRM_TYP_INT, XPRM_TYP_REAL,
XPRM_TYP_STRING, XPRM_TYP_BOOL to indicate an integer, real, string or Boolean return value respectively. The type must be XPRM_TYP_EXTN if the function returns an entity of a type managed by the module ( i.e. the function is a constructor) — in this case, the first word of the parameter string is the name of this type followed by a colon. If the function returns a set or a list the type must also be XPRM_TYP_EXTN and the first word of the parameter string must start with "&{" for a set or "&[" for a list followed by the element type and a colon. The element type is specified by a letter for basic types (same convention as for the parst) or the letter n and the type name for a native type. If the subroutine is a procedure the type must be XPRM_TYP_NOT.
By default a function returning a non-basic type is considered to be a constructor ( i.e. the returned value is a newly created entity). If such a function returns a reference to an existing entity it must increase the reference count of this object (see Section Reference counting) and have the flag XPRM_FTYP_PTR as part of its type.
Functions the name of which starts with the string "get", returning a basic type ( i.e. integer, real, string or Boolean) and taking as their only argument a native type, linctr or mpvar are identified as attribute accessors (see findattrdesc). For instance the function "getsol(mpvar):real" returns the sol attribute of a decision variable. Adding XPRM_FTYP_NOATTR to the type of a function of this kind prevents Mosel from recording it as an attribute accessor.
nbpar:
The number of parameters required by the routine
parstr:
The parameter string is used to describe the type of each parameter.
This string is composed with the following characters:

i an integer
r a real
s a registered text string (see regstring)
S a text string (it might be deleted after the end of execution of the routine)
b a Boolean
v a decision variable (type mpvar)
c a linear constraint (type linctr)
I a range set
a an array (of any kind)
e a set (of any type)
l a list (of any type)
|xxx| external type named `xxx'
!xxx! the set named `xxx'
Andx.t an array indexed by `ndx' of the type `t'. `ndx' is a string describing the type of each indexing set. `ndx' may be omitted in which case any array of type `t' is a valid parameter.
Et a set of type `t'
Lt a list of type `t'
? any type, the routine will receive actually 2 parameters for this marker: the first one, an integer, is the type of the following one (the effective value of the argument)
* must be the last character: the function has a variable number of arguments

If the last character of the parameter string is *, the function accepts a variable number of arguments: the corresponding parameter is a list (possibly empty) containing the supplementary parameters.
Moreover, if the function is of type XPRM_TYP_EXTN, the string starts with the name of the type followed by a colon.
Example: "mytype:ir|mytype|s*" is the signature of a function of type `mytype' expecting at least 4 parameters (integer, real, mytype and string).
The signature for a function that returns a list of text and take a real as only argument will be: "&[ntext:r".
fct:
The function Mosel has to call to perform the operation.
The prototype of all functions must be (see Section Defining subroutines):
int functionname(XPRMcontext ctx, void *libctx);

Example:

static int my_getsol(XPRMcontext ctx, void *libctx);
static int my_getname(XPRMcontext ctx, void *libctx);
static int my_eql(XPRMcontext ctx, void *libctx);
static int my_new(XPRMcontext ctx, void *libctx);

static XPRMdsofct tabfct[]=
    {
     {"getsolarray", 1000, XPRM_TYP_NOT, 2, "aa", my_getsol},
     {"getname", 1005, XPRM_TYP_STRING, 1, "|mytype|", my_getname},
     {"@=", 1011, XPRM_TYP_BOOL, 2, "|mytype||mytype|", my_eql},
     {"@&", 1015, XPRM_TYP_EXTN, 3, "mytype:sri", my_new}
    } 

For details on the definition of operators (such as the third and fourth entries in this example) the reader is referred to Section Special functions/operators.

Table of types

Types introduced by modules are handled by Mosel just like any other standard type (integer, real...). To define a type, some specific functions have to be provided by the module. Each entry of the table of types contains the following items:

name (char *):
The name of the type that will be used in the Mosel language. If the type corresponds to a problem extension, the name must have the form mainpbtyp.extn (see Section Problem types). If the type is to be declared as part of a namespace its name must be fully qualified ( e.g. "mynamspc∼mytype").
code (int):
An internal code for the given type. This code is an integer value not larger than 65535. Note that types must be sorted in ascending order of their internal code.
props (int):
A bit coded set of properties. The supported properties are:
  • XPRM_DTYP_PNCTX: If this flag is set, the function tostring (see below) can be called with a NULL context.
  • XPRM_DTYP_RFCNT: If this flag is set, the module handles reference count for this type. As a consequence Mosel may call the function create (see below) with a reference to a previously created object for increasing its reference count. The function delete (which is mandatory in this case) is then called as many times as the create function has been used for a given object before this object is effectively released. When this property is not available for a type, Mosel handles itself the reference counting: this is in general less efficient except if the type is a problem extension (reference counting is not used in this case).
  • XPRM_DTYP_APPND: If this flag is set, the function copy supports appending.
  • XPRM_DTYP_ORSET: If this flag is set, the function copy can be called only for resetting an object.
  • XPRM_DTYP_PROB: This flag must be set if the type corresponds to a problem.
  • XPRM_DTYP_SHARE: If this flag is set, the create function of this type supports creation of shared entities.
  • XPRM_DTYP_TFBIN: If this flag is set, the tostring and fromstring functions of this type support exportation and exportation in binary format.
  • XPRM_DTYP_ORD: If this flag is set, the compare function implements all comparison operators (i.e. objects of this type are ordered).
  • XPRM_DTYP_CONST: If this flag is set, the create function supports creation of constants and the copy function can compute hash values.
create function (void *):
The function Mosel has to call for creating an object of this type. The function must return a pointer to this new object or NULL in case of failure. The prototype of create is:
void *(*create)(XPRMcontext ctx, void *libctx, void *ref,int tnop)
This function is mandatory. If the module does not support reference count for this type, the parameter ref is always NULL and can be ignored. Otherwise, the flag XPRM_DTYP_RFCNT has to be set (see above) and whenever this function is called with a valid pointer as the third parameter, the reference count for the corresponding object must be incremented (no new object has to be created). The value returned should be the provided reference. The last parameter is the order number associated to this type for the running model.
If the type has property XPRM_DTYP_SHARE or XPRM_DTYP_CONST the semantic of the last parameter changes: it stores both the type order number (which can be extracted using the macro XPRM_TYP(tnop)) and a code indicating what operation to perform. The macro XPRM_CREATE(tnop) returns the following operation codes:
  • XPRM_CREATE_NEW: The routine behaves as described above (i.e. handling of an ordinary entity).
  • XPRM_CREATE_SHR: The routine has to return a shared entity: if the pointer ref is NULL a newly created entitiy must be returned. Otherwise the provided reference ref points to the initial object that is to be shared (that has been created by a preceding call to this routine from another model). The function does not have to return this reference (this can be another datastructure) but it is expected that both pointers refer to the same entity. Note that several models may call this function with the same reference object at the same time. This opton will be used if the type has the property XPRM_DTYP_SHARE.
  • XPRM_CREATE_CST: The function has to return a constant copy of the provided object. The module must make sure that any attempt at modifying such a constant (e.g. by using an assignment) will cause a runtime error. This opton will be used if the type has the property XPRM_DTYP_CONST.
delete function (void *):
The function Mosel has to call for deleting an object previously allocated using the create function.
void (*fdelete)(XPRMcontext ctx, void *libctx, void *todel,int typnum)
This function is optional (the entry may be NULL) when reference count is not handled by the module, if defined, it is used to delete local and temporary objects. Note that if reference count is implemented, this function will be called as many times as the create function has been called for a given reference, the object must be deleted only the last time the function is used. Note that global objects are not explicitly deleted: it is the responsibility of the module to release the resources associated to these objects using the reset and onexit services (see Section Service ``Reset'' and Service ``On Exit''). The last parameter is the order number associated to this type for the running model.
tostring function (void *):
This function has to be called by Mosel for getting a textual representation of an object.
int (*tostring)(XPRMcontext ctx, void *libctx, void *obj, char *dest,
                int maxsize,int typnum)
The textual representation of obj encoded in UTF-8 has to be copied into dest the maximum length of which is maxsize. The reference obj might be NULL: in this case the function is expected to return the textual representation of an entity in its initial state ( i.e. just after having been created). The function must return the length of the generated string (excluding the terminating null byte) or a negative value in case of error. If the string that is to be returned in dest exceeds the given maximum length, function tostring returns the required length but not the string itself : it is then called a second time with a sufficiently large maximum size.
If the type has property XPRM_DTYP_TFBIN the system may use this routine to generate a binary representation of the entity: in this case the last parameter is bit encoded (type number can still be retrieved using XPRM_TYP(typnum)) and the bit XPRM_TFSTR_BIN is set when the binary fomat is requested. The result of the call is expected to be a platform independent sequence of bytes (instead of the default textual representation) that can be decoded by the function fromstring.
This function is optional (the entry may be NULL), if defined, it is used for displaying values (procedures write/ writeln) and by the initializations to procedure.
fromstring function (void *):
This function has to be called by Mosel for initializing an object from a textual representation.
int (*fromstring)(XPRMcontext ctx, void *libctx, void *obj,
                  const char *src,int typnum, const char **end)
The object obj is initialized with the content of the string src encoded in UTF-8. When the end parameter is not NULL, the pointer to the first character not used by the conversion has to be returned via this parameter. It must receive a copy of src in case of failure. If successful, the function must return 0; any other value is interpreted as a failure.
If the type has property XPRM_DTYP_TFBIN the system may use this routine to initialize the entity from a binary representation produced by the tostring function: in this case the last parameter is bit encoded (type number can still be retrieved using XPRM_TYP(typnum)) and the bit XPRM_TFSTR_BIN is set when the input buffer is in binary fomat. In this mode the parameter end is initialized with a reference to the first byte after the data ( i.e. the length of the input buffer is *end-src).
This function is optional (the entry may be NULL), if defined, it is used by the initializations from procedure.
copy function (void *):
This function is required for assignments not explicitly stated ( e.g. in array initialization or when assigning records) and may be used to generate some assignments (as a replacement for the "@:" and "@P" operators, see section Special functions/operators).
int (*copy)(XPRMcontext ctx, void *libctx, void *dest,void *src,int tnop)
The parameter tnop is bit encoded: it stores both the type order number (which can be extracted using the macro XPRM_TYP(tnop)) and a code indicating what operation to perform. The macro XPRM_CPY(tnop) returns the following operation codes:
  • XPRM_CPY_COPY: The object dest receives the content (or becomes a copy) of src (which may be NULL). This operation is not used if the type has property XPRM_DTYP_ORSET.
  • XPRM_CPY_RESET: The object dest is reset (i.e. it returns to its initial state). This operation is essentially used to implement the reset function of the Mosel language.
  • XPRM_CPY_APPEND: The object dest is extended with a copy of src (which may be NULL). This operation is used if the type property XPRM_DTYP_APPND is set and property XPRM_DTYP_ORSET is not set.
  • XPRM_CPY_HASH: The pointer dest references an unsigned integer that must be populated with a hash value computed from the object src (which may be NULL), the implementation may use hashmix for this calculation. This operation is used if the type property XPRM_DTYP_CONST is set and property XPRM_DTYP_ORSET is not set.
If successful, the function must return 0; any other value is interpreted as a failure.
This function is optional (the entry may be NULL) but if it is missing, the operations where it is necessary are disabled by the compiler for the corresponding type.
compare function (void *):
This function is required for comparison of aggregated objects ( e.g. when testing equality of records including fields of this type), it may also be used to implement comparators if the corresponding functions are not defined.
int (*compare)(XPRMcontext ctx, void *libctx, void *obj1,void *obj2,int tnop)
The parameter tnop is bit encoded: it stores both the type order number (which can be extracted using the macro XPRM_TYP(tnop)) and a code indicating what operation to perform. The macro XPRM_COMPARE(tnop) returns the following operation codes:
  • XPRM_COMPARE_EQ: Test whether obj1 and obj2 are equal.
  • XPRM_COMPARE_NEQ: Test whether obj1 and obj2 are different.
  • XPRM_COMPARE_LTH: Test whether obj1 is less than obj2.
  • XPRM_COMPARE_LEQ: Test whether obj1 is less or equal than obj2.
  • XPRM_COMPARE_GEQ: Test whether obj1 is greater or equal than obj2.
  • XPRM_COMPARE_GTH: Test whether obj1 is greater than obj2.
  • XPRM_COMPARE_CMP: Return 0 if obj1 and obj2 are the same, -1 if obj1 is less than obj2 and 1 otherwise.
If successful, the function must return 1 if the comparison is true and 0 otherwise (except for the XPRM_COMPARE_CMP comparison that may also return -1). Error conditions are reported using the special return value XPRM_COMPARE_ERROR.
This function is optional (the entry may be NULL) but if it is missing, the operations where it is necessary are disabled by the compiler for the corresponding type. By default the compiler expects that only the 2 first operations are defined, the type property XPRM_DTYP_ORD indicates that the function supports all operations.

Example:

static XPRMdsotyp tabtyp[]=
{
 {"firsttype", 1, 0, createfirst, del1, tostr1, fromstr1,copy1,cmp},
 {"secondtype", 2, XPRM_DTYP_RFCNT, create2, delete2, NULL, NULL, NULL,NULL},
 {"mpproblem.mypb", 3, XPRM_DTYP_PROB, newpb, delpb, NULL, NULL, cppb,NULL}
};

Table of services

Services are special tasks that are not directly linked to the Mosel language itself (that is, they are not visible to the user of a module). Under some particular circumstances, Mosel looks for a service. If this service is implemented by the module, the corresponding function is called. Each entry of the table of services is the pair ( service code, function to call ).

Example:

static XPRMdsoserv tabserv[]=
{
 {XPRM_SRV_RESET,(void *)my_reset},
 {XPRM_SRV_PRIORITY,XPRM_MKPRIORITY(-1)},
 {XPRM_SRV_UNLOAD,(void *)my_unload}
};

Note that all services are optional. See section Defining services for a comprehensive list of services.