How to create and access a list — How to create and access a list 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 [mt]list, to get some elements stored in that this and to send a new [mt]list using a function written in C.
For this, we will wrote two C gateway function in which we will retrieve the [mt]list, and we will create a new [mt]list.
This example is available in SCI/modules/core/example/print_list.
Let's initialize a mlist in Scilab.
A = mlist(['mytype','var1','var2'],'a string',[1 2; 3 4]);
This mlist is of type 'mytype' (typeof(A)=='mytype') and it has 2 elements:
A('var1') which is equal to 'a string'
A('var2') which is equal to [1 2; 3 4]
We now create a C function called sci_print_list which will print the elements stored in the list.
#include <stack-c.h>
#include <sciprint.h>
int sci_print_list(char * fname)
{
int m_list_in, n_list_in, l_list_in;
int m_type, n_type;
int m_var1, n_var1, l_var1;
int m_var2, n_var2, l_var2;
char ** LabelList = NULL;
CheckRhs(1,1); // We accept only 1 parameter
GetRhsVar(1,"m",&m_list_in,&n_list_in,&l_list_in); // Get a mlist
// Get the type and the name of the variables (the first element of the mlist)
GetListRhsVar(1,1,"S",&m_type,&n_type,&LabelList);
if (strcmp(LabelList[0],"mytype")!=0)
{
sciprint("error, you must ship a mlist or type mytype\n");
return 0;
}
// Get the first variable (a string)
GetListRhsVar(1,2,"c",&m_var1,&n_var1,&l_var1);
sciprint("var1 = %s\n",cstk(l_var1));
// Get the second variable (a double matrix)
GetListRhsVar(1,3,"d",&m_var2,&n_var2,&l_var2);
sciprint("var2 = [%f %f %f %f]\n",*stk(l_var2+0),
*stk(l_var2+1),
*stk(l_var2+2),
*stk(l_var2+3));
return 0;
}
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. The C file is available in the example directory. It is named print_list.c.
// This is the builder.sce
// must be run from this directory
lines(0);
ilib_name = 'lib_print_list';
files = ['print_list.c'];
libs = [];
table =['print_list', 'sci_print_list'];
ldflags = "";
cflags = "";
fflags = "";
ilib_build(ilib_name,table,files,libs,'Makelib',ldflags,cflags,fflags);
</programlisting>
<para>This file must be saved as "builder.sce".</para>
<para>This script will tell Scilab which files must be compiled (here,
it's print_list.c), what will be the name of the shared library (here,
it's lib_print_list) and which C symbol will be linked to a Scilab
function (here, we will link the sci_print_list C symbol to the Scilab
function "print_list").</para>
<para>To build this function, we just need to to:</para>
<programlisting role = ""><![CDATA[
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. Let's test our new function:
exec builder.sce; exec loader.sce; A = mlist(['mytype','var1','var2'],'a string',[1 2; 3 4]); print_list(A);
This example is available in SCI/modules/core/example/create_list.
We now write a simple example to test our new function to create a [mt]list.
A = create_list(); disp(A);
First, let's write the C function:
#include <stack-c.h>
#include <string.h>
int sci_create_list(char * fname)
{
int m_list_out, n_list_out;
int m_var1, n_var1, l_var1, l_list_var1;
int m_var2, n_var2, l_var2, l_list_var2;
int m_mlist, n_mlist, l_mlist;
// The labels of our mlist
static const char * ListLabels [] = {"mylist","var1","var2"};
// First, we create the variables using a classical way
// The size of the Scilab variables
m_var1 = 1; n_var1 = strlen("a string")+1; // a null terminated string
m_var2 = 2; n_var2 = 2; // A 2x2 double matrix
m_mlist = 3; n_mlist = 1; // A mlist with 3 elements
// Creation of the Scilab variables
// A('var1')
CreateVar(1, "c", &m_var1, &n_var1, &l_var1);
// A('var2')
CreateVar(2, "d", &m_var2, &n_var2, &l_var2);
// A
CreateVar(3, "m", &m_mlist, &n_mlist, &l_mlist);
// We store values in the create variables
// The matrix will be stored in A('var2')
*stk(l_var2+0) = 1;
*stk(l_var2+1) = 2;
*stk(l_var2+2) = 3;
*stk(l_var2+3) = 4;
// The string will be stored in A('var1')
strncpy(cstk(l_var1),"a string\0",n_var1);
m_list_out = 3; n_list_out = 1;
// now, affect the variable to the mlist
// The labels (it corresponds to A = mlist(['mylist','var1','var2'], ...
CreateListVarFromPtr(3, 1, "S", &m_list_out, &n_list_out, ListLabels);
// The value stored in A('var1') (it corresponds to A = ...,'a string', ...
CreateListVarFrom(3, 2, "c", &m_var1, &n_var1, &l_list_var1, &l_var1);
// The value stored in A('var2') (it corresponds to A = ...,[1 2,3 4]);
CreateListVarFrom(3, 3, "d", &m_var2, &n_var2, &l_list_var2, &l_var2);
// We return only the mlist which has been created at position 3
LhsVar(1) = 3;
return 0;
}
Some important comments related to the CreateVar(Pos,"m",&m, &n, &l) function. When called on a mlist, only the m parameter is taken in account, the n parameter is not used. So, be careful:
m_list = 3; n_list = 1; CreateVar(1, "m", &m_list, &n_list, &l_list);
creates a mlist with 3 elements but:
m_list = 1; n_list = 3; CreateVar(1, "m", &m_list, &n_list, &l_list);
creates a mlist with only 1 element !
Another important thing: when we create a list element using CreateListVarFrom, it is not recommended to access the created variable using, for example, stk(l_list_var2) because CreateListVarFrom performs type transformation on the list variables.
// This is the builder.sce // must be run from this directory lines(0); ilib_name = 'lib_create_list'; files = ['create_list.c']; libs = []; table =['create_list', 'sci_create_list']; 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 create_list.c), what will be the name of the shared library (here, it's lib_create_list) and which C symbol will be linked to a Scilab function (here, we will link the sci_create_list C symbol to the Scilab function "create_list").
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. Let's test our new function:
exec builder.sce;
exec loader.sce;
A = create_list();
disp(typeof(A))
disp(getfield(1,A))
disp(A('var1'))
disp(A('var2'))