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