Module Subroutines Callable from C

This section describes the user written C interface which allows modules in C to be compiled and loaded into Open GENIE so that they can be run as if they had been built into the original code. Once loaded, a module can be called as efficiently as any other hard coded function from Open GENIE (see the Module() command). The function will run in a "safe" environment so that if it should crash, control will return to Open GENIE without causing a crash of Open GENIE itself.

Here we give reference information for:

  1. C template for a user written module.
  2. Helper functions to aid communication of the module with Open GENIE.

For more general information and examples of using modules, see the Open GENIE User Manual

C Template

The essential purpose of this interface is to allow data transfer and communication with the running Open GENIE session from which the external C module was called. All data transfer is handled by allowing the Module() command in GCL to take a workspace of parameters which are made available to C functions if they adhere to a certain template. To access parts of the workspace in the C interface a set of Helper Functions which allow data to be read and written to and from this parameter workspace are provided.

The C template is actually very simple and is given below. A normal procedure for converting an existing C program is to take the existing analysis functions and to call them from one or more functions following the C template below. User interface functions doing output can be replaced with the print helper functions (or they may more easily be done from GCL and/or the TK graphical interface anyway once the module is in Open GENIE).

/* A C template function for creating an Open GENIE module in C
 * Several functions like the one routine below may be included in one
 * module.
 * Called from GCL with e.g. MODULE:EXECUTE:C("my_c_module", PARS)
 *
 * Freddie Akeroyd, ISIS, 19/2/97 - modified by CM-S 2/7/97
 */
/* 
 * These two genie includes must be present in any C module 
 * They include important definitions and typedefs
 */
#include <genie_cmodule.h>
#include <genie_cmodule_ver.h>

void my_c_module(GenieWorkspace* pars_get, GenieWorkspace* pars_put)
{
/* ... User definitions here ... */
/* 
 * All C modules should do the following test - it ensures that a module
 * linked against a recent version of the genie library is
 * not executed by a program linked against an older version
 */
    if (!cmodule_version_ok(CMODULE_MAJOR_VERSION, CMODULE_MINOR_VERSION))
    {
	cmodule_print("Library version mismatch for MY_C_MODULE",
			CMODULE_PRINT_ERROR);
	return;
    }
/* All user code goes here, generally the format will be to access some
 * data using the helper functions, process it via new or exising user
 * written functions, and finally return any modified parameters using the
 * helper functions
 */
}

Helper Functions

There are three sorts of helper functions provided by the C module interface. They are all listed below

Commands to obtain data from Open GENIE Description
cmodule_get_double Reads a double precision real from the PARS workspace
cmodule_get_int Reads an integer from the PARS workspace
cmodule_get_real Reads a real from the PARS workspace
cmodule_get_string Reads a string from the PARS workspace
cmodule_get_double_array Reads a double precision real array from the PARS workspace
cmodule_get_int_array Reads an integer array from the PARS workspace
cmodule_get_real_array Reads a real array from the PARS workspace
cmodule_get_string_array Reads a string array from the PARS workspace
Commands to return data to Open GENIE Description
cmodule_put_double Replaces a double precision real in the PARS workspace
cmodule_put_int Replaces an integer in the PARS workspace
cmodule_put_real Replaces a real in the PARS workspace
cmodule_put_string Replaces a string in the PARS workspace
cmodule_put_double_array Replaces an double precision real array in the PARS workspace
cmodule_put_int_array Replaces an integer array in the PARS workspace
cmodule_put_real_array Replaces an real array in the PARS workspace
cmodule_put_string_array Replaces an string array in the PARS workspace
cmodule_put_nd_real_array Replaces an n-dimensional real array in the PARS workspace
Commands to communicate with the user Description
cmodule_print Prints to the terminal

HELPER FUNCTION REFERENCE

Commands to Obtain Data from Open Genie

All commands to read data from Genie into a user program start with the "cmodule_get_" prefix, and have their first two parameters in common. The first parameter, called "pars_get", is an pointer to the workspace passed by Genie. The second parameter, "name", is a character variable which is the workspace field name assigned to the variable in GCL when the parameters workspace was created. For arrays, a "len" variable must also be passed; on input this should be set to the maximum allowed number of points, and on output it will be set to the number actually read. If too many points are passed out from GCL, "len" will still indicate how many were passed, but the number actually read will be the length of the array which was passed as input; thus testing "len" on return provides a check for array overflow.

Because C is able to cope with memory allocation, it is possible for the cmodule_get functions to allocate memory if required. You will of course be responsible for calling free() afterwards if this is the case! To get the functions to allocate memory pass a pointer variable containing NULL as the destination for the data and sufficient memory to hold the requested item will be allocated (actual length allocated returned in the "len" parameter where applicable). Note that functions returning strings will always allocate memory and hence you are responsible for calling free().

There is no need for cmodule_get_nd_real_array to correspond to the cmodule_put_nd_real_array function because an array can always be converted to 1-D using the Redim() command from GCL before passing it out.

The function prototypes are given below:

void cmodule_get_double (GenieWorkspace* pars_get, const char* name, fort_double* val);
void cmodule_get_int    (GenieWorkspace* pars_get, const char* name, fort_int* val);
void cmodule_get_real   (GenieWorkspace* pars_get, const char* name, fort_real* val);
void cmodule_get_string (GenieWorkspace* pars_get, const char* name, char** val);
void cmodule_get_double_array (GenieWorkspace* pars_get, const char* name, fort_double** val, fort_int* len);
void cmodule_get_int_array    (GenieWorkspace* pars_get, const char* name, fort_int** val, fort_int* len);
void cmodule_get_real_array   (GenieWorkspace* pars_get, const char* name, fort_real** val, fort_int* len);
void cmodule_get_string_array (GenieWorkspace* pars_put, const char* name, const char** val[], fort_int* len);

Commands to return Data to Open Genie

These commands return data to Open GENIE by replacing the fields in the "pars_put" workspace, otherwise they are very similar to the corresponding "cmodule_get_" commands. The "name" parameter will be the field name in the result workspace returned to GCL, and the "len" parameter for the array routines will indicate how many data points to send.

The function prototypes are given below:

void cmodule_put_double (GenieWorkspace* pars_put, const char* name, fort_double val);
void cmodule_put_int    (GenieWorkspace* pars_put, const char* name, fort_int val);
void cmodule_put_real   (GenieWorkspace* pars_put, const char* name, fort_real val);
void cmodule_put_string (GenieWorkspace* pars_put, const char* name, const char* val);
void cmodule_put_double_array (GenieWorkspace* pars_put, const char* name, const fort_double* val, fort_int len);
void cmodule_put_int_array    (GenieWorkspace* pars_put, const char* name, const fort_int* val, fort_int len);
void cmodule_put_real_array   (GenieWorkspace* pars_put, const char* name, const fort_real* val,fort_int len);
void cmodule_put_string_array (GenieWorkspace* pars_put, const char* name, const char* val[], fort_int len);
fort_int cmodule_put_nd_real_array (GenieWorkspace* pars_put, const char* name, const fort_real* val,
				    const fort_int* dims_array, fort_int ndims);

Commands to Communiate With The User

These provide a means for a C program to send messages to the user through the standard Open GENIE messaging system. This means, for example that informational messages can be switched off using the Toggle/Info command as with ordinary Open GENIE informational messages. Using these routines ensures that the timing of output messages will be properly synchronized with Open GENIE.

The C output helper functionality is combined into one function "cmodule_print". The "cmodule_print" function takes one of three constants, CMODULE_PRINT_NORMAL, CMODULE_PRINT_INFORMATION or CMODULE_PRINT_ERROR as the "option" parameter to select the corresponding Open GENIE I/O stream to print to.

The subroutine names and parameter types and names are given below:

void cmodule_print (const char* s, fort_int option);