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