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