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
6 * Copyright (C) 2012 - 2016 - Scilab Enterprises
8 * This file is hereby licensed under the terms of the GNU GPL v2.0,
9 * pursuant to article 5.3.4 of the CeCILL v.2.1.
10 * This file was originally licensed under the terms of the CeCILL v2.1,
11 * and continues to be available under such terms.
12 * For more information, see the COPYING file which you should have received
13 * along with this program.
20 #include "function.hxx"
22 #include "gatewaystruct.hxx"
23 #include "configvariable.hxx"
24 #include "scilabWrite.hxx"
28 #include "core_math.h"
29 #include "charEncoding.h"
32 #include "localization.h"
34 #include "sci_malloc.h"
35 #include "os_string.h"
36 #include "lasterror.h"
37 #include "dynamic_module.h"
42 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC _pFunc, const std::wstring& _wstModule)
44 return new Function(_wstName, _pFunc, NULL, _wstModule);
47 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, const std::wstring& _wstModule)
49 return new OptFunction(_wstName, _pFunc, NULL, _wstModule);
52 Function* Function::createFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, const std::wstring& _wstModule)
54 return new WrapFunction(_wstName, _pFunc, NULL, _wstModule);
57 Function* Function::createFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, const std::wstring& _wstModule)
59 return new WrapMexFunction(_wstName, _pFunc, NULL, _wstModule);
62 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
64 return new Function(_wstName, _pFunc, _pLoadDeps, _wstModule);
67 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
69 return new OptFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
72 Function* Function::createFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
74 return new WrapFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
77 Function* Function::createFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
79 return new WrapMexFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
82 Function* Function::createFunction(const std::wstring& _wstFunctionName, const std::wstring& _wstEntryPointName, const std::wstring& _wstLibName, FunctionType _iType, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule, bool _bCloseLibAfterCall)
84 return new DynamicFunction(_wstFunctionName, _wstEntryPointName, _wstLibName, _iType, _pLoadDeps, _wstModule, _bCloseLibAfterCall);
87 Function* Function::createFunction(const std::wstring& _wstFunctionName, const std::wstring& _wstEntryPointName, const std::wstring& _wstLibName, FunctionType _iType, const std::wstring& _wstLoadDepsName, const std::wstring& _wstModule, bool _bCloseLibAfterCall)
89 return new DynamicFunction(_wstFunctionName, _wstEntryPointName, _wstLibName, _iType, _wstLoadDepsName, _wstModule, _bCloseLibAfterCall);
92 Function* Function::createFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, const std::wstring& _wstModule)
94 return new WrapCFunction(_wstName, _pFunc, NULL, _wstModule);
97 Function* Function::createFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
99 return new WrapCFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
103 Function::Function(const std::wstring& _wstName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule) : Callable(), m_pFunc(_pFunc), m_pLoadDeps(_pLoadDeps)
106 char* s = wide_string_to_UTF8(m_wstName.data());
110 setModule(_wstModule);
113 Function::~Function()
119 Function::ReturnValue Function::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
122 if (m_pLoadDeps != NULL)
124 ret = m_pLoadDeps(m_wstName);
132 return this->m_pFunc(in, _iRetCount, out);
135 void Function::whoAmI()
137 std::cout << "types::Function";
140 bool Function::toString(std::wostringstream& ostr)
142 // display nothing. ie : c = cos
146 Function* Function::clone()
152 OptFunction::OptFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
154 m_wstName = _wstName;
155 char* s = wide_string_to_UTF8(m_wstName.data());
159 m_pLoadDeps = _pLoadDeps;
160 m_wstModule = _wstModule;
163 OptFunction::OptFunction(OptFunction* _pWrapFunction)
165 m_wstModule = _pWrapFunction->getModule();
166 m_wstName = _pWrapFunction->getName();
167 char* s = wide_string_to_UTF8(m_wstName.data());
170 m_pFunc = _pWrapFunction->getFunc();
171 m_pLoadDeps = _pWrapFunction->getDeps();
174 OptFunction* OptFunction::clone()
176 return new OptFunction(this);
179 Function::ReturnValue OptFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
182 if (m_pLoadDeps != NULL)
184 ret = m_pLoadDeps(m_wstName);
192 return this->m_pFunc(in, opt, _iRetCount, out);
195 WrapFunction::WrapFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
197 m_wstName = _wstName;
199 m_wstModule = _wstModule;
200 char* s = wide_string_to_UTF8(m_wstName.data());
203 m_pLoadDeps = _pLoadDeps;
206 WrapFunction::WrapFunction(WrapFunction* _pWrapFunction)
208 m_wstModule = _pWrapFunction->getModule();
209 m_wstName = _pWrapFunction->getName();
210 char* s = wide_string_to_UTF8(m_wstName.data());
213 m_pOldFunc = _pWrapFunction->getFunc();
214 m_pLoadDeps = _pWrapFunction->getDeps();
217 WrapFunction* WrapFunction::clone()
219 return new WrapFunction(this);
222 Function::ReturnValue WrapFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
225 int inSize = (int)in.size();
226 int optSize = (int)opt.size();
227 bool isRef = checkReferenceModule(m_wstModule.c_str());
229 if (m_pLoadDeps != NULL)
231 ret = m_pLoadDeps(m_wstName);
239 ReturnValue retVal = Callable::OK;
241 _iRetCount = std::max(1, _iRetCount);
242 gStr.m_iIn = inSize + optSize;
243 gStr.m_iOut = _iRetCount;
245 //copy input parameter to prevent calling gateway modifies input data
250 for (int i = 0; i < inSize; i++)
252 inCopy.push_back(in[i]->clone());
257 for (int i = 0; i < inSize; i++)
259 inCopy.push_back(in[i]);
262 gStr.m_pIn = &inCopy;
264 typed_list::value_type tmpOut[MAX_OUTPUT_VARIABLE];
265 std::fill_n(tmpOut, MAX_OUTPUT_VARIABLE, static_cast<typed_list::value_type>(0));
266 gStr.m_pOut = tmpOut;
267 gStr.m_piRetCount = &_iRetCount;
268 gStr.m_pstName = m_stName.data();
269 // we should use a stack array of the max size to avoid dynamic alloc.
270 std::vector<int> outOrder(_iRetCount < 1 ? 1 : _iRetCount, -1);
271 gStr.m_pOutOrder = outOrder.data();
274 m_pOldFunc(const_cast<char*>(m_stName.data()), reinterpret_cast<int*>(&gStr));
275 if (ConfigVariable::isError())
277 retVal = Callable::Error;
278 ConfigVariable::resetError();
282 for (std::size_t i(0); i != (size_t)_iRetCount && outOrder[i] != -1 && outOrder[i] != 0; ++i)
284 if (outOrder[i] - 1 < gStr.m_iIn)
286 std::size_t const iPos(outOrder[i] - 1);
287 //protect variable to deletion
288 inCopy[iPos]->IncreaseRef();
289 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsInteger())
291 types::Double* pD = inCopy[iPos]->getAs<types::Double>();
292 pD->convertFromInteger();
295 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsZComplex())
297 types::Double* pD = inCopy[iPos]->getAs<types::Double>();
298 pD->convertFromZComplex();
301 out.push_back(inCopy[iPos]);
305 std::size_t const iPos(outOrder[i] - gStr.m_iIn - 1);
306 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsInteger())
308 types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
309 pD->convertFromInteger();
312 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsZComplex())
314 types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
315 pD->convertFromZComplex();
318 out.push_back(tmpOut[iPos]);
324 for (std::size_t i(0); i != MAX_OUTPUT_VARIABLE; ++i)
336 int size = (int)out.size();
337 for (int i = 0; i < size; i++)
339 out[i]->IncreaseRef();
342 for (int i = 0; i < inSize; i++)
348 for (int i = 0; i < size; i++)
350 out[i]->DecreaseRef();
357 WrapMexFunction::WrapMexFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
359 m_wstName = _wstName;
360 char* s = wide_string_to_UTF8(m_wstName.data());
364 m_wstModule = _wstModule;
365 m_pLoadDeps = _pLoadDeps;
368 WrapMexFunction::WrapMexFunction(WrapMexFunction* _pWrapFunction)
370 m_wstModule = _pWrapFunction->getModule();
371 char* s = wide_string_to_UTF8(m_wstName.data());
374 m_wstName = _pWrapFunction->getName();
375 m_pOldFunc = _pWrapFunction->getFunc();
376 m_pLoadDeps = _pWrapFunction->getDeps();
379 WrapMexFunction* WrapMexFunction::clone()
381 return new WrapMexFunction(this);
384 Function::ReturnValue WrapMexFunction::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
387 if (m_pLoadDeps != NULL)
389 ret = m_pLoadDeps(m_wstName);
397 ReturnValue retVal = Callable::OK;
399 char* name = wide_string_to_UTF8(getName().c_str());
400 ConfigVariable::setMexFunctionName(name);
403 int nlhs = _iRetCount;
404 int** plhs = new int*[nlhs];
405 memset(plhs, 0x00, sizeof(int*) * nlhs);
407 int nrhs = (int)in.size();
408 int** prhs = new int*[nrhs];
409 for (int i = 0; i < nrhs; i++)
411 prhs[i] = (int*)(in[i]);
416 m_pOldFunc(nlhs, plhs, nrhs, prhs);
418 catch (const ast::InternalError& ie)
425 if (_iRetCount == 1 && plhs[0] == NULL)
427 //dont copy empty values, juste return "no value"
431 for (int i = 0; i < nlhs; i++)
433 out.push_back((types::InternalType*)plhs[i]);
441 WrapCFunction::WrapCFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
443 m_wstName = _wstName;
444 char* s = wide_string_to_UTF8(m_wstName.data());
448 m_wstModule = _wstModule;
449 m_pLoadDeps = _pLoadDeps;
452 WrapCFunction::WrapCFunction(WrapCFunction* _pWrapFunction)
454 m_wstModule = _pWrapFunction->getModule();
455 char* s = wide_string_to_UTF8(m_wstName.data());
458 m_wstName = _pWrapFunction->getName();
459 m_pCFunc = _pWrapFunction->getFunc();
460 m_pLoadDeps = _pWrapFunction->getDeps();
463 WrapCFunction* WrapCFunction::clone()
465 return new WrapCFunction(this);
468 Function::ReturnValue WrapCFunction::call(typed_list& in, optional_list& opt, int _iRetCount, typed_list& out)
470 if (m_pLoadDeps != NULL)
472 if (m_pLoadDeps(m_wstName) == 0)
478 ReturnValue retVal = OK;
484 out.resize(_iRetCount, NULL);
485 if (m_pCFunc((void*)&gcs, (int)in.size(), (scilabVar*)(in.data()), (int)opt.size(), (scilabOpt)&opt, _iRetCount, (scilabVar*)(out.data())))
490 catch (const ast::InternalError& ie)
497 if (_iRetCount == 1 && out[0] == NULL)
499 //dont copy empty values, juste return "no value"
508 DynamicFunction::DynamicFunction(const std::wstring& _wstName, const std::wstring& _wstEntryPointName, const std::wstring& _wstLibName, FunctionType _iType, const std::wstring& _wstLoadDepsName, const std::wstring& _wstModule, bool _bCloseLibAfterCall)
510 m_wstName = _wstName;
511 char* s = wide_string_to_UTF8(m_wstName.data());
514 m_wstLibName = _wstLibName;
515 m_wstModule = _wstModule;
516 m_wstEntryPoint = _wstEntryPointName;
517 m_wstLoadDepsName = _wstLoadDepsName;
519 m_bCloseLibAfterCall = _bCloseLibAfterCall;
529 DynamicFunction::DynamicFunction(const std::wstring& _wstName, const std::wstring& _wstEntryPointName, const std::wstring& _wstLibName, FunctionType _iType, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule, bool _bCloseLibAfterCall)
531 m_wstName = _wstName;
532 char* s = wide_string_to_UTF8(m_wstName.data());
535 m_wstLibName = _wstLibName;
536 m_wstModule = _wstModule;
537 m_wstEntryPoint = _wstEntryPointName;
538 m_pLoadDeps = _pLoadDeps;
539 m_wstLoadDepsName = L"";
540 m_bCloseLibAfterCall = _bCloseLibAfterCall;
550 Function::ReturnValue DynamicFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
552 if (m_pFunction == NULL)
561 if (m_pFunction->call(in, opt, _iRetCount, out) != OK)
566 /*Close lib is mandatory*/
567 if (m_bCloseLibAfterCall)
575 DynamicFunction::~DynamicFunction()
583 Callable::ReturnValue DynamicFunction::Init()
586 if (m_wstLibName.empty())
588 Scierror(999, _("%s: Library name must not be empty\n."), m_wstName.c_str());
592 DynLibHandle hLib = getDynModule(m_wstLibName.c_str());
595 char* pstLibName = wide_string_to_UTF8(m_wstLibName.c_str());
596 hLib = LoadDynLibrary(pstLibName);
600 //2nd chance for linux !
602 char* pstError = strdup(GetLastDynLibError());
604 /* Haven't been able to find the lib with dlopen...
605 * This can happen for two reasons:
606 * - the lib must be dynamically linked
607 * - Some silly issues under Suse (see bug #2875)
608 * Note that we are handling only the "source tree build"
609 * because libraries are split (they are in the same directory
612 wchar_t* pwstScilabPath = getSCIW();
613 wchar_t pwstModulesPath[] = L"/modules/";
614 wchar_t pwstLTDir[] = L".libs/";
616 /* Build the full path to the library */
617 int iPathToLibLen = (wcslen(pwstScilabPath) + wcslen(pwstModulesPath) + wcslen(m_wstModule.c_str()) + wcslen(L"/") + wcslen(pwstLTDir) + wcslen(m_wstLibName.c_str()) + 1);
618 wchar_t* pwstPathToLib = (wchar_t*)MALLOC(iPathToLibLen * sizeof(wchar_t));
619 os_swprintf(pwstPathToLib, iPathToLibLen, L"%ls%ls%ls/%ls%ls", pwstScilabPath, pwstModulesPath, m_wstModule.c_str(), pwstLTDir, m_wstLibName.c_str());
620 FREE(pwstScilabPath);
621 char* pstPathToLib = wide_string_to_UTF8(pwstPathToLib);
623 hLib = LoadDynLibrary(pstPathToLib);
627 Scierror(999, _("An error has been detected while loading %s: %s\n"), pstLibName, pstError);
630 pstError = GetLastDynLibError();
631 Scierror(999, _("An error has been detected while loading %s: %s\n"), pstPathToLib, pstError);
640 char* pstError = wide_string_to_UTF8(m_wstLibName.c_str());
641 Scierror(999, _("Impossible to load %s library\n"), pstError);
648 addDynModule(m_wstLibName.c_str(), hLib);
651 if (m_wstLoadDepsName.empty() == false && m_pLoadDeps == NULL)
653 char* pstLoadDepsName = wide_string_to_UTF8(m_wstLoadDepsName.c_str());
654 m_pLoadDeps = (LOAD_DEPS)GetDynLibFuncPtr(hLib, pstLoadDepsName);
660 if (m_wstName != L"")
662 char* pstEntryPoint = wide_string_to_UTF8(m_wstEntryPoint.c_str());
665 case EntryPointCPPOpt :
666 m_pOptFunc = (GW_FUNC_OPT)GetDynLibFuncPtr(hLib, pstEntryPoint);
669 m_pFunc = (GW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
671 case EntryPointOldC :
672 m_pOldFunc = (OLDGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
675 m_pMexFunc = (MEXGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
678 m_pCFunc = (GW_C_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
685 if (m_pFunc == NULL && m_pOldFunc == NULL && m_pMexFunc == NULL && m_pOptFunc == NULL && m_pCFunc == NULL)
687 char* pstEntry = wide_string_to_UTF8(m_wstEntryPoint.c_str());
688 char* pstLib = wide_string_to_UTF8(m_wstLibName.c_str());
689 Scierror(999, _("Impossible to load %s function in %s library: %s\n"), pstEntry, pstLib, GetLastDynLibError());
697 case EntryPointCPPOpt :
698 m_pFunction = new OptFunction(m_wstName, m_pOptFunc, m_pLoadDeps, m_wstModule);
701 m_pFunction = new Function(m_wstName, m_pFunc, m_pLoadDeps, m_wstModule);
703 case EntryPointOldC :
704 m_pFunction = new WrapFunction(m_wstName, m_pOldFunc, m_pLoadDeps, m_wstModule);
707 m_pFunction = new WrapMexFunction(m_wstName, m_pMexFunc, m_pLoadDeps, m_wstModule);
710 m_pFunction = new WrapCFunction(m_wstName, m_pCFunc, m_pLoadDeps, m_wstModule);
714 if (m_pFunction == NULL)
721 void DynamicFunction::Clear()