0028095: Draw Harness, ViewerTest - use RGBA format instead of BGRA within vreadpixel
[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_GLES2
297   di << "OpenGL: ES2\n";
298 #else
299   di << "OpenGL: desktop\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   #if _MSC_VER < 1900
327     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";
328   #else
329     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";
330   #endif
331 #elif defined(__GNUC__)
332   di << "Compiler: GCC " << __GNUC__ << "." << __GNUC_MINOR__ << "." << __GNUC_PATCHLEVEL__ << "\n";
333 #else
334   di << "Compiler: unrecognized\n";
335 #endif
336
337   // Cygwin and MinGW specifics
338 #if defined(__CYGWIN__)
339   di << "Cygwin\n";
340 #endif
341 #if defined(__MINGW64__)
342   di << "MinGW 64 " << __MINGW64_VERSION_MAJOR << "." << __MINGW64_VERSION_MINOR << "\n";
343 #elif defined(__MINGW32__)
344   di << "MinGW 32 " << __MINGW32_MAJOR_VERSION << "." << __MINGW32_MINOR_VERSION << "\n";
345 #endif 
346
347   // architecture
348 #if defined(__amd64) || defined(__x86_64) || defined(_M_AMD64)
349   di << "Architecture: AMD64\n";
350 #elif defined(__i386) || defined(_M_IX86) || defined(__X86__)|| defined(_X86_)
351   di << "Architecture: Intel x86\n";
352 #elif defined(_M_IA64) || defined(__ia64__)
353   di << "Architecture: Intel Itanium (IA 64)\n";
354 #elif defined(__sparc__) || defined(__sparc)
355   di << "Architecture: SPARC\n";
356 #else
357   di << "Architecture: unrecognized\n";
358 #endif
359
360   // OS
361 #if defined(_WIN32) || defined(__WINDOWS__) || defined(__WIN32__)
362   di << "OS: Windows\n";
363 #elif defined(__APPLE__) || defined(__MACH__)
364   di << "OS: Mac OS X\n";
365 #elif defined(__sun) 
366   di << "OS: SUN Solaris\n";
367 #elif defined(__ANDROID__) /* must be before Linux */
368   #include <android/api-level.h>
369   di << "OS: Android (__ANDROID_API__ = " << __ANDROID_API__ << ")\n";
370 #elif defined(__QNXNTO__)
371   di << "OS: QNX Neutrino\n";
372 #elif defined(__QNX__)
373   di << "OS: QNX\n";
374 #elif defined(__linux__)
375   di << "OS: Linux\n";
376 #elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
377   #include <sys/param.h>
378   di << "OS: BSD (BSD = " << BSD << ")\n";
379 #else
380   di << "OS: unrecognized\n";
381 #endif
382
383   return 0;
384 }
385
386 //=======================================================================
387 //function : wait
388 //purpose  : 
389 //=======================================================================
390
391 static Standard_Integer Draw_wait(Draw_Interpretor& , Standard_Integer n, const char** a)
392 {
393   Standard_Integer w = 10;
394   if (n > 1)
395     w = Draw::Atoi(a[1]);
396   time_t ct = time(NULL) + w;
397   while (time(NULL) < ct) {};
398   return 0;
399 }
400
401 //=======================================================================
402 //function : cpulimit
403 //purpose  : 
404 //=======================================================================
405 #ifdef _WIN32
406 static unsigned int __stdcall CpuFunc (void * /*param*/)
407 {
408   clock_t anElapCurrent;
409   clock_t aCurrent;
410
411   for(;;)
412   {
413     Sleep (5);
414     Standard_Real anUserSeconds, aSystemSeconds;
415     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
416     aCurrent = clock_t(anUserSeconds + aSystemSeconds);
417     anElapCurrent = clock_t(aTimer.ElapsedTime());
418     
419     if (CPU_LIMIT > 0 && (aCurrent - CPU_CURRENT) >= CPU_LIMIT)
420     {
421       cout << "Process killed by CPU limit (" << CPU_LIMIT << " sec)" << endl;
422       aTimer.Stop();
423       ExitProcess (2);
424     }
425     if (CPU_LIMIT > 0 && anElapCurrent >= CPU_LIMIT)
426     {
427       cout << "Process killed by elapsed limit (" << CPU_LIMIT << " sec)" << endl;
428       aTimer.Stop();
429       ExitProcess (2);
430     }
431   }
432 }
433 #else
434 static void cpulimitSignalHandler (int)
435 {
436   cout << "Process killed by CPU limit  (" << CPU_LIMIT << " sec)" << endl;
437   exit(2);
438 }
439 static void *CpuFunc(void* /*threadarg*/)
440 {
441   clock_t anElapCurrent;
442   for(;;)
443   {
444     sleep (5);
445     anElapCurrent = clock_t(aTimer.ElapsedTime());
446     if (CPU_LIMIT >0 && (anElapCurrent) >= CPU_LIMIT) {
447       cout << "Process killed by elapsed limit  (" << CPU_LIMIT << " sec)" << endl;
448       exit(2);
449     }
450   }
451   return NULL;
452 }
453 #endif
454
455 #ifdef _WIN32
456 static Standard_Integer cpulimit(Draw_Interpretor&, Standard_Integer n, const char** a)
457 {
458 #else
459 static Standard_Integer cpulimit(Draw_Interpretor& di, Standard_Integer n, const char** a)
460 {
461 #endif
462   static int aFirst = 1;
463 #ifdef _WIN32
464   // Windows specific code
465   unsigned int __stdcall CpuFunc (void *);
466   unsigned aThreadID;
467
468   if (n <= 1){
469     CPU_LIMIT = RLIM_INFINITY;
470   } else {
471     CPU_LIMIT = Draw::Atoi (a[1]);
472     Standard_Real anUserSeconds, aSystemSeconds;
473     OSD_Chronometer::GetProcessCPU (anUserSeconds, aSystemSeconds);
474     CPU_CURRENT = clock_t(anUserSeconds + aSystemSeconds);
475     aTimer.Reset();
476     aTimer.Start();
477     if (aFirst) // Launch the thread only at the 1st call.
478     {
479       aFirst = 0;
480       _beginthreadex (NULL, 0, CpuFunc, NULL, 0, &aThreadID);
481     }
482   }
483
484 #else 
485   // Unix & Linux
486   rlimit rlp;
487   rlp.rlim_max = RLIM_INFINITY;
488   if (n <= 1)
489     rlp.rlim_cur = RLIM_INFINITY;
490   else
491     rlp.rlim_cur = Draw::Atoi(a[1]);
492   CPU_LIMIT = rlp.rlim_cur;
493
494   int status;
495   status=setrlimit(RLIMIT_CPU,&rlp);
496   if (status !=0)
497     di << "status cpulimit setrlimit : " << status << "\n";
498
499   // set signal handler to print a message before death
500   struct sigaction act, oact;
501   memset (&act, 0, sizeof(act));
502   act.sa_handler = cpulimitSignalHandler;
503   sigaction (SIGXCPU, &act, &oact);
504
505   // cpulimit for elapsed time
506   aTimer.Reset();
507   aTimer.Start();
508   pthread_t cpulimitThread;
509   if (aFirst) // Launch the thread only at the 1st call.
510   {
511     aFirst = 0;
512     pthread_create(&cpulimitThread, NULL, CpuFunc, NULL);
513   }
514 #endif
515   return 0;
516 }
517
518
519 //=======================================================================
520 //function : mallochook
521 //purpose  : 
522 //=======================================================================
523
524 static Standard_Integer mallochook(Draw_Interpretor& di, Standard_Integer n,
525                                    const char** a)
526 {
527   if (n < 2)
528   {
529     di << "\
530 usage: mallochook cmd\n\
531 where cmd is one of:\n\
532   set [<op>]      - set callback to malloc/free; op is one of the following:\n\
533                     0 - set callback to NULL,\n\
534                     1 - set callback OSD_MAllocHook::CollectBySize (default)\n\
535                     2 - set callback OSD_MAllocHook::LogFileHandler\n\
536   reset           - reset the CollectBySize handler\n\
537   report1 [<outfile>]\n\
538                   - write report from CollectBySize handler in <outfile>\n\
539   open [<logfile>]\n\
540                   - open file for writing the log with LogFileHandler\n\
541   close           - close the log file with LogFileHandler\n\
542   report2 [<flag>] [<logfile>] [<outfile>]\n\
543                   - scan <logfile> written with LogFileHandler\n\
544                     and make synthesized report in <outfile>; <flag> can be:\n\
545                     0 - simple stats by sizes (default),\n\
546                     1 - with alive allocation numbers\n\
547 By default <logfile> is \"mem-log.txt\", <outfile> is \"mem-stat.txt\""
548       << "\n";
549     return 0;
550   }
551   if (strcmp(a[1], "set") == 0)
552   {
553     int aType = (n > 2 ? Draw::Atoi(a[2]) : 1);
554     if (aType < 0 || aType > 2)
555     {
556       di << "unknown op of the command set\n";
557       return 1;
558     }
559     else if (aType == 0)
560     {
561       OSD_MAllocHook::SetCallback(NULL);
562       di << "callback is unset\n";
563     }
564     else if (aType == 1)
565     {
566       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetCollectBySize());
567       di << "callback is set to CollectBySize\n";
568     }
569     else //if (aType == 2)
570     {
571       OSD_MAllocHook::SetCallback(OSD_MAllocHook::GetLogFileHandler());
572       di << "callback is set to LogFileHandler\n";
573     }
574   }
575   else if (strcmp(a[1], "reset") == 0)
576   {
577     OSD_MAllocHook::GetCollectBySize()->Reset();
578     di << "CollectBySize handler is reset\n";
579   }
580   else if (strcmp(a[1], "open") == 0)
581   {
582     const char* aFileName = (n > 2 ? a[2] : "mem-log.txt");
583     if (!OSD_MAllocHook::GetLogFileHandler()->Open(aFileName))
584     {
585       di << "cannot create file " << aFileName << " for writing\n";
586       return 1;
587     }
588     di << "log file " << aFileName << " is opened for writing\n";
589   }
590   else if (strcmp(a[1], "close") == 0)
591   {
592     OSD_MAllocHook::GetLogFileHandler()->Close();
593     di << "log file is closed\n";
594   }
595   else if (strcmp(a[1], "report1") == 0)
596   {
597     const char* aOutFile = "mem-stat.txt";
598     if (n > 2)
599       aOutFile = a[2];
600     if (OSD_MAllocHook::GetCollectBySize()->MakeReport(aOutFile))
601     {
602       di << "report " << aOutFile << " has been created\n";
603     }
604     else
605     {
606       di << "cannot create report " << aOutFile << "\n";
607       return 1;
608     }
609   }
610   else if (strcmp(a[1], "report2") == 0)
611   {
612     Standard_Boolean includeAlive = Standard_False;
613     const char* aLogFile = "mem-log.txt";
614     const char* aOutFile = "mem-stat.txt";
615     if (n > 2)
616     {
617       includeAlive = (Draw::Atoi(a[2]) != 0);
618       if (n > 3)
619       {
620         aLogFile = a[3];
621         if (n > 4)
622           aOutFile = a[4];
623       }
624     }
625     if (OSD_MAllocHook::LogFileHandler::MakeReport(aLogFile, aOutFile, includeAlive))
626     {
627       di << "report " << aOutFile << " has been created\n";
628     }
629     else
630     {
631       di << "cannot create report " << aOutFile << " from the log file "
632         << aLogFile << "\n";
633       return 1;
634     }
635   }
636   else
637   {
638     di << "unrecognized command " << a[1] << "\n";
639     return 1;
640   }
641   return 0;
642 }
643
644 //==============================================================================
645 //function : dlocale
646 //purpose  :
647 //==============================================================================
648
649 static int dlocale (Draw_Interpretor& di, Standard_Integer n, const char** argv)
650 {
651   int category = LC_ALL;
652   if (n > 1)
653   {
654     const char *cat = argv[1];
655     if ( ! strcmp (cat, "LC_ALL") ) category = LC_ALL;
656     else if ( ! strcmp (cat, "LC_COLLATE") ) category = LC_COLLATE;
657     else if ( ! strcmp (cat, "LC_CTYPE") ) category = LC_CTYPE;
658     else if ( ! strcmp (cat, "LC_MONETARY") ) category = LC_MONETARY;
659     else if ( ! strcmp (cat, "LC_NUMERIC") ) category = LC_NUMERIC;
660     else if ( ! strcmp (cat, "LC_TIME") ) category = LC_TIME;
661     else 
662     {
663       cout << "Error: cannot recognize argument " << cat << " as one of LC_ macros" << endl;
664       return 1;
665     }
666   }
667   const char* locale = (n > 2 ? argv[2] : NULL);
668   const char* result = setlocale (category, locale);
669   if (result)
670     di << result;
671   else 
672     cout << "Error: unsupported locale specification: " << locale << endl;
673   return 0;
674 }
675
676 //==============================================================================
677 //function : dmeminfo
678 //purpose  :
679 //==============================================================================
680
681 static int dmeminfo (Draw_Interpretor& theDI,
682                      Standard_Integer  theArgNb,
683                      const char**      theArgVec)
684 {
685   OSD_MemInfo aMemInfo;
686   if (theArgNb <= 1)
687   {
688     theDI << aMemInfo.ToString();
689     return 0;
690   }
691
692   for (Standard_Integer anIter = 1; anIter < theArgNb; ++anIter)
693   {
694     TCollection_AsciiString anArg (theArgVec[anIter]);
695     anArg.LowerCase();
696     if (anArg == "virt" || anArg == "v")
697     {
698       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemVirtual)) << " ";
699     }
700     else if (anArg == "heap" || anArg == "h")
701     {
702       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemHeapUsage)) << " ";
703     }
704     else if (anArg == "wset" || anArg == "w")
705     {
706       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSet)) << " ";
707     }
708     else if (anArg == "wsetpeak")
709     {
710       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemWorkingSetPeak)) << " ";
711     }
712     else if (anArg == "swap")
713     {
714       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsage)) << " ";
715     }
716     else if (anArg == "swappeak")
717     {
718       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemSwapUsagePeak)) << " ";
719     }
720     else if (anArg == "private")
721     {
722       theDI << Standard_Real (aMemInfo.Value (OSD_MemInfo::MemPrivate)) << " ";
723     }
724     else
725     {
726       std::cerr << "Unknown argument '" << theArgVec[anIter] << "'!\n";
727     }
728   }
729   theDI << "\n";
730   return 0;
731 }
732
733 //==============================================================================
734 //function : dperf
735 //purpose  :
736 //==============================================================================
737
738 static int dperf (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
739 {
740   // reset if argument is provided and it is not '0'
741   int reset = (theArgNb > 1 ? theArgVec[1][0] != '0' && theArgVec[1][0] != '\0' : 0);
742   char buffer[25600];
743   perf_sprint_all_meters (buffer, 25600 - 1, reset);
744   theDI << buffer;
745   return 0;
746 }
747
748 //==============================================================================
749 //function : dsetsignal
750 //purpose  :
751 //==============================================================================
752
753 static int dsetsignal (Draw_Interpretor& theDI, Standard_Integer theArgNb, const char** theArgVec)
754 {
755   // arm FPE handler if argument is provided and its first symbol is not '0'
756   // or if environment variable CSF_FPE is set and its first symbol is not '0'
757   bool setFPE = false;
758   if (theArgNb > 1)
759   {
760     setFPE = (theArgVec[1][0] == '1' || theArgVec[1][0] == 't');
761   }
762   else
763   {
764     OSD_Environment aEnv ("CSF_FPE");
765     TCollection_AsciiString aEnvStr = aEnv.Value();
766     setFPE = (! aEnvStr.IsEmpty() && aEnvStr.Value(1) != '0');
767   }
768   OSD::SetSignal (setFPE);
769   theDI << "Signal handlers are set, with FPE " << (setFPE ? "armed" : "disarmed"); 
770   return 0;
771 }
772
773 //==============================================================================
774 //function : dtracelevel
775 //purpose  :
776 //==============================================================================
777
778 static int dtracelevel (Draw_Interpretor& theDI,
779                         Standard_Integer  theArgNb,
780                         const char**      theArgVec)
781 {
782   Message_Gravity aLevel = Message_Info;
783   if (theArgNb < 1 || theArgNb > 2)
784   {
785     std::cout << "Error: wrong number of arguments! See usage:\n";
786     theDI.PrintHelp (theArgVec[0]);
787     return 1;
788   }
789   else if (theArgNb == 2)
790   {
791     TCollection_AsciiString aVal (theArgVec[1]);
792     aVal.LowerCase();
793     if (aVal == "trace")
794     {
795       aLevel = Message_Trace;
796     }
797     else if (aVal == "info")
798     {
799       aLevel = Message_Info;
800     }
801     else if (aVal == "warn"
802           || aVal == "warning")
803     {
804       aLevel = Message_Warning;
805     }
806     else if (aVal == "alarm")
807     {
808       aLevel = Message_Alarm;
809     }
810     else if (aVal == "fail")
811     {
812       aLevel = Message_Fail;
813     }
814     else
815     {
816       std::cout << "Error: unknown gravity '" << theArgVec[1] << "'!\n";
817       return 1;
818     }
819   }
820
821   Handle(Message_Messenger) aMessenger = Message::DefaultMessenger();
822   if (aMessenger.IsNull())
823   {
824     std::cout << "Error: default messenger is unavailable!\n";
825     return 1;
826   }
827
828   Message_SequenceOfPrinters& aPrinters = aMessenger->ChangePrinters();
829   if (aPrinters.Length() < 1)
830   {
831     std::cout << "Error: no printers registered in default Messenger!\n";
832     return 0;
833   }
834
835   for (Standard_Integer aPrinterIter = 1; aPrinterIter <= aPrinters.Length(); ++aPrinterIter)
836   {
837     Handle(Message_Printer)& aPrinter = aPrinters.ChangeValue (aPrinterIter);
838     if (theArgNb == 1)
839     {
840       if (aPrinterIter == 1)
841       {
842         aLevel = aPrinter->GetTraceLevel();
843       }
844       else if (aLevel == aPrinter->GetTraceLevel())
845       {
846         continue;
847       }
848
849       switch (aPrinter->GetTraceLevel())
850       {
851         case Message_Trace:   theDI << "trace"; break;
852         case Message_Info:    theDI << "info";  break;
853         case Message_Warning: theDI << "warn";  break;
854         case Message_Alarm:   theDI << "alarm"; break;
855         case Message_Fail:    theDI << "fail";  break;
856       }
857       continue;
858     }
859
860     aPrinter->SetTraceLevel (aLevel);
861   }
862
863   return 0;
864 }
865
866 void Draw::BasicCommands(Draw_Interpretor& theCommands)
867 {
868   static Standard_Boolean Done = Standard_False;
869   if (Done) return;
870   Done = Standard_True;
871
872   ios::sync_with_stdio();
873
874   const char* g = "DRAW General Commands";
875
876   theCommands.Add("batch", "returns 1 in batch mode",
877                   __FILE__,ifbatch,g);
878   theCommands.Add("spy","spy [file], Save commands in file. no file close",
879                   __FILE__,spy,g);
880   theCommands.Add("wait","wait [time(10)], wait time seconds",
881                   __FILE__,Draw_wait,g);
882   theCommands.Add("cpulimit","cpulimit [nbseconds], no args remove limits",
883                   __FILE__,cpulimit,g);
884   theCommands.Add("chrono","chrono [ name start/stop/reset/show]",
885                   __FILE__,chronom,g);
886   theCommands.Add("dchrono","dchrono [ name start/stop/reset/show]",
887                   __FILE__,dchronom,g);
888   theCommands.Add("mallochook",
889                   "debug memory allocation/deallocation, w/o args for help",
890                   __FILE__, mallochook, g);
891   theCommands.Add ("meminfo",
892     "meminfo [virt|v] [heap|h] [wset|w] [wsetpeak] [swap] [swappeak] [private]"
893     " : memory counters for this process",
894           __FILE__, dmeminfo, g);
895   theCommands.Add("dperf","dperf [reset] -- show performance counters, reset if argument is provided",
896                   __FILE__,dperf,g);
897   theCommands.Add("dsetsignal","dsetsignal [fpe=0] -- set OSD signal handler, with FPE option if argument is given",
898                   __FILE__,dsetsignal,g);
899
900   // Logging commands; note that their names are hard-coded in the code
901   // of Draw_Interpretor, thus should not be changed without update of that code!
902   theCommands.Add("dlog", "manage logging of commands and output; run without args to get help",
903                   __FILE__,dlog,g);
904   theCommands.Add("decho", "switch on / off echo of commands to cout; run without args to get help",
905                   __FILE__,decho,g);
906   theCommands.Add("dtracelevel", "dtracelevel [trace|info|warn|alarm|fail]",
907                   __FILE__, dtracelevel, g);
908
909   theCommands.Add("dbreak", "raises Tcl exception if user has pressed Control-Break key",
910                   __FILE__,dbreak,g);
911   theCommands.Add("dversion", "provides information on OCCT build configuration (version, compiler, OS, C library, etc.)",
912                   __FILE__,dversion,g);
913   theCommands.Add("dlocale", "set and / or query locate of C subsystem (function setlocale())",
914                   __FILE__,dlocale,g);
915 }