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 * 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
17 #include "function.hxx"
19 #include "gatewaystruct.hxx"
20 #include "configvariable.hxx"
21 #include "scilabWrite.hxx"
25 #include "core_math.h"
26 #include "charEncoding.h"
29 #include "localization.h"
31 #include "sci_malloc.h"
32 #include "os_string.h"
33 #include "lasterror.h"
34 #include "dynamic_module.h"
39 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC _pFunc, const std::wstring& _wstModule)
41 return new Function(_wstName, _pFunc, NULL, _wstModule);
44 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, const std::wstring& _wstModule)
46 return new OptFunction(_wstName, _pFunc, NULL, _wstModule);
49 Function* Function::createFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, const std::wstring& _wstModule)
51 return new WrapFunction(_wstName, _pFunc, NULL, _wstModule);
54 Function* Function::createFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, const std::wstring& _wstModule)
56 return new WrapMexFunction(_wstName, _pFunc, NULL, _wstModule);
59 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
61 return new Function(_wstName, _pFunc, _pLoadDeps, _wstModule);
64 Function* Function::createFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
66 return new OptFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
69 Function* Function::createFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
71 return new WrapFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
74 Function* Function::createFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
76 return new WrapMexFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
79 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)
81 return new DynamicFunction(_wstFunctionName, _wstEntryPointName, _wstLibName, _iType, _pLoadDeps, _wstModule, _bCloseLibAfterCall);
84 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)
86 return new DynamicFunction(_wstFunctionName, _wstEntryPointName, _wstLibName, _iType, _wstLoadDepsName, _wstModule, _bCloseLibAfterCall);
89 Function* Function::createFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, const std::wstring& _wstModule)
91 return new WrapCFunction(_wstName, _pFunc, NULL, _wstModule);
94 Function* Function::createFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
96 return new WrapCFunction(_wstName, _pFunc, _pLoadDeps, _wstModule);
100 Function::Function(const std::wstring& _wstName, GW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule) : Callable(), m_pFunc(_pFunc), m_pLoadDeps(_pLoadDeps)
103 char* s = wide_string_to_UTF8(m_wstName.data());
107 setModule(_wstModule);
110 Function::~Function()
116 Function::ReturnValue Function::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
119 if (m_pLoadDeps != NULL)
121 ret = m_pLoadDeps(m_wstName);
129 return this->m_pFunc(in, _iRetCount, out);
132 void Function::whoAmI()
134 std::cout << "types::Function";
137 bool Function::toString(std::wostringstream& ostr)
139 // display nothing. ie : c = cos
143 InternalType* Function::clone()
149 OptFunction::OptFunction(const std::wstring& _wstName, GW_FUNC_OPT _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
151 m_wstName = _wstName;
152 char* s = wide_string_to_UTF8(m_wstName.data());
156 m_pLoadDeps = _pLoadDeps;
157 m_wstModule = _wstModule;
160 OptFunction::OptFunction(OptFunction* _pWrapFunction)
162 m_wstModule = _pWrapFunction->getModule();
163 m_wstName = _pWrapFunction->getName();
164 char* s = wide_string_to_UTF8(m_wstName.data());
167 m_pFunc = _pWrapFunction->getFunc();
168 m_pLoadDeps = _pWrapFunction->getDeps();
171 InternalType* OptFunction::clone()
173 return new OptFunction(this);
176 Function::ReturnValue OptFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
179 if (m_pLoadDeps != NULL)
181 ret = m_pLoadDeps(m_wstName);
189 return this->m_pFunc(in, opt, _iRetCount, out);
192 WrapFunction::WrapFunction(const std::wstring& _wstName, OLDGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
194 m_wstName = _wstName;
196 m_wstModule = _wstModule;
197 char* s = wide_string_to_UTF8(m_wstName.data());
200 m_pLoadDeps = _pLoadDeps;
203 WrapFunction::WrapFunction(WrapFunction* _pWrapFunction)
205 m_wstModule = _pWrapFunction->getModule();
206 m_wstName = _pWrapFunction->getName();
207 char* s = wide_string_to_UTF8(m_wstName.data());
210 m_pOldFunc = _pWrapFunction->getFunc();
211 m_pLoadDeps = _pWrapFunction->getDeps();
214 InternalType* WrapFunction::clone()
216 return new WrapFunction(this);
219 Function::ReturnValue WrapFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
222 int inSize = (int)in.size();
223 int optSize = (int)opt.size();
224 bool isRef = checkReferenceModule(m_wstModule.c_str());
226 if (m_pLoadDeps != NULL)
228 ret = m_pLoadDeps(m_wstName);
236 ReturnValue retVal = Callable::OK;
238 _iRetCount = std::max(1, _iRetCount);
239 gStr.m_iIn = inSize + optSize;
240 gStr.m_iOut = _iRetCount;
242 //copy input parameter to prevent calling gateway modifies input data
247 for (int i = 0; i < inSize; i++)
249 inCopy.push_back(in[i]->clone());
254 for (int i = 0; i < inSize; i++)
256 inCopy.push_back(in[i]);
259 gStr.m_pIn = &inCopy;
261 typed_list::value_type tmpOut[MAX_OUTPUT_VARIABLE];
262 std::fill_n(tmpOut, MAX_OUTPUT_VARIABLE, static_cast<typed_list::value_type>(0));
263 gStr.m_pOut = tmpOut;
264 gStr.m_piRetCount = &_iRetCount;
265 gStr.m_pstName = m_stName.data();
266 // we should use a stack array of the max size to avoid dynamic alloc.
267 std::vector<int> outOrder(_iRetCount < 1 ? 1 : _iRetCount, -1);
268 gStr.m_pOutOrder = outOrder.data();
271 m_pOldFunc(const_cast<char*>(m_stName.data()), reinterpret_cast<int*>(&gStr));
272 if (ConfigVariable::isError())
274 retVal = Callable::Error;
275 ConfigVariable::resetError();
279 for (std::size_t i(0); i != (size_t)_iRetCount && outOrder[i] != -1 && outOrder[i] != 0; ++i)
281 if (outOrder[i] - 1 < gStr.m_iIn)
283 std::size_t const iPos(outOrder[i] - 1);
284 //protect variable to deletion
285 inCopy[iPos]->IncreaseRef();
286 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsInteger())
288 types::Double* pD = inCopy[iPos]->getAs<types::Double>();
289 pD->convertFromInteger();
292 if (inCopy[iPos]->isDouble() && ((types::Double*)inCopy[iPos])->isViewAsZComplex())
294 types::Double* pD = inCopy[iPos]->getAs<types::Double>();
295 pD->convertFromZComplex();
298 out.push_back(inCopy[iPos]);
302 std::size_t const iPos(outOrder[i] - gStr.m_iIn - 1);
303 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsInteger())
305 types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
306 pD->convertFromInteger();
309 if (tmpOut[iPos]->isDouble() && ((types::Double*)tmpOut[iPos])->isViewAsZComplex())
311 types::Double* pD = tmpOut[iPos]->getAs<types::Double>();
312 pD->convertFromZComplex();
315 out.push_back(tmpOut[iPos]);
321 for (std::size_t i(0); i != MAX_OUTPUT_VARIABLE; ++i)
333 int size = (int)out.size();
334 for (int i = 0; i < size; i++)
336 out[i]->IncreaseRef();
339 for (int i = 0; i < inSize; i++)
345 for (int i = 0; i < size; i++)
347 out[i]->DecreaseRef();
354 WrapMexFunction::WrapMexFunction(const std::wstring& _wstName, MEXGW_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
356 m_wstName = _wstName;
357 char* s = wide_string_to_UTF8(m_wstName.data());
361 m_wstModule = _wstModule;
362 m_pLoadDeps = _pLoadDeps;
365 WrapMexFunction::WrapMexFunction(WrapMexFunction* _pWrapFunction)
367 m_wstModule = _pWrapFunction->getModule();
368 char* s = wide_string_to_UTF8(m_wstName.data());
371 m_wstName = _pWrapFunction->getName();
372 m_pOldFunc = _pWrapFunction->getFunc();
373 m_pLoadDeps = _pWrapFunction->getDeps();
376 InternalType* WrapMexFunction::clone()
378 return new WrapMexFunction(this);
381 Function::ReturnValue WrapMexFunction::call(typed_list &in, optional_list &/*opt*/, int _iRetCount, typed_list &out)
384 if (m_pLoadDeps != NULL)
386 ret = m_pLoadDeps(m_wstName);
394 ReturnValue retVal = Callable::OK;
396 char* name = wide_string_to_UTF8(getName().c_str());
397 ConfigVariable::setMexFunctionName(name);
400 int nlhs = _iRetCount;
401 int** plhs = new int*[nlhs];
402 memset(plhs, 0x00, sizeof(int*) * nlhs);
404 int nrhs = (int)in.size();
405 int** prhs = new int*[nrhs];
406 for (int i = 0; i < nrhs; i++)
408 prhs[i] = (int*)(in[i]);
413 m_pOldFunc(nlhs, plhs, nrhs, prhs);
415 catch (const ast::InternalError& ie)
422 if (_iRetCount == 1 && plhs[0] == NULL)
424 //dont copy empty values, juste return "no value"
428 for (int i = 0; i < nlhs; i++)
430 out.push_back((types::InternalType*)plhs[i]);
438 WrapCFunction::WrapCFunction(const std::wstring& _wstName, GW_C_FUNC _pFunc, LOAD_DEPS _pLoadDeps, const std::wstring& _wstModule)
440 m_wstName = _wstName;
441 char* s = wide_string_to_UTF8(m_wstName.data());
445 m_wstModule = _wstModule;
446 m_pLoadDeps = _pLoadDeps;
449 WrapCFunction::WrapCFunction(WrapCFunction* _pWrapFunction)
451 m_wstModule = _pWrapFunction->getModule();
452 char* s = wide_string_to_UTF8(m_wstName.data());
455 m_wstName = _pWrapFunction->getName();
456 m_pCFunc = _pWrapFunction->getFunc();
457 m_pLoadDeps = _pWrapFunction->getDeps();
460 InternalType* WrapCFunction::clone()
462 return new WrapCFunction(this);
465 Function::ReturnValue WrapCFunction::call(typed_list& in, optional_list& opt, int _iRetCount, typed_list& out)
467 if (m_pLoadDeps != NULL)
469 if (m_pLoadDeps(m_wstName) == 0)
475 ReturnValue retVal = OK;
481 out.resize(_iRetCount, NULL);
482 if (m_pCFunc((void*)&gcs, (int)in.size(), (scilabVar*)(in.data()), (int)opt.size(), (scilabOpt)&opt, _iRetCount, (scilabVar*)(out.data())))
487 catch (const ast::InternalError& ie)
494 if (_iRetCount == 1 && out[0] == NULL)
496 //dont copy empty values, juste return "no value"
505 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)
507 m_wstName = _wstName;
508 char* s = wide_string_to_UTF8(m_wstName.data());
511 m_wstLibName = _wstLibName;
512 m_wstModule = _wstModule;
513 m_wstEntryPoint = _wstEntryPointName;
514 m_wstLoadDepsName = _wstLoadDepsName;
516 m_bCloseLibAfterCall = _bCloseLibAfterCall;
526 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)
528 m_wstName = _wstName;
529 char* s = wide_string_to_UTF8(m_wstName.data());
532 m_wstLibName = _wstLibName;
533 m_wstModule = _wstModule;
534 m_wstEntryPoint = _wstEntryPointName;
535 m_pLoadDeps = _pLoadDeps;
536 m_wstLoadDepsName = L"";
537 m_bCloseLibAfterCall = _bCloseLibAfterCall;
547 Function::ReturnValue DynamicFunction::call(typed_list &in, optional_list &opt, int _iRetCount, typed_list &out)
549 if (m_pFunction == NULL)
558 if (m_pFunction->call(in, opt, _iRetCount, out) != OK)
563 /*Close lib is mandatory*/
564 if (m_bCloseLibAfterCall)
572 DynamicFunction::~DynamicFunction()
580 Callable::ReturnValue DynamicFunction::Init()
583 if (m_wstLibName.empty())
585 Scierror(999, _("%s: Library name must not be empty\n."), m_wstName.c_str());
589 DynLibHandle hLib = getDynModule(m_wstLibName.c_str());
592 char* pstLibName = wide_string_to_UTF8(m_wstLibName.c_str());
593 hLib = LoadDynLibrary(pstLibName);
597 //2nd chance for linux !
599 char* pstError = strdup(GetLastDynLibError());
601 /* Haven't been able to find the lib with dlopen...
602 * This can happen for two reasons:
603 * - the lib must be dynamically linked
604 * - Some silly issues under Suse (see bug #2875)
605 * Note that we are handling only the "source tree build"
606 * because libraries are split (they are in the same directory
609 wchar_t* pwstScilabPath = getSCIW();
610 wchar_t pwstModulesPath[] = L"/modules/";
611 wchar_t pwstLTDir[] = L".libs/";
613 /* Build the full path to the library */
614 int iPathToLibLen = (wcslen(pwstScilabPath) + wcslen(pwstModulesPath) + wcslen(m_wstModule.c_str()) + wcslen(L"/") + wcslen(pwstLTDir) + wcslen(m_wstLibName.c_str()) + 1);
615 wchar_t* pwstPathToLib = (wchar_t*)MALLOC(iPathToLibLen * sizeof(wchar_t));
616 os_swprintf(pwstPathToLib, iPathToLibLen, L"%ls%ls%ls/%ls%ls", pwstScilabPath, pwstModulesPath, m_wstModule.c_str(), pwstLTDir, m_wstLibName.c_str());
617 FREE(pwstScilabPath);
618 char* pstPathToLib = wide_string_to_UTF8(pwstPathToLib);
620 hLib = LoadDynLibrary(pstPathToLib);
624 Scierror(999, _("An error has been detected while loading %s: %s\n"), pstLibName, pstError);
627 pstError = GetLastDynLibError();
628 Scierror(999, _("An error has been detected while loading %s: %s\n"), pstPathToLib, pstError);
637 char* pstError = wide_string_to_UTF8(m_wstLibName.c_str());
638 Scierror(999, _("Impossible to load %s library\n"), pstError);
645 addDynModule(m_wstLibName.c_str(), hLib);
648 if (m_wstLoadDepsName.empty() == false && m_pLoadDeps == NULL)
650 char* pstLoadDepsName = wide_string_to_UTF8(m_wstLoadDepsName.c_str());
651 m_pLoadDeps = (LOAD_DEPS)GetDynLibFuncPtr(hLib, pstLoadDepsName);
657 if (m_wstName != L"")
659 char* pstEntryPoint = wide_string_to_UTF8(m_wstEntryPoint.c_str());
662 case EntryPointCPPOpt :
663 m_pOptFunc = (GW_FUNC_OPT)GetDynLibFuncPtr(hLib, pstEntryPoint);
666 m_pFunc = (GW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
668 case EntryPointOldC :
669 m_pOldFunc = (OLDGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
672 m_pMexFunc = (MEXGW_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
675 m_pCFunc = (GW_C_FUNC)GetDynLibFuncPtr(hLib, pstEntryPoint);
682 if (m_pFunc == NULL && m_pOldFunc == NULL && m_pMexFunc == NULL && m_pOptFunc == NULL && m_pCFunc == NULL)
684 char* pstEntry = wide_string_to_UTF8(m_wstEntryPoint.c_str());
685 char* pstLib = wide_string_to_UTF8(m_wstLibName.c_str());
686 Scierror(999, _("Impossible to load %s function in %s library: %s\n"), pstEntry, pstLib, GetLastDynLibError());
694 case EntryPointCPPOpt :
695 m_pFunction = new OptFunction(m_wstName, m_pOptFunc, m_pLoadDeps, m_wstModule);
698 m_pFunction = new Function(m_wstName, m_pFunc, m_pLoadDeps, m_wstModule);
700 case EntryPointOldC :
701 m_pFunction = new WrapFunction(m_wstName, m_pOldFunc, m_pLoadDeps, m_wstModule);
704 m_pFunction = new WrapMexFunction(m_wstName, m_pMexFunc, m_pLoadDeps, m_wstModule);
707 m_pFunction = new WrapCFunction(m_wstName, m_pCFunc, m_pLoadDeps, m_wstModule);
711 if (m_pFunction == NULL)
718 void DynamicFunction::Clear()