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.
16 #include "functions_gw.hxx"
19 #include "funcmanager.hxx"
20 #include "context.hxx"
21 #include "printvisitor.hxx"
22 #include "visitor_common.hxx"
23 #include "scilabWrite.hxx"
24 #include "configvariable.hxx"
25 #include "types_tools.hxx"
27 #include "threadmanagement.hxx"
29 #include "macrofile.hxx"
30 #include "filemanager.hxx"
39 #include "os_string.h"
40 #include "expandPathVariable.h"
43 #include "localization.h"
44 #include "os_string.h"
51 void closeFile(std::ifstream* file, int fileId, const std::wstring& wstFile, ast::Exp* pExp)
63 // Check if file has not already been closed (for ex mclose('all') in function)
64 if (FileManager::isOpened(wstFile))
70 /*--------------------------------------------------------------------------*/
71 types::Function::ReturnValue sci_exec(types::typed_list &in, int _iRetCount, types::typed_list &out)
73 int promptMode = 0;//default value at startup, overthise 3 or verbose ";"
75 bool bErrCatch = false;
76 ast::Exp* pExp = NULL;
78 types::Macro* pMacro = NULL;
81 wchar_t* pwstFile = NULL;
85 std::ifstream* file = NULL;
88 if (ConfigVariable::getStartProcessing() == false)
90 if (ConfigVariable::getVerbose())
100 if (in.size() < 1 || in.size() > 3)
102 Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "exec" , 1, 3);
103 return types::Function::Error;
106 // get mode and errcatch
110 if (in[1]->isString() && in[1]->getAs<types::String>()->isScalar())
113 types::String* pS = in[1]->getAs<types::String>();
114 if (os_wcsicmp(pS->get(0), L"errcatch") == 0)
120 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
121 return types::Function::Error;
127 if (in[2]->isDouble() == false || in[2]->getAs<types::Double>()->isScalar() == false)
130 Scierror(999, _("%s: Wrong type for input argument #%d: A integer expected.\n"), "exec", 3);
131 return types::Function::Error;
134 promptMode = (int)in[2]->getAs<types::Double>()->getReal()[0];
137 else if (in[1]->isDouble() && in[1]->getAs<types::Double>()->isScalar())
141 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
142 return types::Function::Error;
145 promptMode = (int)in[1]->getAs<types::Double>()->getReal()[0];
150 Scierror(999, _("%s: Wrong type for input argument #%d: A integer or string expected.\n"), "exec", 2);
151 return types::Function::Error;
155 if (in[0]->isString() && in[0]->getAs<types::String>()->isScalar())
157 //1st argument is a path, parse file and execute it
158 int iParsePathLen = 0;
159 types::String* pS = in[0]->getAs<types::String>();
161 pwstFile = expandPathVariableW(pS->get(0));
162 pstFile = wide_string_to_UTF8(pwstFile);
164 file = new std::ifstream(pstFile);
168 wchar_t* pwstTemp = get_full_pathW(pwstFile);
172 /*fake call to mopen to show file within file()*/
173 if (mopen(pwstTemp, L"r", 0, &iID) != MOPEN_NO_ERROR)
175 closeFile(file, iID, wstFile, pExp);
177 Scierror(999, _("%s: Cannot open file %s.\n"), "exec", stFile.data());
178 return types::Function::Error;
181 // update where to set the name of the executed file.
182 ConfigVariable::setFileNameToLastWhere(&wstFile);
184 ThreadManagement::LockParser();
185 parser.parseFile(pwstTemp, L"exec");
187 if (parser.getExitStatus() != Parser::Succeded)
189 closeFile(file, iID, wstFile, pExp);
192 out.push_back(new types::Double(999));
193 //to lock last error information
194 ConfigVariable::setLastErrorCall();
195 // when the parser can not open file the error is already set in lasterror.
196 if (wcscmp(parser.getErrorMessage(), L""))
198 ConfigVariable::setLastErrorMessage(parser.getErrorMessage());
199 ConfigVariable::setLastErrorNumber(999);
201 delete parser.getTree();
202 ThreadManagement::UnlockParser();
203 return types::Function::OK;
206 char* pst = wide_string_to_UTF8(parser.getErrorMessage());
207 Scierror(999, "%s", pst);
210 delete parser.getTree();
211 ThreadManagement::UnlockParser();
212 return types::Function::Error;
215 if (ConfigVariable::getSerialize())
217 ast::Exp* temp = parser.getTree();
218 if (ConfigVariable::getTimed())
220 pExp = callTyper(temp, L"exec");
224 pExp = callTyper(temp);
231 pExp = parser.getTree();
234 ThreadManagement::UnlockParser();
236 ConfigVariable::setExecutedFile(wstFile);
238 else if (in[0]->isMacro() || in[0]->isMacroFile())
240 if (in[0]->isMacroFile())
242 //1st argument is a macro name, parse and execute it in the current environnement
243 if (in[0]->getAs<types::MacroFile>()->parse() == false)
245 char* pstMacro = wide_string_to_UTF8(in[0]->getAs<types::MacroFile>()->getName().c_str());
246 Scierror(999, _("%s: Unable to parse macro '%s'"), "exec", pstMacro);
248 return types::Function::Error;
250 pMacro = in[0]->getAs<types::MacroFile>()->getMacro();
252 else //1st argument is a macro name, execute it in the current environnement
254 pMacro = in[0]->getAs<types::Macro>();
257 // unable for macro with varargin or varargout
258 auto inputs = pMacro->getInputs();
259 auto outputs = pMacro->getOutputs();
260 if ((inputs->size() != 0 && (inputs->back()->getSymbol().getName() == L"varargin")) ||
261 (outputs->size() != 0 && (outputs->back()->getSymbol().getName() == L"varargout")))
263 Scierror(999, _("%s: Wrong type for input argument #%d: A macro without varargin and varargout expected.\n"), "exec", 1);
264 return types::Function::Error;
267 pExp = pMacro->getBody();
269 // update where to set the name of the executed macro instead of "exec"
270 ConfigVariable::WhereEntry lastWhere = ConfigVariable::getWhere().back();
271 int iLine = lastWhere.m_line;
272 int iAbsLine = lastWhere.m_absolute_line;
273 ConfigVariable::where_end();
274 ConfigVariable::where_begin(iLine, iAbsLine, pMacro);
278 Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "exec", 1);
279 return types::Function::Error;
284 //store the line number where is stored this macro in file.
285 ConfigVariable::macroFirstLine_begin(pMacro->getFirstLine());
288 //save current prompt mode
289 int oldVal = ConfigVariable::getPromptMode();
290 ConfigVariable::setPromptMode(promptMode);
292 ast::SeqExp* pSeqExp = pExp->getAs<ast::SeqExp>();
293 pSeqExp->setExecFrom(ast::SeqExp::EXEC);
294 pSeqExp->setReturnable();
295 std::unique_ptr<ast::ConstVisitor> exec(ConfigVariable::getDefaultVisitor());
299 symbol::Context* pCtx = symbol::Context::getInstance();
300 int scope = pCtx->getScopeLevel();
301 int level = ConfigVariable::getRecursionLevel();
304 pSeqExp->accept(*exec);
306 catch (const ast::RecursionException& /* re */)
308 //close opened scope during try
309 while (pCtx->getScopeLevel() > scope)
314 //decrease recursion to init value
315 while (ConfigVariable::getRecursionLevel() > level)
317 ConfigVariable::where_end();
318 ConfigVariable::decreaseRecursion();
321 //print msg about recursion limit and trigger an error
323 os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
324 throw ast::InternalError(sz);
327 catch (const ast::InternalAbort& ia)
329 closeFile(file, iID, wstFile, pExp);
330 ConfigVariable::setPromptMode(oldVal);
333 catch (const ast::InternalError& ie)
335 if (pMacro && ConfigVariable::getLastErrorFunction() == L"")
337 ConfigVariable::setLastErrorFunction(pMacro->getName());
340 if (bErrCatch == false)
342 closeFile(file, iID, wstFile, pExp);
343 ConfigVariable::setPromptMode(oldVal);
344 ConfigVariable::setExecutedFile(L"");
348 ConfigVariable::resetWhereError();
349 iErr = ConfigVariable::getLastErrorNumber();
352 //restore previous prompt mode
353 ConfigVariable::setPromptMode(oldVal);
356 out.push_back(new types::Double(iErr));
357 //to lock last error information
358 ConfigVariable::setLastErrorCall();
361 closeFile(file, iID, wstFile, pExp);
362 return types::Function::OK;