f7d94c85bcc463020eac0dd9a1dc69b10978e874
[scilab.git] / scilab / modules / functions / sci_gateway / cpp / sci_execstr.cpp
1 /*
2 * Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3 * Copyright (C) 2006 - INRIA - Antoine ELIAS
4 *
5  * Copyright (C) 2012 - 2016 - Scilab Enterprises
6  *
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.
13 *
14 */
15
16 //#include "AnalysisVisitor.hxx"
17 #include "parser.hxx"
18 #include "functions_gw.hxx"
19 #include "visitor_common.hxx"
20 #include "scilabWrite.hxx"
21 #include "configvariable.hxx"
22 #include "threadmanagement.hxx"
23
24 #include <memory>
25 #include <iostream>
26 #include <fstream>
27 #include <string>
28
29 extern "C"
30 {
31 #include "sci_malloc.h"
32 #include "os_string.h"
33 #include "Scierror.h"
34 #include "sciprint.h"
35 #include "localization.h"
36 #include "os_string.h"
37 }
38
39 #define MUTE_FLAG       L"n"
40 #define NO_MUTE_FLAG    L"m"
41
42 /*--------------------------------------------------------------------------*/
43 types::Function::ReturnValue sci_execstr(types::typed_list &in, int _iRetCount, types::typed_list &out)
44 {
45     int iErr            = 0;
46     bool bErrCatch              = false;
47     bool bMute          = false;
48     wchar_t* pstMsg     = NULL;
49     ast::Exp* pExp      = NULL;
50     wchar_t *pstCommand = NULL;
51     Parser parser;
52
53     if (in.size() < 1 || in.size() > 3)
54     {
55         Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "execstr" , 1, 3);
56         return types::Function::Error;
57     }
58
59     //2nd parameter
60     if (in.size() > 1)
61     {
62         //errcatch
63         if (in[1]->isString() == false || in[1]->getAs<types::String>()->getSize() != 1)
64         {
65             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "execstr", 2);
66             return types::Function::Error;
67         }
68
69         types::String* pS = in[1]->getAs<types::String>();
70         if (os_wcsicmp(pS->get(0), L"errcatch") == 0)
71         {
72             bErrCatch = true;
73         }
74         else
75         {
76             Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "execstr", 2);
77             return types::Function::Error;
78         }
79
80         bMute = true;
81     }
82
83     //3rd parameter
84     if (in.size() == 3)
85     {
86         if (in[2]->isString() == false || in[2]->getAs<types::String>()->getSize() != 1)
87         {
88             Scierror(999, _("%s: Wrong type for input argument #%d: string expected.\n"), "execstr", 3);
89             return types::Function::Error;
90         }
91
92         if (os_wcsicmp(in[2]->getAs<types::String>()->get(0), MUTE_FLAG) == 0)
93         {
94             bMute = true;
95         }
96         else if (os_wcsicmp(in[2]->getAs<types::String>()->get(0), NO_MUTE_FLAG) == 0)
97         {
98             bMute = false;
99         }
100         else
101         {
102             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), "execstr", 3, MUTE_FLAG, NO_MUTE_FLAG);
103             return types::Function::Error;
104         }
105     }
106
107     //1st argument
108     if (in[0]->isDouble() && in[0]->getAs<types::Double>()->getSize() == 0)
109     {
110         // execstr([])
111         out.push_back(types::Double::Empty());
112         return types::Function::OK;
113     }
114
115     if (in[0]->isString() == false || (in[0]->getAs<types::String>()->getRows() != 1 && in[0]->getAs<types::String>()->getCols() != 1))
116     {
117         Scierror(999, _("%s: Wrong type for input argument #%d: Vector of strings expected.\n"), "execstr", 1);
118         return types::Function::Error;
119     }
120
121     types::String* pS = in[0]->getAs<types::String>();
122     int iTotalLen = pS->getSize(); //add \n after each string
123     for (int i = 0 ; i < pS->getSize() ; i++)
124     {
125         iTotalLen += (int)wcslen(pS->get(i));
126     }
127
128     pstCommand = (wchar_t*)MALLOC(sizeof(wchar_t) * (iTotalLen + 1));//+1 for null termination
129
130     for (int i = 0, iPos = 0 ; i < pS->getSize() ; i++)
131     {
132         wcscpy(pstCommand + iPos, pS->get(i));
133         iPos = (int)wcslen(pstCommand);
134         pstCommand[iPos++] = L'\n';
135         pstCommand[iPos] = 0;
136     }
137
138     // add execstr in list of macro called
139     // to manage line displayed when error occurred.
140     ConfigVariable::macroFirstLine_begin(1);
141
142     ThreadManagement::LockParser();
143     parser.parse(pstCommand);
144     FREE(pstCommand);
145     if (parser.getExitStatus() !=  Parser::Succeded)
146     {
147         if (bErrCatch)
148         {
149             out.push_back(new types::Double(999));
150             //to lock last error information
151             ConfigVariable::setLastErrorCall();
152             ConfigVariable::setLastErrorMessage(parser.getErrorMessage());
153             ConfigVariable::setLastErrorNumber(999);
154             ThreadManagement::UnlockParser();
155             ConfigVariable::macroFirstLine_end();
156             return types::Function::OK;
157         }
158         else
159         {
160             char* pst = wide_string_to_UTF8(parser.getErrorMessage());
161             Scierror(999, "%s", pst);
162             FREE(pst);
163             ThreadManagement::UnlockParser();
164             ConfigVariable::macroFirstLine_end();
165             return types::Function::Error;
166         }
167     }
168
169     if (ConfigVariable::getSerialize())
170     {
171         ast::Exp* temp = parser.getTree();
172         if (ConfigVariable::getTimed())
173         {
174             pExp = callTyper(temp, L"execstr");
175         }
176         else
177         {
178             pExp = callTyper(temp);
179         }
180
181         delete temp;
182     }
183     else
184     {
185         pExp = parser.getTree();
186     }
187
188     ThreadManagement::UnlockParser();
189
190     if (pExp == NULL)
191     {
192         return types::Function::Error;
193     }
194
195     //save current prompt mode
196     int iPromptMode = ConfigVariable::getPromptMode();
197     ConfigVariable::setPromptMode(-1);
198
199     if (ConfigVariable::getAnalyzerOptions() == 1)
200     {
201         //analysis::AnalysisVisitor analysis;
202         //pExp->accept(analysis);
203         //ast::DebugVisitor debugMe;
204         //pExp->accept(debugMe);
205     }
206
207     ast::SeqExp* pSeqExp = pExp->getAs<ast::SeqExp>();
208     std::unique_ptr<ast::ConstVisitor> run(ConfigVariable::getDefaultVisitor());
209     try
210     {
211         symbol::Context* pCtx = symbol::Context::getInstance();
212         int scope = pCtx->getScopeLevel();
213         int level = ConfigVariable::getRecursionLevel();
214         try
215         {
216             pSeqExp->accept(*run);
217         }
218         catch (const ast::RecursionException& /* re */)
219         {
220             //close opened scope during try
221             while (pCtx->getScopeLevel() > scope)
222             {
223                 pCtx->scope_end();
224             }
225
226             //decrease recursion to init value
227             while (ConfigVariable::getRecursionLevel() > level)
228             {
229                 ConfigVariable::where_end();
230                 ConfigVariable::decreaseRecursion();
231             }
232
233             //print msg about recursion limit and trigger an error
234             wchar_t sz[1024];
235             os_swprintf(sz, 1024, _W("Recursion limit reached (%d).\n").data(), ConfigVariable::getRecursionLimit());
236             throw ast::InternalError(sz);
237         }
238     }
239     catch (const ast::InternalError& ie)
240     {
241         if (bErrCatch == false)
242         {
243             delete pExp;
244             ConfigVariable::macroFirstLine_end();
245             ConfigVariable::setPromptMode(iPromptMode);
246             throw ie;
247         }
248
249         if (bMute == false)
250         {
251             scilabForcedWriteW(ie.GetErrorMessage().c_str());
252         }
253
254         ConfigVariable::resetWhereError();
255         iErr = ConfigVariable::getLastErrorNumber();
256     }
257
258     if (bErrCatch)
259     {
260         out.push_back(new types::Double(iErr));
261         //to lock last error information
262         ConfigVariable::setLastErrorCall();
263         // allow print
264         ConfigVariable::resetError();
265     }
266
267     ConfigVariable::macroFirstLine_end();
268     ConfigVariable::setPromptMode(iPromptMode);
269
270     delete pExp;
271     return types::Function::OK;
272 }
273 /*--------------------------------------------------------------------------*/