utf: ast 2
[scilab.git] / scilab / modules / ast / src / cpp / types / function.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2008-2008 - DIGITEO - Antoine ELIAS
4  *  Copyright (C) 2010-2010 - DIGITEO - Bruno JOFRET
5  *
6  *  This file must be used under the terms of the CeCILL.
7  *  This source file is licensed as described in the file COPYING, which
8  *  you should have received as part of this distribution.  The terms
9  *  are also available at
10  *  http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
11  *
12  */
13
14 #include <algorithm>
15 #include <sstream>
16 #include <vector>
17 #include "function.hxx"
18 #include "double.hxx"
19 #include "gatewaystruct.hxx"
20 #include "configvariable.hxx"
21 #include "scilabWrite.hxx"
22
23 extern "C"
24 {
25 #include "core_math.h"
26 #include "charEncoding.h"
27 #include "Scierror.h"
28 #include "sciprint.h"
29 #include "localization.h"
30 #include "sci_path.h"
31 #include "sci_malloc.h"
32 #include "os_string.h"
33 #include "lasterror.h"
34 #include "dynamic_module.h"
35 }
36
37 namespace types
38 {
39 Function* Function::createFunction(const std::string& _stName, GW_FUNC _pFunc, const std::string& _stModule)
40 {
41     return new Function(_stName, _pFunc, NULL, _stModule);
42 }
43
44 Function* Function::createFunction(const std::string& _stName, GW_FUNC_OPT _pFunc, const std::string& _stModule)
45 {
46     return new OptFunction(_stName, _pFunc, NULL, _stModule);
47 }
48
49 Function* Function::createFunction(const std::string& _stName, OLDGW_FUNC _pFunc, const std::string& _stModule)
50 {
51     return new WrapFunction(_stName, _pFunc, NULL, _stModule);
52 }
53
54 Function* Function::createFunction(const std::string& _stName, MEXGW_FUNC _pFunc, const std::string& _stModule)
55 {
56     return new WrapMexFunction(_stName, _pFunc, NULL, _stModule);
57 }
58
59 Function* Function::createFunction(const std::string& _stName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
60 {
61     return new Function(_stName, _pFunc, _pLoadDeps, _stModule);
62 }
63
64 Function* Function::createFunction(const std::string& _stName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
65 {
66     return new OptFunction(_stName, _pFunc, _pLoadDeps, _stModule);
67 }
68
69 Function* Function::createFunction(const std::string& _stName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
70 {
71     return new WrapFunction(_stName, _pFunc, _pLoadDeps, _stModule);
72 }
73
74 Function* Function::createFunction(const std::string& _stName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
75 {
76     return new WrapMexFunction(_stName, _pFunc, _pLoadDeps, _stModule);
77 }
78
79 Function* Function::createFunction(const std::string& _stFunctionName, const std::string& _stEntryPointName, const std::string& _stLibName, FunctionType _iType, LOAD_DEPS _pLoadDeps, const std::string& _stModule, bool _bCloseLibAfterCall)
80 {
81     return new DynamicFunction(_stFunctionName, _stEntryPointName, _stLibName, _iType, _pLoadDeps, _stModule, _bCloseLibAfterCall);
82 }
83
84 Function* Function::createFunction(const std::string& _stFunctionName, const std::string& _stEntryPointName, const std::string& _stLibName, FunctionType _iType, const std::string& _stLoadDepsName, const std::string& _stModule, bool _bCloseLibAfterCall)
85 {
86     return new DynamicFunction(_stFunctionName, _stEntryPointName, _stLibName, _iType, _stLoadDepsName, _stModule, _bCloseLibAfterCall);
87 }
88
89 Function* Function::createFunction(const std::string& _stName, GW_C_FUNC _pFunc, const std::string& _stModule)
90 {
91     return new WrapCFunction(_stName, _pFunc, NULL, _stModule);
92 }
93
94 Function* Function::createFunction(const std::string& _stName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
95 {
96     return new WrapCFunction(_stName, _pFunc, _pLoadDeps, _stModule);
97 }
98
99
100 Function::Function(const std::string& _stName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule) : Callable(), m_pFunc(_pFunc), m_pLoadDeps(_pLoadDeps)
101 {
102     setName(_stName);
103     setModule(_stModule);
104 }
105
106 Function::~Function()
107 {
108
109 }
110
111
112 Function::ReturnValue Function::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
113 {
114     int ret = 1;
115     if (m_pLoadDeps != NULL)
116     {
117         ret = m_pLoadDeps(m_stName);
118     }
119
120     if (ret == 0)
121     {
122         return Error;
123     }
124
125     return this->m_pFunc(in, _iRetCount, out);
126 }
127
128 void Function::whoAmI()
129 {
130     std::cout << "types::Function";
131 }
132
133 bool Function::toString(std::ostringstream& ostr)
134 {
135     // display nothing. ie : c = cos
136     return true;
137 }
138
139 Function* Function::clone()
140 {
141     IncreaseRef();
142     return this;
143 }
144
145 OptFunction::OptFunction(const std::string& _stName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
146 {
147     m_stName = _stName;
148     m_pFunc = _pFunc;
149     m_pLoadDeps = _pLoadDeps;
150     m_stModule = _stModule;
151 }
152
153 OptFunction::OptFunction(OptFunction* _pWrapFunction)
154 {
155     m_stModule  = _pWrapFunction->getModule();
156     m_stName    = _pWrapFunction->getName();
157     m_pFunc = _pWrapFunction->getFunc();
158     m_pLoadDeps = _pWrapFunction->getDeps();
159 }
160
161 OptFunction* OptFunction::clone()
162 {
163     return new OptFunction(this);
164 }
165
166 Function::ReturnValue OptFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
167 {
168     int ret = 1;
169     if (m_pLoadDeps != NULL)
170     {
171         ret = m_pLoadDeps(m_stName);
172     }
173
174     if (ret == 0)
175     {
176         return Error;
177     }
178
179     return this->m_pFunc(in, opt, _iRetCount, out);
180 }
181
182 WrapFunction::WrapFunction(const std::string& _stName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
183 {
184     m_stName = _stName;
185     m_pOldFunc = _pFunc;
186     m_stModule = _stModule;
187     m_pLoadDeps = _pLoadDeps;
188 }
189
190 WrapFunction::WrapFunction(WrapFunction* _pWrapFunction)
191 {
192     m_stModule = _pWrapFunction->getModule();
193     m_stName = _pWrapFunction->getName();
194     m_pOldFunc  = _pWrapFunction->getFunc();
195     m_pLoadDeps = _pWrapFunction->getDeps();
196 }
197
198 WrapFunction* WrapFunction::clone()
199 {
200     return new WrapFunction(this);
201 }
202
203 Function::ReturnValue WrapFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
204 {
205     int ret = 1;
206     int inSize = (int)in.size();
207     int optSize = (int)opt.size();
208     bool isRef = checkReferenceModule(m_stModule.c_str()) == 1;
209
210     if (m_pLoadDeps != NULL)
211     {
212         ret = m_pLoadDeps(m_stName);
213     }
214
215     if (ret == 0)
216     {
217         return Error;
218     }
219
220     ReturnValue retVal = Callable::OK;
221     GatewayStruct gStr;
222     _iRetCount = std::max(1, _iRetCount);
223     gStr.m_iIn = inSize + optSize;
224     gStr.m_iOut = _iRetCount;
225
226     //copy input parameter to prevent calling gateway modifies input data
227     typed_list inCopy;
228
229     if (isRef == false)
230     {
231         for (int i = 0; i < inSize; i++)
232         {
233             inCopy.push_back(in[i]->clone());
234         }
235     }
236     else
237     {
238         for (int i = 0; i < inSize; i++)
239         {
240             inCopy.push_back(in[i]);
241         }
242     }
243     gStr.m_pIn = &inCopy;
244     gStr.m_pOpt = &opt;
245     typed_list::value_type tmpOut[MAX_OUTPUT_VARIABLE];
246     std::fill_n(tmpOut, MAX_OUTPUT_VARIABLE, static_cast<typed_list::value_type>(0));
247     gStr.m_pOut = tmpOut;
248     gStr.m_piRetCount = &_iRetCount;
249     gStr.m_pstName = m_stName.data();
250     // we should use a stack array of the max size to avoid dynamic alloc.
251     std::vector<int> outOrder(_iRetCount < 1 ? 1 : _iRetCount, -1);
252     gStr.m_pOutOrder = outOrder.data();
253
254     //call gateway
255     m_pOldFunc(const_cast<char*>(m_stName.data()), reinterpret_cast<int*>(&gStr));
256     if (ConfigVariable::isError())
257     {
258         retVal = Callable::Error;
259         ConfigVariable::resetError();
260     }
261     else
262     {
263         for (std::size_t i(0); i != (size_t)_iRetCount && outOrder[i] != -1 && outOrder[i] != 0; ++i)
264         {
265             if (outOrder[i] - 1 < gStr.m_iIn)
266             {
267                 std::size_t const iPos(outOrder[i] - 1);
268                 //protect variable to deletion
269                 inCopy[iPos]->IncreaseRef();
270                 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsInteger())
271                 {
272                     types::Double* pD = inCopy[iPos]->getAs<types::Double>();
273                     pD->convertFromInteger();
274                 }
275
276                 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsZComplex())
277                 {
278                     types::Double* pD = inCopy[iPos]->getAs<types::Double>();
279                     pD->convertFromZComplex();
280                 }
281
282                 out.push_back(inCopy[iPos]);
283             }
284             else
285             {
286                 std::size_t const iPos(outOrder[i] - gStr.m_iIn - 1);
287                 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsInteger())
288                 {
289                     types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
290                     pD->convertFromInteger();
291                 }
292
293                 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsZComplex())
294                 {
295                     types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
296                     pD->convertFromZComplex();
297                 }
298
299                 out.push_back(tmpOut[iPos]);
300                 tmpOut[iPos] = 0;
301             }
302         }
303     }
304
305     for (std::size_t i(0); i != MAX_OUTPUT_VARIABLE; ++i)
306     {
307         if (tmpOut[i])
308         {
309             tmpOut[i]->killMe();
310         }
311     }
312
313     //clean input copy
314     if (isRef == false)
315     {
316         //protect outputs
317         int size = (int)out.size();
318         for (int i = 0; i < size; i++)
319         {
320             out[i]->IncreaseRef();
321         }
322
323         for (int i = 0; i < inSize; i++)
324         {
325             inCopy[i]->killMe();
326         }
327
328         //unprotect outputs
329         for (int i = 0; i < size; i++)
330         {
331             out[i]->DecreaseRef();
332         }
333     }
334
335     return retVal;
336 }
337
338 WrapMexFunction::WrapMexFunction(const std::string& _stName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
339 {
340     m_stName = _stName;
341     m_pOldFunc = _pFunc;
342     m_stModule = _stModule;
343     m_pLoadDeps = _pLoadDeps;
344 }
345
346 WrapMexFunction::WrapMexFunction(WrapMexFunction* _pWrapFunction)
347 {
348     m_stModule = _pWrapFunction->getModule();
349     m_stName = _pWrapFunction->getName();
350     m_pOldFunc = _pWrapFunction->getFunc();
351     m_pLoadDeps = _pWrapFunction->getDeps();
352 }
353
354 WrapMexFunction* WrapMexFunction::clone()
355 {
356     return new WrapMexFunction(this);
357 }
358
359 Function::ReturnValue WrapMexFunction::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
360 {
361     int ret = 1;
362     if (m_pLoadDeps != NULL)
363     {
364         ret = m_pLoadDeps(m_stName);
365     }
366
367     if (ret == 0)
368     {
369         return Error;
370     }
371
372     ReturnValue retVal = Callable::OK;
373
374     ConfigVariable::setMexFunctionName(getName().c_str());
375
376     int nlhs = _iRetCount;
377     int** plhs = new int*[nlhs];
378     memset(plhs, 0x00, sizeof(int*) * nlhs);
379
380     int nrhs = (int)in.size();
381     int** prhs = new int*[nrhs];
382     for (int i = 0; i < nrhs; i++)
383     {
384         prhs[i] = (int*)(in[i]);
385     }
386
387     try
388     {
389         m_pOldFunc(nlhs, plhs, nrhs, prhs);
390     }
391     catch (const ast::InternalError& ie)
392     {
393         delete[] plhs;
394         delete[] prhs;
395         throw ie;
396     }
397
398     if (_iRetCount == 1 && plhs[0] == NULL)
399     {
400         //dont copy empty values, juste return "no value"
401         return retVal;
402     }
403
404     for (int i = 0; i < nlhs; i++)
405     {
406         out.push_back((types::InternalType*)plhs[i]);
407     }
408
409     delete[] plhs;
410     delete[] prhs;
411     return retVal;
412 }
413
414 WrapCFunction::WrapCFunction(const std::string& _stName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::string& _stModule)
415 {
416     m_stName = _stName;
417     m_pCFunc = _pFunc;
418     m_stModule = _stModule;
419     m_pLoadDeps = _pLoadDeps;
420 }
421
422 WrapCFunction::WrapCFunction(WrapCFunction* _pWrapFunction)
423 {
424     m_stModule = _pWrapFunction->getModule();
425     m_stName = _pWrapFunction->getName();
426     m_pCFunc = _pWrapFunction->getFunc();
427     m_pLoadDeps = _pWrapFunction->getDeps();
428 }
429
430 WrapCFunction* WrapCFunction::clone()
431 {
432     return new WrapCFunction(this);
433 }
434
435 Function::ReturnValue WrapCFunction::call(typed_list& in, optional_list& opt, int _iRetCount, typed_list& out)
436 {
437     if (m_pLoadDeps != NULL)
438     {
439         if (m_pLoadDeps(m_stName) == 0)
440         {
441             return Error;
442         }
443     }
444
445     ReturnValue retVal = OK;
446
447     try
448     {
449         GatewayCStruct gcs;
450         gcs.name = m_stName;
451         out.resize(_iRetCount, NULL);
452         if (m_pCFunc((void*)&gcs, (int)in.size(), (scilabVar*)(in.data()), (int)opt.size(), (scilabOpt)&opt, _iRetCount, (scilabVar*)(out.data())))
453         {
454             retVal = Error;
455         }
456     }
457     catch (const ast::InternalError& ie)
458     {
459         throw ie;
460     }
461
462     if (retVal == OK)
463     {
464         if (_iRetCount == 1 && out[0] == NULL)
465         {
466             //dont copy empty values, juste return "no value"
467             out.clear();
468             return retVal;
469         }
470     }
471
472     return retVal;
473 }
474
475 DynamicFunction::DynamicFunction(const std::string& _stName, const std::string& _stEntryPointName, const std::string& _stLibName, FunctionType _iType, const std::string& _stLoadDepsName, const std::string& _stModule, bool _bCloseLibAfterCall)
476 {
477     m_stName = _stName;
478     m_libName = _stLibName;
479     m_stModule = _stModule;
480     m_entryPoint = _stEntryPointName;
481     m_loadDepsName = _stLoadDepsName;
482     m_pLoadDeps = NULL;
483     m_bCloseLibAfterCall = _bCloseLibAfterCall;
484     m_iType = _iType;
485     m_pFunc = NULL;
486     m_pOptFunc = NULL;
487     m_pOldFunc = NULL;
488     m_pMexFunc = NULL;
489     m_pFunction = NULL;
490     m_pCFunc = NULL;
491 }
492
493 DynamicFunction::DynamicFunction(const std::string& _stName, const std::string& _stEntryPointName, const std::string& _stLibName, FunctionType _iType, LOAD_DEPS _pLoadDeps, const std::string& _stModule, bool _bCloseLibAfterCall)
494 {
495     m_stName = _stName;
496     m_libName = _stLibName;
497     m_stModule = _stModule;
498     m_entryPoint = _stEntryPointName;
499     m_pLoadDeps = _pLoadDeps;
500     m_loadDepsName = "";
501     m_bCloseLibAfterCall = _bCloseLibAfterCall;
502     m_iType = _iType;
503     m_pFunc = NULL;
504     m_pOptFunc = NULL;
505     m_pOldFunc = NULL;
506     m_pMexFunc = NULL;
507     m_pFunction = NULL;
508     m_pCFunc = NULL;
509 }
510
511 Function::ReturnValue DynamicFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
512 {
513     if (m_pFunction == NULL)
514     {
515         if (Init() != OK)
516         {
517             return Error;
518         }
519     }
520
521     /*call function*/
522     if (m_pFunction->call(in, opt, _iRetCount, out) != OK)
523     {
524         return Error;
525     }
526
527     /*Close lib is mandatory*/
528     if (m_bCloseLibAfterCall)
529     {
530         Clear();
531     }
532
533     return OK;
534 }
535
536 DynamicFunction::~DynamicFunction()
537 {
538     if (m_pFunction)
539     {
540         delete m_pFunction;
541     }
542 }
543
544 Callable::ReturnValue DynamicFunction::Init()
545 {
546     /*Load library*/
547     if (m_libName.empty())
548     {
549         Scierror(999, _("%s: Library name must not be empty\n."), m_stName.c_str());
550         return Error;
551     }
552
553     DynLibHandle hLib = getDynModule(m_libName.c_str());
554     if (hLib == 0)
555     {
556         hLib = LoadDynLibrary(m_libName.c_str());
557
558         if (hLib == 0)
559         {
560             //2nd chance for linux !
561 #ifndef _MSC_VER
562             char* pstError = strdup(GetLastDynLibError());
563
564             /* Haven't been able to find the lib with dlopen...
565             * This can happen for two reasons:
566             * - the lib must be dynamically linked
567             * - Some silly issues under Suse (see bug #2875)
568             * Note that we are handling only the "source tree build"
569             * because libraries are split (they are in the same directory
570             * in the binary)
571             */
572             char* pstScilabPath = getSCI();
573             char pstModulesPath[] = "/modules/";
574             char pstLTDir[] =  ".libs/";
575
576             /* Build the full path to the library */
577             int iPathToLibLen = (strlen(pstScilabPath) + strlen(pstModulesPath) + strlen(m_stModule.c_str()) + strlen("/") + strlen(pstLTDir) + strlen(m_libName.c_str()) + 1);
578             char* pstPathToLib = (char*)MALLOC(iPathToLibLen * sizeof(char));
579 #ifdef _MSC_VER
580             os_sprintf(pstPathToLib, iPathToLibLen, "%s%s%s/%s%s", pstScilabPath, pstModulesPath, m_stModule.c_str(), pstLTDir, m_libName.c_str());
581 #else
582             os_sprintf(pstPathToLib, "%s%s%s/%s%s", pstScilabPath, pstModulesPath, m_stModule.c_str(), pstLTDir, m_libName.c_str());
583 #endif
584             FREE(pstScilabPath);
585             hLib = LoadDynLibrary(pstPathToLib);
586
587             if (hLib == 0)
588             {
589                 Scierror(999, _("An error has been detected while loading %s: %s\n"), m_libName.c_str(), pstError);
590                 FREE(pstError);
591
592                 pstError = GetLastDynLibError();
593                 Scierror(999, _("An error has been detected while loading %s: %s\n"), pstPathToLib, pstError);
594
595                 FREE(pstPathToLib);
596                 return Error;
597             }
598             FREE(pstPathToLib);
599             FREE(pstError);
600 #else
601             Scierror(999, _("Impossible to load %s library\n"), m_libName.c_str());
602             return Error;
603 #endif
604         }
605         addDynModule(m_libName.c_str(), hLib);
606
607         /*Load deps*/
608         if (m_loadDepsName.empty() == false && m_pLoadDeps == NULL)
609         {
610             m_pLoadDeps = (LOAD_DEPS)GetDynLibFuncPtr(hLib, m_loadDepsName.c_str());
611         }
612
613     }
614
615     /*Load gateway*/
616     if (m_stName != "")
617     {
618         const char* pstEntryPoint = m_entryPoint.c_str();
619         switch (m_iType)
620         {
621             case EntryPointCPPOpt :
622                 m_pOptFunc = (GW_FUNC_OPT)GetDynLibFuncPtr(hLib, pstEntryPoint);
623                 break;
624             case EntryPointCPP :
625                 m_pFunc = (GW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
626                 break;
627             case EntryPointOldC :
628                 m_pOldFunc = (OLDGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
629                 break;
630             case EntryPointMex:
631                 m_pMexFunc = (MEXGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
632                 break;
633             case EntryPointC:
634                 m_pCFunc = (GW_C_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
635                 break;
636         }
637     }
638
639     if (m_pFunc == NULL && m_pOldFunc == NULL && m_pMexFunc == NULL && m_pOptFunc == NULL && m_pCFunc == NULL)
640     {
641         const char* pstEntry = m_entryPoint.c_str();
642         const char* pstLib = m_libName.c_str();
643         Scierror(999, _("Impossible to load %s function in %s library: %s\n"), pstEntry, pstLib, GetLastDynLibError());
644         return Error;
645     }
646
647     switch (m_iType)
648     {
649         case EntryPointCPPOpt :
650             m_pFunction = new OptFunction(m_stName, m_pOptFunc, m_pLoadDeps, m_stModule);
651             break;
652         case EntryPointCPP :
653             m_pFunction = new Function(m_stName, m_pFunc, m_pLoadDeps, m_stModule);
654             break;
655         case EntryPointOldC :
656             m_pFunction = new WrapFunction(m_stName, m_pOldFunc, m_pLoadDeps, m_stModule);
657             break;
658         case EntryPointMex:
659             m_pFunction = new WrapMexFunction(m_stName, m_pMexFunc, m_pLoadDeps, m_stModule);
660             break;
661         case EntryPointC:
662             m_pFunction = new WrapCFunction(m_stName, m_pCFunc, m_pLoadDeps, m_stModule);
663             break;
664     }
665
666     if (m_pFunction == NULL)
667     {
668         return Error;
669     }
670     return OK;
671 }
672
673 void DynamicFunction::Clear()
674 {
675     m_pFunc     = NULL;
676     m_pOldFunc  = NULL;
677     m_pMexFunc  = NULL;
678 }
679
680 }