mclose("all") showed a warning when it was executed in scinotes.
[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 "configvariable.hxx"
25 #include "types_tools.hxx"
26 #include "runner.hxx"
27 #include "threadmanagement.hxx"
28 #include "macro.hxx"
29 #include "macrofile.hxx"
30 #include "filemanager.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                 // Check if file has not already been closed (for ex mclose('all') in function)
178                 if (FileManager::isOpened(pwstFile) == true)
179                 {
180                     mclose(iID);
181                 }
182                 ThreadManagement::UnlockParser();
183                 return Function::OK;
184             }
185
186             char* pst = wide_string_to_UTF8(parser.getErrorMessage());
187             Scierror(999, "%s", pst);
188             FREE(pst);
189
190             delete parser.getTree();
191             // Check if file has not already been closed (for ex mclose('all') in function)
192             if (FileManager::isOpened(pwstFile) == true)
193             {
194                 mclose(iID);
195             }
196             ThreadManagement::UnlockParser();
197             return Function::Error;
198         }
199
200         if (ConfigVariable::getSerialize())
201         {
202             ast::Exp* temp = parser.getTree();
203             if (ConfigVariable::getTimed())
204             {
205                 pExp = callTyper(temp, L"exec");
206             }
207             else
208             {
209                 pExp = callTyper(temp);
210             }
211
212             delete temp;
213         }
214         else
215         {
216             pExp = parser.getTree();
217         }
218
219         ThreadManagement::UnlockParser();
220         // update where to set the name of the executed file.
221         ConfigVariable::setFileNameToLastWhere(pwstFile);
222
223         ConfigVariable::setExecutedFileID(iID);
224     }
225     else if (in[0]->isMacro() || in[0]->isMacroFile())
226     {
227         typed_list input;
228         optional_list optional;
229         typed_list output;
230         ast::ExecVisitor execFunc;
231
232         if (in[0]->isMacroFile())
233         {
234             //1st argument is a macro name, parse and execute it in the current environnement
235             if (in[0]->getAs<MacroFile>()->parse() == false)
236             {
237                 char* pstMacro = wide_string_to_UTF8(in[0]->getAs<MacroFile>()->getName().c_str());
238                 Scierror(999, _("%s: Unable to parse macro '%s'"), "exec", pstMacro);
239                 FREE(pstMacro);
240                 return Function::Error;
241             }
242             pMacro = in[0]->getAs<MacroFile>()->getMacro();
243         }
244         else //1st argument is a macro name, execute it in the current environnement
245         {
246             pMacro = in[0]->getAs<Macro>();
247         }
248
249         // unable for macro with varargin or varargout
250         auto inputs = pMacro->getInputs();
251         auto outputs = pMacro->getOutputs();
252         if ((inputs->size() != 0 && inputs->back()->getSymbol().getName() == L"varargin") ||
253                 outputs->size() != 0 && outputs->back()->getSymbol().getName() == L"varargout")
254         {
255             Scierror(999, _("%s: Wrong type for input argument #%d: A macro without varargin and varargout expected.\n"), "exec", 1);
256             return Function::Error;
257         }
258
259         pExp = pMacro->getBody();
260
261         // update where to set the name of the executed macro instead of "exec"
262         ConfigVariable::WhereEntry lastWhere = ConfigVariable::getWhere().back();
263         int iLine = lastWhere.m_line;
264         int iAbsLine = lastWhere.m_absolute_line;
265         ConfigVariable::where_end();
266         ConfigVariable::where_begin(iLine, iAbsLine, pMacro);
267     }
268     else
269     {
270         Scierror(999, _("%s: Wrong type for input argument #%d: A string expected.\n"), "exec", 1);
271         return Function::Error;
272     }
273
274     if (pMacro)
275     {
276         //store the line number where is stored this macro in file.
277         ConfigVariable::macroFirstLine_begin(pMacro->getFirstLine());
278     }
279
280     //save current prompt mode
281     int oldVal = ConfigVariable::getPromptMode();
282     ConfigVariable::setPromptMode(promptMode);
283
284     // if not exp displaying, just execute the seqexp
285     if (file == NULL || promptMode == 0 || promptMode == 2)
286     {
287         ast::SeqExp* pSeqExp = pExp->getAs<SeqExp>();
288
289         try
290         {
291             ExecVisitor execExps;
292             pSeqExp->accept(execExps);
293         }
294         catch (const ast::InternalError ie)
295         {
296             if (bErrCatch == false)
297             {
298                 ConfigVariable::setPromptMode(oldVal);
299                 ConfigVariable::setExecutedFileID(0);
300                 throw ie;
301             }
302
303             ConfigVariable::resetWhereError();
304             iErr = ConfigVariable::getLastErrorNumber();
305         }
306     }
307     else
308     {
309         ast::exps_t& LExp = pExp->getAs<SeqExp>()->getExps();
310
311         char pstPrompt[64];
312         //get prompt
313         GetCurrentPrompt(pstPrompt);
314         std::string stPrompt(pstPrompt);
315
316         std::string str;
317         int iCurrentLine = -1; //no data in str
318         int iCurrentCol = 0; //no data in str
319
320         for (ast::exps_t::iterator j = LExp.begin(), itEnd = LExp.end() ; j != itEnd; ++j)
321         {
322             // printf some exp
323             ast::exps_t::iterator k = j;
324             int iLastLine = (*j)->getLocation().last_line;
325             do
326             {
327                 str = printExp(*file, *k, stPrompt, &iCurrentLine, &iCurrentCol, str);
328                 iLastLine = (*k)->getLocation().last_line;
329                 k++;
330             }
331             while (k != LExp.end() && (*k)->getLocation().first_line == iLastLine);
332
333             // In case where the line ends by spaces, iCurrentCol is not reset
334             // by printExp because we don't know if that's the end of the expression
335             // before go out of the loop. So we have to reset column count
336             // and print a new line before manage the next line.
337             if (iCurrentCol != 0)
338             {
339                 iCurrentCol = 0;
340                 printLine("", "", true);
341             }
342
343             // create a seqexp with printed exp
344             ast::exps_t* someExps = new ast::exps_t();
345             someExps->assign(j, k);
346             k--;
347             SeqExp seqExp(Location((*j)->getLocation().first_line,      (*k)->getLocation().last_line,
348                                    (*j)->getLocation().first_column,    (*k)->getLocation().last_column),
349                           *someExps);
350
351             j = k;
352
353             try
354             {
355                 // execute printed exp
356                 ExecVisitor execExps;
357                 seqExp.accept(execExps);
358             }
359             catch (const ast::InternalError& ie)
360             {
361                 ConfigVariable::setExecutedFileID(0);
362                 ConfigVariable::fillWhereError(ie.GetErrorLocation().first_line);
363                 if (ConfigVariable::getLastErrorLine() == 0)
364                 {
365                     ConfigVariable::setLastErrorLine(ie.GetErrorLocation().first_line);
366                 }
367
368                 //store message
369                 iErr = ConfigVariable::getLastErrorNumber();
370                 if (bErrCatch == false)
371                 {
372                     if (file)
373                     {
374                         delete pExp;
375                         // Check if file has not already been closed (for ex mclose('all') in function)
376                         if (FileManager::isOpened(pwstFile) == true)
377                         {
378                             mclose(iID);
379                         }
380                         file->close();
381                         delete file;
382                         FREE(pstFile);
383                         FREE(pwstFile);
384                     }
385
386                     //restore previous prompt mode
387                     ConfigVariable::setPromptMode(oldVal);
388
389                     // avoid double delete on exps when "seqExp" is destryed and "LExp" too
390                     ast::exps_t& protectExp = seqExp.getExps();
391                     for (int i = 0; i < protectExp.size(); ++i)
392                     {
393                         protectExp[i] = NULL;
394                     }
395
396                     throw ie;
397                 }
398
399                 if (pMacro)
400                 {
401                     // reset last first line of macro called
402                     ConfigVariable::macroFirstLine_end();
403                 }
404
405                 ConfigVariable::resetWhereError();
406                 break;
407             }
408
409             ConfigVariable::setExecutedFileID(0);
410
411             // avoid double delete on exps when "seqExp" is destryed and "LExp" too
412             ast::exps_t& protectExp = seqExp.getExps();
413             for (int i = 0; i < protectExp.size(); ++i)
414             {
415                 protectExp[i] = NULL;
416             }
417         }
418     }
419
420     //restore previous prompt mode
421     ConfigVariable::setPromptMode(oldVal);
422     if (bErrCatch)
423     {
424         out.push_back(new Double(iErr));
425         //to lock last error information
426         ConfigVariable::setLastErrorCall();
427     }
428
429     if (file)
430     {
431         delete pExp;
432         // Check if file has not already been closed (for ex mclose('all') in function)
433         if (FileManager::isOpened(pwstFile) == true)
434         {
435             mclose(iID);
436         }
437         file->close();
438         delete file;
439         FREE(pstFile);
440         FREE(pwstFile);
441     }
442
443     return Function::OK;
444 }
445
446 std::string getExpression(const std::string& _stFile, Exp* _pExp)
447 {
448     std::string out;
449     std::string stBuffer;
450     int iLine = 0;
451     Location loc = _pExp->getLocation();
452     std::ifstream file(_stFile.c_str());
453
454     //bypass previous lines
455     for (int i = 0 ; i < loc.first_line; i++)
456     {
457         std::getline(file, stBuffer);
458     }
459
460     if (loc.first_line == loc.last_line)
461     {
462         int iStart = loc.first_column - 1;
463         int iEnd = loc.last_column - 1;
464         int iLen = iEnd - iStart;
465         out += string(stBuffer.c_str() + iStart, iLen);
466     }
467     else
468     {
469         //
470
471         //first line, entire or not
472         out += string(stBuffer.c_str() + loc.first_column - 1);
473         out += "\n";
474
475         //print other full lines
476         for (int i = loc.first_line; i < (loc.last_line - 1) ; i++)
477         {
478             std::getline(file, stBuffer);
479             out += stBuffer;
480             out += "\n";
481         }
482
483
484         //last line, entire or not
485         getline(file, stBuffer);
486         out += string(stBuffer.c_str(), loc.last_column - 1);
487         out += "\n";
488     }
489     return out;
490 }
491
492 std::string printExp(std::ifstream& _File, Exp* _pExp, const std::string& _stPrompt, int* _piLine /* in/out */, int* _piCol /* in/out */, std::string& _stPreviousBuffer)
493 {
494     //case 1, exp is on 1 line and take the entire line
495
496     //case 2, exp is multiline
497
498     //case 3, exp is part of a line.
499     //ex : 3 exp on the same line a = 1; b = 2; c = 3;
500
501     //case 4, exp is multiline but start and/or finish in the middle of a line
502     //ex :
503     //a = 10;for i = 1 : a
504     //  a
505     //end, b = 1;
506
507     Location loc = _pExp->getLocation();
508
509     //positionning file curser at loc.first_line
510     {
511         //strange case, current position is after the wanted position
512         if (*_piLine > loc.first_line)
513         {
514             //reset line counter and restart reading at the start of the file.
515             *_piLine = -1;
516             _File.seekg( 0, ios_base::beg );
517         }
518
519         //bypass previous lines
520         for (int i = *_piLine ; i < loc.first_line - 1; i++)
521         {
522
523             (*_piLine)++;
524             if ((*_piLine) != (loc.first_line - 1))
525             {
526                 //empty line but not sequential lines
527                 printLine("", "", true);
528             }
529             std::getline(_File, _stPreviousBuffer);
530         }
531     }
532
533     if (loc.first_line == loc.last_line)
534     {
535         //1 line
536         int iStart = loc.first_column - 1;
537         int iEnd = loc.last_column - 1;
538         int iLen = iEnd - iStart;
539         std::string strLastLine(_stPreviousBuffer.c_str() + iStart, iLen);
540         int iExpLen = iLen;
541         int iLineLen = (int)_stPreviousBuffer.size();
542         //printLine(_pstPrompt, strLastLine, true, false);
543
544         if (iStart == 0 && iExpLen == iLineLen)
545         {
546             //entire line
547             if (*_piCol)
548             {
549                 //blank char at the end of previous line
550                 printLine("", "", true);
551             }
552             printLine(_stPrompt, strLastLine, true);
553             *_piCol = 0;
554         }
555         else
556         {
557             if (iStart == 0)
558             {
559                 //begin of line
560                 if (*_piCol)
561                 {
562                     //blank char at the end of previous line
563                     printLine("", "", true);
564                 }
565                 printLine(_stPrompt, strLastLine, false);
566                 *_piCol = loc.last_column;
567             }
568             else
569             {
570                 if (*_piCol == 0)
571                 {
572                     printLine(_stPrompt, "", false);
573                     (*_piCol)++;
574                 }
575
576                 if (*_piCol < loc.first_column)
577                 {
578                     //pickup separator between expressionsfrom file and add to output
579                     int iSize = loc.first_column - *_piCol;
580                     std::string stTemp(_stPreviousBuffer.c_str() +  (*_piCol - 1), iSize);
581                     printLine("", stTemp, false);
582                     *_piCol = loc.first_column;
583                 }
584
585                 if (iEnd == iLineLen)
586                 {
587                     printLine("", strLastLine, true);
588                     *_piCol = 0;
589                 }
590                 else
591                 {
592                     printLine("", strLastLine, false);
593                     *_piCol = loc.last_column;
594                 }
595             }
596         }
597     }
598     else
599     {
600         //multiline
601
602         if (loc.first_column == 1)
603         {
604             if (*_piCol)
605             {
606                 //blank char at the end of previous line
607                 printLine("", "", true);
608             }
609             printLine(_stPrompt, _stPreviousBuffer.c_str() + (loc.first_column - 1), false);
610         }
611         else
612         {
613             if (*_piCol < loc.first_column)
614             {
615                 //pickup separator between expressionsfrom file and add to output
616                 printLine(_stPrompt, _stPreviousBuffer.c_str(), false);
617                 *_piCol = loc.first_column;
618             }
619         }
620
621         //print other full lines
622         for (int i = loc.first_line; i < (loc.last_line - 1) ; i++)
623         {
624             (*_piLine)++;
625             std::getline(_File, _stPreviousBuffer);
626             // dont print empty line of function body
627             if (_stPreviousBuffer.size() != 0)
628             {
629                 printLine(_stPrompt, _stPreviousBuffer.c_str(), false);
630             }
631         }
632
633         //last line
634         std::getline(_File, _stPreviousBuffer);
635         (*_piLine)++;
636
637         int iSize = loc.last_column - 1;
638         std::string stLastLine(_stPreviousBuffer.c_str(), iSize);
639         int iLineLen = (int)_stPreviousBuffer.size();
640         if (iLineLen == iSize)
641         {
642             printLine(_stPrompt, stLastLine, true);
643             *_piCol = 0;
644         }
645         else
646         {
647             printLine(_stPrompt, stLastLine, false);
648             *_piCol = loc.last_column;
649         }
650     }
651
652     return _stPreviousBuffer;
653 }
654
655 void printLine(const std::string& _stPrompt, const std::string& _stLine, bool _bLF)
656 {
657     std::string st;
658
659     if (_stPrompt.size() != 0)
660     {
661         st = "\n" + _stPrompt;
662     }
663
664     st += _stLine;
665     if (_bLF && ConfigVariable::isEmptyLineShow())
666     {
667         st += "\n";
668     }
669
670     scilabWrite(st.c_str());
671 }
672 /*--------------------------------------------------------------------------*/