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 = (wchar_t*)MALLOC(sizeof(wchar_t) * (PATH_MAX * 2));
169 get_full_pathW(pwstTemp, pwstFile, PATH_MAX * 2);
173 /*fake call to mopen to show file within file()*/
174 if (mopen(pwstTemp, L"r", 0, &iID) != MOPEN_NO_ERROR)
176 closeFile(file, iID, wstFile, pExp);
178 Scierror(999, _("%s: Cannot open file %s.\n"), "exec", stFile.data());
179 return types::Function::Error;
182 // update where to set the name of the executed file.
183 ConfigVariable::setFileNameToLastWhere(wstFile.data());
185 ThreadManagement::LockParser();
186 parser.parseFile(pwstTemp, L"exec");
188 if (parser.getExitStatus() != Parser::Succeded)
190 closeFile(file, iID, wstFile, pExp);
193 out.push_back(new types::Double(999));
194 //to lock last error information
195 ConfigVariable::setLastErrorCall();
196 // when the parser can not open file the error is already set in lasterror.
197 if (wcscmp(parser.getErrorMessage(), L""))
199 ConfigVariable::setLastErrorMessage(parser.getErrorMessage());
200 ConfigVariable::setLastErrorNumber(999);
202 delete parser.getTree();
203 ThreadManagement::UnlockParser();
204 return types::Function::OK;
207 char* pst = wide_string_to_UTF8(parser.getErrorMessage());
208 Scierror(999, "%s", pst);
211 delete parser.getTree();
212 ThreadManagement::UnlockParser();
213 return types::Function::Error;
216 if (ConfigVariable::getSerialize())
218 ast::Exp* temp = parser.getTree();
219 if (ConfigVariable::getTimed())
221 pExp = callTyper(temp, L"exec");
225 pExp = callTyper(temp);
232 pExp = parser.getTree();
235 ThreadManagement::UnlockParser();
237 ConfigVariable::setExecutedFileID(iID);
239 else if (in[0]->isMacro() || in[0]->isMacroFile())
241 if (in[0]->isMacroFile())
243 //1st argument is a macro name, parse and execute it in the current environnement
244 if (in[0]->getAs<types::MacroFile>()->parse() == false)
246 char* pstMacro = wide_string_to_UTF8(in[0]->getAs<types::MacroFile>()->getName().c_str());
247 Scierror(999, _("%s: Unable to parse macro '%s'"), "exec", pstMacro);
249 return types::Function::Error;
251 pMacro = in[0]->getAs<types::MacroFile>()->getMacro();
253 else //1st argument is a macro name, execute it in the current environnement
255 pMacro = in[0]->getAs<types::Macro>();
258 // unable for macro with varargin or varargout
259 auto inputs = pMacro->getInputs();
260 auto outputs = pMacro->getOutputs();
261 if ((inputs->size() != 0 && (inputs->back()->getSymbol().getName() == L"varargin")) ||
262 (outputs->size() != 0 && (outputs->back()->getSymbol().getName() == L"varargout")))
264 Scierror(999, _("%s: Wrong type for input argument #%d: A macro without varargin and varargout expected.\n"), "exec", 1);
265 return types::Function::Error;
268 pExp = pMacro->getBody();
270 // update where to set the name of the executed macro instead of "exec"
271 ConfigVariable::WhereEntry lastWhere = ConfigVariable::getWhere().back();
272 int iLine = lastWhere.m_line;
273 int iAbsLine = lastWhere.m_absolute_line;
274 ConfigVariable::where_end();
275 ConfigVariable::where_begin(iLine, iAbsLine, pMacro);
279 Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "exec", 1);
280 return types::Function::Error;
285 //store the line number where is stored this macro in file.
286 ConfigVariable::macroFirstLine_begin(pMacro->getFirstLine());
289 //save current prompt mode
290 int oldVal = ConfigVariable::getPromptMode();
291 ConfigVariable::setPromptMode(promptMode);
293 ast::SeqExp* pSeqExp = pExp->getAs<ast::SeqExp>();
294 pSeqExp->setExecFrom(ast::SeqExp::EXEC);
295 pSeqExp->setReturnable();
296 std::unique_ptr<ast::ConstVisitor> exec(ConfigVariable::getDefaultVisitor());
300 symbol::Context* pCtx = symbol::Context::getInstance();
301 int scope = pCtx->getScopeLevel();
302 int level = ConfigVariable::getRecursionLevel();
305 pSeqExp->accept(*exec);
307 catch (const ast::RecursionException& /* re */)
309 //close opened scope during try
310 while (pCtx->getScopeLevel() > scope)
315 //decrease recursion to init value
316 while (ConfigVariable::getRecursionLevel() > level)
318 ConfigVariable::where_end();
319 ConfigVariable::decreaseRecursion();
322 //print msg about recursion limit and trigger an error
324 os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
325 throw ast::InternalError(sz);
328 catch (const ast::InternalAbort& ia)
330 closeFile(file, iID, wstFile, pExp);
331 ConfigVariable::setPromptMode(oldVal);
334 catch (const ast::InternalError& ie)
336 if (pMacro && ConfigVariable::getLastErrorFunction() == L"")
338 ConfigVariable::setLastErrorFunction(pMacro->getName());
341 if (bErrCatch == false)
343 closeFile(file, iID, wstFile, pExp);
344 ConfigVariable::setPromptMode(oldVal);
345 ConfigVariable::setExecutedFileID(0);
349 ConfigVariable::resetWhereError();
350 iErr = ConfigVariable::getLastErrorNumber();
353 //restore previous prompt mode
354 ConfigVariable::setPromptMode(oldVal);
357 out.push_back(new types::Double(iErr));
358 //to lock last error information
359 ConfigVariable::setLastErrorCall();
362 closeFile(file, iID, wstFile, pExp);
363 return types::Function::OK;