User FunctionsIt is possible to include your own functions within Gsharp. These functions can be written in either C or FORTRAN and can be used to get data in or out of Gsharp or to process data already within Gsharp. There are two steps required to include these functions
A full list of functions that can be used in writing your user function can be found in the Reference Manual. Writing The FunctionThe source for a skeleton user function file is provided in UserFunc.c in the $UNIDIR\misc\Gsharp directory.
Datum StructureAll I/O parameters to a user-defined function are passed as a structure called Datum. This structure is defined as follows:
An example of a user-defined function will illustrate how this structure is used. To define the GSL function: import_user(filename, data_type, rec_type) This function declaration is added to UserFunc.c.
Parameters are passed to user functions via the pointer stack variable
argv. Depending on the function, the parameter(s) are either required
or optional. Required parameters must be specified, otherwise Gsharp will
generate an error when it parses the function reference. filename = *argv++; This next two parameters are optional, so a test must be done to see if they are present: if( argc >= 2) rec_type = *argv++; if( argc >= 3) data_type = *argv+0+; I/O parameters are defined as required when the user function is registered
with Gsharp. Refer to Registering User-defined Functions
for details. printf("import_user: filename=%s\n",*(char**)filename->dp);
Registering User-defined FunctionsAll user-defined functions must be registered with Gsharp by calling the function InstallCFunction from UserFunc.c. InstallCFunction has the following parameters: InstallCFunction( (string) gsl_name, (pointer) c_function, (int) return_type, (int) MinNumArgs, (int) MaxNumArgs, (int) arg_type, ByRef, ... (int) arg_type, ByRef, (int) AEND ) return_type and arg_type must be set to one of the following
enumerated types: RealData, TextData, DateData, or TimeData. MaxNumArgs is set to 0 if the number of arguments is unlimited, or it is set to n if the number of arguments of fixed. The example below demonstrates how InstallCFunction is used to register a function with one required and two optional arguments.
Managing the Output of User-defined FunctionsUser functions can output messages to the Gsharp message area (and message log file if message logging is on) using the functions UpgMsgHandler or CLRuntimeMessage. CLRuntimeMessage always writes its output, while UpgMsgHandler output is filtered according to the message status set by the function set_messages. Example UpgMsgHandler( (int) message_type, (char*)message ) UpgMsgHandler(CL_USER,"File could not be opened\n"); Example sprintf(buf, "%s\n", "no data read"); CLRuntimeMessage(CL_INFO, buf); Some Examplesstatic Stack GETENV (int argc, Stack *argv)
{
Datum d1, dt;
VarString str, env;
d1 = *argv;
dt = VarCreate(TextData, Scalar);
env = VarGetStringData(d1, 1, 1, 1);
if(env && (str = UpgGetEnv(env)))
VarSetStringData(dt, 1, 1, 1, str);
return dt;
}
static Stack PUTENV(int argc, Stack *argv)
{
Datum d1, dt;
VarString str, env;
d1 = *argv;
dt = VarCreate(RealData, Scalar);
env = VarGetStringData(d1, 1, 1, 1);
if(env && putenv(strdup(env)))
VarSetRealData(dt, 1, 1, 1, 1.0);
return dt;
}
/* Convert an array of floats into a string. e.g. "1:4,8:9,11" */ static Stack CREATEEXPRESSION(int argc, Stack *argv)
{ Datum d1, dt;
char out[10024], num[10];
int i, nlines;
VarFloat *vals;
d1 = *argv;
nlines = VarNumRows(d1);
vals = (VarFloat *) VarCopyData(d1);
sprintf(out, "%g", vals[0]);
for (i=1; i<nlines; i++)
{ if (vals[i]==vals[i-1]+1 )
{ if ((i<nlines-1) && (vals[i+1]==vals[i]+1)) continue;
else strcat(out,":");
}
else
{ strcat(out,",");
}
sprintf(num,"%g",vals[i]);
strcat(out,num);
if (strlen(out)>10000) break;
}
dt = VarCreate(TextData, Scalar);
VarSetStringData(dt,1,1,1,out);
if (VarNumRows(d1)==1 && vals[0]>999.99 && vals[0]<999.9999)
VarSetStringData(dt,1,1,1,"");
free(vals);
return dt;
}
/* Return the elements of d1 that can be found in d2 */
static Stack VALIDLINES(int argc, Stack *argv)
{ Datum d1, d2, dt;
DatumDimension dim;
VarFloat *arr1, *arr2;
VarFloat *out;
int i, j, n, n1, n2;
d1 = *argv++; d2 = *argv;
n2 = VarNumRows(d2); n1 = VarNumRows(d1);
n = 0;
out = (VarFloat *) calloc(n1,sizeof(int));
arr1 = VarCopyData(d1);
arr2 = VarCopyData(d2);
for(i=0; i<n2; i++)
for(j=0; j<n1; j++)
if (arr1[j] == arr2[i])
out[n++] = (VarFloat) j+1;
free(arr1); free(arr2);
if (n>n1)
{ puts("Overflow in VALIDLINES");
}
if (n==0)
{ n=1; out[0]=999.999;
}
dim[0] = n; dim[1]=dim[2]=1;
dt = VarCreate(RealData,dim);
for (i=0; i<n; i++)
VarSetRealData(dt,i+1,1,1,out[i]);
free(out);
return dt;
}
static Stack SHOWHOURGLASS(int argc, Stack *argv)
{ Datum d1, dt;
void GshShowHourglass(), GshRemoveHourglass();
d1 = *argv;
if (VarGetRealData(d1, 1, 1, 1) == 0.0)
GshRemoveHourglass();
else
GshShowHourglass();
dt = VarCreate(RealData, Scalar);
VarSetRealData(dt, 1, 1, 1, 0.0);
return dt;
}
void RegisterUserFunc(void)
{
InstallCFunction("getenv", &GETENV, TextData, 1, 1,
TextData, ByRef,
ANAMES, "environment_variable",
AMSGS, 0,
ACAT, FInterface,
AFMSG, MSG_DP_F_GETENV,
AEND);
InstallCFunction("putenv", &PUTENV, RealData, 1, 1,
TextData, ByRef,
ANAMES, "environment_assignment",
AMSGS, 0,
ACAT, FInterface,
AFMSG, MSG_DP_F_PUTENV,
AEND);
InstallCFunction("CreateExpression",&CREATEEXPRESSION, TextData, 1, 1,
RealData, ByRef,
ACAT, FUser,
AEND);
InstallCFunction("ValidLines",&VALIDLINES, RealData, 2, 2,
RealData, ByRef,
RealData, ByRef,
ACAT, FUser,
AEND);
InstallCFunction("ShowHourglass",&SHOWHOURGLASS, RealData, 1, 1,
RealData, ByRef,
AEND);
|