1 /***************************************************************************
2 gdl.cpp - main program
3 -------------------
4 begin : Wed Apr 18 16:58:14 JST 2001
5 copyright : (C) 2002-2006 by Marc Schellens
6 email : m_schellens@users.sourceforge.net
7 ***************************************************************************/
8
9 /***************************************************************************
10 * *
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
15 * *
16 ***************************************************************************/
17
18 #include "includefirst.hpp"
19
20 // #ifndef VERSION
21 // #define VERSION "0.9"
22 // #endif
23
24 #include <string>
25 #include <csignal>
26 #include <cstdlib>
27 #if defined(_MSC_VER) || defined (_WIN32)
28 #include <io.h>
29 #define isatty _isatty
30 #else
31 #include <unistd.h> // isatty
32 #endif
33 #include <climits> // PATH_MAX
34 //patch #90
35 #ifndef PATH_MAX
36 #define PATH_MAX 4096
37 #endif
38 #ifndef _WIN32
39 #include <sys/resource.h> //rlimits to augment stack size (needed fot DICOM objects)
40 #endif
41
42 //#include <fenv.h>
43
44 #include "str.hpp"
45 #include "dinterpreter.hpp"
46 #include "terminfo.hpp"
47 #include "sigfpehandler.hpp"
48 #include "gdleventhandler.hpp"
49
50 #ifdef _OPENMP
51 #include <omp.h>
52 #endif
53
54 #ifdef USE_MPI
55 # include "mpi.h"
56 #endif
57
58 #ifdef HAVE_LOCALE_H
59 # include <locale.h>
60 #endif
61
62 // GDLDATADIR
63 #include "config.h"
64
65 //initialize wxWidgets system
66 #ifdef HAVE_LIBWXWIDGETS
67 #include "gdlwidget.hpp"
68 #ifndef __WXMAC__
69 wxIMPLEMENT_APP_NO_MAIN( wxAppGDL);
70 #else
71 wxIMPLEMENT_APP_NO_MAIN( wxApp);
72 #endif
73 #endif
74
75 using namespace std;
76
StartupMessage()77 static void StartupMessage()
78 {
79 cerr << " GDL - GNU Data Language, Version " << VERSION << endl;
80 cerr << "- For basic information type HELP,/INFO" << endl;
81 }
82
83 void LibInit(); // defined in libinit.cpp
84
85 namespace lib {
86 void SetGDLGenericGSLErrorHandler(); // defined in gsl_fun.cpp
87 }
88
89 // Nodar and Alain, May 2013: we try to optimize the value for CpuTPOOL_NTHREADS
90 // if *valid* external value for OMP_NUM_THREADS (0 < OMP_NUM_THREADS < nb_cores) we used it
91 // if not provided, we try to estimate a value looking at the average load
92
InitOpenMP()93 void InitOpenMP() {
94 #ifdef _OPENMP
95 int suggested_num_threads, omp_num_core;
96 suggested_num_threads=get_suggested_omp_num_threads();
97 omp_num_core=omp_get_num_procs();
98
99 // cerr << "estimated Threads :" << suggested_num_threads << endl;
100
101 // we update iff needed (by default, "omp_num_threads" is initialiazed to "omp_num_core"
102 if ((suggested_num_threads > 0) && (suggested_num_threads < omp_num_core)) {
103
104 // update of !cpu.TPOOL_NTHREADS
105 DStructGDL* cpu = SysVar::Cpu();
106 static unsigned NTHREADSTag = cpu->Desc()->TagIndex( "TPOOL_NTHREADS");
107 (*static_cast<DLongGDL*>( cpu->GetTag( NTHREADSTag, 0)))[0] =suggested_num_threads;
108
109 // effective global change of num of treads using omp_set_num_threads()
110 CpuTPOOL_NTHREADS=suggested_num_threads;
111 omp_set_num_threads(suggested_num_threads);
112 } else {
113 CpuTPOOL_NTHREADS=omp_get_num_procs();
114 omp_set_num_threads(CpuTPOOL_NTHREADS);
115 }
116 // cout << CpuTPOOL_NTHREADS <<endl;
117 #endif
118 }
119
AtExit()120 void AtExit()
121 {
122 //this function probably cleans otherwise cleaned objets and should be called only for debugging purposes.
123 cerr << "Using AtExit() for debugging" << endl;
124 cerr << flush; cout << flush; clog << flush;
125 // clean up everything
126 // (for debugging memory leaks)
127 ResetObjects();
128 PurgeContainer(libFunList);
129 PurgeContainer(libProList);
130 }
131
132 #ifndef _WIN32
GDLSetLimits()133 void GDLSetLimits()
134 {
135 #define GDL_PREFERED_STACKSIZE 20480000 //20000*1024 OK for the time being
136 struct rlimit* gdlstack=new struct rlimit;
137 int r=getrlimit(RLIMIT_STACK,gdlstack);
138 // cerr <<"Current rlimit = "<<gdlstack->rlim_cur<<endl;
139 // cerr<<"Max rlimit = "<< gdlstack->rlim_max<<endl;
140 if (gdlstack->rlim_cur >= GDL_PREFERED_STACKSIZE ) return; //the bigger the better.
141 if (gdlstack->rlim_max > GDL_PREFERED_STACKSIZE ) gdlstack->rlim_cur=GDL_PREFERED_STACKSIZE; //not completely satisfactory.
142 r=setrlimit(RLIMIT_STACK,gdlstack);
143 }
144 #endif
145
InitGDL()146 void InitGDL()
147 {
148 #ifndef _WIN32
149 GDLSetLimits();
150 #endif
151
152 //rl_event_hook (defined below) uses a wxwidgets event loop, so wxWidgets must be started
153 #ifdef HAVE_LIBWXWIDGETS
154 if (useWxWidgets) GDLWidget::Init();
155 #endif
156
157 #if defined(HAVE_LIBREADLINE)
158 // initialize readline (own version - not pythons one)
159 // in includefirst.hpp readline is disabled for python_module
160 rl_initialize();
161 char rlName[] = "GDL";
162 rl_readline_name = rlName;
163 //Our handler takes too long
164 //when editing the command line with ARROW keys. (bug 562). (used also in dinterpreted.cpp )
165 //but... without it we have no graphics event handler! FIXME!!!
166 rl_event_hook = GDLEventHandler;
167 #endif
168
169 // ncurses blurs the output, initialize TermWidth here
170 TermWidth();
171
172 // initializations
173 InitObjects();
174
175 // init library functions
176 LibInit();
177
178 // ensuring we work in the C locale (needs to be called after InitObjects and LibInit!!!
179 // as some code there calls setlocale as well, e.g. MagickInit)
180 #ifdef HAVE_LOCALE_H
181 setlocale(LC_ALL, "C");
182 #endif
183
184 // turn on all floating point exceptions
185 // feenableexcept(FE_DIVBYZERO | FE_INVALID | FE_OVERFLOW );
186
187 signal(SIGINT,ControlCHandler);
188 signal(SIGFPE,SigFPEHandler);
189
190 lib::SetGDLGenericGSLErrorHandler();
191 }
192
193 static bool trace_me;
194
195 // SA: for use in COMMAND_LINE_ARGS()
196 namespace lib {
197 extern std::vector<std::string> command_line_args;
198 #ifdef _WIN32
199 bool posixpaths;
200 #endif
gdlarg_present(const char * s)201 bool gdlarg_present(const char* s)
202 {
203 for (size_t i = 0; i < command_line_args.size(); i++)
204 if( command_line_args[i] == s ) return true;
205 return false;
206 }
trace_arg()207 bool trace_arg()
208 {
209 for (size_t i = 0; i < command_line_args.size(); i++)
210 if( command_line_args[i] == "trace" ) return true;
211 return false;
212 }
213
214 }
215
main(int argc,char * argv[])216 int main(int argc, char *argv[])
217 {
218 #if GDL_DEBUG
219 if( atexit( AtExit) != 0) cerr << "atexit registration failed." << endl;
220 #endif
221 // indicates if the user wants to see the welcome message
222 bool quiet = false;
223 bool gdlde = false;
224
225 // keeps a list of files to be executed after the startup file
226 // and before entering the interactive mode
227 vector<string> batch_files;
228 string statement;
229 string pretendRelease;
230 bool strict_syntax=false;
231 bool syntaxOptionSet=false;
232
233 bool force_no_wxgraphics = false;
234 usePlatformDeviceName=false;
235 forceWxWidgetsUglyFonts = false;
236 useDSFMTAcceleration = true;
237 iAmANotebook=false; //option --notebook
238 #ifdef HAVE_LIBWXWIDGETS
239 useWxWidgets=true;
240 #else
241 useWxWidgets=false;
242 #endif
243 #ifdef _WIN32
244 lib::posixpaths = false;
245 #endif
246 for( SizeT a=1; a< argc; ++a)
247 {
248 if( string( argv[a]) == "--help" | string( argv[a]) == "-h") {
249 cerr << "Usage: gdl [ OPTIONS ] [ batch_file ... ]" << endl;
250 cerr << "Start the GDL interpreter (incremental compiler)" << endl;
251 cerr << endl;
252 cerr << "GDL options:" << endl;
253 cerr << " --help (-h) display this message" << endl;
254 cerr << " --version (-V, -v) show version information" << endl;
255 cerr << " --fakerelease X.y pretend that !VERSION.RELEASE is X.y" << endl;
256 cerr << " --fussy implies that procedures adhere with modern IDL, where \"()\" are for functions and \"[]\" are for arrays." << endl;
257 cerr << " This speeds up (sometimes terribly) compilation but choke on every use of \"()\" with arrays." << endl;
258 cerr << " Conversion of procedures to modern IDL can be done with D. Landsman's idlv4_to_v5 procedure." << endl;
259 cerr << " Use enviromnment variable \"GDL_IS_FUSSY\" to set up permanently this feature." << endl;
260 cerr << " --sloppy Sets the traditional (default) compiling option where \"()\" can be used both with functions and arrays." << endl;
261 cerr << " Needed to counteract temporarily the effect of the enviromnment variable \"GDL_IS_FUSSY\"." << endl;
262 cerr << " --MAC Graphic device will be called 'MAC' on MacOSX. (default: 'X')" << endl;
263 cerr << " --no-use-wx Tells GDL not to use WxWidgets graphics." << endl;
264 cerr << " Also enabled by setting the environment variable GDL_DISABLE_WX_PLOTS to a non-null value." << endl;
265 cerr << " --notebook Force SVG-only device, used only when GDL is a Python Notebook Kernel." << endl;
266 cerr << " --widget-compat Tells GDL to use a default (rather ugly) fixed pitch font for compatiblity with IDL widgets." << endl;
267 cerr << " Also enabled by setting the environment variable GDL_WIDGET_COMPAT to a non-null value." << endl;
268 cerr << " Using this option may render some historical widgets unworkable (as they are based on fixed sizes)." << endl;
269 cerr << " --no-dSFMT Tells GDL not to use double precision SIMD oriented Fast Mersenne Twister(dSFMT) for random doubles." << endl;
270 cerr << " Also disable by setting the environment variable GDL_NO_DSFMT to a non-null value." << endl;
271 #ifdef _WIN32
272 cerr << " --posix (Windows only): paths will be posix paths (experimental)." << endl;
273 #endif
274 cerr << endl;
275 cerr << "IDL-compatible options:" << endl;
276 cerr << " -arg value tells COMMAND_LINE_ARGS() to report" << endl;
277 cerr << " the following argument (may be specified more than once)" << endl;
278 cerr << " -args ... tells COMMAND_LINE_ARGS() to report " << endl;
279 cerr << " all following arguments" << endl;
280 cerr << " -e value execute given statement and exit (last occurrence taken into account only," << endl;
281 cerr << " executed after startup file, may not be specified together with batch files)" << endl;
282 cerr << " -pref=/path/to/params_file loads the specified preference file" << endl;
283 cerr << " -quiet (--quiet, -q) suppress welcome messages" << endl;
284 cerr << endl;
285 cerr << "Homepage: https://gnudatalanguage.github.io" << endl;
286 return 0;
287 }
288 else if (string(argv[a])=="--version" | string(argv[a])=="-v" | string(argv[a])=="-V")
289 {
290 cerr << "GDL - GNU Data Language, Version " << VERSION << endl;
291 return 0;
292 }
293 else if( string( argv[a]) == "-arg")
294 {
295 if (a == argc - 1)
296 {
297 cerr << "gdl: -arg must be followed by a user argument." << endl;
298 return 0;
299 }
300 lib::command_line_args.push_back(string(argv[++a]));
301 }
302 else if( string( argv[a]) == "-args")
303 {
304 for (int i = a + 1; i < argc; i++) lib::command_line_args.push_back(string(argv[i]));
305 break;
306 }
307 else if (string(argv[a])=="-quiet" | string(argv[a])=="--quiet" | string(argv[a])=="-q")
308 {
309 quiet = true;
310 }
311 else if (string(argv[a]).find("-pref=") ==0)
312 {
313 cerr << "This option is not operational now" << endl;
314 string tmp;
315 tmp=string(argv[a]);
316 string params_file(tmp.begin()+6,tmp.end());
317 //cerr << "(not ready) to be processed file >>" << params_file << "<<" << endl;
318 WordExp(params_file);
319 ifstream file_params;
320 file_params.open(params_file.c_str());
321 if (!file_params.is_open()) {
322 cerr << "Error opening file. File: "<< params_file << endl;
323 cerr << "No such file or directory"<< endl;
324 return 0;
325 }
326 file_params.close();
327 }
328 else if (string(argv[a]) == "-e")
329 {
330 if (a == argc - 1)
331 {
332 cerr << "gdl: -e must be followed by a user argument." << endl;
333 return 0;
334 }
335 statement = string(argv[++a]);
336 statement.append("\n"); // apparently not needed but this way the empty-string case is covered
337 // (e.g. $ gdl -e "")
338 }
339 else if (
340 string(argv[a]) == "-demo" ||
341 string(argv[a]) == "-em" ||
342 string(argv[a]) == "-novm" ||
343 string(argv[a]) == "-queue" ||
344 string(argv[a]) == "-rt" ||
345 string(argv[a]) == "-ulicense" ||
346 string(argv[a]) == "-vm"
347 )
348 cerr << argv[0] << ": " << argv[a] << " option ignored." << endl;
349 else if (string(argv[a]) == "-gdlde")
350 {
351 gdlde = true;
352 }
353 else if (string(argv[a]) == "--fussy")
354 {
355 strict_syntax = true;
356 syntaxOptionSet = true;
357 }
358 else if (string(argv[a]) == "--sloppy")
359 {
360 strict_syntax = false;
361 syntaxOptionSet = true;
362 }
363 else if (string(argv[a]) == "--no-dSFMT")
364 {
365 useDSFMTAcceleration = false;
366 }
367 else if (string(argv[a]) == "--widget-compat")
368 {
369 forceWxWidgetsUglyFonts = true;
370 }
371 #ifdef _WIN32
372 else if (string(argv[a]) == "--posix") lib::posixpaths=true;
373 #endif
374 else if (string(argv[a]) == "--MAC")
375 {
376 usePlatformDeviceName = true;
377 }
378 else if (string(argv[a]) == "--no-use-wx")
379 {
380 force_no_wxgraphics = true;
381 }
382 else if (string(argv[a]) == "--notebook")
383 {
384 iAmANotebook = true;
385 }
386 else if (string(argv[a]) == "--fakerelease")
387 {
388 if (a == argc - 1)
389 {
390 cerr << "gdl: --fakerelease must be followed by a string argument like \"6.4\"" << endl;
391 return 0;
392 }
393 pretendRelease = string(argv[++a]);
394 }
395 else if (*argv[a] == '-')
396 {
397 cerr << argv[0] << ": " << argv[a] << " option not recognized." << endl;
398 return 0;
399 }
400 else
401 {
402 batch_files.push_back(argv[a]);
403 }
404 }
405
406 if (0&&statement.length() > 0 && batch_files.size() > 0)
407 {
408 cerr << argv[0] << ": " << "-e option cannot be specified with batch files" << endl;
409 return 0;
410 }
411
412 //before InitGDL() as InitGDL() starts graphic!
413
414 #ifdef HAVE_LIBWXWIDGETS
415 //tells if wxWidgets is working (may not be the case if DISPLAY is not set) by setting useWxWidgets to false
416 useWxWidgets=GDLWidget::InitWx();
417 // default is wx Graphics...
418 useWxWidgetsForGraphics=useWxWidgets;
419 #else
420 useWxWidgetsForGraphics=false;
421 #endif
422 #ifdef HAVE_X
423 // unless we have X and want to see it for plots
424 std::string disableWXPlots=GetEnvString("GDL_DISABLE_WX_PLOTS");
425 if ( disableWXPlots.length() > 0) useWxWidgetsForGraphics=false; //not necessary "YES".
426 if (force_no_wxgraphics) useWxWidgetsForGraphics=false; //this has the last answer, whatever the setup.
427 #endif
428 std::string doUseUglyFonts=GetEnvString("GDL_WIDGETS_COMPAT");
429 if ( doUseUglyFonts.length() > 0) forceWxWidgetsUglyFonts=true;
430
431 InitGDL();
432
433 // must be after !cpu initialisation
434 InitOpenMP();
435
436 if (gdlde || (isatty(0) && !quiet)) StartupMessage();
437
438 // instantiate the interpreter
439 DInterpreter interpreter;
440
441 string gdlPath=GetEnvString("GDL_PATH");
442 if( gdlPath == "") gdlPath=GetEnvString("IDL_PATH");
443 if( gdlPath == "")
444 {
445 gdlPath = "+" GDLDATADIR "/lib";
446 if (gdlde || (isatty(0) && !quiet)) cerr <<
447 "- Default library routine search path used (GDL_PATH/IDL_PATH env. var. not set): " GDLDATADIR "/lib" << endl;
448 }
449 if (useWxWidgetsForGraphics) {
450 if (gdlde || (isatty(0) && !quiet)) cerr << "- Using WxWidgets as graphics library (windows and widgets)." << endl;
451 }
452
453
454 if (useDSFMTAcceleration && (GetEnvString("GDL_NO_DSFMT").length() > 0)) useDSFMTAcceleration=false;
455
456 //report in !GDL status struct
457 DStructGDL* gdlconfig = SysVar::GDLconfig();
458 unsigned DSFMTTag= gdlconfig->Desc()->TagIndex("GDL_USE_DSFMT");
459 (*static_cast<DByteGDL*> (gdlconfig->GetTag(DSFMTTag, 0)))[0]=useDSFMTAcceleration;
460
461 //same for use of wxwidgets
462 unsigned useWXTAG= gdlconfig->Desc()->TagIndex("GDL_USE_WX");
463 (*static_cast<DByteGDL*> (gdlconfig->GetTag(useWXTAG, 0)))[0]=useWxWidgetsForGraphics;
464
465 SysVar::SetGDLPath( gdlPath); //probably duplicate with the one in initobjects!
466
467 if (!pretendRelease.empty()) SysVar::SetFakeRelease(pretendRelease);
468 //fussyness setup and change if switch at start
469 if (syntaxOptionSet) { //take it no matters any env. var.
470 if (strict_syntax == true) SetStrict(true);
471 } else {
472 if (GetEnvString("GDL_IS_FUSSY").size()> 0) SetStrict(true);
473 }
474
475
476 string startup=GetEnvString("GDL_STARTUP");
477 if( startup == "") startup=GetEnvString("IDL_STARTUP");
478 if( startup == "")
479 {
480 if (gdlde || (isatty(0) && !quiet)) cerr <<
481 "- No startup file read (GDL_STARTUP/IDL_STARTUP env. var. not set). " << endl;
482 }
483
484 if (gdlde || (isatty(0) && !quiet))
485 {
486 cerr << "- Please report bugs, feature or help requests and patches at: https://github.com/gnudatalanguage/gdl" << endl << endl;
487 }
488 // else
489 // {
490 // // if path not given, add users home
491 // if( !PathGiven(startup))
492 // {
493 // string home=GetEnvString("HOME");
494 // if( home != "")
495 // {
496 // AppendIfNeeded(home,"/");
497 // startup=home+startup;
498 // }
499 // }
500 // }
501
502 #ifdef USE_MPI
503 {
504 // warning the user if MPI changes the working directory of GDL
505 char wd1[PATH_MAX], wd2[PATH_MAX];
506 char *wd1p, *wd2p;
507 wd1p = getcwd(wd1, PATH_MAX);
508 MPI_Init(&argc, &argv);
509 wd2p = getcwd(wd2, PATH_MAX);
510 if (strcmp(wd1, wd2) != 0)
511 cerr << "Warning: MPI has changed the working directory of GDL!" << endl;
512 }
513 int myrank = 0;
514 MPI_Comm_rank( MPI_COMM_WORLD, &myrank);
515 int size;
516 MPI_Comm_size(MPI_COMM_WORLD, &size);
517
518 int tag = 0;
519 char* mpi_procedure = getenv("GDL_MPI");
520 if (myrank == 0 && mpi_procedure != NULL){
521 for( SizeT i = 0; i < size; i++)
522 MPI_Send(mpi_procedure, strlen(mpi_procedure)+1, MPI_CHAR, i,
523 tag, MPI_COMM_WORLD);
524 }
525 #endif // USE_MPI
526
527 interpreter.InterpreterLoop( startup, batch_files, statement);
528
529 return 0;
530 }
531