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