This article describes how to create a Scilab interface function, also called "gateway".
Gateways can in particular be created in Toolboxes (Scilab extension modules). For more general informations on toolboxes, see howto/Create a toolbox.
First, it defines what a gateway is, then it shows on concrete examples how to write a gateway for different languages.
Introduction
A gateway is a function, part of a Scilab internal or external module, which does the bridge between Scilab and an external library or code. When a Scilab primitive is executed, the corresponding native C/C++ or Fortran function is called through its Scilab gateway. The gateway function is responsible of checking, converting, and transmitting data from Scilab to this external function (and reversely from the external function to Scilab), and calling this function.
Gateways are usually written in C, and use a dedicated Scilab API, which is called "Scilab Gateway API" (or simply "Scilab API"). This API provides functions to get the type and value of the passed arguments to the called gateway function (input arguments), and also to return values, in a choosen type, from that gateway function (output arguments).
Usually it is recommended to separate the gateway function from the business function. But if the business code is very short, it is sometimes included in the gateway.
Examples of gateways
Following are some examples of gateway functions, for C and Fortran. We do not explain how to implement gateways functions, which is explained in the Scilab API documentation.
Gateway for C function
We consider a C function csum which returns the sum of two scalars. We suppose that the name of the corresponding primitive in Scilab is c_sum and the associated interface program name is sci_csum. By convention all interface program names begin with "sci_". The both following scripts represent the C code of csum and sci_csum.
The gateway for c_sum primitive looks like following:
--> Y = c_sum(A,B)
Source code of csum.c:
int csum(double *a, double *b, double *c) { *c = *a + *b; return 0; }
Source code of sci_csum.c:
#include "api_scilab.h" /* ==================================================================== */ extern int csum(double *a,double *b,double *c); /* ==================================================================== */ int sci_csum(char *fname) { /* error management*/ SciErr sciErr; int iRet = 0; /* Variables for first input argument*/ int* piAddr1 = NULL; double dblVal1 = 0; /* Variables for second input argument*/ int* piAddr2 = NULL; double dblVal2 = 0; /* Variable for return value */ double dblRetVal = 0; /* Check that we have only 2 input parameters */ CheckInputArgument(pvApiCtx, 2, 2); /* Check that we have only 1 output parameter */ CheckOutputArgument(pvApiCtx, 1, 1); /* get first parameter and put in 'dblVal1' */ sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1); if(sciErr.iErr) { printError(&sciErr, 0); /* No return variable */ LhsVar(1) = 0; return 0; } iRet = getScalarDouble(pvApiCtx, piAddr1, &dblVal1); if(iRet) { /* No return variable */ LhsVar(1) = 0; return 0; } /* get second parameter and put in 'dblVal2' */ sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); if(sciErr.iErr) { printError(&sciErr, 0); /* No return variable */ LhsVar(1) = 0; return 1; } iRet = getScalarDouble(pvApiCtx, piAddr2, &dblVal2); if(iRet) { /* No return variable */ LhsVar(1) = 0; return 1; } /* call csum subroutine */ csum(&dblVal1, &dblVal2, &dblRetVal); /* create a variable on scilab's memory */ iRet = createScalarDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, dblRetVal); if(iRet) { /* If error, no return variable */ AssignOutputVariable(pvApiCtx, 1) = 0; return 1; } /* assign new variable to return value*/ AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; return 0; }
Gateway for Fortran function
We consider an fortran subroutine fsum which returns the sum of two scalars. We suppose that the name of the corresponding primitive in Scilab is fortran_sum and the associated interface program name is sci_fsum. By convention all interface program names begin by "sci_". The both following scripts represent the fortran code of fsum and sci_fsum.
The primitive fortran_sum in can be called in Scilab as follows:
--> Y = fortran_sum(A,B)
Source code of fsum.f:
c ================================= subroutine fsum(a,b,c) c ================================= double precision a,b,c c = a + b end c =================================
Source code of the gateway in Fortran is globally the same as for C :
#include "api_scilab.h" /* ==================================================================== */ extern int F2C(fsum)(double *a,double *b,double *c); /* ==================================================================== */ int sci_fsum(char *fname) { /* error management*/ SciErr sciErr; int iRet = 0; /* Variables for first input argument*/ int* piAddr1 = NULL; double dblVal1 = 0; /* Variables for second input argument*/ int* piAddr2 = NULL; double dblVal2 = 0; /* Variable for return value */ double dblRetVal = 0; /* Check that we have only 2 input parameters */ CheckInputArgument(pvApiCtx, 2, 2); /* Check that we have only 1 output parameter */ CheckOutputArgument(pvApiCtx, 1, 1); /* get first parameter and put in 'dblVal1' */ sciErr = getVarAddressFromPosition(pvApiCtx, 1, &piAddr1); if(sciErr.iErr) { printError(&sciErr, 0); /* No return variable */ LhsVar(1) = 0; return 0; } iRet = getScalarDouble(pvApiCtx, piAddr1, &dblVal1); if(iRet) { /* No return variable */ LhsVar(1) = 0; return 0; } /* get second parameter and put in 'dblVal2' */ sciErr = getVarAddressFromPosition(pvApiCtx, 2, &piAddr2); if(sciErr.iErr) { printError(&sciErr, 0); /* No return variable */ LhsVar(1) = 0; return 1; } iRet = getScalarDouble(pvApiCtx, piAddr2, &dblVal2); if(iRet) { /* No return variable */ LhsVar(1) = 0; return 1; } /* call fortran fsum subroutine */ F2C(fsum)(&dblVal1, &dblVal2, &dblRetVal); /* create a variable on scilab's memory */ iRet = createScalarDouble(pvApiCtx, nbInputArgument(pvApiCtx) + 1, dblRetVal); if(iRet) { /* If error, no return variable */ AssignOutputVariable(pvApiCtx, 1) = 0; return 1; } /* assign new variable to return value*/ AssignOutputVariable(pvApiCtx, 1) = nbInputArgument(pvApiCtx) + 1; return 0; }
Further reading
All the possibilities about gateway functions are not described in this document. For more examples of what can be done with gateways, you can see the directory SCI/dynamic_link/examples. You can also read the Scilab API documentation.