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/