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