Initializing help system before first use

Structures for passing information

The module that we are about to write needs to provide the following:

  • definition of the new type
  • functions and operations on this new type, namely
    • creation and initialization functions for the new type
    • a set of subroutines for accessing (and changing) detailed task information
    • functions for reading and printing or outputting to file
    • comparison operation between tasks
  • a reset service
  • initialization of the module

We shall first look at the structures that must be defined for passing to Mosel the information provided by the module.

List of types

A type definition in Mosel has the following form:

 static XPRMdsotyp tabtyp[]=
    {
     {"task", 1, XPRM_DTYP_PNCTX|XPRM_DTYP_RFCNT,
      task_create, task_delete, task_tostr, task_fromstr, task_copy, task_compare}
    };

The arguments given in the definition of the new type are

  • the name of the new type,
  • a reference number to this type within the module followed by another integer encoding type properties (here: enable calls to task_tostr with NULL context and indicate that the type implements reference counting);
  • the six type-related functions: the first, the type instance creation function, is required whereas the remaining five: deletion, converting to string, initializing from string, copying and comparison, are optional.

A complete description of the possible values for the entries of this structure is given in Section List of types.

List of subroutines

To be able to work with this new type as shown in the model example in the previous section we have to define a list of subroutines as follows:

static XPRMdsofct tabfct[]=
    {
     {"getname", 1000, XPRM_TYP_STRING, 1, "|task|", task_getname},
     {"getduration", 1002, XPRM_TYP_REAL, 1, "|task|", task_getdur},
     {"getaflag", 1003, XPRM_TYP_BOOL, 1, "|task|", task_getaflag},
     {"getduedate", 1004, XPRM_TYP_INT, 1, "|task|", task_getdue},
     {"setname", 1005, XPRM_TYP_NOT, 2, "|task|s", task_setname},
     {"setduration", 1006, XPRM_TYP_NOT, 2, "|task|r", task_setdur},
     {"setaflag", 1007, XPRM_TYP_NOT, 2, "|task|b", task_setaflag},
     {"setduedate", 1008, XPRM_TYP_NOT, 2, "|task|i", task_setdue},
     {"@&", 1011, XPRM_TYP_EXTN, 1, "task:|task|", task_clone},
     {"@&", 1012, XPRM_TYP_EXTN, 1, "task:s", task_new1},
     {"@&", 1013, XPRM_TYP_EXTN, 1, "task:r", task_new2},
     {"@&", 1014, XPRM_TYP_EXTN, 2, "task:sr", task_new3},
     {"@&", 1015, XPRM_TYP_EXTN, 4, "task:srbi", task_new4},
     {"@&", 1016, XPRM_TYP_EXTN, 3, "task:rbi", task_new5},
     {"@:", 1020, XPRM_TYP_NOT, 2, "|task||task|", task_assign},
     {"@=", 1021, XPRM_TYP_BOOL, 2, "|task||task|", task_eql}
    };

Some of the notations used in this list are new and may require an explanation. The first eight subroutine definitions (get... and set...) are similar to the subroutine definition we have seen in the previous chapter:

     {"getname", 1000, XPRM_TYP_STRING, 1, "|task|", task_getname},

defines the function getname that returns a string and takes a single argument, namely a task. The line

     {"setname", 1005, XPRM_TYP_NOT, 2, "|task|s", task_setname},

defines a procedure (no return value!) that takes two arguments, a task (|task|) and a string (s). The names of external types must be surrounded by `|' in the parameter format encoding to distinguish them clearly from the one-letter encoding of Mosel's own types.

The remaining entries in the list of subroutines have special names starting with the symbol `@': they define operators:

@&
constructors
@:
assignment operator
@=
comparison operator

The constructors return new objects of an external type (return code XPRM_TYP_EXTN). Since a module could specify several new types, the exact return type must be indicated in the format string, separated by a colon from the list of argument types.
The assignment operator `:' has a predefined format, as does the comparison operator `='.

As may be deduced from the list above, the reference numbers of the functions within the module must be in ascending order, but need not necessarily be consecutive numbers.

List of services

In this example, for the first time, we need to define a service. A service function is called by Mosel at certain predefined places (it has no direct correspondence in Mosel programs). The service function that needs to be defined when working with new types is a reset function. It is also required in any other cases where between several calls to module functions something needs to be kept in memory (the context of the module). The reset service is called at the beginning and the termination of the execution of a Mosel program that uses the module. At its first call, the reset function creates and initializes a context for the model, and deletes this context (and any other resources used by the module for this model) at the second call.

 static XPRMdsoserv tabserv[]=
    {
     {XPRM_SRV_RESET, (void *)task_reset}
    };

The entry in the list of services simply indicates the type of service that is provided (here: reset) and the name of the library function that implements it.

Interface structure

The interface structure of this example defines all but the first entry with the lists of functions, types, and services shown above.

static XPRMdsointer dsointer=
    {
     0, NULL,
     sizeof(tabfct)/sizeof(XPRMdsofct), tabfct,
     sizeof(tabtyp)/sizeof(XPRMdsotyp), tabtyp,
     sizeof(tabserv)/sizeof(XPRMdsoserv), tabserv
    };

Module context

As mentioned earlier, the task module defines a context to collect all objects that have been created by this module during the execution of a model so that all allocated space may be freed when the execution is terminated. In this example, the context is nothing but a chained list of tasks:

typedef struct
    {
     s_task *firsttask;
    } s_taskctx;

A module context can also be used to store the current values of control parameters (see Chapter Control parameters) or any other information that needs to be preserved between different calls to the module functions during the execution of a model.