missing Lock on parseur added.
[scilab.git] / scilab / modules / functions / sci_gateway / cpp / sci_exec.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 "functions_gw.hxx"
15
16 #include "parser.hxx"
17 #include "funcmanager.hxx"
18 #include "context.hxx"
19 #include "execvisitor.hxx"
20 #include "mutevisitor.hxx"
21 #include "printvisitor.hxx"
22 #include "visitor_common.hxx"
23 #include "scilabWrite.hxx"
24 #include "scilabexception.hxx"
25 #include "configvariable.hxx"
26 #include "types_tools.hxx"
27 #include "runner.hxx"
28 #include "threadmanagement.hxx"
29 #include "macro.hxx"
30 #include "macrofile.hxx"
31
32 #include <iostream>
33 #include <fstream>
34 #include <string>
35
36 extern "C"
37 {
38 #include "os_string.h"
39 #include "expandPathVariable.h"
40 #include "prompt.h"
41 #include "Scierror.h"
42 #include "localization.h"
43 #include "os_string.h"
44 #include "mopen.h"
45 #include "mclose.h"
46 #include "fullpath.h"
47 #include "PATH_MAX.h"
48 }
49
50 using namespace ast;
51 void printLine(const std::string& _stPrompt, const std::string& _stLine, bool _bLF);
52 std::string printExp(std::ifstream& _File, Exp* _pExp, const std::string& _stPrompt, int* _piLine /* in/out */, int* _piCol /* in/out */, std::string& _stPreviousBuffer);
53 std::string getExpression(const std::string& _stFile, Exp* _pExp);
54
55 /*--------------------------------------------------------------------------*/
56 types::Function::ReturnValue sci_exec(types::typed_list &in, int _iRetCount, types::typed_list &out)
57 {
58     int promptMode      = 0;//default value at startup, overthise 3 or verbose ";"
59     bool bPromptMode    = false;
60     int iErr            = 0;
61     bool bErrCatch      = false;
62     Exp* pExp           = NULL;
63     int iID             = 0;
64     types::Macro* pMacro = NULL;
65     Parser parser;
66
67     wchar_t* pwstFile = NULL;
68     char* pstFile = NULL;
69
70     std::string stFile;
71     std::ifstream* file = NULL;
72
73     if (ConfigVariable::getStartProcessing() == false)
74     {
75         if (ConfigVariable::getVerbose())
76         {
77             promptMode = 3;
78         }
79         else
80         {
81             promptMode = 0;
82         }
83     }
84
85     if (in.size() < 1 || in.size() > 3)
86     {
87         Scierror(999, _("%s: Wrong number of input arguments: %d to %d expected.\n"), "exec" , 1, 3);
88         return Function::Error;
89     }
90
91     // get mode and errcatch
92     if (in.size() > 1)
93     {
94         //errcatch or mode
95         if (in[1]->isString() && in[1]->getAs<types::String>()->isScalar())
96         {
97             //errcatch
98             String* pS = in[1]->getAs<types::String>();
99             if (os_wcsicmp(pS->get(0), L"errcatch") == 0)
100             {
101                 bErrCatch = true;
102             }
103             else
104             {
105                 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
106                 return Function::Error;
107             }
108
109             if (in.size() > 2)
110             {
111
112                 if (in[2]->isDouble() == false || in[2]->getAs<Double>()->isScalar() == false)
113                 {
114                     //mode
115                     Scierror(999, _("%s: Wrong type for input argument #%d: A integer expected.\n"), "exec", 3);
116                     return Function::Error;
117                 }
118
119                 promptMode = (int)in[2]->getAs<Double>()->getReal()[0];
120                 bPromptMode = true;
121             }
122         }
123         else if (in[1]->isDouble() && in[1]->getAs<Double>()->isScalar())
124         {
125             if (in.size() > 2)
126             {
127                 Scierror(999, _("%s: Wrong value for input argument #%d: 'errcatch' expected.\n"), "exec", 2);
128                 return Function::Error;
129             }
130             //mode
131             promptMode = (int)in[1]->getAs<Double>()->getReal()[0];
132             bPromptMode = true;
133         }
134         else
135         {
136             //not managed
137             Scierror(999, _("%s: Wrong type for input argument #%d: A integer or string expected.\n"), "exec", 2);
138             return Function::Error;
139         }
140     }
141
142     if (in[0]->isString() && in[0]->getAs<types::String>()->isScalar())
143     {
144         //1st argument is a path, parse file and execute it
145         int iParsePathLen = 0;
146         String* pS = in[0]->getAs<types::String>();
147
148         pwstFile = expandPathVariableW(pS->get(0));
149         pstFile = wide_string_to_UTF8(pwstFile);
150         stFile = std::string(pstFile);
151         file = new std::ifstream(pstFile);
152
153         wchar_t* pwstTemp = (wchar_t*)MALLOC(sizeof(wchar_t) * (PATH_MAX * 2));
154         get_full_pathW(pwstTemp, (const wchar_t*)pwstFile, PATH_MAX * 2);
155
156         /*fake call to mopen to show file within file()*/
157         if (mopen(pwstTemp, L"r", 0, &iID) != MOPEN_NO_ERROR)
158         {
159             FREE(pwstTemp);
160             Scierror(999, _("%s: Cannot open file %s.\n"), "exec", pstFile);
161             return Function::Error;
162         }
163
164         ThreadManagement::LockParser();
165         parser.parseFile(pwstTemp, L"exec");
166         FREE(pwstTemp);
167         if (parser.getExitStatus() !=  Parser::Succeded)
168         {
169             if (bErrCatch)
170             {
171                 out.push_back(new Double(999));
172                 //to lock last error information
173                 ConfigVariable::setLastErrorCall();
174                 ConfigVariable::setLastErrorMessage(parser.getErrorMessage());
175                 ConfigVariable::setLastErrorNumber(999);
176                 delete parser.getTree();
177                 mclose(iID);
178                 ThreadManagement::UnlockParser();
179                 return Function::OK;
180             }
181
182             char* pst = wide_string_to_UTF8(parser.getErrorMessage());
183             Scierror(999, "%s", pst);
184             FREE(pst);
185
186             delete parser.getTree();
187             mclose(iID);
188             ThreadManagement::UnlockParser();
189             return Function::Error;
190         }
191
192         if (ConfigVariable::getSerialize())
193         {
194             ast::Exp* temp = parser.getTree();
195             if (ConfigVariable::getTimed())
196             {
197                 pExp = callTyper(temp, L"exec");
198             }
199             else
200             {
201                 pExp = callTyper(temp);
202             }
203
204             delete temp;
205         }
206         else
207         {
208             pExp = parser.getTree();
209         }
210
211         ThreadManagement::UnlockParser();
212         // update where to set the name of the executed file.
213         ConfigVariable::setFileNameToLastWhere(pwstFile);
214
215         ConfigVariable::setExecutedFileID(iID);
216     }
217     else if (in[0]->isMacro() || in[0]->isMacroFile())
218     {
219         typed_list input;
220         optional_list optional;
221         typed_list output;
222         ast::ExecVisitor execFunc;
223
224         if (in[0]->isMacroFile())
225         {
226             //1st argument is a macro name, parse and execute it in the current environnement
227             if (in[0]->getAs<MacroFile>()->parse() == false)
228             {
229                 char* pstMacro = wide_string_to_UTF8(in[0]->getAs<MacroFile>()->getName().c_str());
230                 Scierror(999, _("%s: Unable to parse macro '%s'"), "exec", pstMacro);
231                 FREE(pstMacro);
232                 return Function::Error;
233             }
234             pMacro = in[0]->getAs<MacroFile>()->getMacro();
235         }
236         else //1st argument is a macro name, execute it in the current environnement
237         {
238             pMacro = in[0]->getAs<Macro>();
239         }
240
241         // unable for macro with varargin or varargout
242         auto inputs = pMacro->getInputs();
243         auto outputs = pMacro->getOutputs();
244         if ((inputs->size() != 0 && inputs->back()->getSymbol().getName() == L"varargin") ||
245                 outputs->size() != 0 && outputs->back()->getSymbol().getName() == L"varargout")
246         {
247             Scierror(999, _("%s: Wrong type for input argument #%d: A macro without varargin and varargout expected.\n"), "exec", 1);
248             return Function::Error;
249         }
250
251         pExp = pMacro->getBody();
252
253         // update where to set the name of the executed macro instead of "exec"
254         ConfigVariable::WhereEntry lastWhere = ConfigVariable::getWhere().back();
255         int iLine = lastWhere.m_line;
256         int iAbsLine = lastWhere.m_absolute_line;
257         ConfigVariable::where_end();
258         ConfigVariable::where_begin(iLine, iAbsLine, pMacro);
259     }
260     else
261     {
262         Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "exec", 1);
263         return Function::Error;
264     }
265
266     if (pMacro)
267     {
268         //store the line number where is stored this macro in file.
269         ConfigVariable::macroFirstLine_begin(pMacro->getFirstLine());
270     }
271
272     //save current prompt mode
273     int oldVal = ConfigVariable::getPromptMode();
274     ConfigVariable::setPromptMode(promptMode);
275
276     // if not exp displaying, just execute the seqexp
277     if (file == NULL || promptMode == 0 || promptMode == 2)
278     {
279         ast::SeqExp* pSeqExp = pExp->getAs<SeqExp>();
280
281         try
282         {
283             ExecVisitor execExps;
284             pSeqExp->accept(execExps);
285         }
286         catch (ast::ScilabMessage sm)
287         {
288             if (bErrCatch == false)
289             {
290                 ConfigVariable::setPromptMode(oldVal);
291                 ConfigVariable::setExecutedFileID(0);
292                 throw sm;
293             }
294
295             ConfigVariable::resetWhereError();
296             iErr = ConfigVariable::getLastErrorNumber();
297         }
298     }
299     else
300     {
301         ast::exps_t& LExp = pExp->getAs<SeqExp>()->getExps();
302
303         char pstPrompt[64];
304         //get prompt
305         GetCurrentPrompt(pstPrompt);
306         std::string stPrompt(pstPrompt);
307
308         std::string str;
309         int iCurrentLine = -1; //no data in str
310         int iCurrentCol = 0; //no data in str
311
312         for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end() ; j != itEnd; ++j)
313         {
314             // printf some exp
315             ast::exps_t::iterator k = j;
316             int iLastLine = (*j)->getLocation().last_line;
317             do
318             {
319                 str = printExp(*file, *k, stPrompt, &iCurrentLine, &iCurrentCol, str);
320                 iLastLine = (*k)->getLocation().last_line;
321                 k++;
322             }
323             while (k != LExp.end() && (*k)->getLocation().first_line == iLastLine);
324
325             // In case where the line ends by spaces, iCurrentCol is not reset
326             // by printExp because we don't know if that's the end of the expression
327             // before go out of the loop. So we have to reset column count
328             // and print a new line before manage the next line.
329             if (iCurrentCol != 0)
330             {
331                 iCurrentCol = 0;
332                 printLine("", "", true);
333             }
334
335             // create a seqexp with printed exp
336             ast::exps_t* someExps = new ast::exps_t();
337             someExps->assign(j, k);
338             k--;
339             SeqExp seqExp(Location((*j)->getLocation().first_line,      (*k)->getLocation().last_line,
340                                    (*j)->getLocation().first_column,    (*k)->getLocation().last_column),
341                           *someExps);
342
343             j = k;
344
345             try
346             {
347                 // execute printed exp
348                 ExecVisitor execExps;
349                 seqExp.accept(execExps);
350             }
351             catch (ast::ScilabMessage sm)
352             {
353                 ConfigVariable::fillWhereError(sm.GetErrorLocation().first_line);
354
355                 if (file)
356                 {
357                     delete pExp;
358                     mclose(iID);
359                     file->close();
360                     delete file;
361                     FREE(pstFile);
362                     FREE(pwstFile);
363                 }
364
365                 if (pMacro)
366                 {
367                     // reset last first line of macro called
368                     ConfigVariable::macroFirstLine_end();
369                 }
370
371                 if (bErrCatch == false)
372                 {
373                     ConfigVariable::setPromptMode(oldVal);
374                     ConfigVariable::setExecutedFileID(0);
375
376                     // avoid double delete on exps when "seqExp" is destryed and "LExp" too
377                     ast::exps_t& protectExp = seqExp.getExps();
378                     for (int i = 0; i < protectExp.size(); ++i)
379                     {
380                         protectExp[i] = NULL;
381                     }
382
383                     throw sm;
384                 }
385
386                 ConfigVariable::resetWhereError();
387                 iErr = ConfigVariable::getLastErrorNumber();
388             }
389             catch (ast::ScilabError& se)
390             {
391                 ConfigVariable::setExecutedFileID(0);
392                 ConfigVariable::fillWhereError(se.GetErrorLocation().first_line);
393                 if (ConfigVariable::getLastErrorNumber() == 0)
394                 {
395                     ConfigVariable::setLastErrorMessage(se.GetErrorMessage());
396                     ConfigVariable::setLastErrorNumber(se.GetErrorNumber());
397                     ConfigVariable::setLastErrorLine(se.GetErrorLocation().first_line);
398                     ConfigVariable::setLastErrorFunction(wstring(L""));
399                 }
400
401                 //store message
402                 iErr = ConfigVariable::getLastErrorNumber();
403                 if (bErrCatch == false)
404                 {
405                     if (file)
406                     {
407                         delete pExp;
408                         mclose(iID);
409                         file->close();
410                         delete file;
411                         FREE(pstFile);
412                         FREE(pwstFile);
413                     }
414
415                     //restore previous prompt mode
416                     ConfigVariable::setPromptMode(oldVal);
417
418                     // avoid double delete on exps when "seqExp" is destryed and "LExp" too
419                     ast::exps_t& protectExp = seqExp.getExps();
420                     for (int i = 0; i < protectExp.size(); ++i)
421                     {
422                         protectExp[i] = NULL;
423                     }
424
425                     throw se;
426                 }
427
428                 if (pMacro)
429                 {
430                     // reset last first line of macro called
431                     ConfigVariable::macroFirstLine_end();
432                 }
433
434                 ConfigVariable::resetWhereError();
435                 break;
436             }
437
438             ConfigVariable::setExecutedFileID(0);
439
440             // avoid double delete on exps when "seqExp" is destryed and "LExp" too
441             ast::exps_t& protectExp = seqExp.getExps();
442             for (int i = 0; i < protectExp.size(); ++i)
443             {
444                 protectExp[i] = NULL;
445             }
446         }
447     }
448
449     //restore previous prompt mode
450     ConfigVariable::setPromptMode(oldVal);
451     if (bErrCatch)
452     {
453         out.push_back(new Double(iErr));
454         //to lock last error information
455         ConfigVariable::setLastErrorCall();
456     }
457
458     if (file)
459     {
460         delete pExp;
461         mclose(iID);
462         file->close();
463         delete file;
464         FREE(pstFile);
465         FREE(pwstFile);
466     }
467
468     return Function::OK;
469 }
470
471 std::string getExpression(const std::string& _stFile, Exp* _pExp)
472 {
473     std::string out;
474     std::string stBuffer;
475     int iLine = 0;
476     Location loc = _pExp->getLocation();
477     std::ifstream file(_stFile.c_str());
478
479     //bypass previous lines
480     for (int i = 0 ; i < loc.first_line; i++)
481     {
482         std::getline(file, stBuffer);
483     }
484
485     if (loc.first_line == loc.last_line)
486     {
487         int iStart = loc.first_column - 1;
488         int iEnd = loc.last_column - 1;
489         int iLen = iEnd - iStart;
490         out += string(stBuffer.c_str() + iStart, iLen);
491     }
492     else
493     {
494         //
495
496         //first line, entire or not
497         out += string(stBuffer.c_str() + loc.first_column - 1);
498         out += "\n";
499
500         //print other full lines
501         for (int i = loc.first_line; i < (loc.last_line - 1) ; i++)
502         {
503             std::getline(file, stBuffer);
504             out += stBuffer;
505             out += "\n";
506         }
507
508
509         //last line, entire or not
510         getline(file, stBuffer);
511         out += string(stBuffer.c_str(), loc.last_column - 1);
512         out += "\n";
513     }
514     return out;
515 }
516
517 std::string printExp(std::ifstream& _File, Exp* _pExp, const std::string& _stPrompt, int* _piLine /* in/out */, int* _piCol /* in/out */, std::string& _stPreviousBuffer)
518 {
519     //case 1, exp is on 1 line and take the entire line
520
521     //case 2, exp is multiline
522
523     //case 3, exp is part of a line.
524     //ex : 3 exp on the same line a = 1; b = 2; c = 3;
525
526     //case 4, exp is multiline but start and/or finish in the middle of a line
527     //ex :
528     //a = 10;for i = 1 : a
529     //  a
530     //end, b = 1;
531
532     Location loc = _pExp->getLocation();
533
534     //positionning file curser at loc.first_line
535     {
536         //strange case, current position is after the wanted position
537         if (*_piLine > loc.first_line)
538         {
539             //reset line counter and restart reading at the start of the file.
540             *_piLine = -1;
541             _File.seekg( 0, ios_base::beg );
542         }
543
544         //bypass previous lines
545         for (int i = *_piLine ; i < loc.first_line - 1; i++)
546         {
547
548             (*_piLine)++;
549             if ((*_piLine) != (loc.first_line - 1))
550             {
551                 //empty line but not sequential lines
552                 printLine("", "", true);
553             }
554             std::getline(_File, _stPreviousBuffer);
555         }
556     }
557
558     if (loc.first_line == loc.last_line)
559     {
560         //1 line
561         int iStart = loc.first_column - 1;
562         int iEnd = loc.last_column - 1;
563         int iLen = iEnd - iStart;
564         std::string strLastLine(_stPreviousBuffer.c_str() + iStart, iLen);
565         int iExpLen = iLen;
566         int iLineLen = (int)_stPreviousBuffer.size();
567         //printLine(_pstPrompt, strLastLine, true, false);
568
569         if (iStart == 0 && iExpLen == iLineLen)
570         {
571             //entire line
572             if (*_piCol)
573             {
574                 //blank char at the end of previous line
575                 printLine("", "", true);
576             }
577             printLine(_stPrompt, strLastLine, true);
578             *_piCol = 0;
579         }
580         else
581         {
582             if (iStart == 0)
583             {
584                 //begin of line
585                 if (*_piCol)
586                 {
587                     //blank char at the end of previous line
588                     printLine("", "", true);
589                 }
590                 printLine(_stPrompt, strLastLine, false);
591                 *_piCol = loc.last_column;
592             }
593             else
594             {
595                 if (*_piCol == 0)
596                 {
597                     printLine(_stPrompt, "", false);
598                     (*_piCol)++;
599                 }
600
601                 if (*_piCol < loc.first_column)
602                 {
603                     //pickup separator between expressionsfrom file and add to output
604                     int iSize = loc.first_column - *_piCol;
605                     std::string stTemp(_stPreviousBuffer.c_str() +  (*_piCol - 1), iSize);
606                     printLine("", stTemp, false);
607                     *_piCol = loc.first_column;
608                 }
609
610                 if (iEnd == iLineLen)
611                 {
612                     printLine("", strLastLine, true);
613                     *_piCol = 0;
614                 }
615                 else
616                 {
617                     printLine("", strLastLine, false);
618                     *_piCol = loc.last_column;
619                 }
620             }
621         }
622     }
623     else
624     {
625         //multiline
626
627         if (loc.first_column == 1)
628         {
629             if (*_piCol)
630             {
631                 //blank char at the end of previous line
632                 printLine("", "", true);
633             }
634             printLine(_stPrompt, _stPreviousBuffer.c_str() + (loc.first_column - 1), false);
635         }
636         else
637         {
638             if (*_piCol < loc.first_column)
639             {
640                 //pickup separator between expressionsfrom file and add to output
641                 printLine(_stPrompt, _stPreviousBuffer.c_str(), false);
642                 *_piCol = loc.first_column;
643             }
644         }
645
646         //print other full lines
647         for (int i = loc.first_line; i < (loc.last_line - 1) ; i++)
648         {
649             (*_piLine)++;
650             std::getline(_File, _stPreviousBuffer);
651             // dont print empty line of function body
652             if (_stPreviousBuffer.size() != 0)
653             {
654                 printLine(_stPrompt, _stPreviousBuffer.c_str(), false);
655             }
656         }
657
658         //last line
659         std::getline(_File, _stPreviousBuffer);
660         (*_piLine)++;
661
662         int iSize = loc.last_column - 1;
663         std::string stLastLine(_stPreviousBuffer.c_str(), iSize);
664         int iLineLen = (int)_stPreviousBuffer.size();
665         if (iLineLen == iSize)
666         {
667             printLine(_stPrompt, stLastLine, true);
668             *_piCol = 0;
669         }
670         else
671         {
672             printLine(_stPrompt, stLastLine, false);
673             *_piCol = loc.last_column;
674         }
675     }
676
677     return _stPreviousBuffer;
678 }
679
680 void printLine(const std::string& _stPrompt, const std::string& _stLine, bool _bLF)
681 {
682     std::string st;
683
684     if (_stPrompt.size() != 0)
685     {
686         st = "\n" + _stPrompt;
687     }
688
689     st += _stLine;
690     if (_bLF && ConfigVariable::isEmptyLineShow())
691     {
692         st += "\n";
693     }
694
695     scilabWrite(st.c_str());
696 }
697 /*--------------------------------------------------------------------------*/