<?xml version="1.0" encoding="UTF-8"?>
<!--
* Scilab ( https://www.scilab.org/ ) - This file is part of Scilab
* Copyright (C) 2012 - Scilab Enterprises - Sylvestre LEDRU
*
 * Copyright (C) 2012 - 2016 - Scilab Enterprises
 *
 * This file is hereby licensed under the terms of the GNU GPL v2.0,
 * pursuant to article 5.3.4 of the CeCILL v.2.1.
 * This file was originally licensed under the terms of the CeCILL v2.1,
 * and continues to be available under such terms.
 * For more information, see the COPYING file which you should have received
 * along with this program.
*
-->
<refentry xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:svg="http://www.w3.org/2000/svg" xmlns:ns5="http://www.w3.org/1999/xhtml" xmlns:mml="http://www.w3.org/1998/Math/MathML" xmlns:db="http://docbook.org/ns/docbook" xmlns:scilab="http://www.scilab.org" xml:id="api_scilab_getting_started" xml:lang="en">
    <refnamediv>
        <refname>Getting started with API_Scilab</refname>
        <refpurpose>How to load a C, C++ or fortran code in the Scilab engine as a new function</refpurpose>
    </refnamediv>
    <refsection>
        <title>Description</title>
        <para>
            As described in the <link linkend="api_scilab">api_scilab presentation</link>, Scilab offers an API to extend the language with C, C++ or Fortran code (sources or libraries).
        </para>
        <para>
            The link between the Scilab engine and the application code is called <literal>gateway</literal> and have this prototype:
            <refsection id="api_scilab_entrypoint">
                <para></para>
                <literallayout>
                    int <varname>your_new_gateway</varname>(<literal><link linkend="api_types_scilabEnv"><command>scilabEnv</command></link></literal> env,
                    int nin, <literal><link linkend="api_types_scilabVar"><command>scilabVar</command></link></literal> *in,
                    int nopt, <literal><link linkend="api_types_scilabOpt"><command>scilabOpt</command></link></literal> opt,
                    int nout, <literal><link linkend="api_types_scilabVar"><command>scilabVar</command></link></literal> *out)
                </literallayout>
                <itemizedlist>
                    <listitem>
                        <para>
                            <varname>env</varname>: <literal><link linkend="api_types_scilabEnv"><command>scilabEnv</command></link></literal> variable provided by kernel. You must forward it to API functions.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>nin</varname>: number of input arguments.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>in</varname>: array of <literal><link linkend="api_types_scilabVar"><command>scilabVar</command></link></literal> containing input parameters.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>nopt</varname>: number of optional parameters.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>opt</varname>: <literal><link linkend="api_types_scilabOpt"><command>scilabOpt</command></link></literal> containing optional parameters. Use <link linkend="api_optional_scilab_getOptional"><varname>scilab_getOptional</varname></link> to get optional information.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>nout</varname>: number of expected output parameters.
                        </para>
                    </listitem>
                    <listitem>
                        <para>
                            <varname>out</varname>: preallocated array of <literal><link linkend="api_types_scilabVar"><command>scilabVar</command></link></literal> with a size of <varname>nout</varname>.
                        </para>
                    </listitem>
                </itemizedlist>
                <para>Return 0 or STATUS_OK for OK and other value or STATUS_ERROR to trigger an error.</para>
            </refsection>
        </para>
        <para>
            Most of the time, the process is always the same:
            <orderedlist>
                <listitem>
                    <para>Check the number of arguments (both input and output) provided by the user.</para>
                    <para>
                        For example, if the function <literal>foo(x)</literal> is called with <literal>foo()</literal> or <literal>foo(2,3)</literal>, the user must get an answer.
                    </para>
                </listitem>
                <listitem>
                    <para>Manage input arguments</para>
                    <para>
                        Several tasks are performed:
                        <orderedlist inheritnum="inherit">
                            <listitem>
                                <para>
                                    Check the type of the variable: matrix of double (complex or not), string, etc with <link linkend="api_common_scilab_getType"><varname>scilab_getType</varname></link>
                                </para>
                                <para>
                                    Other functions are also provided:
                                    <itemizedlist>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isDouble"><varname>scilab_isDouble</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isBoolean"><varname>scilab_isBoolean</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isString"><varname>scilab_isString</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isInt"><varname>scilab_isInt</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isPoly"><varname>scilab_isPoly</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isList"><varname>scilab_isList</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isTList"><varname>scilab_isTList</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isMList"><varname>scilab_isMList</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isHandle"><varname>scilab_isHandle</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isStruct"><varname>scilab_isStruct</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isCell"><varname>scilab_isCell</varname></link>
                                            </para>
                                        </listitem>
                                        <listitem>
                                            <para>
                                                <link linkend="api_common_scilab_isPointer"><varname>scilab_isPointer</varname></link>
                                            </para>
                                        </listitem>
                                    </itemizedlist>
                                </para>
                            </listitem>
                            <listitem>
                                <para>
                                    If it is relevant, check if the input argument is complex or not with <link linkend="api_common_scilab_isComplex">scilab_isComplex</link>
                                </para>
                            </listitem>
                            <listitem>
                                <para>
                                    Dealing with integer, further checks should be done on the precision of the integer with <link linkend="api_integer_scilab_getIntegerPrecision">scilab_getIntegerPrecision</link>
                                </para>
                            </listitem>
                            <listitem>
                                <para>Check the dimensions of the variable: square matrix, scalar, etc</para>
                                <itemizedlist>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_getDim"><varname>scilab_getDim</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_getDim2d"><varname>scilab_getDim2d</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_getDimArray"><varname>scilab_getDimArray</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_getSize"><varname>scilab_getSize</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isEmpty"><varname>scilab_isEmpty</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isMatrix2d"><varname>scilab_isMatrix2d</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isScalar"><varname>scilab_isScalar</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isSquare"><varname>scilab_isSquare</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isVector"><varname>scilab_isVector</varname></link>, <link linkend="api_common_scilab_isNVector"><varname>scilab_isNVector</varname></link>, <link linkend="api_common_scilab_isRowVector"><varname>scilab_isRowVector</varname></link>, <link linkend="api_common_scilab_isColVector"><varname>scilab_isColVector</varname></link>
                                        </para>
                                    </listitem>
                                    <listitem>
                                        <para>
                                            <link linkend="api_common_scilab_isHypermat"><varname>scilab_isHypermat</varname></link>
                                        </para>
                                    </listitem>
                                </itemizedlist>
                                <para>Almost all Scilab datatypes have an equivalent C function to perform such task.</para>
                            </listitem>
                            <listitem>
                                <para>Other checks can be done like specific values expected, consistency between the first and second input arguments, etc.</para>
                            </listitem>
                            <listitem>
                                <para>Data transformation (optional).</para>
                                <para>Depending on the code or library targeted, some transformations can be applied to the data. A classical example is changing the storage of a matrix from column-stored to line-stored.</para>
                                <para>Please note that it is usually a performance killer.</para>
                            </listitem>
                        </orderedlist>
                    </para>
                </listitem>
                <listitem>
                    <para>Application code</para>
                    <para>Once all the checks and data retrieval have been performed, the actual core code can be called. The actual intelligence (processes, data transformations, etc) will be performed here.</para>
                    <para>
                        This can be done through a thirdparty code stored and built in <literal>src/c</literal>, <literal>src/cpp</literal> or <literal>src/fortran</literal> but also under the form of a library. Virtually, any library could be linked to Scilab.
                    </para>
                </listitem>
                <listitem>
                    <para>Create the output arguments for the Scilab engine</para>
                    <para>Once the application code has been executed, usually, some data will be returned to the Scilab interpreter.</para>
                    <para>
                        For example, to create in the Scilab engine memory a matrix of double, the C function
                        <literal>
                            <link linkend="api_double_scilab_createDoubleMatrix">scilab_createDoubleMatrix</link>
                        </literal>
                        should be called.
                    </para>
                </listitem>
            </orderedlist>
        </para>
        <para>
            By default, Scilab numerical values are stored with the C type <literal>double</literal>.
        </para>
        <para>
            As convention, gateways are stored in <literal>sci_gateway/c/</literal> (or <literal>/cpp/</literal>) and are called <literal>sci_functionName.c</literal>.
        </para>
    </refsection>
    <refsection>
        <title>Real life example</title>
        <para>Taking the sample Scilab function:</para>
        <para>
            <literal>[c,d] = foo(a,b)</literal>
        </para>
        <para>
            with <literal>a</literal> being a matrix of double and <literal>b</literal> a matrix of boolean with the same size of <literal>a</literal>, foo will multiply each element of <literal>a</literal> by 2 and return it as <literal>c</literal> and transform each element of element of b to its opposite.
        </para>
        <para>
            The example is available in the toolbox skeleton provided with the Scilab binary. The path is <literal>contrib/toolbox_skeleton/sci_gateway/c/sci_foo6.c</literal>
        </para>
        <para>Detailed explanations are provided under the form of C comment in the following example.</para>
        <programlisting role="code_gateway">
            <![CDATA[
// Full source can be found in the sci_gateway/c/ directory of the toolbox skeleton

#include "api_scilab.h"
#include "Scierror.h"
#include "BOOL.h"
#include "localization.h"

static const char fname[] = "foo6";
/* ==================================================================== */
int sci_foo6(scilabEnv env, int nin, scilabVar* in, int nopt, scilabOpt* opt, int nout, scilabVar* out)
{
    int i = 0;
    int row1 = 0;
    int col1 = 0;
    int size1 = 0;
    double* in1 = NULL;
    double* out1 = NULL;

    int row2 = 0;
    int col2 = 0;
    int size2 = 0;
    int* in2 = NULL;
    int* out2 = NULL;

    /* --> [a,b] = foo(d[i,j], b[i,j])
    /* check that we have only 2 input arguments */
    /* check that we have only 1 output argument */
    if (nin > 2)
    {
        Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), fname, 2);
        return 1;
    }

    if (scilab_isDouble(env, in[0]) == 0 || scilab_isMatrix2d(env, in[0]) == 0 || scilab_isComplex(env, in[0]) == 1)
    {
        Scierror(999, _("%s: Wrong type for input argument #%d: A scalar expected.\n"), fname, 1);
        return 1;
    }

    if (scilab_isBoolean(env, in[1]) == 0 || scilab_isMatrix2d(env, in[1]) == 0)
    {
        Scierror(999, _("%s: Wrong type for input argument #%d: A boolean matrix expected.\n"), fname, 2);
        return 1;
    }

    size1 = scilab_getDim2d(env, in[0], &row1, &col1);
    size2 = scilab_getDim2d(env, in[1], &row2, &col2);

    if (row1 != row2 || col1 != col2)
    {
        Scierror(999, _("%s: Wrong size for input arguments: Same size expected.\n"), fname);
        return 1;
    }

    scilab_getDoubleArray(env, in[0], &in1);
    scilab_getBooleanArray(env, in[1], &in2);

    out[0] = scilab_createDoubleMatrix2d(env, row1, col1, 0);
    out[1] = scilab_createBooleanMatrix2d(env, row2, col2);

    scilab_getDoubleArray(env, out[0], &out1);
    scilab_getBooleanArray(env, out[1], &out2);

    for (i = 0; i < size1; ++i)
    {
        //For each element of the matrix, multiply by 2
        out1[i] = in1[i] * 2;
    }

    for (i = 0; i < size2; ++i)
    {
        //For each element of the matrix, invert the value
        out2[i] = in2[i] == TRUE ? FALSE : TRUE;
    }

    return 0;
}
      ]]>
        </programlisting>
        <para>
            To build this code and load it to Scilab, we use the dynamic link capabilities of Scilab. Delegating the build process to Scilab, this code is multiplaform.
            <programlisting role="no-scilab-exec">
                <![CDATA[
      files=["sci_foo6.c"];
      ilib_build('build_lib',['foo6','sci_foo6','csci6'],files,[]);
      exec loader.sce
      [c, d] = foo6([2,%pi], [%t, %f])
      ]]>
            </programlisting>
        </para>
        <para>
            Various checks can be performed:
            <programlisting role="no-scilab-exec">
                <![CDATA[
--> [c, d] = foo6(2, 2)

foo6: Wrong type for input argument #2: A boolean matrix expected.
      ]]>
            </programlisting>
            <programlisting role="no-scilab-exec">
                <![CDATA[
-->[c, d] = foo6([2,2], %t)
                        !--error 999
foo6: Wrong size for input arguments: Same size expected.
      ]]>
            </programlisting>
            <programlisting role="no-scilab-exec">
                <![CDATA[
-->[a,b]=foo6(2+%i,%t)
                   !--error 999
foo6: Wrong type for input argument #1: A real matrix expected.
      ]]>
            </programlisting>
            <programlisting role="no-scilab-exec">
                <![CDATA[
-->[c, d] = foo6([2,%pi], [%t, %f])
 d  =

  F T
 c  =

    4.    6.2831853
      ]]>
            </programlisting>
        </para>
    </refsection>
</refentry>
