CMODULE Interface
The C module interface is used in almost exactly the same way as the FORTRAN
interface, and provides similar routines - in fact most have the same name
but with a prefix of cmodule_ rather than module_
Invoking from the GCL command line is similar, except that an extra qualifier
of "C" must be specified for COMPILE and EXECUTE operations (it could also
be specified on a load for consistency, but is not strictly necessary)
e.g. MODULE/COMPILE/C "myprog.c"
MODULE/LOAD "myprog.so"
VALS=MODULE:EXECUTE:C("myfunc", PARS)
The major difference between the two is in the arguments - the C module routines
can allocate memory for returned array structures using malloc(), unlike in
FORTRAN where a pre-allocated array must always be passed. To indicate that you
wish a routine to allocate the memory for you, set the array pointer to NULL
before passing the address of it to the routine
e.g.
GenieWorkspace *pars_get, *pars_put; /* passed from GENIE */
const char* name = "twotheta"; /* parameter to get */
fort_real* val_array = NULL; /* tell routine to malloc() memory */
fort_int len;
cmodule_get_real_array(pars_get, name, &val_array, &len); /* get array */
/* do some manipulations */
cmodule_put_real_array(pars_put, name, val_array, len); /* return new values */
free(val_array); /* release storage */
If a pointer is not NULL, the routine will assume it points to valid
storage of size "len" - on return, "len" with be set to the number of
elements of the array actually set, or 0 on an error
A C module must contain the following header files
#include <genie_cmodule.h>
#include <genie_cmodule_ver.h>
To set up the correct definitions and typedefs
The MODULE/COMPILE/C GENIE command will insert the correct path
for picking up these header files, but they are contained in the
$GENIE_DIR/library directory if you wish to peruse them
The C module function must be declared like:
void my_c_module(GenieWorkspace* pars_get, GenieWorkspace* pars_put);
{
if (!cmodule_version_ok(CMODULE_MAJOR_VERSION, CMODULE_MINOR_VERSION))
{
cmodule_print("Library version mismatch in MY_C_MODULE",
CMODULE_PRINT_ERROR);
return;
}
/* all OK, proceed */
}
Variables are obtained and set by calling the following functions
with either pars_get or pars_put and the variable name:
(taken form $GENIE_DIR/library/genie_cmodule.h )
/* Get REAL parameter NAME from GENIE as VAL */ void cmodule_get_real(GenieWorkspace* pars_get, const char* name, fort_real* val);
/* Return REAL variable VAL to GENIE as NAME */ void cmodule_put_real(GenieWorkspace* pars_put, const char* name, fort_real val);
/* Return DOUBLE variable VAL to GENIE as NAME */ void cmodule_put_double(GenieWorkspace* pars_put, const char* name, fort_double val);
/*
Get STRING parameter NAME from GENIE as VAL
This routine ALWAYS allocates space for val with malloc(),
and you will need to free() at a later stage
*
*/
void cmodule_get_string(GenieWorkspace* pars_get, const char* name, char** val);
/* Return STRING variable VAL to GENIE as NAME */ void cmodule_put_string(GenieWorkspace* pars_put, const char* name, const char* val);
/* Return STRING array VAL of LEN elements to GENIE as NAME */
void cmodule_put_string_array(GenieWorkspace* pars_put, const char* name,
const char* val[], fort_int len);
/* Get INTEGER parameter NAME from GENIE as VAL */ void cmodule_get_int(GenieWorkspace* pars_get, const char* name, fort_int* val);
/* Return INTEGER variable VAL to GENIE as NAME */ void cmodule_put_int(GenieWorkspace* pars_put, const char* name, fort_int val);
/*
Get REAL array parameter NAME from GENIE as VAL
On Input:
The routine will malloc() space for the array if (*val == NULL),
otherwise it will assume *val points to an array of size len
*
On Output:
On error, *len will be set to 0
Otherwise, *len will be set to the number of elements read into *val
*/
void cmodule_get_real_array(GenieWorkspace* pars_get, const char* name, fort_real** val, fort_int* len);
/* Comments as for cmodule_get_real_array() */ void cmodule_get_double_array(GenieWorkspace* pars_get, const char* name, fort_double** val, fort_int* len);
/* Comments as for cmodule_get_real_array() */ void cmodule_get_int_array(GenieWorkspace* pars_get, const char* name, fort_int** val, fort_int* len);
/* Return a REAL array VAL of length LEN to GENIE as NAME */ void cmodule_put_real_array(GenieWorkspace* pars_put, const char* name, const fort_real* val, fort_int len);
/* Return a DOUBLE array VAL of length LEN to GENIE as NAME */ void cmodule_put_double_array(GenieWorkspace* pars_put, const char* name, const fort_double* val, fort_int len);
/* Return an INTEGER array VAL of length LEN to GENIE as NAME */ void cmodule_put_int_array(GenieWorkspace* pars_put, const char* name, const fort_int* val, fort_int len);
/* Print a message s to an output stream governed by option */
void cmodule_print(const char* s, fort_int option);
/* possible values for "option" in cmodule_print() are */
#define CMODULE_PRINT_NORMAL 0 /* Like GCL PRINTN */
#define CMODULE_PRINT_INFORMATION 1 /* Like GCL PRINTIN */
#define CMODULE_PRINT_ERROR 2 /* Like GCL PRINTEN */
/*
Return a multi-dimensionsal array to GENIE; the array val has
ndims dimensions and these are stored sequentially in the array
dims_array[]
*/
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);
/* return MAJOR and MINOR version of genie module interface */ fort_int cmodule_get_version(fort_int* major, fort_int* minor);
/* Check versions MAJOR and MINOR are compatable with
the current genie module interface; return 1 if all OK, 0 if
an error */
fort_int cmodule_version_ok(fort_int major, fort_int minor);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* GENIE_CMODULE */
--- The following is an example C module program, taken from
--- $GENIEDIR/examples/modules/c_example.c
/*
$Id: c_example.c,v 1.6 1997/06/20 11:19:43 faa Exp $
*
A program to illustrate calling a module from C
*
Called from GCL with e.g. MODULE:EXECUTE:C("my_c_module", PARS)
*
Freddie Akeroyd, ISIS, 19/2/97
*
*/
#include <stdio.h>
#include <stdlib.h>
/*
The next two includes must be present in any C module
They include important definitions and typedefs
*/
#include <genie_cmodule.h>
#include <genie_cmodule_ver.h>
static const char* sa[] = { "string1", "string2", 0 };
void my_c_module(GenieWorkspace* pars_get, GenieWorkspace* pars_put)
{
fort_real val1 = 3.4, val2 = 5.2;
char* s;
fort_real* ra;
fort_int len_ra;
fort_real val3[3][2] = { {1.6, 2.3}, {3.1, 4.7}, {7.4, 9.2} };
fort_int dims_array[] = { 3, 2}; /* dimensions of val3 */
int i;
/*
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;
}
cmodule_print("Running MY_C_MODULE", CMODULE_PRINT_INFORMATION);
/* read some data */
cmodule_get_real(pars_get, "R1", &val1); printf("val1 = %f\n", (double)val1);
ra = (void*)0; /* we want genie to malloc() for us */
cmodule_get_real_array(pars_get, "RA", &ra, &len_ra);
for(i=0; i<len_ra; i++)
{
printf("%d = %f\n", i, ra[i]);
}
free(ra);
cmodule_get_string(pars_get, "S", &s);
printf("%s\n", s);
free(s);
/* write some data into fields of the returned Workspace */
cmodule_put_real(pars_put, "R2", val2); cmodule_put_double(pars_put, "D2", val2); cmodule_put_int(pars_put, "an_int", 5); cmodule_put_string(pars_put, "junk", "hello");
/* This allocates a size 10 string array, but only the first two elements
will be occupied (as sa has two strings + a NULL third element). If the size you pass is greater than the array length, the last array element MUST be NULL */ cmodule_put_string_array(pars_put, "sa", sa, 10);
/* We need a (fort_real*) cast as the program treats 2-D arrays
as 1-D ones */ cmodule_put_nd_real_array(pars_put, "ndra", (fort_real*)val3, dims_array, 2); cmodule_print("Finished MY_C_MODULE", CMODULE_PRINT_INFORMATION);
}
--- This is the GCL prodecure to call the C module
--- $GENIEDIR/examples/modules/c_example.gcl
#
# $Id: c_example.gcl,v 1.5 1997/06/20 11:20:00 faa Exp $
#
PROCEDURE C_EXAMPLE
LOCAL PARS RES
PARS=FIELDS()
PARS.R1=6.8
PARS.RA=DIMENSIONS(10)
FILL PARS.RA 1.0 10.0
PARS.S="The string \"abc\""
MODULE/COMPILE/C "c_example.c" SYMBOLS="my_c_module" MODULE/LOAD "c_example.so" RES=MODULE:EXECUTE:C("my_c_module", PARS)
PRINTN RES
ENDPROCEDURE
#
--
Freddie Akeroyd Email: faa@isise.rl.ac.uk
ISIS Facility Tel: +44 1235 445457
Rutherford Appleton Laboratory Fax: +44 1235 445720
Chilton, DIDCOT, OX11 OQX WWW: http://www.isis.rl.ac.uk/