Defining subroutines
All library functions that implement subroutines (or operators, see Section Special functions/operators) have the same prototype
int functionname(XPRMcontext ctx, void *libctx);
The first parameter of such a function is the Mosel execution context under which the function is called. This context describes the state of the Mosel Virtual Machine plus various pieces of information related to the model that is executed. It is required by most functions of the Native Interface. The second parameter is the module context defined by the reset service (see Section Service ``Reset''). If this service is not implemented, the value of this parameter is NULL.
The return value of a library function must be XPRM_RT_OK if the function succeeded, XPRM_RT_ERROR if it failed (in which case the execution terminates with an error) or XPRM_RT_STOP to interrupt the execution of the model. It is also possible to terminate the execution in the same way as exit(code) does by pushing onto the stack the exit code then returning XPRM_RT_EXIT.
If the execution of a routine is not immediate (it performs a solution algorithm that requires several seconds for instance), it is recommanded to implement cancelation points: from time to time, the routine should call the NI function chkinterrupt to check whether execution is to be continued. If the return value of this function is not 0, the execution is expected to terminate and the routine has to interrupt its processing as soon as possible then return.
During the execution of the function, the actual parameters of the subroutine (in the Mosel language) have to be taken from the Mosel stack and if the routine is a function, the return value must be put onto this stack before the termination of the function. The following macros are provided for accessing the Mosel stack.
Macros for taking objects from the stack:
XPRM_POP_INT(XPRMcontext ctx)
XPRM_POP_REAL(XPRMcontext ctx)
XPRM_POP_STRING(XPRMcontext ctx)
XPRM_POP_REF(XPRMcontext ctx)
Macros for putting objects onto the stack:
XPRM_PUSH_INT(XPRMcontext ctx, i)
XPRM_PUSH_REAL(XPRMcontext ctx, r)
XPRM_PUSH_STRING(XPRMcontext ctx, s)
XPRM_PUSH_REF(XPRMcontext ctx, r)
Note that the Mosel stack manipulates only three basic types: integer, real, and string. Boolean values are handled as integers (0 is false, 1 is true); all other types (including arrays, sets and external types) are passed by reference (the macros XPRM_POP_REF and XPRM_PUSH_REF have to be used for those types). Routines taking references as parameters must have appropriate handling for the NULL pointer: this is the representation of an empty string and the value returned when accessing an uninitialized object (set, array or non existent dynamic array entry).
Text strings manipulated by Mosel are stored in a dictionary. As a consequence, strings produced by a native routine (for instance as the result of a concatenation) have to be registered using the function regstring before being sent to Mosel either as a return value (macro XPRM_PUSH_STRING) or stored in a Mosel object (as an identifier, set element or array entry).
Mosel maintains a reference count of all referenced objects (decision variables, linear constraints, lists, sets, arrays and external types): an object is released when its last reference is deleted. If a native routine needs to keep a reference to an object after its termination (to be used later in a subsequent call for instance) it should save the reference using newref in order to make sure the object will not be deleted. The native code should then use delref after it no longer requires the saved reference.
Example:
Assume the routine myfct takes an integer, a real and a set of decision variables as parameters and returns a string. If the C function providing the implementation of this routine is c_myfct and its internal code is 1010, the declaration in the table of functions is:
{"myfct",1010,XPRM_TYP_STRING,3,"irEv",c_myfct}
The function c_myfct has to get from the Mosel stack the three parameters and before its termination, to put back the result value. The skeleton of this function is therefore:
int c_myfct(XPRMcontext ctx, void *libctx) { int int_param; char *result; double real_param; XPRMset set_param; int_param =XPRM_POP_INT(ctx); /* Get the first parameter */ real_param=XPRM_POP_REAL(ctx); /* Get the second parameter */ set_param =XPRM_POP_REF(ctx); /* Get the third parameter */ /* Body of the function: assigns the result variable */ /* Put the result onto the stack */ XPRM_PUSH_STRING(ctx,mm->regstring(ctx,result)); return XPRM_RT_OK; /* The function succeeded */ }
If a module defines control parameters, it needs to implement the special routines getparam and setparam for its parameters. Function getparam takes as its only argument the code of the control parameter in the module (obtained at compilation through the service ``find parameter'', see Section Service ``Find Parameter'') and returns the current value of the parameter. The procedure setparam has two arguments, the code of the parameter and its new value.
At the beginning of the table of functions, the following two lines must be added in the order shown here (assuming that my_getpar and my_setpar are the implementations of the two subroutines):
{"", XPRM_FCT_GETPAR, XPRM_TYP_NOT, 0, NULL, my_getpar}, {"", XPRM_FCT_SETPAR, XPRM_TYP_NOT, 0, NULL, my_setpar},