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