How to deal with optional parameters — how to deal with optional parameters send to an interface using the C gateway functions
WARNING: This API is deprecated from Scilab 5.2.0 and is going to be removed with Scilab 6.0. Please use API Scilab (the new Scilab API).
The goal is to get a set of optional parameters via a C gateway and then to perform some checks in the C function (number of optional parameters, does an optional parameters exists, etc.).
This example is available in the directory core/examples/optional_parameters
#include <stack-c.h> int ex2c(double * a, int * ma, int * na, double * b, int * mb, int * nb) { int i; for(i=0;i<(*ma)*(*na);i++) a[i] = 2*a[i]; for(i=0;i<(*mb)*(*nb);i++) b[i] = 3*b[i]; return(0); } int sci_optional_parameters(char * fname) { int m1,n1,l1; // optional names must be stored in alphabetical order in opts static rhs_opts opts[]= {{-1,"v1","d",0,0,0}, {-1,"v2","d",0,0,0}, {-1,NULL,NULL,0,0}}; int minrhs = 1, maxrhs = 1; int minlhs = 1, maxlhs = 3; int nopt, iopos, res; char buffer_name[csiz]; // csiz used for character coding nopt = NumOpt(); CheckRhs(minrhs,maxrhs+nopt); CheckLhs(minlhs,maxlhs); // first non optional argument GetRhsVar( 1, "c", &m1, &n1, &l1); if (get_optionals(fname,opts)==0) return 0; // default values if optional arguments are not given: v1=[99] and v2=[3] sciprint("number of optional parameters = %d\n", NumOpt()); sciprint("first optional parameters = %d\n", FirstOpt()); sciprint("FindOpt(v1) = %d\n", FindOpt("v1", opts)); sciprint("FindOpt(v2) = %d\n", FindOpt("v2", opts)); if (IsOpt(1,buffer_name)) sciprint("parameter 1 is optional: %s\n", buffer_name); if (IsOpt(2,buffer_name)) sciprint("parameter 2 is optional: %s\n", buffer_name); if (IsOpt(3,buffer_name)) sciprint("parameter 3 is optional: %s\n", buffer_name); iopos = Rhs; if (opts[0].position==-1) { iopos++; opts[0].position = iopos; opts[0].m = 1; opts[0].n = 1; opts[0].type = "d"; CreateVar(opts[0].position, opts[0].type, &opts[0].m, &opts[0].n, &opts[0].l); *stk(opts[0].l) = 99.0; } if (opts[1].position==-1) { iopos++ ; opts[1].position = iopos; opts[1].m = 1; opts[1].n = 1; opts[1].type = "d"; CreateVar(opts[1].position, opts[1].type, &opts[1].m, &opts[1].n, &opts[1].l); *stk(opts[1].l) = 3; } ex2c(stk(opts[0].l),&opts[0].m,&opts[0].n, stk(opts[1].l),&opts[1].m,&opts[1].n); // return the first argument (unchanged ) then v1 and v2 LhsVar(1) = 1; LhsVar(2) = opts[0].position; LhsVar(3) = opts[1].position; return 0; }
This file must be saved as "optional_parameters.c".
The main thing to highlight is that, to build a C interface function, we need to include the header stack-c.h. In this header, we find the prototypes and macros of the main C interface functions. We also need to include sciprint.h because we use the sciprint function.
To be able to build and link such a C function to scilab, we need to write a Scilab script which will compile this C function and then create a loader script which will link the C function to a Scilab function.
// This is the builder.sce // must be run from this directory lines(0); ilib_name = 'lib_optional_parameters'; files = ['optional_parameters.c']; libs = []; table =['optional_parameters', 'sci_optional_parameters']; ldflags = ""; cflags = ""; fflags = ""; ilib_build(ilib_name,table,files,libs,'Makelib',ldflags,cflags,fflags);
This file must be saved as "builder.sce".
This script will tell Scilab which files must be compiled (here, it's optional_parameters.c), what will be the name of the shared library (here, it's lib_optional_parameters) and which C symbol will be linked to a Scilab function (here, we will link the sci_optional_parameters C symbol to the Scilab function "optional_parameters").
To build this function, we just need to to:
exec builder.sce;
Now we are able to test our new C function. First, let's load this new function in scilab:
exec loader.sce;
The script loader.sce is normally automatically built by builder.sce.
We now write a simple example to test our new functions.
// Example with optional argument specified with the 'arg=value syntax' // [a,b,c] = ex12c(x1, [v1 = arg1, v2 = arg2]), arg1 default value 99 // arg2 default value 3 // only v1 and v2 are recognized as optional argument names // the return value are a = x1, b = 2*v2, c = 3*v2 [a,b,c] = optional_parameters('test'); disp('a = ' + a + ' b = ' + string(b) + ' c = ' + string(c)); [a,b,c] = optional_parameters('test',v1=[10,20]); disp('a = ' + a + ' b = ' + string(b) + ' c = ' + string(c)); [a,b,c] = optional_parameters('test',v1=[10,20],v2=8); disp('a = ' + a + ' b = ' + string(b) + ' c = ' + string(c)); [a,b,c] = optional_parameters('test',v2=8,v1=[10]); disp('a = ' + a + ' b = ' + string(b) + ' c = ' + string(c));
The script must be saved as "optional_parameters.sce".
Let's run our scripts and see what is the result:
-->;exec builder.sce; Génère un fichier gateway Génère un fichier loader Génère un Makefile : Makelib Exécute le makefile Compilation de optional_parameters.c Construction de la bibliothèque partagée (soyez patient) -->;exec loader.sce; Bibliothèque partagée chargée. Link done. -->;exec optional_parameters.sce; number of optional parameters = 0 first optional parameters = 2 FindOpt(v1) = 0 FindOpt(v2) = 0 a = test b = 198 c = 9 number of optional parameters = 1 first optional parameters = 2 FindOpt(v1) = 2 FindOpt(v2) = 0 parameter 2 is optional: v1 !a = test b = 20 c = 9 a = test b = 40 c = 9 ! number of optional parameters = 2 first optional parameters = 2 FindOpt(v1) = 2 FindOpt(v2) = 3 parameter 2 is optional: v1 parameter 3 is optional: v2 !a = test b = 20 c = 24 a = test b = 40 c = 24 ! number of optional parameters = 2 first optional parameters = 2 FindOpt(v1) = 3 FindOpt(v2) = 2 parameter 2 is optional: v2 parameter 3 is optional: v1 a = test b = 20 c = 24