0024275: Cppcheck warnings on uninitialized class members
[occt.git] / src / Draw / Draw_Interpretor.cxx
CommitLineData
b311480e 1// Created on: 1995-02-23
2// Created by: Remi LEQUETTE
3// Copyright (c) 1995-1999 Matra Datavision
4// Copyright (c) 1999-2012 OPEN CASCADE SAS
5//
6// The content of this file is subject to the Open CASCADE Technology Public
7// License Version 6.5 (the "License"). You may not use the content of this file
8// except in compliance with the License. Please obtain a copy of the License
9// at http://www.opencascade.org and read it completely before using this file.
10//
11// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
12// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
13//
14// The Original Code and all software distributed under the License is
15// distributed on an "AS IS" basis, without warranty of any kind, and the
16// Initial Developer hereby disclaims all such warranties, including without
17// limitation, any warranties of merchantability, fitness for a particular
18// purpose or non-infringement. Please see the License for the specific terms
19// and conditions governing the rights and limitations under the License.
20
7fd59977 21
22
23#include <Draw_Interpretor.ixx>
24#include <Draw_Appli.hxx>
25#include <Standard_SStream.hxx>
26#include <Standard_RangeError.hxx>
27#include <Standard_ErrorHandler.hxx>
28#include <Standard_Macro.hxx>
29
30#include <TCollection_AsciiString.hxx>
31#include <TCollection_ExtendedString.hxx>
e9b037ef 32#include <OSD_Process.hxx>
d33dea30 33#include <OSD_Path.hxx>
8a262fa1 34#include <OSD.hxx>
7fd59977 35
36#include <string.h>
7fd59977 37#include <tcl.h>
38
aa02980d 39// for capturing of cout and cerr (dup(), dup2())
40#ifdef _MSC_VER
41#include <io.h>
42#endif
43#ifdef HAVE_UNISTD_H
44#include <unistd.h>
45#endif
46
47#if ! defined(STDOUT_FILENO)
48#define STDOUT_FILENO fileno(stdout)
49#endif
50#if ! defined(STDERR_FILENO)
51#define STDERR_FILENO fileno(stderr)
52#endif
53
7fd59977 54#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
55#define TCL_USES_UTF8
56#endif
57
58//
59// Auxiliary tool to convert strings in command arguments from UTF-8
60// (Tcl internal encoding since Tcl 8.1) to system local encoding,
61// normally extended Ascii as expected by OCC commands
62//
63class TclUTFToLocalStringSentry {
64 public:
65
66#ifdef TCL_USES_UTF8
67 TclUTFToLocalStringSentry (int argc, const char **argv) :
68 nb(0),
69 TclArgv(new Tcl_DString[argc]),
70 Argv(new char*[argc])
71 {
72 for (; nb < argc; nb++ ) {
73 Tcl_UtfToExternalDString ( NULL, argv[nb], -1, &TclArgv[nb] );
74 Argv[nb] = Tcl_DStringValue ( &TclArgv[nb] );
75 }
76 }
77
78 ~TclUTFToLocalStringSentry ()
79 {
80 delete[] Argv;
81 while ( nb-- >0 ) Tcl_DStringFree ( &TclArgv[nb] );
82 delete[] TclArgv;
83 }
84#else
c24d4017 85 TclUTFToLocalStringSentry (int, const char **argv) :
86 nb(0),
87 TclArgv(NULL),
88 Argv((char**)argv)
89 {}
7fd59977 90#endif
91
92 const char **GetArgv () const { return (const char **)Argv; }
93
94 private:
95 int nb;
96 Tcl_DString *TclArgv;
97 char **Argv;
98};
99
100
101//
102// Call backs for TCL
103//
104
105struct CData {
106 CData(Draw_CommandFunction ff, Draw_Interpretor* ii) : f(ff), i(ii) {}
107 Draw_CommandFunction f;
108 Draw_Interpretor* i;
109};
110
aa02980d 111// logging helpers
112namespace {
113 void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
114 {
115 for (int i=0; i < argc; i++)
116 os << argv[i] << " ";
117 os << endl;
118 }
119
120 void flush_standard_streams ()
121 {
122 fflush (stderr);
123 fflush (stdout);
124 cerr << flush;
125 cout << flush;
126 }
127
e9b037ef 128 FILE* capture_start (int std_fd, int *save_fd, char*& tmp_name)
aa02980d 129 {
e9b037ef 130 *save_fd = 0;
aa02980d 131
132 // open temporary files
e9b037ef 133 #if defined(_WIN32)
134 // use _tempnam() to decrease chances of failure (tmpfile() creates
135 // file in root folder and will fail if it is write protected), see #24132
136 static const char* tmpdir = getenv("TEMP");
137 static char prefix[256] = ""; // prefix for temporary files, initialize once per process using pid
138 if (prefix[0] == '\0')
139 sprintf (prefix, "drawtmp%d_", (int)OSD_Process().ProcessId());
140 tmp_name = _tempnam (tmpdir, prefix);
141 FILE* aTmpFile = (tmp_name != NULL ? fopen (tmp_name, "w+b") : tmpfile());
142 #else
143 tmp_name = NULL;
144 FILE* aTmpFile = tmpfile();
145 #endif
146 int fd_tmp = (aTmpFile != NULL ? fileno (aTmpFile) : -1);
147 if (fd_tmp < 0)
aa02980d 148 {
149 cerr << "Error: cannot create temporary file for capturing console output" << endl;
150 fclose (aTmpFile);
151 return NULL;
152 }
153
154 // remember current file descriptors of standard stream, and replace it by temporary
155 (*save_fd) = dup(std_fd);
156 dup2(fd_tmp, std_fd);
157 return aTmpFile;
158 }
159
e9b037ef 160 void capture_end (FILE* tmp_file, int std_fd, int save_fd, char* tmp_name, Standard_OStream &log, Standard_Boolean doEcho)
aa02980d 161 {
e9b037ef 162 if (! tmp_file)
163 return;
164
aa02980d 165 // restore normal descriptors of console stream
166 dup2 (save_fd, std_fd);
167 close(save_fd);
168
169 // extract all output and copy it to log and optionally to cout
170 const int BUFSIZE = 2048;
171 char buf[BUFSIZE];
172 rewind(tmp_file);
173 while (fgets (buf, BUFSIZE, tmp_file) != NULL)
174 {
175 log << buf;
176 if (doEcho)
177 cout << buf;
178 }
179
180 // close temporary file
181 fclose (tmp_file);
e9b037ef 182
183 // remove temporary file if this is not done by the system
184 if (tmp_name)
185 remove (tmp_name);
aa02980d 186 }
187};
188
7fd59977 189// MKV 29.03.05
190#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
191static Standard_Integer CommandCmd
192(ClientData clientData, Tcl_Interp *interp,
193 Standard_Integer argc, const char* argv[])
194#else
195static Standard_Integer CommandCmd
196(ClientData clientData, Tcl_Interp *interp,
197 Standard_Integer argc, char* argv[])
198#endif
199{
200 static Standard_Integer code;
201 code = TCL_OK;
202 CData* C = (CData*) clientData;
aa02980d 203 Draw_Interpretor& di = *(C->i);
204
205 // log command execution, except commands manipulating log itself and echo
206 Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
207 strcmp (argv[0], "decho") == 0);
208 Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
209 Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
210 if (doLog)
211 dumpArgs (di.Log(), argc, argv);
212 if (doEcho)
213 dumpArgs (cout, argc, argv);
214
215 // flush cerr and cout
216 flush_standard_streams();
217
218 // capture cout and cerr to log
e9b037ef 219 char *err_name = NULL, *out_name = NULL;
aa02980d 220 FILE * aFile_err = NULL;
221 FILE * aFile_out = NULL;
222 int fd_err_save = 0;
223 int fd_out_save = 0;
224 if (doLog)
225 {
e9b037ef 226 aFile_out = capture_start (STDOUT_FILENO, &fd_out_save, out_name);
227 aFile_err = capture_start (STDERR_FILENO, &fd_err_save, err_name);
aa02980d 228 }
7fd59977 229
aa02980d 230 // run command
7fd59977 231 try {
232 OCC_CATCH_SIGNALS
233
8a262fa1 234 // get exception if control-break has been pressed
235 OSD::ControlBreak();
236
7fd59977 237 // OCC63: Convert strings from UTF-8 to local encoding, normally expected by OCC commands
238 TclUTFToLocalStringSentry anArgs ( argc, (const char**)argv );
239
7fd59977 240 Standard_Integer fres = C->f ( di, argc, anArgs.GetArgv() );
241 if (fres != 0)
242 code = TCL_ERROR;
243 }
244 catch (Standard_Failure) {
245
246 Handle(Standard_Failure) E = Standard_Failure::Caught();
247
248 // fail if Draw_ExitOnCatch is set
249 // MKV 29.03.05
250#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
251 const char* cc = Tcl_GetVar(interp,
252 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
253#else
254 char* const cc = Tcl_GetVar(interp,
255 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
256#endif
257
258 cout << "An exception was caught " << E << endl;
259
91322f44 260 if (cc && Draw::Atoi(cc)) {
7fd59977 261#ifdef WNT
262 Tcl_Exit(0);
263#else
264 Tcl_Eval(interp,"exit");
265#endif
266 }
267
268 // get the error message
269 Standard_SStream ss;
270 ss << "** Exception ** " << E << ends ;
271#ifdef USE_STL_STREAM
272 Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
273#else
274 Tcl_SetResult(interp,(char*)(ss.str()),TCL_VOLATILE);
275#endif
276 code = TCL_ERROR;
277 }
aa02980d 278
279 // flush streams
280 flush_standard_streams();
281
282 // end capturing cout and cerr
283 if (doLog)
284 {
e9b037ef 285 capture_end (aFile_err, STDERR_FILENO, fd_err_save, err_name, di.Log(), doEcho);
286 capture_end (aFile_out, STDOUT_FILENO, fd_out_save, out_name, di.Log(), doEcho);
aa02980d 287 }
288
289 // log command result
290 const char* aResultStr = NULL;
291 if (doLog)
292 {
293 aResultStr = Tcl_GetStringResult (interp);
294 if (aResultStr != 0 && aResultStr[0] != '\0' )
295 di.Log() << Tcl_GetStringResult (interp) << endl;
296 }
297 if (doEcho)
298 {
299 if (aResultStr == NULL)
300 aResultStr = Tcl_GetStringResult (interp);
301 if (aResultStr != 0 && aResultStr[0] != '\0' )
302 cout << Tcl_GetStringResult (interp) << endl;
303 }
304
7fd59977 305 return code;
306}
307
308
309static void CommandDelete (ClientData clientData)
310{
311 CData *C = (CData*) clientData;
312 delete C;
313}
314
315//=======================================================================
316//function : Draw_Interpretor
317//purpose :
318//=======================================================================
319
320Draw_Interpretor::Draw_Interpretor() :
aa02980d 321 isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
7fd59977 322{
0d969553
Y
323// The tcl interpreter is not created immediately as it is kept
324// by a global variable and created and deleted before the main().
7fd59977 325 myInterp = NULL;
326}
327
328//=======================================================================
329//function : Init
0d969553 330//purpose : It is necessary to call this function
7fd59977 331//=======================================================================
332
333void Draw_Interpretor::Init()
334{
335 if (isAllocated)
336 Tcl_DeleteInterp(myInterp);
337 isAllocated=Standard_True;
338 myInterp=Tcl_CreateInterp();
339}
340
341//=======================================================================
342//function : Draw_Interpretor
343//purpose :
344//=======================================================================
345
346Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
347 isAllocated(Standard_False),
aa02980d 348 myInterp(p),
349 myDoLog(Standard_False),
350 myDoEcho(Standard_False)
7fd59977 351{
352}
353
354//=======================================================================
355//function : Add
356//purpose :
357//=======================================================================
358//#ifdef WNT
359void Draw_Interpretor::Add(const Standard_CString n,
360 const Standard_CString help,
361 const Draw_CommandFunction f,
362 const Standard_CString group)
363//#else
364//void Draw_Interpretor::Add(const Standard_CString n,
365// const Standard_CString help,
366// const Draw_CommandFunction& f,
367// const Standard_CString group)
368//#endif
369{
370 Standard_PCharacter pN, pHelp, pGroup;
371 //
372 pN=(Standard_PCharacter)n;
373 pHelp=(Standard_PCharacter)help;
374 pGroup=(Standard_PCharacter)group;
375 //
376 if (myInterp==NULL) Init();
377
378 CData* C = new CData(f,this);
379
380 Tcl_CreateCommand(myInterp, pN ,CommandCmd, (ClientData) C, CommandDelete);
381
382 // add the help
383 Tcl_SetVar2(myInterp,"Draw_Helps", pN, pHelp, TCL_GLOBAL_ONLY);
384 Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
385 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
386}
387//=======================================================================
388//function : Add
389//purpose :
390//=======================================================================
391void Draw_Interpretor::Add(const Standard_CString n,
392 const Standard_CString help,
393 const Standard_CString file_name,
394 const Draw_CommandFunction f,
395 const Standard_CString group)
396{
397 Standard_PCharacter pN, pHelp, pGroup, pFileName;
398 //
399 pN=(Standard_PCharacter)n;
400 pHelp=(Standard_PCharacter)help;
401 pGroup=(Standard_PCharacter)group;
402 pFileName=(Standard_PCharacter)file_name;
403 //
404 if (myInterp==NULL) Init();
405
406 CData* C = new CData(f,this);
7fd59977 407 Tcl_CreateCommand(myInterp,pN,CommandCmd, (ClientData) C, CommandDelete);
408
409 // add the help
410 Tcl_SetVar2(myInterp,"Draw_Helps",pN,pHelp,TCL_GLOBAL_ONLY);
411 Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
412 TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
938a360f 413
d33dea30
PK
414 // add path to source file (keep not more than two last subdirectories)
415 OSD_Path aPath (pFileName);
416 Standard_Integer nbTrek = aPath.TrekLength();
417 for (Standard_Integer i = 2; i < nbTrek; i++)
418 aPath.RemoveATrek (1);
419 aPath.SetDisk("");
420 aPath.SetNode("");
421 TCollection_AsciiString aSrcPath;
422 aPath.SystemName (aSrcPath);
423 Tcl_SetVar2(myInterp,"Draw_Files",pN,aSrcPath.ToCString(),TCL_GLOBAL_ONLY);
7fd59977 424}
425
426
427//=======================================================================
428//function : Remove
429//purpose :
430//=======================================================================
431
432Standard_Boolean Draw_Interpretor::Remove(Standard_CString const n)
433{
434 Standard_PCharacter pN;
435 //
436 pN=(Standard_PCharacter)n;
437
438 Standard_Integer result = Tcl_DeleteCommand(myInterp,pN);
439 return result == 0;
440}
441
442//=======================================================================
443//function : Result
444//purpose :
445//=======================================================================
446
447Standard_CString Draw_Interpretor::Result() const
448{
449#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
450 return Tcl_GetStringResult(myInterp);
451#else
452 return myInterp->result;
453#endif
454}
455
456//=======================================================================
457//function : Reset
458//purpose :
459//=======================================================================
460
461void Draw_Interpretor::Reset()
462{
463 Tcl_ResetResult(myInterp);
464}
465
466//=======================================================================
467//function : Append
468//purpose :
469//=======================================================================
470
471Draw_Interpretor& Draw_Interpretor::Append(const Standard_CString s)
472{
473#ifdef TCL_USES_UTF8
474 // Convert string to UTF-8 format for Tcl
475 Tcl_DString TclString;
476 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
477 Tcl_AppendResult ( myInterp, Tcl_DStringValue ( &TclString ), (Standard_CString)0 );
478 Tcl_DStringFree ( &TclString );
479#else
480 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
481#endif
482 return *this;
483}
484
485//=======================================================================
486//function : Append
487//purpose :
488//=======================================================================
489
490Draw_Interpretor& Draw_Interpretor::Append(const TCollection_AsciiString& s)
491{
492 return Append (s.ToCString());
493}
494
495//=======================================================================
496//function : Append
497//purpose :
498//=======================================================================
499
500Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& theString)
501{
502#ifdef TCL_USES_UTF8
503 // Convert string to UTF-8 format for Tcl
504 char *str = new char[theString.LengthOfCString()+1];
505 theString.ToUTF8CString (str);
506 Tcl_AppendResult ( myInterp, str, (Standard_CString)0 );
507 delete[] str;
508#else
509 // put as ascii string, replacing non-ascii characters by '?'
510 TCollection_AsciiString str (theString, '?');
511 Tcl_AppendResult(myInterp,str.ToCString(),(Standard_CString)0);
512#endif
513 return *this;
514}
515
516//=======================================================================
517//function : Append
518//purpose :
519//=======================================================================
520
521Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
522{
523 char c[100];
91322f44 524 Sprintf(c,"%d",i);
7fd59977 525 Tcl_AppendResult(myInterp,c,(Standard_CString)0);
526 return *this;
527}
528
529//=======================================================================
530//function : Append
531//purpose :
532//=======================================================================
533
534Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
535{
536 char s[100];
91322f44 537 Sprintf(s,"%.17g",r);
7fd59977 538 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
539 return *this;
540}
541
542//=======================================================================
543//function : Append
544//purpose :
545//=======================================================================
546
547Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
548{
549#ifdef USE_STL_STREAM
550 return Append (s.str().c_str());
551#else
552 // Note: use dirty tricks -- unavoidable with old streams
553 TCollection_AsciiString aStr (((Standard_SStream&)AReason).str(), AReason.pcount());
554 ((Standard_SStream&)AReason).freeze (false);
555 return Append (aStr.ToCString());
556#endif
557}
558
559//=======================================================================
560//function : AppendElement
561//purpose :
562//=======================================================================
563
564void Draw_Interpretor::AppendElement(const Standard_CString s)
565{
566#ifdef TCL_USES_UTF8
567 // Convert string to UTF-8 format for Tcl
568 Tcl_DString TclString;
569 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
570 Tcl_AppendElement ( myInterp, Tcl_DStringValue ( &TclString ) );
571 Tcl_DStringFree ( &TclString );
572#else
573#ifdef IRIX
574 //AppendElement is declared as (Tcl_Interp *interp, char *string)
575 //on SGI 32
576 Tcl_AppendElement(myInterp,(char*) s);
577#else
578 Tcl_AppendElement(myInterp, s);
579#endif
580#endif
581}
582
583//=======================================================================
584//function : Eval
585//purpose :
586//=======================================================================
587
588Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
589{
590 Standard_PCharacter pLine;
591 //
592 pLine=(Standard_PCharacter)line;
593 //
594 return Tcl_Eval(myInterp,pLine);
595}
596
597
598//=======================================================================
599//function : Eval
600//purpose :
601//=======================================================================
602
603Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
604 const Standard_Integer flags)
605{
606 Standard_PCharacter pLine;
607 //
608 pLine=(Standard_PCharacter)line;
609 return Tcl_RecordAndEval(myInterp,pLine,flags);
610}
611
612//=======================================================================
613//function : EvalFile
614//purpose :
615//=======================================================================
616
617Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
618{
619 Standard_PCharacter pfname;
620 //
621 pfname=(Standard_PCharacter)fname;
622 return Tcl_EvalFile(myInterp,pfname);
623}
624
625//=======================================================================
626//function :Complete
627//purpose :
628//=======================================================================
629
630Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line)
631{
632 Standard_PCharacter pLine;
633 //
634 pLine=(Standard_PCharacter)line;
635 return Tcl_CommandComplete(pLine);
636}
637
638//=======================================================================
639//function : Destroy
640//purpose :
641//=======================================================================
642
643void Draw_Interpretor::Destroy()
644{
645 // MKV 01.02.05
646#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
647 try {
648 OCC_CATCH_SIGNALS
649 Tcl_Exit(0);
650 }
651 catch (Standard_Failure) {
652#ifdef DEB
653 cout <<"Tcl_Exit have an exeption" << endl;
654#endif
655 }
656#else
657#ifdef WNT
658 Tcl_Exit(0);
659#endif
660#endif
661}
662
663//=======================================================================
664//function : Interp
665//purpose :
666//=======================================================================
667
668Draw_PInterp Draw_Interpretor::Interp() const
669{
670 Standard_DomainError_Raise_if (myInterp==NULL , "No call for Draw_Interpretor::Init()");
671 return myInterp;
672}
673
674void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
675{
676 if (isAllocated)
677 Tcl_DeleteInterp(myInterp);
678 isAllocated = Standard_False;
679 myInterp = PIntrp;
680}
aa02980d 681
682//=======================================================================
683//function : Logging
684//purpose :
685//=======================================================================
686
687void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
688{
689 myDoLog = doLog;
690}
691
692void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
693{
694 myDoEcho = doEcho;
695}
696
697Standard_Boolean Draw_Interpretor::GetDoLog () const
698{
699 return myDoLog;
700}
701
702Standard_Boolean Draw_Interpretor::GetDoEcho () const
703{
704 return myDoEcho;
705}
706
707Standard_SStream& Draw_Interpretor::Log ()
708{
709 return myLog;
60be1f9b 710}