2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA - Antoine ELIAS
5 * Copyright (C) 2012 - 2016 - Scilab Enterprises
7 * This file is hereby licensed under the terms of the GNU GPL v2.0,
8 * pursuant to article 5.3.4 of the CeCILL v.2.1.
9 * This file was originally licensed under the terms of the CeCILL v2.1,
10 * and continues to be available under such terms.
11 * For more information, see the COPYING file which you should have received
12 * along with this program.
17 #include "functions_gw.hxx"
20 #include "funcmanager.hxx"
21 #include "context.hxx"
22 #include "printvisitor.hxx"
23 #include "visitor_common.hxx"
24 #include "scilabWrite.hxx"
25 #include "configvariable.hxx"
26 #include "types_tools.hxx"
28 #include "threadmanagement.hxx"
30 #include "macrofile.hxx"
31 #include "filemanager.hxx"
40 #include "os_string.h"
41 #include "expandPathVariable.h"
44 #include "localization.h"
45 #include "os_string.h"
52 void closeFile(std::ifstream* file, int fileId, const std::wstring& wstFile, ast::Exp* pExp)
64 // Check if file has not already been closed (for ex mclose('all') in function)
65 if (FileManager::isOpened(wstFile))
71 /*--------------------------------------------------------------------------*/
72 types::Function::ReturnValue sci_exec(types::typed_list &in, int _iRetCount, types::typed_list &out)
74 int promptMode = 0;//default value at startup, overthise 3 or verbose ";"
75 bool bPromptMode = false;
77 bool bErrCatch = false;
78 ast::Exp* pExp = NULL;
80 types::Macro* pMacro = NULL;
83 wchar_t* pwstFile = NULL;
87 std::ifstream* file = NULL;
90 if (ConfigVariable::getStartProcessing() == false)
92 if (ConfigVariable::getVerbose())
102 if (in.size() < 1 || in.size() > 3)
104 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "exec" , 1, 3);
105 return types::Function::Error;
108 // get mode and errcatch
112 if (in[1]->isString() && in[1]->getAs<types::String>()->isScalar())
115 types::String* pS = in[1]->getAs<types::String>();
116 if (os_wcsicmp(pS->get(0), L"errcatch") == 0)
122 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
123 return types::Function::Error;
129 if (in[2]->isDouble() == false || in[2]->getAs<types::Double>()->isScalar() == false)
132 Scierror(999, _("%s: Wrong type for input argument #%d: A integer expected.\n"), "exec", 3);
133 return types::Function::Error;
136 promptMode = (int)in[2]->getAs<types::Double>()->getReal()[0];
140 else if (in[1]->isDouble() && in[1]->getAs<types::Double>()->isScalar())
144 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
145 return types::Function::Error;
148 promptMode = (int)in[1]->getAs<types::Double>()->getReal()[0];
154 Scierror(999, _("%s: Wrong type for input argument #%d: A integer or string expected.\n"), "exec", 2);
155 return types::Function::Error;
159 if (in[0]->isString() && in[0]->getAs<types::String>()->isScalar())
161 //1st argument is a path, parse file and execute it
162 int iParsePathLen = 0;
163 types::String* pS = in[0]->getAs<types::String>();
165 pwstFile = expandPathVariableW(pS->get(0));
166 pstFile = wide_string_to_UTF8(pwstFile);
168 file = new std::ifstream(pstFile);
172 wchar_t* pwstTemp = (wchar_t*)MALLOC(sizeof(wchar_t) * (PATH_MAX * 2));
173 get_full_pathW(pwstTemp, pwstFile, PATH_MAX * 2);
177 /*fake call to mopen to show file within file()*/
178 if (mopen(pwstTemp, L"r", 0, &iID) != MOPEN_NO_ERROR)
180 closeFile(file, iID, wstFile, pExp);
182 Scierror(999, _("%s: Cannot open file %s.\n"), "exec", stFile.data());
183 return types::Function::Error;
186 // update where to set the name of the executed file.
187 ConfigVariable::setFileNameToLastWhere(wstFile.data());
189 ThreadManagement::LockParser();
190 parser.parseFile(pwstTemp, L"exec");
192 if (parser.getExitStatus() != Parser::Succeded)
194 closeFile(file, iID, wstFile, pExp);
197 out.push_back(new types::Double(999));
198 //to lock last error information
199 ConfigVariable::setLastErrorCall();
200 // when the parser can not open file the error is already set in lasterror.
201 if (wcscmp(parser.getErrorMessage(), L""))
203 ConfigVariable::setLastErrorMessage(parser.getErrorMessage());
204 ConfigVariable::setLastErrorNumber(999);
206 delete parser.getTree();
207 ThreadManagement::UnlockParser();
208 return types::Function::OK;
211 char* pst = wide_string_to_UTF8(parser.getErrorMessage());
212 Scierror(999, "%s", pst);
215 delete parser.getTree();
216 ThreadManagement::UnlockParser();
217 return types::Function::Error;
220 if (ConfigVariable::getSerialize())
222 ast::Exp* temp = parser.getTree();
223 if (ConfigVariable::getTimed())
225 pExp = callTyper(temp, L"exec");
229 pExp = callTyper(temp);
236 pExp = parser.getTree();
239 ThreadManagement::UnlockParser();
241 ConfigVariable::setExecutedFileID(iID);
243 else if (in[0]->isMacro() || in[0]->isMacroFile())
245 if (in[0]->isMacroFile())
247 //1st argument is a macro name, parse and execute it in the current environnement
248 if (in[0]->getAs<types::MacroFile>()->parse() == false)
250 char* pstMacro = wide_string_to_UTF8(in[0]->getAs<types::MacroFile>()->getName().c_str());
251 Scierror(999, _("%s: Unable to parse macro '%s'"), "exec", pstMacro);
253 return types::Function::Error;
255 pMacro = in[0]->getAs<types::MacroFile>()->getMacro();
257 else //1st argument is a macro name, execute it in the current environnement
259 pMacro = in[0]->getAs<types::Macro>();
262 // unable for macro with varargin or varargout
263 auto inputs = pMacro->getInputs();
264 auto outputs = pMacro->getOutputs();
265 if ((inputs->size() != 0 && inputs->back()->getSymbol().getName() == L"varargin") ||
266 outputs->size() != 0 && outputs->back()->getSymbol().getName() == L"varargout")
268 Scierror(999, _("%s: Wrong type for input argument #%d: A macro without varargin and varargout expected.\n"), "exec", 1);
269 return types::Function::Error;
272 pExp = pMacro->getBody();
274 // update where to set the name of the executed macro instead of "exec"
275 ConfigVariable::WhereEntry lastWhere = ConfigVariable::getWhere().back();
276 int iLine = lastWhere.m_line;
277 int iAbsLine = lastWhere.m_absolute_line;
278 ConfigVariable::where_end();
279 ConfigVariable::where_begin(iLine, iAbsLine, pMacro);
283 Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "exec", 1);
284 return types::Function::Error;
289 //store the line number where is stored this macro in file.
290 ConfigVariable::macroFirstLine_begin(pMacro->getFirstLine());
293 //save current prompt mode
294 int oldVal = ConfigVariable::getPromptMode();
295 ConfigVariable::setPromptMode(promptMode);
297 ast::SeqExp* pSeqExp = pExp->getAs<ast::SeqExp>();
298 pSeqExp->setExecFrom(ast::SeqExp::EXEC);
299 pSeqExp->setReturnable();
300 std::unique_ptr<ast::ConstVisitor> exec(ConfigVariable::getDefaultVisitor());
304 symbol::Context* pCtx = symbol::Context::getInstance();
305 int scope = pCtx->getScopeLevel();
306 int level = ConfigVariable::getRecursionLevel();
309 pSeqExp->accept(*exec);
311 catch (const ast::RecursionException& /* re */)
313 //close opened scope during try
314 while (pCtx->getScopeLevel() > scope)
319 //decrease recursion to init value
320 while (ConfigVariable::getRecursionLevel() > level)
322 ConfigVariable::where_end();
323 ConfigVariable::decreaseRecursion();
326 //print msg about recursion limit and trigger an error
328 os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
329 throw ast::InternalError(sz);
332 catch (const ast::InternalAbort& ia)
334 closeFile(file, iID, wstFile, pExp);
337 catch (const ast::InternalError& ie)
339 if (bErrCatch == false)
341 closeFile(file, iID, wstFile, pExp);
342 ConfigVariable::setPromptMode(oldVal);
343 ConfigVariable::setExecutedFileID(0);
347 ConfigVariable::resetWhereError();
348 iErr = ConfigVariable::getLastErrorNumber();
351 //restore previous prompt mode
352 ConfigVariable::setPromptMode(oldVal);
355 out.push_back(new types::Double(iErr));
356 //to lock last error information
357 ConfigVariable::setLastErrorCall();
360 closeFile(file, iID, wstFile, pExp);
361 return types::Function::OK;