* Bug #15046 fixed - Dynamic_link: call() couldn't mix inputs and outputs
[scilab.git] / scilab / modules / dynamic_link / sci_gateway / cpp / sci_call.cpp
1 /*
2  * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  * Copyright (C) Scilab Enterprises - 2015 - Antoine ELIAS
4  *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
7  * This file is hereby licensed under the terms of the GNU GPL v2.0,
8  * pursuant to article 5.3.4 of the CeCILL v.2.1.
9  * This file was originally licensed under the terms of the CeCILL v2.1,
10  * and continues to be available under such terms.
11  * For more information, see the COPYING file which you should have received
12  * along with this program.
13  *
14  */
15
16 #include <vector>
17 #include "api_scilab.h"
18 #include "configvariable.hxx"
19
20 extern "C"
21 {
22 #include "gw_dynamic_link.h"
23 #include "Scierror.h"
24 #include "localization.h"
25 }
26
27 bool isOut(scilabEnv env, scilabVar var);
28
29 typedef void(*fct)(void* p0, void* p1, void* p2, void* p3, void* p4, void* p5, void* p6, void* p7, void* p8, void* p9,
30                    void* p10, void* p11, void* p12, void* p13, void* p14, void* p15, void* p16, void* p17, void* p18, void* p19,
31                    void* p20, void* p21, void* p22, void* p23, void* p24, void* p25, void* p26, void* p27, void* p28, void* p29);
32
33
34 struct Parameter
35 {
36     Parameter() : data(nullptr), type(L'\0'), alloc(false), row(0), col(0) {}
37     ~Parameter()
38     {
39         if (alloc)
40         {
41             free(data);
42         }
43     }
44
45     void* data;
46     wchar_t type;
47     bool alloc;
48     int row;
49     int col;
50 };
51
52 static const char fname[] = "call";
53
54 int sci_call(scilabEnv env, int nin, scilabVar* in, int nopt, scilabOpt opt, int nout, scilabVar* out)
55 {
56     std::vector<Parameter> params(30);
57     std::vector<int> output_order(nout);
58     wchar_t* interf = NULL;
59     if (nin < 1)
60     {
61         Scierror(77, _("%s: Wrong number of input argument(s): %d expected.\n"), fname, 1);
62         return 1;
63     }
64
65     //1st is the interface name
66     if (scilab_isString(env, in[0]) == 0 || scilab_isScalar(env, in[0]) == 0)
67     {
68         Scierror(999, _("%s: Wrong type for input argument #%d: String expected.\n"), fname, 1);
69         return 1;
70     }
71
72     scilab_getString(env, in[0], &interf);
73
74     ConfigVariable::EntryPointStr* func = ConfigVariable::getEntryPoint(interf);
75     if (func == NULL)
76     {
77         Scierror(999, _("%s: unable to find entry point %ls.\n"), fname, interf);
78         return 1;
79     }
80
81     int pos = 1;
82     bool hasOutputs = true;
83     //inputs
84     while (1)
85     {
86         //check "out" to break loop
87         if (isOut(env, in[pos]))
88         {
89             hasOutputs = true;
90             break;
91         }
92
93         if (pos > nin)
94         {
95             break;
96         }
97
98         int type = 0;
99         if (nin < pos + 2)
100         {
101             Scierror(77, _("%s: Wrong number of input argument(s).\n"), fname);
102             return 1;
103         }
104
105         type = scilab_getType(env, in[pos]);
106         if (type != sci_matrix && type != sci_strings)
107         {
108             Scierror(77, _("%s: Wrong type for input argument #%d: A real matrix or a string expected.\n"), fname, pos + 1);
109             return 1;
110         }
111
112         //data
113
114         //position
115         if (scilab_isDouble(env, in[pos + 1]) == 0 || scilab_isScalar(env, in[pos + 1]) == 0)
116         {
117             Scierror(77, _("%s: Wrong type for input argument #%d : A real scalar expected.\n"), fname, pos + 2);
118             return 1;
119         }
120
121         double param_pos = 0;
122         scilab_getDouble(env, in[pos + 1], &param_pos);
123
124         //type
125         if (scilab_isString(env, in[pos + 2]) == 0 || scilab_isScalar(env, in[pos + 2]) == 0)
126         {
127             Scierror(77, _("%s: Wrong type for input argument #%d : string expected.\n"), fname, pos + 3);
128             return 1;
129         }
130
131         void* data = NULL;
132         int row = 0;
133         int col = 0;
134
135         wchar_t* param_type = NULL;
136         scilab_getString(env, in[pos + 2], &param_type);
137
138         if (param_type[0] == L'c' || type == sci_strings)
139         {
140             if (param_type[0] != L'c' || type != sci_strings)
141             {
142                 Scierror(77, _("%s: Wrong type for input argument #%d : string expected.\n"), fname, pos + 1);
143                 return 1;
144             }
145         }
146
147         bool alloc = false;
148         switch (param_type[0])
149         {
150             case L'c':
151             {
152                 wchar_t* strs = NULL;
153                 scilab_getString(env, in[pos], &strs);
154                 char* c = wide_string_to_UTF8(strs);
155                 data = c;
156                 alloc = true;
157                 break;
158             }
159             case L'd':
160             {
161                 double* dbls = NULL;
162                 scilab_getDoubleArray(env, in[pos], &dbls);
163                 data = dbls;
164                 break;
165             }
166             case L'r':
167             {
168                 double* dbls = NULL;
169                 int size = scilab_getSize(env, in[pos]);
170                 scilab_getDoubleArray(env, in[pos], &dbls);
171                 float* f = (float*)malloc(size * sizeof(float));
172                 for (int i = 0; i < size; ++i)
173                 {
174                     f[i] = (float)dbls[i];
175                 }
176
177                 data = f;
178                 alloc = true;
179                 break;
180             }
181             case L'i':
182             {
183                 double* dbls = NULL;
184                 int size = scilab_getSize(env, in[pos]);
185                 scilab_getDoubleArray(env, in[pos], &dbls);
186                 int* ints = (int*)malloc(size * sizeof(int));
187                 for (int i = 0; i < size; ++i)
188                 {
189                     ints[i] = (int)dbls[i];
190                 }
191
192                 data = ints;
193                 alloc = true;
194                 break;
195             }
196             default:
197             {
198                 Scierror(77, _("%s: Wrong value for input argument #%d: '%s', '%s', '%s' or '%s' expected.\n"), fname, pos + 3, "d", "r", "i", "c");
199                 return 1;
200             }
201         }
202
203         scilab_getDim2d(env, in[pos], &row, &col);
204
205         Parameter& p = params[(int)param_pos - 1];
206         p.alloc = alloc;
207         p.data = data;
208         p.row = row;
209         p.col = col;
210         p.type = param_type[0];
211
212         pos += 3;
213     }
214
215     int output_pos = 0;
216     //outputs
217     if (hasOutputs)
218     {
219         ++pos; //avoid "out"
220         while (1)
221         {
222             //check if is 3 or 1 arg ...
223             if (scilab_isDouble(env, in[pos]) == 0)
224             {
225                 Scierror(77, _("%s: Wrong type for input argument #%d: A real matrix expected.\n"), fname, pos + 1);
226                 return 1;
227             }
228
229             if (scilab_isScalar(env, in[pos]))
230             {
231                 double dorder = 0;
232                 scilab_getDouble(env, in[pos], &dorder);
233                 int order = (int)dorder;
234                 if (params[order - 1].data == nullptr)
235                 {
236                     Scierror(77, _("%s: Wrong value for input argument #%d.\n"), fname, pos + 1);
237                     return 1;
238                 }
239
240                 pos += 1;
241                 output_order[output_pos] = order - 1;
242             }
243             else
244             {
245                 //dims
246                 double* dims = 0;
247                 scilab_getDoubleArray(env, in[pos], &dims);
248                 int size = (int)dims[0] * (int)dims[1];
249
250                 //pos
251                 if (scilab_isDouble(env, in[pos + 1]) == 0 || scilab_isScalar(env, in[pos + 1]) == 0)
252                 {
253                     Scierror(77, _("%s: Wrong type for input argument #%d : A real scalar expected.\n"), fname, pos + 2);
254                     return 1;
255                 }
256
257                 double param_pos = 0;
258                 scilab_getDouble(env, in[pos + 1], &param_pos);
259
260                 //type
261                 if (scilab_isString(env, in[pos + 2]) == 0 || scilab_isScalar(env, in[pos + 2]) == 0)
262                 {
263                     Scierror(77, _("%s: Wrong type for input argument #%d : string expected.\n"), fname, pos + 3);
264                     return 1;
265                 }
266
267                 wchar_t* param_type = NULL;
268                 scilab_getString(env, in[pos + 2], &param_type);
269
270                 void* data = NULL;
271                 Parameter& p = params[(int)param_pos - 1];
272
273                 if (p.data != nullptr) // Reuse the input slot if it is passed as output
274                 {
275                     if (p.type != param_type[0])
276                     {
277                         Scierror(999, _("%s: incompatible type between input and output variables.\n"), fname);
278                         return 1;
279                     }
280                     if (p.row != dims[0] || p.col != dims[1])
281                     {
282                         Scierror(999, _("%s: incompatible sizes between input and output variables.\n"), fname);
283                         return 1;
284                     }
285                 }
286                 else // Otherwise allocate one
287                 {
288                     switch (param_type[0])
289                     {
290                         case L'c':
291                         {
292                             data = malloc((size + 1) * sizeof(char));
293                             break;
294                         }
295                         case L'd':
296                         {
297                             data = malloc(size * sizeof(double));
298                             break;
299                         }
300                         case L'r':
301                         {
302                             data = malloc(size * sizeof(float));
303                             break;
304                         }
305                         case L'i':
306                         {
307                             data = malloc(size * sizeof(int));
308                             break;
309                         }
310                     }
311                     p.row = (int)dims[0];
312                     p.col = (int)dims[1];
313                     p.alloc = true;
314                     p.type = param_type[0];
315                     p.data = data;
316                 }
317                 pos += 3;
318                 output_order[output_pos] = (int)param_pos - 1;
319             }
320
321             ++output_pos;
322
323             if (pos + 1 > nin)
324             {
325                 break;
326             }
327         }
328
329     }
330     //the unbelievable call !
331     ((fct)func->functionPtr)(params[0].data, params[1].data, params[2].data, params[3].data, params[4].data, params[5].data, params[6].data, params[7].data, params[8].data, params[9].data,
332                              params[10].data, params[11].data, params[12].data, params[13].data, params[14].data, params[15].data, params[16].data, params[17].data, params[18].data, params[19].data,
333                              params[20].data, params[21].data, params[22].data, params[23].data, params[24].data, params[25].data, params[26].data, params[27].data, params[28].data, params[29].data);
334
335     //create output variables
336     for (int i = 0; i < nout; ++i)
337     {
338         Parameter& p = params[output_order[i]];
339
340         switch (p.type)
341         {
342             case L'c':
343             {
344                 wchar_t* w = to_wide_string((char*)p.data);
345                 scilabVar var = scilab_createString(env, w);
346                 out[i] = var;
347                 FREE(w);
348                 break;
349             }
350             case L'd':
351             {
352                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
353                 scilab_setDoubleArray(env, var, (double*)p.data);
354                 out[i] = var;
355                 break;
356             }
357             case L'r':
358             {
359                 double* d = NULL;
360                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
361                 scilab_getDoubleArray(env, var, &d);
362                 int size = p.row * p.col;
363                 for (int j = 0; j < size; ++j)
364                 {
365                     d[j] = (double)((float*)p.data)[j];
366                 }
367
368                 out[i] = var;
369                 break;
370             }
371             case L'i':
372             {
373                 double* d = NULL;
374                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
375                 scilab_getDoubleArray(env, var, &d);
376                 int size = p.row * p.col;
377                 for (int j = 0; j < size; ++j)
378                 {
379                     d[j] = (double)((int*)p.data)[j];
380                 }
381
382                 out[i] = var;
383                 break;
384             }
385         }
386     }
387     return STATUS_OK;
388 }
389
390 bool isOut(scilabEnv env, scilabVar var)
391 {
392     if (scilab_isString(env, var) && scilab_isScalar(env, var))
393     {
394         wchar_t* strs = NULL;
395         scilab_getString(env, var, &strs);
396         if (wcscmp(strs, L"out") == 0 || wcscmp(strs, L"sort") == 0)
397         {
398             return true;
399         }
400     }
401
402     return false;
403 }