thread management fixed.
[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 * This file must be used under the terms of the CeCILL.
6 * This source file is licensed as described in the file COPYING, which
7 * you should have received as part of this distribution.  The terms
8 * are also available at
9 * http://www.cecill.info/licences/Licence_CeCILL_V2-en.txt
10 *
11 */
12
13 #include <string.h>
14 #include "parser.hxx"
15 #include "functions_gw.hxx"
16 //#include "debugvisitor.hxx"
17 #include "execvisitor.hxx"
18 #include "mutevisitor.hxx"
19 #include "printvisitor.hxx"
20 #include "AnalysisVisitor.hxx"
21 #include "visitor_common.hxx"
22 #include "scilabWrite.hxx"
23 #include "scilabexception.hxx"
24 #include "configvariable.hxx"
25 #include "context.hxx"
26 #include "runner.hxx"
27
28 #include <iostream>
29 #include <fstream>
30 #include <string>
31
32 extern "C"
33 {
34 #include "sci_malloc.h"
35 #include "os_string.h"
36 #include "Scierror.h"
37 #include "sciprint.h"
38 #include "localization.h"
39 #include "os_string.h"
40 }
41
42 #define MUTE_FLAG       L"n"
43 #define NO_MUTE_FLAG    L"m"
44
45 using namespace std;
46 using namespace types;
47 using namespace ast;
48 /*--------------------------------------------------------------------------*/
49 Function::ReturnValue sci_execstr(types::typed_list &in, int _iRetCount, types::typed_list &out)
50 {
51     int iErr            = 0;
52     bool bErrCatch              = false;
53     bool bMute          = false;
54     wchar_t* pstMsg     = NULL;
55     Exp* pExp           = NULL;
56     wchar_t *pstCommand = NULL;
57     Parser parser;
58
59     int iOldSilentError = ConfigVariable::getSilentError();
60     if (in.size() < 1 || in.size() > 3)
61     {
62         Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "execstr" , 1, 3);
63         return Function::Error;
64     }
65
66     //2nd parameter
67     if (in.size() > 1)
68     {
69         //errcatch
70         if (in[1]->isString() == false || in[1]->getAs<types::String>()->getSize() != 1)
71         {
72             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "execstr", 2);
73             return Function::Error;
74         }
75
76         String* pS = in[1]->getAs<types::String>();
77         if (os_wcsicmp(pS->get(0), L"errcatch") == 0)
78         {
79             bErrCatch = true;
80         }
81         else
82         {
83             Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "execstr", 2);
84             return Function::Error;
85         }
86
87         bMute = true;
88     }
89
90     //3rd parameter
91     if (in.size() == 3)
92     {
93         if (in[2]->isString() == false || in[2]->getAs<types::String>()->getSize() != 1)
94         {
95             Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "execstr", 3);
96             return Function::Error;
97         }
98
99         if (os_wcsicmp(in[2]->getAs<types::String>()->get(0), MUTE_FLAG) == 0)
100         {
101             bMute = true;
102         }
103         else if (os_wcsicmp(in[2]->getAs<types::String>()->get(0), NO_MUTE_FLAG) == 0)
104         {
105             bMute = false;
106         }
107         else
108         {
109             Scierror(999, _("%s: Wrong value for input argument #%d: '%s' or '%s' expected.\n"), "execstr", 3, MUTE_FLAG, NO_MUTE_FLAG);
110             return Function::Error;
111         }
112     }
113
114     //1st argument
115     if (in[0]->isDouble() && in[0]->getAs<Double>()->getSize() == 0)
116     {
117         // execstr([])
118         out.push_back(Double::Empty());
119         return Function::OK;
120     }
121
122     if (in[0]->isString() == false || (in[0]->getAs<types::String>()->getRows() != 1 && in[0]->getAs<types::String>()->getCols() != 1))
123     {
124         Scierror(999, _("%s: Wrong type for input argument #%d: Vector of strings expected.\n"), "execstr", 1);
125         return Function::Error;
126     }
127
128     String* pS = in[0]->getAs<types::String>();
129     int iTotalLen = pS->getSize(); //add \n after each string
130     for (int i = 0 ; i < pS->getSize() ; i++)
131     {
132         iTotalLen += (int)wcslen(pS->get(i));
133     }
134
135     pstCommand = (wchar_t*)MALLOC(sizeof(wchar_t) * (iTotalLen + 1));//+1 for null termination
136
137     for (int i = 0, iPos = 0 ; i < pS->getSize() ; i++)
138     {
139         wcscpy(pstCommand + iPos, pS->get(i));
140         iPos = (int)wcslen(pstCommand);
141         pstCommand[iPos++] = L'\n';
142         pstCommand[iPos] = 0;
143     }
144
145     parser.parse(pstCommand);
146     FREE(pstCommand);
147     if (parser.getExitStatus() !=  Parser::Succeded)
148     {
149         if (bErrCatch)
150         {
151             out.push_back(new Double(999));
152             //to lock last error information
153             ConfigVariable::setLastErrorCall();
154             return Function::OK;
155         }
156         else
157         {
158             char* pst = wide_string_to_UTF8(parser.getErrorMessage());
159             Scierror(999, "%s", pst);
160             FREE(pst);
161             return Function::Error;
162         }
163     }
164
165     if (ConfigVariable::getSerialize())
166     {
167         ast::Exp* temp = parser.getTree();
168         if (ConfigVariable::getTimed())
169         {
170             pExp = callTyper(temp, L"execstr");
171         }
172         else
173         {
174             pExp = callTyper(temp);
175         }
176
177         delete temp;
178     }
179     else
180     {
181         pExp = parser.getTree();
182     }
183
184     if (pExp == NULL)
185     {
186         return Function::Error;
187     }
188
189     //save current prompt mode
190     int oldVal = ConfigVariable::getPromptMode();
191     ConfigVariable::setPromptMode(-1);
192
193     if (bErrCatch)
194     {
195         ConfigVariable::setSilentError(1);
196     }
197
198     if (ConfigVariable::getAnalyzerOptions() == 1)
199     {
200         analysis::AnalysisVisitor analysis;
201         pExp->accept(analysis);
202         //ast::DebugVisitor debugMe;
203         //pExp->accept(debugMe);
204     }
205
206     ast::exps_t LExp = pExp->getAs<SeqExp>()->getExps();
207
208     types::ThreadId* pThreadMe = ConfigVariable::getThread(__GetCurrentThreadKey());
209
210     for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end(); j != itEnd ; ++j)
211     {
212         try
213         {
214             if (pThreadMe && pThreadMe->getInterrupt())
215             {
216                 __Signal(getAstPendingSignal());
217                 pThreadMe->suspend();
218             }
219
220             //excecute script
221             ExecVisitor execMe;
222             (*j)->accept(execMe);
223
224             //to manage call without ()
225             if (execMe.getResult() != NULL && execMe.getResult()->isCallable())
226             {
227                 Callable *pCall = execMe.getResult()->getAs<Callable>();
228                 types::typed_list out;
229                 types::typed_list in;
230                 types::optional_list opt;
231
232                 try
233                 {
234                     ExecVisitor execCall;
235                     Function::ReturnValue Ret = pCall->call(in, opt, 1, out, &execCall);
236
237                     if (Ret == Callable::OK)
238                     {
239                         if (out.size() == 0)
240                         {
241                             execMe.setResult(NULL);
242                         }
243                         else if (out.size() == 1)
244                         {
245                             out[0]->DecreaseRef();
246                             execMe.setResult(out[0]);
247                         }
248                         else
249                         {
250                             for (int i = 0 ; i < static_cast<int>(out.size()) ; i++)
251                             {
252                                 out[i]->DecreaseRef();
253                                 execMe.setResult(i, out[i]);
254                             }
255                         }
256                     }
257                     else if (Ret == Callable::Error)
258                     {
259                         ConfigVariable::setSilentError(iOldSilentError);
260                         if (ConfigVariable::getLastErrorFunction() == L"")
261                         {
262                             ConfigVariable::setLastErrorFunction(pCall->getName());
263                         }
264
265                         if (pCall->isMacro() || pCall->isMacroFile())
266                         {
267                             wchar_t szError[bsiz];
268                             os_swprintf(szError, bsiz, _W("at line % 5d of function %ls called by :\n").c_str(), (*j)->getLocation().first_line, pCall->getName().c_str());
269                             throw ast::ScilabMessage(szError);
270                         }
271                         else
272                         {
273                             throw ast::ScilabMessage();
274                         }
275                     }
276                 }
277                 catch (ScilabMessage sm)
278                 {
279                     ConfigVariable::setSilentError(iOldSilentError);
280                     wostringstream os;
281                     PrintVisitor printMe(os);
282                     (*j)->accept(printMe);
283                     os << std::endl << std::endl;
284                     if (ConfigVariable::getLastErrorFunction() == L"")
285                     {
286                         ConfigVariable::setLastErrorFunction(pCall->getName());
287                     }
288
289                     if (pCall->isMacro() || pCall->isMacroFile())
290                     {
291                         wstring szAllError;
292                         wchar_t szError[bsiz];
293                         os_swprintf(szError, bsiz, _W("at line % 5d of function %ls called by :\n").c_str(), sm.GetErrorLocation().first_line, pCall->getName().c_str());
294                         szAllError = szError + os.str();
295                         os_swprintf(szError, bsiz, _W("in  execstr instruction    called by :\n").c_str());
296                         szAllError += szError;
297                         throw ast::ScilabMessage(szAllError);
298                     }
299                     else
300                     {
301                         sm.SetErrorMessage(sm.GetErrorMessage() + os.str());
302                         throw sm;
303                     }
304                 }
305             }
306
307             //update ans variable.
308             if (execMe.getResult() != NULL && execMe.getResult()->isDeletable())
309             {
310                 InternalType* pITAns = execMe.getResult();
311                 symbol::Context::getInstance()->put(symbol::Symbol(L"ans"), pITAns);
312                 if ( (*j)->isVerbose() && bErrCatch == false)
313                 {
314                     std::wostringstream ostr;
315                     ostr << L" ans  =" << std::endl;
316                     ostr << std::endl;
317                     pITAns->toString(ostr);
318                     ostr << std::endl;
319                     scilabWriteW(ostr.str().c_str());
320                 }
321             }
322
323             //if( !checkPrompt(iMode, EXEC_MODE_MUTE) &&
324             //             bErrCatch == false)
325             //{
326             //  scilabWriteW(L"\n");
327             //}
328         }
329         catch (ScilabMessage sm)
330         {
331             ConfigVariable::setSilentError(iOldSilentError);
332             if (bErrCatch  == false && bMute == false)
333             {
334                 scilabErrorW(sm.GetErrorMessage().c_str());
335
336                 CallExp* pCall = dynamic_cast<CallExp*>(*j);
337                 if (pCall != NULL)
338                 {
339                     //to print call expression only of it is a macro
340                     ExecVisitor execFunc;
341                     pCall->getName().accept(execFunc);
342
343                     if (execFunc.getResult() != NULL &&
344                             (execFunc.getResult()->isMacro() || execFunc.getResult()->isMacroFile()))
345                     {
346                         wostringstream os;
347
348                         //add function failed
349                         PrintVisitor printMe(os);
350                         pCall->accept(printMe);
351                         os << std::endl;
352
353                         //add info on file failed
354                         wchar_t szError[bsiz];
355                         os_swprintf(szError, bsiz, _W("at line % 5d of exec file called by :\n").c_str(), (*j)->getLocation().first_line);
356                         os << szError;
357
358                         if (ConfigVariable::getLastErrorFunction() == L"")
359                         {
360                             ConfigVariable::setLastErrorFunction(execFunc.getResult()->getAs<Callable>()->getName());
361                         }
362
363                         //restore previous prompt mode
364                         ConfigVariable::setPromptMode(oldVal);
365                         throw ast::ScilabMessage(os.str(), 0, (*j)->getLocation());
366                     }
367                 }
368                 throw ast::ScilabMessage((*j)->getLocation());
369             }
370             else
371             {
372                 iErr = ConfigVariable::getLastErrorNumber();
373                 break;
374             }
375         }
376         catch (ast::ScilabError se)
377         {
378             ConfigVariable::setSilentError(iOldSilentError);
379             // check on error number because error message can be empty.
380             if (ConfigVariable::getLastErrorNumber() == 0)
381             {
382                 ConfigVariable::setLastErrorMessage(se.GetErrorMessage());
383                 ConfigVariable::setLastErrorNumber(se.GetErrorNumber());
384                 ConfigVariable::setLastErrorLine(se.GetErrorLocation().first_line);
385                 ConfigVariable::setLastErrorFunction(wstring(L""));
386             }
387
388             //store message
389             iErr = ConfigVariable::getLastErrorNumber();
390             if (bErrCatch == false)
391             {
392                 //in case of error, change mode to 2 ( prompt )
393                 ConfigVariable::setPromptMode(2);
394                 //write error
395                 scilabErrorW(se.GetErrorMessage().c_str());
396
397                 //write positino
398                 // sciprint(_("in  execstr instruction    called by :\n"));
399                 //restore previous prompt mode
400                 ConfigVariable::setPromptMode(oldVal);
401                 //throw ast::ScilabMessage(szError, 1, (*j)->getLocation());
402                 //print already done, so just foward exception but with message
403                 //throw ast::ScilabError();
404                 return Function::Error;
405             }
406             break;
407         }
408     }
409
410     //restore previous prompt mode and silent mode
411     ConfigVariable::setPromptMode(oldVal);
412     ConfigVariable::setSilentError(iOldSilentError);
413
414     if (bErrCatch)
415     {
416         out.push_back(new Double(iErr));
417         //to lock last error information
418         ConfigVariable::setLastErrorCall();
419         // allow print
420         ConfigVariable::resetError();
421     }
422
423     delete pExp;
424     return Function::OK;
425 }
426 /*--------------------------------------------------------------------------*/