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