Linux/MacOSX: fix timeout implementation
[scilab.git] / scilab / modules / startup / src / cpp / scilab.cpp
1 /*
2  *  Scilab ( http://www.scilab.org/ ) - This file is part of Scilab
3  *  Copyright (C) 2006-2008 - DIGITEO - Bruno JOFRET
4  *  Copyright (C) 2013 - Scilab Enterprises - Antoine ELIAS
5  *
6  * Copyright (C) 2012 - 2016 - Scilab Enterprises
7  *
8  * This file is hereby licensed under the terms of the GNU GPL v2.0,
9  * pursuant to article 5.3.4 of the CeCILL v.2.1.
10  * This file was originally licensed under the terms of the CeCILL v2.1,
11  * and continues to be available under such terms.
12  * For more information, see the COPYING file which you should have received
13  * along with this program.
14  *
15  */
16
17
18 #ifdef _MSC_VER
19 #pragma comment(lib,"../../../../../bin/libintl.lib")
20 #endif
21
22 #include <cstdio>
23 #include <iostream>
24 #include <string.h>
25 #include <setjmp.h>
26
27 extern "C"
28 {
29 #ifdef __APPLE__
30 #include "initMacOSXEnv.h"
31 #endif
32 #include "InitScilab.h"
33 #include "configvariable_interface.h"
34 #include "scilabRead.h"
35 #include "ConsoleRead.h"
36 #include "version.h"
37 #include "sci_malloc.h"
38 #include "lasterror.h"
39 #include "getpipeline.h"
40
41     extern char *getCmdLine(void);
42
43 #ifdef _MSC_VER
44 #include "FilesAssociations.h"
45 #include "PATH_MAX.h"
46     jmp_buf ScilabJmpEnv;
47 #else
48     extern jmp_buf ScilabJmpEnv;
49 #endif
50 #include "isatty.hxx"
51 }
52
53 #include "configvariable.hxx"
54 #include "exit_status.hxx"
55 #include "scilabWrite.hxx"
56
57 #define INTERACTIVE     -1
58
59 extern "C"
60 {
61 #ifdef ENABLE_MPI
62 #include "initMPI.h"
63 #endif
64 }
65
66 /*
67 ** Usage
68 **
69 ** Display usage : options available
70 */
71 static void usage(void)
72 {
73     std::cerr << "Usage: Scilab <options>" << std::endl;
74     std::cerr << "      -e Instruction   : execute the scilab instruction given in Instruction argument.";
75     std::cerr << "                         -e and -f arguments are mutually exclusive.";
76     std::cerr << "      -f File          : execute the scilab script given in File argument.";
77     std::cerr << "                         -e and -f arguments are mutually exclusive.";
78     std::cerr << "      -quit            : force scilab exit after execution of script from -e or -f argument.";
79     std::cerr << "                         this flag is ignored if it is not used with -e or -f argument.";
80     std::cerr << "      -l lang          : Change the language of scilab ( default : en_US )." << std::endl;
81     std::cerr << "      -nw              : Enable console mode." << std::endl;
82     std::cerr << "      -nwni            : Enable terminal mode." << std::endl;
83     std::cerr << "      -ns              : Don't execute etc/scilab.start." << std::endl;
84     std::cerr << "      --help           : Display this help." << std::endl;
85     std::cerr << "Developer Trace arguments:" << std::endl;
86     std::cerr << "      --parse-trace    : Display bison state machine evolution." << std::endl;
87     std::cerr << "      --AST-trace      : Display ASCII-art AST to be human readable." << std::endl;
88     std::cerr << "      --pretty-print   : Display pretty-printed code, standard Scilab syntax." << std::endl;
89     std::cerr << " " << std::endl;
90     std::cerr << "Developer Timer arguments:" << std::endl;
91     std::cerr << "      --AST-timed      : Time each AST node." << std::endl;
92     std::cerr << "      --timed          : Time global execution." << std::endl;
93     std::cerr << " " << std::endl;
94     std::cerr << "Developer Debug arguments:" << std::endl;
95     std::cerr << "      --no-exec        : Only do Lexing/parsing do not execute instructions." << std::endl;
96     std::cerr << "      --context-dump   : Display context status." << std::endl;
97     std::cerr << "      --exec-verbose   : Display command before running it." << std::endl;
98     std::cerr << "      --timeout delay  : Kill the Scilab process after a delay." << std::endl;
99 }
100
101 /*
102 ** Get Options
103 **
104 */
105 static int get_option(const int argc, char *argv[], ScilabEngineInfo* _pSEI)
106 {
107     int i = 0;
108
109 #ifdef DEBUG
110     std::cerr << "-*- Getting Options -*-" << std::endl;
111 #endif
112
113     for (i = 1; i < argc; ++i)
114     {
115         if (!strcmp("--parse-trace", argv[i]))
116         {
117             _pSEI->iParseTrace = 1;
118         }
119         else if (!strcmp("--pretty-print", argv[i]))
120         {
121             _pSEI->iPrintAst = 1;
122         }
123         else if (!strcmp("--help", argv[i]))
124         {
125             usage();
126             exit(WELL_DONE);
127         }
128         else if (!strcmp("--AST-trace", argv[i]))
129         {
130             _pSEI->iDumpAst = 1;
131         }
132         else if (!strcmp("--no-exec", argv[i]))
133         {
134             _pSEI->iExecAst = 0;
135         }
136         else if (!strcmp("--context-dump", argv[i]))
137         {
138             _pSEI->iDumpStack = 1;
139         }
140         else if (!strcmp("--timed", argv[i]))
141         {
142             _pSEI->iTimed = 1;
143             ConfigVariable::setTimed(true);
144         }
145         else if (!strcmp("--serialize", argv[i]))
146         {
147             _pSEI->iSerialize = 1;
148             ConfigVariable::setSerialize(true);
149         }
150         else if (!strcmp("--AST-timed", argv[i]))
151         {
152             std::cout << "Timed execution" << std::endl;
153             _pSEI->iAstTimed = 1;
154         }
155         else if (!strcmp("--parse-file", argv[i]))
156         {
157             i++;
158             if (argc >= i)
159             {
160                 _pSEI->pstParseFile = argv[i];
161             }
162         }
163         else if (!strcmp("-quit", argv[i]))
164         {
165             _pSEI->iForceQuit = 1;
166         }
167         else if (!strcmp("-version", argv[i]))
168         {
169             i++;
170             if (argc >= i)
171             {
172                 _pSEI->iShowVersion = 1;
173             }
174         }
175         else if (!strcmp("-f", argv[i]))
176         {
177             i++;
178             if (argc >= i)
179             {
180                 _pSEI->pstFile = argv[i];
181             }
182         }
183         else if (!strcmp("-e", argv[i]))
184         {
185             i++;
186             if (argc >= i)
187             {
188                 _pSEI->pstExec = argv[i];
189             }
190         }
191         else if (!strcmp("-O", argv[i]))
192         {
193             i++;
194             if (argc >= i)
195             {
196                 _pSEI->pstExec = argv[i];
197                 _pSEI->iCodeAction = 0;
198             }
199         }
200         else if (!strcmp("-X", argv[i]))
201         {
202             i++;
203             if (argc >= i)
204             {
205                 _pSEI->pstExec = argv[i];
206                 _pSEI->iCodeAction = 1;
207             }
208         }
209         else if (!strcmp("-P", argv[i]))
210         {
211             i++;
212             if (argc >= i)
213             {
214                 _pSEI->pstExec = argv[i];
215                 _pSEI->iCodeAction = 2;
216             }
217         }
218         else if (!strcmp("-l", argv[i]))
219         {
220             i++;
221             if (argc >= i)
222             {
223                 _pSEI->pstLang = argv[i];
224             }
225         }
226         else if (!strcmp("-nw", argv[i]))
227         {
228             _pSEI->iConsoleMode = 1;
229         }
230         else if (!strcmp("-nwni", argv[i]))
231         {
232             _pSEI->iConsoleMode = 1;
233             _pSEI->iNoJvm = 1;
234         }
235         else if (!strcmp("-ns", argv[i]))
236         {
237             _pSEI->iNoStart = 1;
238         }
239         else if (!strcmp("-nb", argv[i]))
240         {
241             _pSEI->iNoBanner = 0;
242         }
243         else if (!strcmp("--exec-verbose", argv[i]))
244         {
245             _pSEI->iExecVerbose = 1;
246         }
247         else if (!strcmp("--timeout", argv[i]))
248         {
249             i++;
250             if (argc > i)
251             {
252                 char* timeout = argv[i];
253
254                 char* str_end = NULL;
255                 int iTimeoutDelay = strtol(timeout, &str_end, 0);
256
257                 int modifier;
258                 switch (*str_end)
259                 {
260                     case 'd':
261                         modifier = 86400;
262                         break;
263                     case 'h':
264                         modifier = 3600;
265                         break;
266                     case 'm':
267                         modifier = 60;
268                         break;
269                     case 's':
270                     case '\0': // no modifiers
271                         modifier = 1;
272                         break;
273                     default:
274                         std::cerr << "Invalid timeout delay unit: s (for seconds, default), m (for minutes), h (for hours), d (for days) are supported" << std::endl;
275                         exit(EXIT_FAILURE);
276                         break;
277                 }
278
279                 _pSEI->iTimeoutDelay = iTimeoutDelay * modifier;
280             }
281             else
282             {
283                 std::cerr << "Unspecified timeout delay" << std::endl;
284                 exit(EXIT_FAILURE);
285             }
286
287         }
288         else if (!strcmp("-keepconsole", argv[i]))
289         {
290             _pSEI->iKeepConsole = 1;
291         }
292     }
293
294     ConfigVariable::setCommandLineArgs(argc, argv);
295     return 0;
296 }
297
298 extern "C"
299 {
300 #include <stdio.h>
301
302 #ifndef _MSC_VER
303 #include <unistd.h>
304 #endif
305     extern char *getCmdLine(void);
306     extern void ConsolePrintf(const char *);
307 }
308
309 static void TermPrintf(const char *text)
310 {
311     //std::cout << text;
312     printf("%s", text);
313 }
314
315 /*
316 ** -*- MAIN -*-
317 */
318 //#if defined(_WIN32) && !defined(WITHOUT_GUI)
319 //int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLine, int iCmdShow)
320 //#else
321 int main(int argc, char *argv[])
322 //#endif
323 {
324     int iRet = 0;
325
326 #ifdef ENABLE_MPI
327     initScilabMPI();
328 #endif
329
330     ScilabEngineInfo* pSEI = InitScilabEngineInfo();
331 #ifdef WITHOUT_GUI
332     /* Building Scilab-cli-bin. We won't ever had the gui nor the jvm */
333     pSEI->iConsoleMode = 1;
334     pSEI->iNoJvm = 1;
335     setScilabMode(SCILAB_NWNI);
336 #else
337     setScilabMode(SCILAB_STD);
338 #endif
339
340     //#if defined(_WIN32) && !defined(WITHOUT_GUI)
341     //    {
342     //        LPSTR my_argv[256];
343     //        int nArgs = 0;
344     //        LPWSTR *szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
345     //        if (szArglist)
346     //        {
347     //            for (int i = 0; i < nArgs; i++)
348     //            {
349     //                my_argv[i] = wide_string_to_UTF8(szArglist[i]);
350     //            }
351     //            LocalFree(szArglist);
352     //        }
353     //        get_option(nArgs, my_argv, pSEI);
354     //    }
355     //#else
356     get_option(argc, argv, pSEI);
357     //#endif
358
359     // if WITHOUT_GUI is defined
360     // force Terminal IO -> Terminal IO + StartScilabEngine
361
362     // WITHOUT_GUI (All Platform) => Terminal IO + StartScilabEngine
363     // GUI (MacOSX) =>      [no option]     -> Console IO + InitMacOSXEnv
364     //                      | [-nwni]       -> Terminal IO + StartScilabEngine
365     //                      | [-nw]         -> Terminal IO + InitMacOSXEnv
366 #ifndef WITHOUT_GUI
367     if (pSEI->iConsoleMode)
368     {
369         setScilabMode(SCILAB_NW);
370         setScilabInputMethod(&getCmdLine);
371         setScilabOutputMethod(&TermPrintf);
372 #if defined(__APPLE__)
373         if (pSEI->iNoJvm == 0)
374         {
375             return initMacOSXEnv(pSEI);
376         }
377 #endif // !defined(__APPLE__)
378     }
379     else
380     {
381         setScilabMode(SCILAB_STD);
382         setScilabInputMethod(&ConsoleRead);
383         setScilabOutputMethod(&ConsolePrintf);
384
385 #ifdef _MSC_VER
386         if (pSEI->iCodeAction != -1)
387         {
388             //manage calls from explorer ( double click on sce file , ... )
389             char* Cmd = (char*)MALLOC(((PATH_MAX * 2) + 1) * sizeof(char));
390             strcpy(Cmd, "");
391             int ret = CommandByFileExtension(pSEI->pstExec, pSEI->iCodeAction, Cmd);
392
393             if (ret && Cmd[0] != '\0')
394             {
395                 pSEI->pstExec = Cmd; //Cmd must be freed in StartScilabEngine after process.
396             }
397             else
398             {
399                 pSEI->iCodeAction = -1;
400             }
401         }
402 #endif
403
404 #if defined(__APPLE__)
405         return initMacOSXEnv(pSEI);
406 #endif // !defined(__APPLE__)
407     }
408 #else
409     setScilabMode(SCILAB_NWNI);
410     setScilabInputMethod(&getCmdLine);
411     setScilabOutputMethod(&TermPrintf);
412 #endif // defined(WITHOUT_GUI)
413
414 #ifdef _MSC_VER
415     /* if file descriptor returned is -2 stdin is not associated with an input stream */
416     /* example : echo plot3d | scilex -nw -e */
417     if (!isatty(_fileno(stdin)) && (_fileno(stdin) != -2))
418 #else
419     if (!isatty(fileno(stdin)))
420 #endif
421     {
422         // We are in a pipe
423         setScilabInputMethod(&getPipeLine);
424     }
425
426     if (pSEI->iShowVersion == 1)
427     {
428         disp_scilab_version();
429         exit(0);
430     }
431
432     int val = setjmp(ScilabJmpEnv);
433     if (!val)
434     {
435         iRet = StartScilabEngine(pSEI);
436         if (iRet == 0)
437         {
438             iRet = RunScilabEngine(pSEI);
439         }
440
441         StopScilabEngine(pSEI);
442         FREE(pSEI);
443         return iRet;
444     }
445     else
446     {
447         // We probably had a segfault so print error
448         std::wcerr << getLastErrorMessage() << std::endl;
449         return val;
450     }
451 }
452