0032308: Configuration - make Xlib dependency optional
[occt.git] / src / Draw / Draw_BasicCommands.cxx
1 // Created on: 1995-02-23
2 // Created by: Remi LEQUETTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17
18 #include <Draw.hxx>
19 #include <Draw_Appli.hxx>
20 #include <Draw_Chronometer.hxx>
21 #include <Draw_Drawable3D.hxx>
22 #include <Draw_Printer.hxx>
23 #include <Draw_ProgressIndicator.hxx>
24 #include <Message.hxx>
25 #include <Message_Messenger.hxx>
26 #include <Message_PrinterOStream.hxx>
27 #include <OSD.hxx>
28 #include <OSD_Chronometer.hxx>
29 #include <OSD_Environment.hxx>
30 #include <OSD_Exception_CTRL_BREAK.hxx>
31 #include <OSD_MAllocHook.hxx>
32 #include <OSD_MemInfo.hxx>
33 #include <OSD_Parallel.hxx>
34 #include <OSD_ThreadPool.hxx>
35 #include <Standard_Macro.hxx>
36 #include <Standard_SStream.hxx>
37 #include <Standard_Stream.hxx>
38 #include <Standard_Version.hxx>
39 #include <TCollection_AsciiString.hxx>
40
41 #include <OSD_PerfMeter.h>
42 #ifdef _WIN32
43
44 #include <windows.h>
45 #include <winbase.h>
46 #include <process.h>
47 #include <stdio.h>
48 #include <stdlib.h>
49 #include <time.h>
50 #include <limits>
51
52 #define RLIM_INFINITY   0x7fffffff
53
54 static clock_t CPU_CURRENT; // cpu time already used at last
55                             // cpulimit call. (sec.) 
56 #else /* _WIN32 */
57
58 #include <sys/resource.h>
59 #include <signal.h>
60 #include <unistd.h>
61
62 #if defined (__hpux) || defined ( HPUX )
63 #define RLIM_INFINITY   0x7fffffff
64 #define RLIMIT_CPU      0
65 #endif
66
67 #endif /* _WIN32 */
68
69 extern Standard_Boolean Draw_Batch;
70
71 static clock_t CPU_LIMIT;   // Cpu_limit in Sec.
72 static OSD_Timer aTimer;
73
74 //=======================================================================
75 // chronom
76 //=======================================================================
77
78 extern Standard_Boolean Draw_Chrono;
79
80 static Standard_Integer chronom(Draw_Interpretor& di,
81                                 Standard_Integer n,const char** a)
82 {
83   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
84     if (n == 1)
85       Draw_Chrono = !Draw_Chrono;
86     else
87       Draw_Chrono = (*a[1] == '1');
88
89     if (Draw_Chrono) di << "Chronometers activated.\n";
90     else di << "Chronometers deactivated.\n";
91   }
92   else {
93     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
94     Handle(Draw_Chronometer) C;
95     if (!D.IsNull()) {
96       C = Handle(Draw_Chronometer)::DownCast(D);
97     }
98     if (C.IsNull()) {
99       C = new Draw_Chronometer();
100     Draw::Set(a[1],C,Standard_False);
101     }
102     if (n <= 2) {
103       C->Timer().Reset();
104     }
105     else {
106       for (Standard_Integer anIter = 2; anIter < n; ++anIter)
107       {
108         TCollection_AsciiString anArg (a[anIter]);
109         anArg.LowerCase();
110
111         if (anArg == "reset")
112         {
113           C->Timer().Reset();
114         }
115         else if (anArg == "restart")
116         {
117           C->Timer().Restart();
118         }
119         else if (anArg == "start")
120         {
121           C->Timer().Start();
122         }
123         else if (anArg == "stop")
124         {
125           C->Timer().Stop();
126         }
127         else if (anArg == "show")
128         {
129           C->Timer().Show();
130         }
131         else if (anArg == "counter")
132         {
133           Standard_Real aSeconds,aCPUtime;
134           Standard_Integer aMinutes, aHours;
135           C->Timer().Show(aSeconds,aMinutes,aHours,aCPUtime);
136           std::cout << "COUNTER " << a[++anIter] << ": " << aCPUtime << "\n";
137         }
138         else
139         {
140           std::cerr << "Unknown argument '" << a[anIter] << "'!\n";
141         }
142       }
143     }
144   }
145   return 0;
146 }
147
148 static Standard_Integer dchronom(Draw_Interpretor& theDI,
149                                  Standard_Integer n,const char** a)
150 {
151   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
152     if (n == 1)
153       Draw_Chrono = !Draw_Chrono;
154     else
155       Draw_Chrono = (*a[1] == '1');
156
157     if (Draw_Chrono) theDI << "Chronometers activated.\n";
158     else theDI << "Chronometers deactivated.\n";
159   }
160   else {
161     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
162     Handle(Draw_Chronometer) C;
163     if (!D.IsNull()) {
164       C = Handle(Draw_Chronometer)::DownCast(D);
165     }
166     if (C.IsNull()) {
167       C = new Draw_Chronometer();
168       Draw::Set(a[1],C,Standard_False);
169     }
170     if (n <= 2) {
171       C->Timer().Reset();
172     }
173     else {
174       for (Standard_Integer anIter = 2; anIter < n; ++anIter)
175       {
176         TCollection_AsciiString anArg (a[anIter]);
177         anArg.LowerCase();
178
179         if (anArg == "reset")
180         {
181           C->Timer().Reset();
182         }
183         else if (anArg == "restart")
184         {
185           C->Timer().Restart();
186         }
187         else if (anArg == "start")
188         {
189           C->Timer().Start();
190         }
191         else if (anArg == "stop")
192         {
193           C->Timer().Stop();
194         }
195         else if (anArg == "show")
196         {
197           Standard_SStream ss;
198           C->Timer().Show(ss);
199           theDI << ss;
200         }
201         else if (anArg == "counter")
202         {
203           Standard_Real aSeconds,aCPUtime;
204           Standard_Integer aMinutes, aHours;
205           C->Timer().Show(aSeconds,aMinutes,aHours,aCPUtime);
206           theDI << "COUNTER " << a[++anIter] << ": " << aCPUtime << "\n";
207         }
208         else
209         {
210           theDI << "Unknown argument '" << a[anIter] << "'!\n";
211         }
212       }
213     }
214   }
215   return 0;
216 }
217
218
219
220 //=======================================================================
221 //function : ifbatch
222 //purpose  : 
223 //=======================================================================
224
225 static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
226 {
227   if (Draw_Batch)
228     DI << "1";
229   else
230     DI << "0";
231   
232   return 0;
233 }
234
235 //=======================================================================
236 //function : spy
237 //purpose  : 
238 //=======================================================================
239
240 extern Standard_Boolean Draw_Spying;
241 extern std::filebuf Draw_Spyfile;
242
243 static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
244 {
245   if (Draw_Spying) 
246     Draw_Spyfile.close();
247   Draw_Spying = Standard_False;
248   if (n > 1) {
249     if (!Draw_Spyfile.open(a[1],std::ios::out)) {
250       di << "Cannot open "<<a[1]<<" for writing\n";
251       return 1;
252     }
253     Draw_Spying = Standard_True;
254   }
255   return 0;
256 }
257
258 static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
259 {
260   if (n != 2 && n != 3)
261   {
262     Message::SendFail() << "Enable or disable logging: " << a[0] << " {on|off}\n"
263                         << "Reset log: " << a[0] << " reset\n"
264                         << "Get log content: " << a[0] << " get";
265     return 1;
266   }
267
268   if (! strcmp (a[1], "on") && n == 2)
269   {
270     di.SetDoLog (Standard_True);
271 //    di.Log() << "dlog on" << std::endl; // for symmetry
272   }
273   else if (! strcmp (a[1], "off") && n == 2)
274   {
275     di.SetDoLog (Standard_False);
276   }
277   else if (! strcmp (a[1], "reset") && n == 2)
278   {
279     di.ResetLog();
280   }
281   else if (! strcmp (a[1], "get") && n == 2)
282   {
283     di << di.GetLog();
284   }
285   else if (! strcmp (a[1], "add") && n == 3)
286   {
287     di.AddLog (a[2]);
288     di.AddLog ("\n");
289   }
290   else if (! strcmp (a[1], "status") && n == 2)
291   {
292     di << (di.GetDoLog() ? "on" : "off");
293   }
294   else {
295     Message::SendFail() << "Unrecognized option(s): " << a[1];
296     return 1;
297   }
298   return 0;
299 }
300
301 static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
302 {
303   if (n != 2)
304   {
305     Message::SendFail() << "Enable or disable echoing: " << a[0] << " {on|off}";
306     return 1;
307   }
308
309   if (! strcmp (a[1], "on"))
310   {
311     di.SetDoEcho (Standard_True);
312   }
313   else if (! strcmp (a[1], "off"))
314   {
315     di.SetDoEcho (Standard_False);
316   }
317   else {
318     Message::SendFail() << "Unrecognized option: " << a[1];
319     return 1;
320   }
321   return 0;
322 }
323
324 static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**)
325 {
326   try {
327     OSD::ControlBreak();
328   }
329   catch (OSD_Exception_CTRL_BREAK const&) {
330     di << "User pressed Control-Break";
331     return 1; // Tcl exception
332   }
333
334   return 0;
335 }
336
337 static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**)
338 {
339   // print OCCT version and OCCTY-specific macros used
340   di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n";
341 #ifdef OCCT_DEBUG
342   di << "Extended debug mode\n";
343 #elif defined(_DEBUG)
344   di << "Debug mode\n";
345 #endif
346 #ifdef HAVE_TK
347   di << "Tk enabled (HAVE_TK)\n";
348 #else
349   di << "Tk disabled\n";
350 #endif
351 #ifdef HAVE_XLIB
352   di << "Xlib enabled (HAVE_XLIB)\n";
353 #elif !defined(_WIN32)
354   di << "Xlib disabled\n";
355 #endif
356 #ifdef HAVE_TBB
357   di << "TBB enabled (HAVE_TBB)\n";
358 #else 
359   di << "TBB disabled\n";
360 #endif
361 #ifdef HAVE_FREETYPE
362   di << "FreeType enabled (HAVE_FREETYPE)\n";
363 #else
364   di << "FreeType disabled\n";
365 #endif
366 #ifdef HAVE_FREEIMAGE
367   di << "FreeImage enabled (HAVE_FREEIMAGE)\n";
368 #else
369   di << "FreeImage disabled\n";
370 #endif
371 #ifdef HAVE_FFMPEG
372   di << "FFmpeg enabled (HAVE_FFMPEG)\n";
373 #else
374   di << "FFmpeg disabled\n";
375 #endif
376 #ifdef HAVE_OPENGL_EXT
377   di << "OpenGL: enabled (HAVE_OPENGL_EXT)\n";
378 #endif
379 #ifdef HAVE_GLES2_EXT
380   di << "OpenGL ES: enabled (HAVE_GLES2_EXT)\n";
381 #endif
382 #ifdef HAVE_OPENVR
383   di << "OpenVR enabled (HAVE_OPENVR)\n";
384 #else
385   di << "OpenVR disabled\n";
386 #endif
387 #ifdef HAVE_RAPIDJSON
388   di << "RapidJSON enabled (HAVE_RAPIDJSON)\n";
389 #else
390   di << "RapidJSON disabled\n";
391 #endif
392 #ifdef HAVE_VTK
393   di << "VTK enabled (HAVE_VTK)\n";
394 #else
395   di << "VTK disabled\n";
396 #endif
397 #ifdef No_Exception
398   di << "Exceptions disabled (No_Exception)\n";
399 #else
400   di << "Exceptions enabled\n";
401 #endif
402
403   // check compiler, OS, etc. using pre-processor macros provided by compiler
404   // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/
405   // note that only modern compilers that are known to be used for OCCT are recognized
406
407   // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER
408 #if defined(__INTEL_COMPILER)
409   di << "Compiler: Intel " << __INTEL_COMPILER << "\n";
410 #elif defined(__BORLANDC__)
411   di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n";
412 #elif defined(__clang__)
413   di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n";
414 #elif defined(__SUNPRO_C)
415   di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n";
416 #elif defined(_MSC_VER)
417   #if _MSC_VER < 1900
418     di << "Compiler: MS Visual C++ " << (int)(_MSC_VER/100-6) << "." << (int)((_MSC_VER/10)-60-10*(int)(_MSC_VER/100-6)) << " (_MSC_FULL_VER = " << _MSC_FULL_VER << ")\n";
419   #else
420     di << "Compiler: MS Visual C++ " << (int)(_MSC_VER/100-5) << "." << (int)((_MSC_VER/10)-50-10*(int)(_MSC_VER/100-5)) << " (_MSC_FULL_VER = " << _MSC_FULL_VER << ")\n";
421   #endif
422 #elif defined(__GNUC__)
423   di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
424 #else
425   di << "Compiler: unrecognized\n";
426 #endif
427
428   // Cygwin and MinGW specifics
429 #if defined(__CYGWIN__)
430   di << "Cygwin\n";
431 #endif
432 #if defined(__MINGW64__)
433   di << "MinGW 64 " << __MINGW64_VERSION_MAJOR << "." << __MINGW64_VERSION_MINOR << "\n";
434 #elif defined(__MINGW32__)
435   di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
436 #endif 
437
438   // architecture
439 #if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
440   di << "Architecture: AMD64\n";
441 #elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
442   di << "Architecture: Intel x86\n";
443 #elif defined(_M_IA64) || defined(__ia64__)
444   di << "Architecture: Intel Itanium (IA 64)\n";
445 #elif defined(__sparc__) || defined(__sparc)
446   di << "Architecture: SPARC\n";
447 #elif defined(__aarch64__) && defined(__LP64__)
448   di << "Architecture: ARM 64-bit\n";
449 #elif defined(__arm__) || defined(__arm64__)
450   #if defined(__LP64__)
451   di << "Architecture: ARM 64-bit\n";
452   #else
453   di << "Architecture: ARM 32-bit\n";
454   #endif
455 #else
456   di << "Architecture: unrecognized\n";
457 #endif
458
459   // OS
460 #if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
461   di << "OS: Windows\n";
462 #elif defined(__APPLE__) || defined(__MACH__)
463   di << "OS: Mac OS X\n";
464 #elif defined(__sun) 
465   di << "OS: SUN Solaris\n";
466 #elif defined(__ANDROID__) /* must be before Linux */
467   #include <android/api-level.h>
468   di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
469 #elif defined(__QNXNTO__)
470   di << "OS: QNX Neutrino\n";
471 #elif defined(__QNX__)
472   di << "OS: QNX\n";
473 #elif defined(__linux__)
474   di << "OS: Linux\n";
475 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
476   #include <sys/param.h>
477   di << "OS: BSD (BSD = " << BSD << ")\n";
478 #else
479   di << "OS: unrecognized\n";
480 #endif
481
482   return 0;
483 }
484
485 //=======================================================================
486 //function : wait
487 //purpose  : 
488 //=======================================================================
489
490 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
491 {
492   Standard_Integer w = 10;
493   if (n > 1)
494     w = Draw::Atoi(a[1]);
495   time_t ct = time(NULL) + w;
496   while (time(NULL) < ct) {};
497   return 0;
498 }
499
500 //=======================================================================
501 //function : cpulimit
502 //purpose  : 
503 //=======================================================================
504 #ifdef _WIN32
505 static unsigned int __stdcall CpuFunc (void * /*param*/)
506 {
507   clock_t anElapCurrent;
508   clock_t aCurrent;
509
510   for(;;)
511   {
512     Sleep (5);
513     Standard_Real anUserSeconds, aSystemSeconds;
514     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
515     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
516     anElapCurrent = clock_t(aTimer.ElapsedTime());
517     
518     if (CPU_LIMIT > 0 && (aCurrent - CPU_CURRENT) >= CPU_LIMIT)
519     {
520       aTimer.Stop();
521       if (IsDebuggerPresent())
522       {
523         std::cout << "Info: CPU limit (" << CPU_LIMIT << " sec) has been reached but ignored because of attached Debugger" << std::endl;
524         return 0;
525       }
526       else
527       {
528         std::cout << "ERROR: Process killed by CPU limit (" << CPU_LIMIT << " sec)" << std::endl;
529         ExitProcess (2);
530       }
531     }
532     if (CPU_LIMIT > 0 && anElapCurrent >= CPU_LIMIT)
533     {
534       aTimer.Stop();
535       if (IsDebuggerPresent())
536       {
537         std::cout << "Info: Elapsed limit (" << CPU_LIMIT << " sec) has been reached but ignored because of attached Debugger" << std::endl;
538         return 0;
539       }
540       else
541       {
542         std::cout << "ERROR: Process killed by elapsed limit (" << CPU_LIMIT << " sec)" << std::endl;
543         ExitProcess (2);
544       }
545     }
546   }
547 }
548 #else
549 static void cpulimitSignalHandler (int)
550 {
551   std::cout << "Process killed by CPU limit  (" << CPU_LIMIT << " sec)" << std::endl;
552   exit(2);
553 }
554 static void *CpuFunc(void* /*threadarg*/)
555 {
556   clock_t anElapCurrent;
557   for(;;)
558   {
559     sleep (5);
560     anElapCurrent = clock_t(aTimer.ElapsedTime());
561     if (CPU_LIMIT >0 && (anElapCurrent) >= CPU_LIMIT) {
562       std::cout << "Process killed by elapsed limit  (" << CPU_LIMIT << " sec)" << std::endl;
563       exit(2);
564     }
565   }
566   return NULL;
567 }
568 #endif
569
570 // Returns time in seconds defined by the argument string,
571 // multiplied by factor defined in environment variable
572 // CSF_CPULIMIT_FACTOR (if it exists, 1 otherwise)
573 static clock_t GetCpuLimit (const Standard_CString theParam)
574 {
575   clock_t aValue = Draw::Atoi (theParam);
576
577   OSD_Environment aEnv("CSF_CPULIMIT_FACTOR");
578   TCollection_AsciiString aEnvStr = aEnv.Value();
579   if (!aEnvStr.IsEmpty())
580   {
581     aValue *= Draw::Atoi (aEnvStr.ToCString());
582   }
583   return aValue;
584 }
585
586 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
587 {
588   static int aFirst = 1;
589 #ifdef _WIN32
590   // Windows specific code
591   unsigned int __stdcall CpuFunc (void *);
592   unsigned aThreadID;
593
594   if (n <= 1){
595     CPU_LIMIT = RLIM_INFINITY;
596   } else {
597     CPU_LIMIT = GetCpuLimit (a[1]);
598     Standard_Real anUserSeconds, aSystemSeconds;
599     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
600     CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
601     aTimer.Reset();
602     aTimer.Start();
603     if (aFirst) // Launch the thread only at the 1st call.
604     {
605       aFirst = 0;
606       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
607     }
608   }
609
610 #else 
611   // Unix & Linux
612   rlimit rlp;
613   rlp.rlim_max = RLIM_INFINITY;
614   if (n <= 1)
615     rlp.rlim_cur = RLIM_INFINITY;
616   else
617     rlp.rlim_cur = GetCpuLimit (a[1]);
618   CPU_LIMIT = rlp.rlim_cur;
619
620   int status;
621   status=setrlimit(RLIMIT_CPU,&rlp);
622   if (status !=0)
623     di << "status cpulimit setrlimit : " << status << "\n";
624
625   // set signal handler to print a message before death
626   struct sigaction act, oact;
627   memset (&act, 0, sizeof(act));
628   act.sa_handler = cpulimitSignalHandler;
629   sigaction (SIGXCPU, &act, &oact);
630
631   // cpulimit for elapsed time
632   aTimer.Reset();
633   aTimer.Start();
634   pthread_t cpulimitThread;
635   if (aFirst) // Launch the thread only at the 1st call.
636   {
637     aFirst = 0;
638     pthread_create(&cpulimitThread, NULL, CpuFunc, NULL);
639   }
640 #endif
641   di << "CPU and elapsed time limit set to " << (double)CPU_LIMIT << " seconds";
642   return 0;
643 }
644
645 //=======================================================================
646 //function : mallochook
647 //purpose  : 
648 //=======================================================================
649
650 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
651                                    const char** a)
652 {
653   if (n < 2)
654   {
655     di << "\
656 usage: mallochook cmd\n\
657 where cmd is one of:\n\
658   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
659                     0 - set callback to NULL,\n\
660                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
661                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
662   reset           - reset the CollectBySize handler\n\
663   report1 [<outfile>]\n\
664                   - write report from CollectBySize handler in <outfile>\n\
665   open [<logfile>]\n\
666                   - open file for writing the log with LogFileHandler\n\
667   close           - close the log file with LogFileHandler\n\
668   report2 [<flag>] [<logfile>] [<outfile>]\n\
669                   - scan <logfile> written with LogFileHandler\n\
670                     and make synthesized report in <outfile>; <flag> can be:\n\
671                     0 - simple stats by sizes (default),\n\
672                     1 - with alive allocation numbers\n\
673 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
674       << "\n";
675     return 0;
676   }
677   if (strcmp(a[1], "set") == 0)
678   {
679     int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
680     if (aType < 0 || aType > 2)
681     {
682       di << "unknown op of the command set\n";
683       return 1;
684     }
685     else if (aType == 0)
686     {
687       OSD_MAllocHook::SetCallback(NULL);
688       di << "callback is unset\n";
689     }
690     else if (aType == 1)
691     {
692       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
693       di << "callback is set to CollectBySize\n";
694     }
695     else //if (aType == 2)
696     {
697       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
698       di << "callback is set to LogFileHandler\n";
699     }
700   }
701   else if (strcmp(a[1], "reset") == 0)
702   {
703     OSD_MAllocHook::GetCollectBySize()->Reset();
704     di << "CollectBySize handler is reset\n";
705   }
706   else if (strcmp(a[1], "open") == 0)
707   {
708     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
709     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
710     {
711       di << "cannot create file " << aFileName << " for writing\n";
712       return 1;
713     }
714     di << "log file " << aFileName << " is opened for writing\n";
715   }
716   else if (strcmp(a[1], "close") == 0)
717   {
718     OSD_MAllocHook::GetLogFileHandler()->Close();
719     di << "log file is closed\n";
720   }
721   else if (strcmp(a[1], "report1") == 0)
722   {
723     const char* aOutFile = "mem-stat.txt";
724     if (n > 2)
725       aOutFile = a[2];
726     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
727     {
728       di << "report " << aOutFile << " has been created\n";
729     }
730     else
731     {
732       di << "cannot create report " << aOutFile << "\n";
733       return 1;
734     }
735   }
736   else if (strcmp(a[1], "report2") == 0)
737   {
738     Standard_Boolean includeAlive = Standard_False;
739     const char* aLogFile = "mem-log.txt";
740     const char* aOutFile = "mem-stat.txt";
741     if (n > 2)
742     {
743       includeAlive = (Draw::Atoi(a[2]) != 0);
744       if (n > 3)
745       {
746         aLogFile = a[3];
747         if (n > 4)
748           aOutFile = a[4];
749       }
750     }
751     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
752     {
753       di << "report " << aOutFile << " has been created\n";
754     }
755     else
756     {
757       di << "cannot create report " << aOutFile << " from the log file "
758         << aLogFile << "\n";
759       return 1;
760     }
761   }
762   else
763   {
764     di << "unrecognized command " << a[1] << "\n";
765     return 1;
766   }
767   return 0;
768 }
769
770 //==============================================================================
771 //function : dlocale
772 //purpose  :
773 //==============================================================================
774
775 static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
776 {
777   int category = LC_ALL;
778   if (n > 1)
779   {
780     const char *cat = argv[1];
781     if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
782     else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
783     else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
784     else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
785     else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
786     else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
787     else 
788     {
789       Message::SendFail() << "Error: cannot recognize argument " << cat << " as one of LC_ macros";
790       return 1;
791     }
792   }
793   const char* locale = (n > 2 ? argv[2] : NULL);
794   const char* result = setlocale (category, locale);
795   if (result)
796     di << result;
797   else 
798     std::cout << "Error: unsupported locale specification: " << locale << std::endl;
799   return 0;
800 }
801
802 //==============================================================================
803 //function : dmeminfo
804 //purpose  :
805 //==============================================================================
806
807 static int dmeminfo (Draw_Interpretor& theDI,
808                      Standard_Integer  theArgNb,
809                      const char**      theArgVec)
810 {
811   if (theArgNb <= 1)
812   {
813     OSD_MemInfo aMemInfo;
814     theDI << aMemInfo.ToString();
815     return 0;
816   }
817
818   NCollection_Map<OSD_MemInfo::Counter> aCounters;
819   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
820   {
821     TCollection_AsciiString anArg (theArgVec[anIter]);
822     anArg.LowerCase();
823     if (anArg == "virt" || anArg == "v")
824     {
825       aCounters.Add (OSD_MemInfo::MemVirtual);
826     }
827     else if (anArg == "heap" || anArg == "h")
828     {
829       aCounters.Add (OSD_MemInfo::MemHeapUsage);
830     }
831     else if (anArg == "wset" || anArg == "w")
832     {
833       aCounters.Add (OSD_MemInfo::MemWorkingSet);
834     }
835     else if (anArg == "wsetpeak")
836     {
837       aCounters.Add (OSD_MemInfo::MemWorkingSetPeak);
838     }
839     else if (anArg == "swap")
840     {
841       aCounters.Add (OSD_MemInfo::MemSwapUsage);
842     }
843     else if (anArg == "swappeak")
844     {
845       aCounters.Add (OSD_MemInfo::MemSwapUsagePeak);
846     }
847     else if (anArg == "private")
848     {
849       aCounters.Add (OSD_MemInfo::MemPrivate);
850     }
851     else
852     {
853       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
854     }
855   }
856
857   OSD_MemInfo aMemInfo (Standard_False);
858   aMemInfo.SetActive (Standard_False);
859   for (NCollection_Map<OSD_MemInfo::Counter>::Iterator aCountersIt (aCounters); aCountersIt.More(); aCountersIt.Next())
860   {
861     aMemInfo.SetActive (aCountersIt.Value(), Standard_True);
862   }
863   aMemInfo.Update();
864
865   for (NCollection_Map<OSD_MemInfo::Counter>::Iterator aCountersIt (aCounters); aCountersIt.More(); aCountersIt.Next())
866   {
867     theDI << Standard_Real (aMemInfo.Value (aCountersIt.Value())) << " ";
868   }
869   theDI << "\n";
870   return 0;
871 }
872
873 //==============================================================================
874 //function : dparallel
875 //purpose  :
876 //==============================================================================
877 static int dparallel (Draw_Interpretor& theDI,
878                       Standard_Integer  theArgNb,
879                       const char**      theArgVec)
880 {
881   const Handle(OSD_ThreadPool)& aDefPool = OSD_ThreadPool::DefaultPool();
882   if (theArgNb <= 1)
883   {
884     theDI << "NbLogicalProcessors: " << OSD_Parallel::NbLogicalProcessors() << "\n"
885           << "NbThreads:           " << aDefPool->NbThreads() << "\n"
886           << "NbDefThreads:        " << aDefPool->NbDefaultThreadsToLaunch() << "\n"
887           << "UseOcct:             " << (OSD_Parallel::ToUseOcctThreads() ? 1 : 0);
888     return 0;
889   }
890
891   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
892   {
893     TCollection_AsciiString anArg (theArgVec[anIter]);
894     anArg.LowerCase();
895     if (anIter + 1 < theArgNb
896      && (anArg == "-nbthreads"
897       || anArg == "-threads"))
898     {
899       const Standard_Integer aVal = Draw::Atoi (theArgVec[++anIter]);
900       aDefPool->Init (aVal);
901     }
902     else if (anIter + 1 < theArgNb
903           && (anArg == "-nbdefthreads"
904            || anArg == "-defthreads"
905            || anArg == "-nbmaxdefthreads"
906            || anArg == "-maxdefthreads"))
907     {
908       const Standard_Integer aVal = Draw::Atoi (theArgVec[++anIter]);
909       if (aVal <= 0 || aVal > aDefPool->NbThreads())
910       {
911         Message::SendFail() << "Syntax error: maximum number of threads to use should be <= of threads in the pool";
912         return 1;
913       }
914       aDefPool->SetNbDefaultThreadsToLaunch (aVal);
915     }
916     else if (anIter + 1 < theArgNb
917           && (anArg == "-useocct"
918            || anArg == "-touseocct"
919            || anArg == "-occt"))
920     {
921       const Standard_Integer aVal = Draw::Atoi (theArgVec[++anIter]);
922       OSD_Parallel::SetUseOcctThreads (aVal == 1);
923       if (OSD_Parallel::ToUseOcctThreads() != (aVal == 1))
924       {
925         std::cout << "Warning: unable to switch threads library - no options available\n";
926       }
927     }
928     else if (anIter + 1 < theArgNb
929           && (anArg == "-usetbb"
930            || anArg == "-tousetbb"
931            || anArg == "-tbb"))
932     {
933       const Standard_Integer aVal = Draw::Atoi (theArgVec[++anIter]);
934       OSD_Parallel::SetUseOcctThreads (aVal == 0);
935       if (OSD_Parallel::ToUseOcctThreads() != (aVal == 0))
936       {
937         std::cout << "Warning: unable to switch threads library - no options available\n";
938       }
939     }
940     else
941     {
942       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
943       return 1;
944     }
945   }
946   return 0;
947 }
948
949 //==============================================================================
950 //function : dperf
951 //purpose  :
952 //==============================================================================
953
954 static int dperf (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
955 {
956   // reset if argument is provided and it is not '0'
957   int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
958   char buffer[25600];
959   perf_sprint_all_meters (buffer, 25600 - 1, reset);
960   theDI << buffer;
961   return 0;
962 }
963
964 //==============================================================================
965 //function : dsetsignal
966 //purpose  :
967 //==============================================================================
968
969 static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
970 {
971   OSD_SignalMode aMode = OSD_SignalMode_Set;
972   Standard_Boolean aSetFPE = OSD::ToCatchFloatingSignals();
973   Standard_Integer aStackLen = OSD::SignalStackTraceLength();
974
975   // default for FPE signal is defined by CSF_FPE variable, if set
976   OSD_Environment aEnv("CSF_FPE");
977   TCollection_AsciiString aEnvStr = aEnv.Value();
978   if (!aEnvStr.IsEmpty())
979   {
980     aSetFPE = (aEnvStr.Value(1) != '0');
981   }
982
983   // parse arguments
984   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
985   {
986     TCollection_AsciiString anArg(theArgVec[anArgIter]);
987     anArg.LowerCase();
988     if (anArg == "asis")
989     {
990       aMode = OSD_SignalMode_AsIs;
991     }
992     else if (anArg == "set")
993     {
994       aMode = OSD_SignalMode_Set;
995     }
996     else if (anArg == "unhandled")
997     {
998       aMode = OSD_SignalMode_SetUnhandled;
999     }
1000     else if (anArg == "unset")
1001     {
1002       aMode = OSD_SignalMode_Unset;
1003     }
1004     else if (anArg == "1" || anArg == "on")
1005     {
1006       aSetFPE = Standard_True;
1007     }
1008     else if (anArg == "0" || anArg == "off")
1009     {
1010       aSetFPE = Standard_False;
1011     }
1012     else if (anArg == "default")
1013     {
1014     }
1015     else if (anArgIter + 1 < theArgNb
1016           && (anArg == "-stracktracelength"
1017            || anArg == "-stracktracelen"
1018            || anArg == "-stracklength"
1019            || anArg == "-stracklen"))
1020     {
1021       aStackLen = Draw::Atoi (theArgVec[++anArgIter]);
1022     }
1023     else
1024     {
1025       Message::SendFail() << "Syntax error: unknown argument '" << anArg << "'";
1026       return 1;
1027     }
1028   }
1029
1030   OSD::SetSignal(aMode, aSetFPE);
1031   OSD::SetSignalStackTraceLength (aStackLen);
1032
1033   // report actual status in the end
1034   const char* aModeStr = 0;
1035   switch (OSD::SignalMode())
1036   {
1037     default:
1038     case OSD_SignalMode_AsIs:         aModeStr = "asis";      break;
1039     case OSD_SignalMode_Set:          aModeStr = "set";       break;
1040     case OSD_SignalMode_SetUnhandled: aModeStr = "unhandled"; break;
1041     case OSD_SignalMode_Unset:        aModeStr = "unset";     break;
1042   }
1043   theDI << "Signal mode: " << aModeStr << "\n"
1044         << "Catch FPE: " << (OSD::ToCatchFloatingSignals() ? "1" : "0") << "\n"
1045         << "Stack Trace Length: " << aStackLen << "\n";
1046   return 0;
1047 }
1048
1049 //==============================================================================
1050 //function : dtracelevel
1051 //purpose  :
1052 //==============================================================================
1053
1054 static int dtracelevel (Draw_Interpretor& theDI,
1055                         Standard_Integer  theArgNb,
1056                         const char**      theArgVec)
1057 {
1058   Message_Gravity aLevel = Message_Info;
1059   if (theArgNb < 1 || theArgNb > 2)
1060   {
1061     Message::SendFail() << "Error: wrong number of arguments! See usage:";
1062     theDI.PrintHelp (theArgVec[0]);
1063     return 1;
1064   }
1065   else if (theArgNb == 2)
1066   {
1067     TCollection_AsciiString aVal (theArgVec[1]);
1068     aVal.LowerCase();
1069     if (aVal == "trace")
1070     {
1071       aLevel = Message_Trace;
1072     }
1073     else if (aVal == "info")
1074     {
1075       aLevel = Message_Info;
1076     }
1077     else if (aVal == "warn"
1078           || aVal == "warning")
1079     {
1080       aLevel = Message_Warning;
1081     }
1082     else if (aVal == "alarm")
1083     {
1084       aLevel = Message_Alarm;
1085     }
1086     else if (aVal == "fail")
1087     {
1088       aLevel = Message_Fail;
1089     }
1090     else
1091     {
1092       Message::SendFail() << "Error: unknown gravity '" << theArgVec[1] << "'";
1093       return 1;
1094     }
1095   }
1096
1097   Handle(Message_Messenger) aMessenger = Message::DefaultMessenger();
1098   if (aMessenger.IsNull())
1099   {
1100     Message::SendFail() << "Error: default messenger is unavailable";
1101     return 1;
1102   }
1103
1104   Message_SequenceOfPrinters& aPrinters = aMessenger->ChangePrinters();
1105   if (aPrinters.Length() < 1)
1106   {
1107     Message::SendFail() << "Error: no printers registered in default Messenger";
1108     return 0;
1109   }
1110
1111   for (Standard_Integer aPrinterIter = 1; aPrinterIter <= aPrinters.Length(); ++aPrinterIter)
1112   {
1113     Handle(Message_Printer)& aPrinter = aPrinters.ChangeValue (aPrinterIter);
1114     if (theArgNb == 1)
1115     {
1116       if (aPrinterIter == 1)
1117       {
1118         aLevel = aPrinter->GetTraceLevel();
1119       }
1120       else if (aLevel == aPrinter->GetTraceLevel())
1121       {
1122         continue;
1123       }
1124
1125       switch (aPrinter->GetTraceLevel())
1126       {
1127         case Message_Trace:   theDI << "trace"; break;
1128         case Message_Info:    theDI << "info";  break;
1129         case Message_Warning: theDI << "warn";  break;
1130         case Message_Alarm:   theDI << "alarm"; break;
1131         case Message_Fail:    theDI << "fail";  break;
1132       }
1133       continue;
1134     }
1135
1136     aPrinter->SetTraceLevel (aLevel);
1137   }
1138
1139   return 0;
1140 }
1141
1142 //==============================================================================
1143 //function : ddebugtraces
1144 //purpose  :
1145 //==============================================================================
1146 static int ddebugtraces (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
1147 {
1148   if (theArgNb < 2)
1149   {
1150     theDI << Standard_Failure::DefaultStackTraceLength();
1151     return 0;
1152   }
1153   else if (theArgNb != 2)
1154   {
1155     theDI << "Syntax error: wrong number of arguments";
1156     return 1;
1157   }
1158
1159   Standard_Failure::SetDefaultStackTraceLength (Draw::Atoi (theArgVec[1]));
1160   return 0;
1161 }
1162
1163 //==============================================================================
1164 //function : dputs
1165 //purpose  :
1166 //==============================================================================
1167 static int dputs (Draw_Interpretor& theDI,
1168                   Standard_Integer theArgNb,
1169                   const char** theArgVec)
1170 {
1171   Standard_OStream* aStream = &std::cout;
1172   bool isNoNewline = false, toIntense = false;
1173   Message_ConsoleColor aColor = Message_ConsoleColor_Default;
1174   for (Standard_Integer anArgIter = 1; anArgIter < theArgNb; ++anArgIter)
1175   {
1176     TCollection_AsciiString anArg (theArgVec[anArgIter]);
1177     anArg.LowerCase();
1178     if (anArg == "-nonewline")
1179     {
1180       isNoNewline = true;
1181     }
1182     else if (anArg == "stdcout")
1183     {
1184       aStream = &std::cout;
1185     }
1186     else if (anArg == "stdcerr")
1187     {
1188       aStream = &std::cerr;
1189     }
1190     else if (anArg == "-intense")
1191     {
1192       toIntense = true;
1193     }
1194     else if (anArg == "-black")
1195     {
1196       aColor = Message_ConsoleColor_Black;
1197     }
1198     else if (anArg == "-white")
1199     {
1200       aColor = Message_ConsoleColor_White;
1201     }
1202     else if (anArg == "-red")
1203     {
1204       aColor = Message_ConsoleColor_Red;
1205     }
1206     else if (anArg == "-blue")
1207     {
1208       aColor = Message_ConsoleColor_Blue;
1209     }
1210     else if (anArg == "-green")
1211     {
1212       aColor = Message_ConsoleColor_Green;
1213     }
1214     else if (anArg == "-yellow")
1215     {
1216       aColor = Message_ConsoleColor_Yellow;
1217     }
1218     else if (anArg == "-cyan")
1219     {
1220       aColor = Message_ConsoleColor_Cyan;
1221     }
1222     else if (anArg == "-magenta")
1223     {
1224       aColor = Message_ConsoleColor_Magenta;
1225     }
1226     else if (anArgIter + 1 == theArgNb)
1227     {
1228       if (!theDI.ToColorize())
1229       {
1230         toIntense = false;
1231         aColor = Message_ConsoleColor_Default;
1232       }
1233       if (toIntense || aColor != Message_ConsoleColor_Default)
1234       {
1235         Message_PrinterOStream::SetConsoleTextColor (aStream, aColor, toIntense);
1236       }
1237
1238       *aStream << theArgVec[anArgIter];
1239       if (!isNoNewline)
1240       {
1241         *aStream << std::endl;
1242       }
1243
1244       if (toIntense || aColor != Message_ConsoleColor_Default)
1245       {
1246         Message_PrinterOStream::SetConsoleTextColor (aStream, Message_ConsoleColor_Default, false);
1247       }
1248       return 0;
1249     }
1250     else
1251     {
1252       Message::SendFail() << "Syntax error at '" << anArg << "'";
1253       return 1;
1254     }
1255   }
1256
1257   Message::SendFail() << "Syntax error: wrong number of arguments";
1258   return 1;
1259 }
1260
1261 void Draw::BasicCommands(Draw_Interpretor& theCommands)
1262 {
1263   static Standard_Boolean Done = Standard_False;
1264   if (Done) return;
1265   Done = Standard_True;
1266
1267   std::ios::sync_with_stdio();
1268
1269   const char* g = "DRAW General Commands";
1270
1271   theCommands.Add("batch", "returns 1 in batch mode",
1272                   __FILE__,ifbatch,g);
1273   theCommands.Add("spy","spy [file], Save commands in file. no file close",
1274                   __FILE__,spy,g);
1275   theCommands.Add("wait","wait [time(10)], wait time seconds",
1276                   __FILE__,Draw_wait,g);
1277   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
1278                   __FILE__,cpulimit,g);
1279   theCommands.Add("chrono","chrono [name action [action...]] \n  Operates named timer.\n"
1280                            "  Supported actions: reset, start, stop, restart, show, counter [text].\n"
1281                            "  Without arguments enables / disables global timer for all DRAW commands.",
1282                   __FILE__,chronom,g);
1283   theCommands.Add("dchrono","see help of chrono command",
1284                   __FILE__,dchronom,g);
1285   theCommands.Add("mallochook",
1286                   "debug memory allocation/deallocation, w/o args for help",
1287                   __FILE__, mallochook, g);
1288   theCommands.Add ("meminfo",
1289     "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
1290     " : memory counters for this process",
1291           __FILE__, dmeminfo, g);
1292   theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided",
1293                   __FILE__,dperf,g);
1294   theCommands.Add("dsetsignal",
1295             "dsetsignal [{asIs|set|unhandled|unset}=set] [{0|1|default=$CSF_FPE}]"
1296     "\n\t\t:            [-strackTraceLength Length]"
1297     "\n\t\t: Sets OSD signal handler, with FPE option if argument is given."
1298     "\n\t\t:  -strackTraceLength specifies length of stack trace to put into exceptions redirected from signals.",
1299                   __FILE__,dsetsignal,g);
1300
1301   theCommands.Add("dparallel",
1302     "dparallel [-occt {0|1}] [-nbThreads Count] [-nbDefThreads Count]"
1303     "\n\t\t: Manages global parallelization parameters:"
1304     "\n\t\t:   -occt         use OCCT implementation or external library (if available)"
1305     "\n\t\t:   -nbThreads    specify the number of threads in default thread pool"
1306     "\n\t\t:   -nbDefThreads specify the upper limit of threads to be used for default thread pool"
1307     "\n\t\t:                 within single parallelization call (should be <= of overall number of threads),"
1308     "\n\t\t:                 so that nested algorithm can also use this pool",
1309       __FILE__,dparallel,g);
1310
1311   // Logging commands; note that their names are hard-coded in the code
1312   // of Draw_Interpretor, thus should not be changed without update of that code!
1313   theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
1314                   __FILE__,dlog,g);
1315   theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
1316                   __FILE__,decho,g);
1317   theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
1318                   __FILE__, dtracelevel, g);
1319   theCommands.Add("ddebugtraces",
1320     "ddebugtraces nbTraces"
1321     "\n\t\t: Sets the number of lines for the stack trace within Standard_Failure constructor."
1322     "\n\t\t: Intended for debug purposes.",
1323     __FILE__, ddebugtraces, g);
1324
1325   theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
1326                   __FILE__,dbreak,g);
1327   theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
1328                   __FILE__,dversion,g);
1329   theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",
1330                   __FILE__,dlocale,g);
1331
1332   theCommands.Add("dputs",
1333             "dputs [-intense] [-black|-white|-red|-green|-blue|-yellow|-cyan|-magenta]"
1334     "\n\t\t:       [-nonewline] [stdcout|stdcerr] text"
1335     "\n\t\t: Puts text into console output",
1336                   __FILE__,dputs,g);
1337 }