73beb20842290e0a80474d777ff1d9d4aabf581d
[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 = false;
83     //inputs
84     while (pos < nin)
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                 //need to clone double input data to avoid modification
241                 if (params[order - 1].type == L'd')
242                 {
243                     int size = params[order - 1].row * params[order - 1].col * sizeof(double);
244                     double* dbls = (double*)malloc(size);
245                     memcpy(dbls, params[order - 1].data, size);
246                     params[order - 1].data = dbls;
247                     params[order - 1].alloc = true;
248                 }
249
250                 pos += 1;
251                 output_order[output_pos] = order - 1;
252             }
253             else
254             {
255                 //dims
256                 double* dims = 0;
257                 scilab_getDoubleArray(env, in[pos], &dims);
258                 int size = (int)dims[0] * (int)dims[1];
259
260                 //pos
261                 if (scilab_isDouble(env, in[pos + 1]) == 0 || scilab_isScalar(env, in[pos + 1]) == 0)
262                 {
263                     Scierror(77, _("%s: Wrong type for input argument #%d : A real scalar expected.\n"), fname, pos + 2);
264                     return 1;
265                 }
266
267                 double param_pos = 0;
268                 scilab_getDouble(env, in[pos + 1], &param_pos);
269
270                 //type
271                 if (scilab_isString(env, in[pos + 2]) == 0 || scilab_isScalar(env, in[pos + 2]) == 0)
272                 {
273                     Scierror(77, _("%s: Wrong type for input argument #%d : string expected.\n"), fname, pos + 3);
274                     return 1;
275                 }
276
277                 wchar_t* param_type = NULL;
278                 scilab_getString(env, in[pos + 2], &param_type);
279
280                 void* data = NULL;
281                 Parameter& p = params[(int)param_pos - 1];
282
283                 if (p.data != nullptr) // Reuse the input slot if it is passed as output
284                 {
285                     if (p.type != param_type[0])
286                     {
287                         Scierror(999, _("%s: incompatible type between input and output variables.\n"), fname);
288                         return 1;
289                     }
290                     if (p.row != dims[0] || p.col != dims[1])
291                     {
292                         Scierror(999, _("%s: incompatible sizes between input and output variables.\n"), fname);
293                         return 1;
294                     }
295
296                     //need to clone double input data to avoid modification
297                     if (p.type == L'd')
298                     {
299                         int size = p.row * p.col * sizeof(double);
300                         double* dbls = (double*)malloc(size);
301                         memcpy(dbls, p.data, size);
302                         p.data = dbls;
303                         p.alloc = true;
304                     }
305                 }
306                 else // Otherwise allocate one
307                 {
308                     switch (param_type[0])
309                     {
310                         case L'c':
311                         {
312                             data = malloc((size + 1) * sizeof(char));
313                             break;
314                         }
315                         case L'd':
316                         {
317                             data = malloc(size * sizeof(double));
318                             break;
319                         }
320                         case L'r':
321                         {
322                             data = malloc(size * sizeof(float));
323                             break;
324                         }
325                         case L'i':
326                         {
327                             data = malloc(size * sizeof(int));
328                             break;
329                         }
330                     }
331                     p.row = (int)dims[0];
332                     p.col = (int)dims[1];
333                     p.alloc = true;
334                     p.type = param_type[0];
335                     p.data = data;
336                 }
337                 pos += 3;
338                 output_order[output_pos] = (int)param_pos - 1;
339             }
340
341             ++output_pos;
342
343             if (pos + 1 > nin)
344             {
345                 break;
346             }
347         }
348
349     }
350     //the unbelievable call !
351     ((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,
352                              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,
353                              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);
354
355     //create output variables
356     for (int i = 0; i < nout && hasOutputs; ++i)
357     {
358         Parameter& p = params[output_order[i]];
359
360         switch (p.type)
361         {
362             case L'c':
363             {
364                 wchar_t* w = to_wide_string((char*)p.data);
365                 scilabVar var = scilab_createString(env, w);
366                 out[i] = var;
367                 FREE(w);
368                 break;
369             }
370             case L'd':
371             {
372                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
373                 scilab_setDoubleArray(env, var, (double*)p.data);
374                 out[i] = var;
375                 break;
376             }
377             case L'r':
378             {
379                 double* d = NULL;
380                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
381                 scilab_getDoubleArray(env, var, &d);
382                 int size = p.row * p.col;
383                 for (int j = 0; j < size; ++j)
384                 {
385                     d[j] = (double)((float*)p.data)[j];
386                 }
387
388                 out[i] = var;
389                 break;
390             }
391             case L'i':
392             {
393                 double* d = NULL;
394                 scilabVar var = scilab_createDoubleMatrix2d(env, p.row, p.col, 0);
395                 scilab_getDoubleArray(env, var, &d);
396                 int size = p.row * p.col;
397                 for (int j = 0; j < size; ++j)
398                 {
399                     d[j] = (double)((int*)p.data)[j];
400                 }
401
402                 out[i] = var;
403                 break;
404             }
405         }
406     }
407
408     //allocated data will be clean by structure dtor
409     return STATUS_OK;
410 }
411
412 bool isOut(scilabEnv env, scilabVar var)
413 {
414     if (scilab_isString(env, var) && scilab_isScalar(env, var))
415     {
416         wchar_t* strs = NULL;
417         scilab_getString(env, var, &strs);
418         if (wcscmp(strs, L"out") == 0 || wcscmp(strs, L"sort") == 0)
419         {
420             return true;
421         }
422     }
423
424     return false;
425 }