7c9487db10acd346f3d71cd6d8aa508119b022d4
[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 <OSD.hxx>
27 #include <OSD_Chronometer.hxx>
28 #include <OSD_Environment.hxx>
29 #include <OSD_Exception_CTRL_BREAK.hxx>
30 #include <OSD_MAllocHook.hxx>
31 #include <OSD_MemInfo.hxx>
32 #include <Standard_Macro.hxx>
33 #include <Standard_SStream.hxx>
34 #include <Standard_Stream.hxx>
35 #include <Standard_Version.hxx>
36 #include <TCollection_AsciiString.hxx>
37
38 #include <OSD_PerfMeter.h>
39 #ifdef _WIN32
40
41 #include <windows.h>
42 #include <winbase.h>
43 #include <process.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <time.h>
47 #include <limits>
48
49 #define RLIM_INFINITY   0x7fffffff
50
51 static clock_t CPU_CURRENT; // cpu time already used at last
52                             // cpulimit call. (sec.) 
53 #else /* _WIN32 */
54
55 #include <sys/resource.h>
56 #include <signal.h>
57 #include <unistd.h>
58
59 #if defined (__hpux) || defined ( HPUX )
60 #define RLIM_INFINITY   0x7fffffff
61 #define RLIMIT_CPU      0
62 #endif
63
64 #endif /* _WIN32 */
65
66 extern Standard_Boolean Draw_Batch;
67
68 static clock_t CPU_LIMIT;   // Cpu_limit in Sec.
69 static OSD_Timer aTimer;
70
71 //=======================================================================
72 // chronom
73 //=======================================================================
74
75 extern Standard_Boolean Draw_Chrono;
76
77 static Standard_Integer chronom(Draw_Interpretor& di,
78                                 Standard_Integer n,const char** a)
79 {
80   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
81     if (n == 1)
82       Draw_Chrono = !Draw_Chrono;
83     else
84       Draw_Chrono = (*a[1] == '1');
85
86     if (Draw_Chrono) di << "Chronometers activated.\n";
87     else di << "Chronometers desactivated.\n";
88   }
89   else {
90     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
91     Handle(Draw_Chronometer) C;
92     if (!D.IsNull()) {
93       C = Handle(Draw_Chronometer)::DownCast(D);
94     }
95     if (C.IsNull()) {
96       C = new Draw_Chronometer();
97     Draw::Set(a[1],C,Standard_False);
98     }
99     if (n <= 2) {
100       C->Timer().Reset();
101     }
102     else {
103       if (!strcasecmp(a[2],"reset"))
104         C->Timer().Reset();
105       if (!strcasecmp(a[2],"start"))
106         C->Timer().Start();
107       if (!strcasecmp(a[2],"stop"))
108         C->Timer().Stop();
109       if (!strcasecmp(a[2],"show"))
110         C->Timer().Show();
111     }
112   }
113   return 0;
114 }
115
116 static Standard_Integer dchronom(Draw_Interpretor& I,
117                                  Standard_Integer n,const char** a)
118 {
119   if ((n == 1) || (*a[1] == '0') || (*a[1] == '1')) {
120     if (n == 1)
121       Draw_Chrono = !Draw_Chrono;
122     else
123       Draw_Chrono = (*a[1] == '1');
124
125     if (Draw_Chrono) I << "Chronometers activated.\n";
126     else I << "Chronometers desactivated.\n";
127   }
128   else {
129     Handle(Draw_Drawable3D) D = Draw::Get(a[1]);
130     Handle(Draw_Chronometer) C;
131     if (!D.IsNull()) {
132       C = Handle(Draw_Chronometer)::DownCast(D);
133     }
134     if (C.IsNull()) {
135       C = new Draw_Chronometer();
136     Draw::Set(a[1],C,Standard_False);
137     }
138     if (n <= 2) {
139       C->Timer().Reset();
140     }
141     else {
142       if (!strcasecmp(a[2],"reset"))
143         C->Timer().Reset();
144       if (!strcasecmp(a[2],"start"))
145         C->Timer().Start();
146       if (!strcasecmp(a[2],"stop"))
147         C->Timer().Stop();
148       if (!strcasecmp(a[2],"show")) {
149         Standard_SStream ss;
150         C->Timer().Show(ss);
151         I << ss;
152       }
153     }
154   }
155   return 0;
156 }
157
158
159
160 //=======================================================================
161 //function : ifbatch
162 //purpose  : 
163 //=======================================================================
164
165 static Standard_Integer ifbatch(Draw_Interpretor& DI, Standard_Integer , const char** )
166 {
167   if (Draw_Batch)
168     DI << "1";
169   else
170     DI << "0";
171   
172   return 0;
173 }
174
175 //=======================================================================
176 //function : spy
177 //purpose  : 
178 //=======================================================================
179
180 extern Standard_Boolean Draw_Spying;
181 extern filebuf Draw_Spyfile;
182
183 static Standard_Integer spy(Draw_Interpretor& di, Standard_Integer n, const char** a)
184 {
185   if (Draw_Spying) 
186     Draw_Spyfile.close();
187   Draw_Spying = Standard_False;
188   if (n > 1) {
189     if (!Draw_Spyfile.open(a[1],ios::out)) {
190       di << "Cannot open "<<a[1]<<" for writing\n";
191       return 1;
192     }
193     Draw_Spying = Standard_True;
194   }
195   return 0;
196 }
197
198 static Standard_Integer dlog(Draw_Interpretor& di, Standard_Integer n, const char** a)
199 {
200   if (n != 2 && n != 3)
201   {
202     cout << "Enable or disable logging: " << a[0] << " {on|off}" << endl;
203     cout << "Reset log: " << a[0] << " reset" << endl;
204     cout << "Get log content: " << a[0] << " get" << endl;
205     return 1;
206   }
207
208   if (! strcmp (a[1], "on") && n == 2)
209   {
210     di.SetDoLog (Standard_True);
211 //    di.Log() << "dlog on" << endl; // for symmetry
212   }
213   else if (! strcmp (a[1], "off") && n == 2)
214   {
215     di.SetDoLog (Standard_False);
216   }
217   else if (! strcmp (a[1], "reset") && n == 2)
218   {
219     di.Log().str("");
220   }
221   else if (! strcmp (a[1], "get") && n == 2)
222   {
223     di << di.Log().str().c_str();
224   }
225   else if (! strcmp (a[1], "add") && n == 3)
226   {
227     di.Log() << a[2] << "\n";
228   }
229   else {
230     cout << "Unrecognized option(s): " << a[1] << endl;
231     return 1;
232   }
233   return 0;
234 }
235
236 static Standard_Integer decho(Draw_Interpretor& di, Standard_Integer n, const char** a)
237 {
238   if (n != 2)
239   {
240     cout << "Enable or disable echoing: " << a[0] << " {on|off}" << endl;
241     return 1;
242   }
243
244   if (! strcmp (a[1], "on"))
245   {
246     di.SetDoEcho (Standard_True);
247   }
248   else if (! strcmp (a[1], "off"))
249   {
250     di.SetDoEcho (Standard_False);
251   }
252   else {
253     cout << "Unrecognized option: " << a[1] << endl;
254     return 1;
255   }
256   return 0;
257 }
258
259 static Standard_Integer dbreak(Draw_Interpretor& di, Standard_Integer, const char**)
260 {
261   try {
262     OSD::ControlBreak();
263   }
264   catch (OSD_Exception_CTRL_BREAK) {
265     di << "User pressed Control-Break";
266     return 1; // Tcl exception
267   }
268
269   return 0;
270 }
271
272 static Standard_Integer dversion(Draw_Interpretor& di, Standard_Integer, const char**)
273 {
274   // print OCCT version and OCCTY-specific macros used
275   di << "Open CASCADE Technology " << OCC_VERSION_STRING_EXT << "\n";
276 #ifdef OCCT_DEBUG
277   di << "Extended debug mode\n";
278 #elif defined(_DEBUG)
279   di << "Debug mode\n";
280 #endif
281 #ifdef HAVE_TBB
282   di << "TBB enabled (HAVE_TBB)\n";
283 #else 
284   di << "TBB disabled\n";
285 #endif
286 #ifdef HAVE_GL2PS
287   di << "GL2PS enabled (HAVE_GL2PS)\n";
288 #else
289   di << "GL2PS disabled\n";
290 #endif
291 #ifdef HAVE_FREEIMAGE
292   di << "FreeImage enabled (HAVE_FREEIMAGE)\n";
293 #else
294   di << "FreeImage disabled\n";
295 #endif
296 #ifdef HAVE_OPENCL
297   di << "OpenCL enabled (HAVE_OPENCL)\n";
298 #else
299   di << "OpenCL disabled\n";
300 #endif
301 #ifdef HAVE_VTK
302   di << "VTK enabled (HAVE_VTK)\n";
303 #else
304   di << "VTK disabled\n";
305 #endif
306 #ifdef No_Exception
307   di << "Exceptions disabled (No_Exception)\n";
308 #else
309   di << "Exceptions enabled\n";
310 #endif
311
312   // check compiler, OS, etc. using pre-processor macros provided by compiler
313   // see "Pre-defined C/C++ Compiler Macros" http://sourceforge.net/p/predef/wiki/
314   // note that only modern compilers that are known to be used for OCCT are recognized
315
316   // compiler; note that GCC and MSVC are last as other compilers (e.g. Intel) can also define __GNUC__ and _MSC_VER
317 #if defined(__INTEL_COMPILER)
318   di << "Compiler: Intel " << __INTEL_COMPILER << "\n";
319 #elif defined(__BORLANDC__)
320   di << "Compiler: Borland C++ (__BORLANDC__ = " << __BORLANDC__ << ")\n";
321 #elif defined(__clang__)
322   di << "Compiler: Clang " << __clang_major__ << "." << __clang_minor__ << "." << __clang_patchlevel__ << "\n";
323 #elif defined(__SUNPRO_C)
324   di << "Compiler: Sun Studio (__SUNPRO_C = " << __SUNPROC_C << ")\n";
325 #elif defined(_MSC_VER)
326   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";
327 #elif defined(__GNUC__)
328   di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
329 #else
330   di << "Compiler: unrecognized\n";
331 #endif
332
333   // Cygwin and MinGW specifics
334 #if defined(__CYGWIN__)
335   di << "Cygwin\n";
336 #endif
337 #if defined(__MINGW64__)
338   di << "MinGW 64 " << __MINGW64_VERSION_MAJOR << "." << __MINGW64_VERSION_MINOR << "\n";
339 #elif defined(__MINGW32__)
340   di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
341 #endif 
342
343   // architecture
344 #if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
345   di << "Architecture: AMD64\n";
346 #elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
347   di << "Architecture: Intel x86\n";
348 #elif defined(_M_IA64) || defined(__ia64__)
349   di << "Architecture: Intel Itanium (IA 64)\n";
350 #elif defined(__sparc__) || defined(__sparc)
351   di << "Architecture: SPARC\n";
352 #else
353   di << "Architecture: unrecognized\n";
354 #endif
355
356   // OS
357 #if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
358   di << "OS: Windows\n";
359 #elif defined(__APPLE__) || defined(__MACH__)
360   di << "OS: Mac OS X\n";
361 #elif defined(__sun) 
362   di << "OS: SUN Solaris\n";
363 #elif defined(__ANDROID__) /* must be before Linux */
364   #include <android/api-level.h>
365   di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
366 #elif defined(__QNXNTO__)
367   di << "OS: QNX Neutrino\n";
368 #elif defined(__QNX__)
369   di << "OS: QNX\n";
370 #elif defined(__linux__)
371   di << "OS: Linux\n";
372 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
373   #include <sys/param.h>
374   di << "OS: BSD (BSD = " << BSD << ")\n";
375 #else
376   di << "OS: unrecognized\n";
377 #endif
378
379   return 0;
380 }
381
382 //=======================================================================
383 //function : wait
384 //purpose  : 
385 //=======================================================================
386
387 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
388 {
389   Standard_Integer w = 10;
390   if (n > 1)
391     w = Draw::Atoi(a[1]);
392   time_t ct = time(NULL) + w;
393   while (time(NULL) < ct) {};
394   return 0;
395 }
396
397 //=======================================================================
398 //function : cpulimit
399 //purpose  : 
400 //=======================================================================
401 #ifdef _WIN32
402 static unsigned int __stdcall CpuFunc (void * /*param*/)
403 {
404   clock_t anElapCurrent;
405   clock_t aCurrent;
406
407   for(;;)
408   {
409     Sleep (5);
410     Standard_Real anUserSeconds, aSystemSeconds;
411     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
412     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
413     anElapCurrent = clock_t(aTimer.ElapsedTime());
414     
415     if (CPU_LIMIT > 0 && (aCurrent - CPU_CURRENT) >= CPU_LIMIT)
416     {
417       cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
418       aTimer.Stop();
419       ExitProcess (2);
420     }
421     if (CPU_LIMIT > 0 && anElapCurrent >= CPU_LIMIT)
422     {
423       cout << "Process killed by elapsed limit (" << CPU_LIMIT << " sec)" << endl;
424       aTimer.Stop();
425       ExitProcess (2);
426     }
427   }
428 }
429 #else
430 static void cpulimitSignalHandler (int)
431 {
432   cout << "Process killed by CPU limit  (" << CPU_LIMIT << " sec)" << endl;
433   exit(2);
434 }
435 static void *CpuFunc(void* /*threadarg*/)
436 {
437   clock_t anElapCurrent;
438   for(;;)
439   {
440     sleep (5);
441     anElapCurrent = clock_t(aTimer.ElapsedTime());
442     if (CPU_LIMIT >0 && (anElapCurrent) >= CPU_LIMIT) {
443       cout << "Process killed by elapsed limit  (" << CPU_LIMIT << " sec)" << endl;
444       exit(2);
445     }
446   }
447   return NULL;
448 }
449 #endif
450
451 #ifdef _WIN32
452 static Standard_Integer cpulimit(Draw_Interpretor&, Standard_Integer n, const char** a)
453 {
454 #else
455 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
456 {
457 #endif
458   static int aFirst = 1;
459 #ifdef _WIN32
460   // Windows specific code
461   unsigned int __stdcall CpuFunc (void *);
462   unsigned aThreadID;
463
464   if (n <= 1){
465     CPU_LIMIT = RLIM_INFINITY;
466   } else {
467     CPU_LIMIT = Draw::Atoi (a[1]);
468     Standard_Real anUserSeconds, aSystemSeconds;
469     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
470     CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
471     aTimer.Reset();
472     aTimer.Start();
473     if (aFirst) // Launch the thread only at the 1st call.
474     {
475       aFirst = 0;
476       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
477     }
478   }
479
480 #else 
481   // Unix & Linux
482   rlimit rlp;
483   rlp.rlim_max = RLIM_INFINITY;
484   if (n <= 1)
485     rlp.rlim_cur = RLIM_INFINITY;
486   else
487     rlp.rlim_cur = Draw::Atoi(a[1]);
488   CPU_LIMIT = rlp.rlim_cur;
489
490   int status;
491   status=setrlimit(RLIMIT_CPU,&rlp);
492   if (status !=0)
493     di << "status cpulimit setrlimit : " << status << "\n";
494
495   // set signal handler to print a message before death
496   struct sigaction act, oact;
497   memset (&act, 0, sizeof(act));
498   act.sa_handler = cpulimitSignalHandler;
499   sigaction (SIGXCPU, &act, &oact);
500
501   // cpulimit for elapsed time
502   aTimer.Reset();
503   aTimer.Start();
504   pthread_t cpulimitThread;
505   if (aFirst) // Launch the thread only at the 1st call.
506   {
507     aFirst = 0;
508     pthread_create(&cpulimitThread, NULL, CpuFunc, NULL);
509   }
510 #endif
511   return 0;
512 }
513
514
515 //=======================================================================
516 //function : mallochook
517 //purpose  : 
518 //=======================================================================
519
520 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
521                                    const char** a)
522 {
523   if (n < 2)
524   {
525     di << "\
526 usage: mallochook cmd\n\
527 where cmd is one of:\n\
528   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
529                     0 - set callback to NULL,\n\
530                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
531                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
532   reset           - reset the CollectBySize handler\n\
533   report1 [<outfile>]\n\
534                   - write report from CollectBySize handler in <outfile>\n\
535   open [<logfile>]\n\
536                   - open file for writing the log with LogFileHandler\n\
537   close           - close the log file with LogFileHandler\n\
538   report2 [<flag>] [<logfile>] [<outfile>]\n\
539                   - scan <logfile> written with LogFileHandler\n\
540                     and make synthesized report in <outfile>; <flag> can be:\n\
541                     0 - simple stats by sizes (default),\n\
542                     1 - with alive allocation numbers\n\
543 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
544       << "\n";
545     return 0;
546   }
547   if (strcmp(a[1], "set") == 0)
548   {
549     int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
550     if (aType < 0 || aType > 2)
551     {
552       di << "unknown op of the command set\n";
553       return 1;
554     }
555     else if (aType == 0)
556     {
557       OSD_MAllocHook::SetCallback(NULL);
558       di << "callback is unset\n";
559     }
560     else if (aType == 1)
561     {
562       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
563       di << "callback is set to CollectBySize\n";
564     }
565     else //if (aType == 2)
566     {
567       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
568       di << "callback is set to LogFileHandler\n";
569     }
570   }
571   else if (strcmp(a[1], "reset") == 0)
572   {
573     OSD_MAllocHook::GetCollectBySize()->Reset();
574     di << "CollectBySize handler is reset\n";
575   }
576   else if (strcmp(a[1], "open") == 0)
577   {
578     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
579     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
580     {
581       di << "cannot create file " << aFileName << " for writing\n";
582       return 1;
583     }
584     di << "log file " << aFileName << " is opened for writing\n";
585   }
586   else if (strcmp(a[1], "close") == 0)
587   {
588     OSD_MAllocHook::GetLogFileHandler()->Close();
589     di << "log file is closed\n";
590   }
591   else if (strcmp(a[1], "report1") == 0)
592   {
593     const char* aOutFile = "mem-stat.txt";
594     if (n > 2)
595       aOutFile = a[2];
596     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
597     {
598       di << "report " << aOutFile << " has been created\n";
599     }
600     else
601     {
602       di << "cannot create report " << aOutFile << "\n";
603       return 1;
604     }
605   }
606   else if (strcmp(a[1], "report2") == 0)
607   {
608     Standard_Boolean includeAlive = Standard_False;
609     const char* aLogFile = "mem-log.txt";
610     const char* aOutFile = "mem-stat.txt";
611     if (n > 2)
612     {
613       includeAlive = (Draw::Atoi(a[2]) != 0);
614       if (n > 3)
615       {
616         aLogFile = a[3];
617         if (n > 4)
618           aOutFile = a[4];
619       }
620     }
621     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
622     {
623       di << "report " << aOutFile << " has been created\n";
624     }
625     else
626     {
627       di << "cannot create report " << aOutFile << " from the log file "
628         << aLogFile << "\n";
629       return 1;
630     }
631   }
632   else
633   {
634     di << "unrecognized command " << a[1] << "\n";
635     return 1;
636   }
637   return 0;
638 }
639
640 //==============================================================================
641 //function : dlocale
642 //purpose  :
643 //==============================================================================
644
645 static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
646 {
647   int category = LC_ALL;
648   if (n > 1)
649   {
650     const char *cat = argv[1];
651     if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
652     else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
653     else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
654     else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
655     else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
656     else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
657     else 
658     {
659       cout << "Error: cannot recognize argument " << cat << " as one of LC_ macros" << endl;
660       return 1;
661     }
662   }
663   const char* locale = (n > 2 ? argv[2] : NULL);
664   const char* result = setlocale (category, locale);
665   if (result)
666     di << result;
667   else 
668     cout << "Error: unsupported locale specification: " << locale << endl;
669   return 0;
670 }
671
672 //==============================================================================
673 //function : dmeminfo
674 //purpose  :
675 //==============================================================================
676
677 static int dmeminfo (Draw_Interpretor& theDI,
678                      Standard_Integer  theArgNb,
679                      const char**      theArgVec)
680 {
681   OSD_MemInfo aMemInfo;
682   if (theArgNb <= 1)
683   {
684     theDI << aMemInfo.ToString();
685     return 0;
686   }
687
688   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
689   {
690     TCollection_AsciiString anArg (theArgVec[anIter]);
691     anArg.LowerCase();
692     if (anArg == "virt" || anArg == "v")
693     {
694       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
695     }
696     else if (anArg == "heap" || anArg == "h")
697     {
698       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemHeapUsage)) << " ";
699     }
700     else if (anArg == "wset" || anArg == "w")
701     {
702       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
703     }
704     else if (anArg == "wsetpeak")
705     {
706       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
707     }
708     else if (anArg == "swap")
709     {
710       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
711     }
712     else if (anArg == "swappeak")
713     {
714       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
715     }
716     else if (anArg == "private")
717     {
718       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
719     }
720     else
721     {
722       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
723     }
724   }
725   theDI << "\n";
726   return 0;
727 }
728
729 //==============================================================================
730 //function : dperf
731 //purpose  :
732 //==============================================================================
733
734 static int dperf (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
735 {
736   // reset if argument is provided and it is not '0'
737   int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
738   char buffer[25600];
739   perf_sprint_all_meters (buffer, 25600 - 1, reset);
740   theDI << buffer;
741   return 0;
742 }
743
744 //==============================================================================
745 //function : dsetsignal
746 //purpose  :
747 //==============================================================================
748
749 static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
750 {
751   // arm FPE handler if argument is provided and its first symbol is not '0'
752   // or if environment variable CSF_FPE is set and its first symbol is not '0'
753   bool setFPE = false;
754   if (theArgNb > 1)
755   {
756     setFPE = (theArgVec[1][0] == '1' || theArgVec[1][0] == 't');
757   }
758   else
759   {
760     OSD_Environment aEnv ("CSF_FPE");
761     TCollection_AsciiString aEnvStr = aEnv.Value();
762     setFPE = (! aEnvStr.IsEmpty() && aEnvStr.Value(1) != '0');
763   }
764   OSD::SetSignal (setFPE);
765   theDI << "Signal handlers are set, with FPE " << (setFPE ? "armed" : "disarmed"); 
766   return 0;
767 }
768
769 //==============================================================================
770 //function : dtracelevel
771 //purpose  :
772 //==============================================================================
773
774 static int dtracelevel (Draw_Interpretor& theDI,
775                         Standard_Integer  theArgNb,
776                         const char**      theArgVec)
777 {
778   Message_Gravity aLevel = Message_Info;
779   if (theArgNb < 1 || theArgNb > 2)
780   {
781     std::cout << "Error: wrong number of arguments! See usage:\n";
782     theDI.PrintHelp (theArgVec[0]);
783     return 1;
784   }
785   else if (theArgNb == 2)
786   {
787     TCollection_AsciiString aVal (theArgVec[1]);
788     aVal.LowerCase();
789     if (aVal == "trace")
790     {
791       aLevel = Message_Trace;
792     }
793     else if (aVal == "info")
794     {
795       aLevel = Message_Info;
796     }
797     else if (aVal == "warn"
798           || aVal == "warning")
799     {
800       aLevel = Message_Warning;
801     }
802     else if (aVal == "alarm")
803     {
804       aLevel = Message_Alarm;
805     }
806     else if (aVal == "fail")
807     {
808       aLevel = Message_Fail;
809     }
810     else
811     {
812       std::cout << "Error: unknown gravity '" << theArgVec[1] << "'!\n";
813       return 1;
814     }
815   }
816
817   Handle(Message_Messenger) aMessenger = Message::DefaultMessenger();
818   if (aMessenger.IsNull())
819   {
820     std::cout << "Error: default messenger is unavailable!\n";
821     return 1;
822   }
823
824   Message_SequenceOfPrinters& aPrinters = aMessenger->ChangePrinters();
825   if (aPrinters.Length() < 1)
826   {
827     std::cout << "Error: no printers registered in default Messenger!\n";
828     return 0;
829   }
830
831   for (Standard_Integer aPrinterIter = 1; aPrinterIter <= aPrinters.Length(); ++aPrinterIter)
832   {
833     Handle(Message_Printer)& aPrinter = aPrinters.ChangeValue (aPrinterIter);
834     if (theArgNb == 1)
835     {
836       if (aPrinterIter == 1)
837       {
838         aLevel = aPrinter->GetTraceLevel();
839       }
840       else if (aLevel == aPrinter->GetTraceLevel())
841       {
842         continue;
843       }
844
845       switch (aPrinter->GetTraceLevel())
846       {
847         case Message_Trace:   theDI << "trace"; break;
848         case Message_Info:    theDI << "info";  break;
849         case Message_Warning: theDI << "warn";  break;
850         case Message_Alarm:   theDI << "alarm"; break;
851         case Message_Fail:    theDI << "fail";  break;
852       }
853       continue;
854     }
855
856     aPrinter->SetTraceLevel (aLevel);
857   }
858
859   return 0;
860 }
861
862 void Draw::BasicCommands(Draw_Interpretor& theCommands)
863 {
864   static Standard_Boolean Done = Standard_False;
865   if (Done) return;
866   Done = Standard_True;
867
868   ios::sync_with_stdio();
869
870   const char* g = "DRAW General Commands";
871
872   theCommands.Add("batch", "returns 1 in batch mode",
873                   __FILE__,ifbatch,g);
874   theCommands.Add("spy","spy [file], Save commands in file. no file close",
875                   __FILE__,spy,g);
876   theCommands.Add("wait","wait [time(10)], wait time seconds",
877                   __FILE__,Draw_wait,g);
878   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
879                   __FILE__,cpulimit,g);
880   theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
881                   __FILE__,chronom,g);
882   theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
883                   __FILE__,dchronom,g);
884   theCommands.Add("mallochook",
885                   "debug memory allocation/deallocation, w/o args for help",
886                   __FILE__, mallochook, g);
887   theCommands.Add ("meminfo",
888     "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
889     " : memory counters for this process",
890           __FILE__, dmeminfo, g);
891   theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided",
892                   __FILE__,dperf,g);
893   theCommands.Add("dsetsignal","dsetsignal [fpe=0] -- set OSD signal handler, with FPE option if argument is given",
894                   __FILE__,dsetsignal,g);
895
896   // Logging commands; note that their names are hard-coded in the code
897   // of Draw_Interpretor, thus should not be changed without update of that code!
898   theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
899                   __FILE__,dlog,g);
900   theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
901                   __FILE__,decho,g);
902   theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
903                   __FILE__, dtracelevel, g);
904
905   theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
906                   __FILE__,dbreak,g);
907   theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
908                   __FILE__,dversion,g);
909   theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",
910                   __FILE__,dlocale,g);
911 }