0027772: Foundation Classes - define Standard_Boolean using C++ type "bool" instead...
[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
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
dda67c1c 17#include <Draw_Interpretor.hxx>
7fd59977 18#include <Draw_Appli.hxx>
19#include <Standard_SStream.hxx>
20#include <Standard_RangeError.hxx>
21#include <Standard_ErrorHandler.hxx>
22#include <Standard_Macro.hxx>
23
24#include <TCollection_AsciiString.hxx>
25#include <TCollection_ExtendedString.hxx>
e9b037ef 26#include <OSD_Process.hxx>
d33dea30 27#include <OSD_Path.hxx>
8a262fa1 28#include <OSD.hxx>
95e05159 29#include <OSD_File.hxx>
7fd59977 30
31#include <string.h>
7fd59977 32#include <tcl.h>
03155c18 33#ifndef _WIN32
34#include <unistd.h>
35#endif
7fd59977 36
aa02980d 37// for capturing of cout and cerr (dup(), dup2())
7c65581d 38#ifdef _WIN32
aa02980d 39#include <io.h>
40#endif
aa02980d 41
42#if ! defined(STDOUT_FILENO)
43#define STDOUT_FILENO fileno(stdout)
44#endif
45#if ! defined(STDERR_FILENO)
46#define STDERR_FILENO fileno(stderr)
47#endif
48
7fd59977 49#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
50#define TCL_USES_UTF8
51#endif
52
aa02980d 53// logging helpers
54namespace {
55 void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
56 {
57 for (int i=0; i < argc; i++)
58 os << argv[i] << " ";
59 os << endl;
60 }
61
62 void flush_standard_streams ()
63 {
64 fflush (stderr);
65 fflush (stdout);
66 cerr << flush;
67 cout << flush;
68 }
69
95e05159 70 int capture_start (OSD_File& theTmpFile, int std_fd)
aa02980d 71 {
95e05159 72 theTmpFile.BuildTemporary();
73 if (theTmpFile.Failed())
aa02980d 74 {
75 cerr << "Error: cannot create temporary file for capturing console output" << endl;
95e05159 76 return -1;
aa02980d 77 }
78
79 // remember current file descriptors of standard stream, and replace it by temporary
95e05159 80 return theTmpFile.Capture(std_fd);
aa02980d 81 }
82
95e05159 83 void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
aa02980d 84 {
95e05159 85 if (!tmp_file)
e9b037ef 86 return;
87
aa02980d 88 // restore normal descriptors of console stream
7c65581d 89 #ifdef _WIN32
90 _dup2(save_fd, std_fd);
91 _close(save_fd);
92 #else
95e05159 93 dup2(save_fd, std_fd);
aa02980d 94 close(save_fd);
7c65581d 95 #endif
aa02980d 96
97 // extract all output and copy it to log and optionally to cout
98 const int BUFSIZE = 2048;
95e05159 99 TCollection_AsciiString buf;
100 tmp_file->Rewind();
101 while (tmp_file->ReadLine (buf, BUFSIZE) > 0)
aa02980d 102 {
103 log << buf;
104 if (doEcho)
105 cout << buf;
106 }
107
108 // close temporary file
95e05159 109 tmp_file->Close();
e9b037ef 110
111 // remove temporary file if this is not done by the system
95e05159 112 if (tmp_file->Exists())
113 tmp_file->Remove();
aa02980d 114 }
95e05159 115
68858c7d 116} // anonymous namespace
aa02980d 117
7fd59977 118// MKV 29.03.05
119#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
120static Standard_Integer CommandCmd
dda67c1c 121(ClientData theClientData, Tcl_Interp *interp,
7fd59977 122 Standard_Integer argc, const char* argv[])
123#else
124static Standard_Integer CommandCmd
dda67c1c 125(ClientData theClientData, Tcl_Interp *interp,
7fd59977 126 Standard_Integer argc, char* argv[])
127#endif
128{
129 static Standard_Integer code;
130 code = TCL_OK;
dda67c1c 131 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
132 Draw_Interpretor& di = *(aCallback->myDI);
aa02980d 133
134 // log command execution, except commands manipulating log itself and echo
135 Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
136 strcmp (argv[0], "decho") == 0);
137 Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
138 Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
139 if (doLog)
140 dumpArgs (di.Log(), argc, argv);
141 if (doEcho)
142 dumpArgs (cout, argc, argv);
143
144 // flush cerr and cout
145 flush_standard_streams();
146
147 // capture cout and cerr to log
95e05159 148 OSD_File aFile_out, aFile_err;
149 int fd_err_save = -1;
150 int fd_out_save = -1;
aa02980d 151 if (doLog)
152 {
95e05159 153 fd_out_save = capture_start (aFile_out, STDOUT_FILENO);
154 fd_err_save = capture_start (aFile_err, STDERR_FILENO);
aa02980d 155 }
7fd59977 156
aa02980d 157 // run command
7fd59977 158 try {
159 OCC_CATCH_SIGNALS
160
8a262fa1 161 // get exception if control-break has been pressed
162 OSD::ControlBreak();
163
d9ff84e8 164 // OCC680: Transfer UTF-8 directly to OCC commands without locale usage
7fd59977 165
d9ff84e8 166 Standard_Integer fres = aCallback->Invoke ( di, argc, argv /*anArgs.GetArgv()*/ );
7fd59977 167 if (fres != 0)
168 code = TCL_ERROR;
169 }
170 catch (Standard_Failure) {
171
172 Handle(Standard_Failure) E = Standard_Failure::Caught();
173
174 // fail if Draw_ExitOnCatch is set
175 // MKV 29.03.05
176#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
177 const char* cc = Tcl_GetVar(interp,
178 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
179#else
180 char* const cc = Tcl_GetVar(interp,
181 "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
182#endif
183
184 cout << "An exception was caught " << E << endl;
185
91322f44 186 if (cc && Draw::Atoi(cc)) {
57c28b61 187#ifdef _WIN32
7fd59977 188 Tcl_Exit(0);
189#else
190 Tcl_Eval(interp,"exit");
191#endif
192 }
193
194 // get the error message
195 Standard_SStream ss;
d41f6af3 196 ss << "** Exception ** " << E << ends;
7fd59977 197 Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
7fd59977 198 code = TCL_ERROR;
199 }
aa02980d 200
201 // flush streams
202 flush_standard_streams();
203
204 // end capturing cout and cerr
205 if (doLog)
206 {
95e05159 207 capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
208 capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
aa02980d 209 }
210
211 // log command result
212 const char* aResultStr = NULL;
213 if (doLog)
214 {
215 aResultStr = Tcl_GetStringResult (interp);
216 if (aResultStr != 0 && aResultStr[0] != '\0' )
217 di.Log() << Tcl_GetStringResult (interp) << endl;
218 }
219 if (doEcho)
220 {
221 if (aResultStr == NULL)
222 aResultStr = Tcl_GetStringResult (interp);
223 if (aResultStr != 0 && aResultStr[0] != '\0' )
224 cout << Tcl_GetStringResult (interp) << endl;
225 }
226
7fd59977 227 return code;
228}
229
dda67c1c 230static void CommandDelete (ClientData theClientData)
7fd59977 231{
dda67c1c 232 Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
233 delete aCallback;
7fd59977 234}
235
236//=======================================================================
237//function : Draw_Interpretor
238//purpose :
239//=======================================================================
240
241Draw_Interpretor::Draw_Interpretor() :
aa02980d 242 isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
7fd59977 243{
0d969553
Y
244// The tcl interpreter is not created immediately as it is kept
245// by a global variable and created and deleted before the main().
7fd59977 246 myInterp = NULL;
247}
248
249//=======================================================================
250//function : Init
0d969553 251//purpose : It is necessary to call this function
7fd59977 252//=======================================================================
253
254void Draw_Interpretor::Init()
255{
256 if (isAllocated)
257 Tcl_DeleteInterp(myInterp);
258 isAllocated=Standard_True;
259 myInterp=Tcl_CreateInterp();
260}
261
262//=======================================================================
263//function : Draw_Interpretor
264//purpose :
265//=======================================================================
266
267Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
268 isAllocated(Standard_False),
aa02980d 269 myInterp(p),
270 myDoLog(Standard_False),
271 myDoEcho(Standard_False)
7fd59977 272{
273}
274
275//=======================================================================
dda67c1c 276//function : add
277//purpose :
7fd59977 278//=======================================================================
dda67c1c 279void Draw_Interpretor::add (const Standard_CString theCommandName,
280 const Standard_CString theHelp,
281 const Standard_CString theFileName,
282 Draw_Interpretor::CallBackData* theCallback,
283 const Standard_CString theGroup)
7fd59977 284{
dda67c1c 285 if (myInterp == NULL)
286 {
287 Init();
288 }
7fd59977 289
dda67c1c 290 Standard_PCharacter aName = (Standard_PCharacter )theCommandName;
291 Standard_PCharacter aHelp = (Standard_PCharacter )theHelp;
292 Standard_PCharacter aGroup = (Standard_PCharacter )theGroup;
293 Tcl_CreateCommand (myInterp, aName, CommandCmd, (ClientData )theCallback, CommandDelete);
7fd59977 294
295 // add the help
dda67c1c 296 Tcl_SetVar2 (myInterp, "Draw_Helps", aName, aHelp, TCL_GLOBAL_ONLY);
297 Tcl_SetVar2 (myInterp, "Draw_Groups", aGroup, aName,
298 TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
938a360f 299
d33dea30 300 // add path to source file (keep not more than two last subdirectories)
dda67c1c 301 if (theFileName == NULL
302 || *theFileName == '\0')
303 {
304 return;
305 }
306
307 OSD_Path aPath (theFileName);
d33dea30 308 Standard_Integer nbTrek = aPath.TrekLength();
dda67c1c 309 for (Standard_Integer i = 2; i < nbTrek; ++i)
310 {
d33dea30 311 aPath.RemoveATrek (1);
dda67c1c 312 }
313 aPath.SetDisk ("");
314 aPath.SetNode ("");
d33dea30
PK
315 TCollection_AsciiString aSrcPath;
316 aPath.SystemName (aSrcPath);
dda67c1c 317 Tcl_SetVar2 (myInterp, "Draw_Files", aName, aSrcPath.ToCString(), TCL_GLOBAL_ONLY);
7fd59977 318}
319
7fd59977 320//=======================================================================
321//function : Remove
322//purpose :
323//=======================================================================
324
325Standard_Boolean Draw_Interpretor::Remove(Standard_CString const n)
326{
327 Standard_PCharacter pN;
328 //
329 pN=(Standard_PCharacter)n;
330
331 Standard_Integer result = Tcl_DeleteCommand(myInterp,pN);
332 return result == 0;
333}
334
335//=======================================================================
336//function : Result
337//purpose :
338//=======================================================================
339
340Standard_CString Draw_Interpretor::Result() const
341{
342#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 5)))
343 return Tcl_GetStringResult(myInterp);
344#else
345 return myInterp->result;
346#endif
347}
348
349//=======================================================================
350//function : Reset
351//purpose :
352//=======================================================================
353
354void Draw_Interpretor::Reset()
355{
356 Tcl_ResetResult(myInterp);
357}
358
359//=======================================================================
360//function : Append
361//purpose :
362//=======================================================================
363
364Draw_Interpretor& Draw_Interpretor::Append(const Standard_CString s)
365{
366#ifdef TCL_USES_UTF8
367 // Convert string to UTF-8 format for Tcl
368 Tcl_DString TclString;
369 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
370 Tcl_AppendResult ( myInterp, Tcl_DStringValue ( &TclString ), (Standard_CString)0 );
371 Tcl_DStringFree ( &TclString );
372#else
373 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
374#endif
375 return *this;
376}
377
378//=======================================================================
379//function : Append
380//purpose :
381//=======================================================================
382
383Draw_Interpretor& Draw_Interpretor::Append(const TCollection_AsciiString& s)
384{
385 return Append (s.ToCString());
386}
387
388//=======================================================================
389//function : Append
390//purpose :
391//=======================================================================
392
393Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& theString)
394{
395#ifdef TCL_USES_UTF8
396 // Convert string to UTF-8 format for Tcl
397 char *str = new char[theString.LengthOfCString()+1];
398 theString.ToUTF8CString (str);
399 Tcl_AppendResult ( myInterp, str, (Standard_CString)0 );
400 delete[] str;
401#else
402 // put as ascii string, replacing non-ascii characters by '?'
403 TCollection_AsciiString str (theString, '?');
404 Tcl_AppendResult(myInterp,str.ToCString(),(Standard_CString)0);
405#endif
406 return *this;
407}
408
409//=======================================================================
410//function : Append
411//purpose :
412//=======================================================================
413
414Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
415{
416 char c[100];
91322f44 417 Sprintf(c,"%d",i);
7fd59977 418 Tcl_AppendResult(myInterp,c,(Standard_CString)0);
419 return *this;
420}
421
422//=======================================================================
423//function : Append
424//purpose :
425//=======================================================================
426
427Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
428{
429 char s[100];
91322f44 430 Sprintf(s,"%.17g",r);
7fd59977 431 Tcl_AppendResult(myInterp,s,(Standard_CString)0);
432 return *this;
433}
434
435//=======================================================================
436//function : Append
437//purpose :
438//=======================================================================
439
440Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
441{
7fd59977 442 return Append (s.str().c_str());
7fd59977 443}
444
445//=======================================================================
446//function : AppendElement
447//purpose :
448//=======================================================================
449
450void Draw_Interpretor::AppendElement(const Standard_CString s)
451{
452#ifdef TCL_USES_UTF8
453 // Convert string to UTF-8 format for Tcl
454 Tcl_DString TclString;
455 Tcl_ExternalToUtfDString ( NULL, s, -1, &TclString );
456 Tcl_AppendElement ( myInterp, Tcl_DStringValue ( &TclString ) );
457 Tcl_DStringFree ( &TclString );
458#else
459#ifdef IRIX
460 //AppendElement is declared as (Tcl_Interp *interp, char *string)
461 //on SGI 32
462 Tcl_AppendElement(myInterp,(char*) s);
463#else
464 Tcl_AppendElement(myInterp, s);
465#endif
466#endif
467}
468
469//=======================================================================
470//function : Eval
471//purpose :
472//=======================================================================
473
474Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
475{
476 Standard_PCharacter pLine;
477 //
478 pLine=(Standard_PCharacter)line;
479 //
480 return Tcl_Eval(myInterp,pLine);
481}
482
483
484//=======================================================================
485//function : Eval
486//purpose :
487//=======================================================================
488
489Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
490 const Standard_Integer flags)
491{
492 Standard_PCharacter pLine;
493 //
494 pLine=(Standard_PCharacter)line;
495 return Tcl_RecordAndEval(myInterp,pLine,flags);
496}
497
498//=======================================================================
499//function : EvalFile
500//purpose :
501//=======================================================================
502
503Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
504{
505 Standard_PCharacter pfname;
506 //
507 pfname=(Standard_PCharacter)fname;
508 return Tcl_EvalFile(myInterp,pfname);
509}
510
511//=======================================================================
785a9540 512//function : PrintHelp
513//purpose :
514//=======================================================================
515
516Standard_Integer Draw_Interpretor::PrintHelp (const Standard_CString theCommandName)
517{
518 TCollection_AsciiString aCmd = TCollection_AsciiString ("help ") + theCommandName;
519 Standard_PCharacter aLinePtr = (Standard_PCharacter )aCmd.ToCString();
520 return Tcl_Eval (myInterp, aLinePtr);
521}
522
523//=======================================================================
7fd59977 524//function :Complete
525//purpose :
526//=======================================================================
527
528Standard_Boolean Draw_Interpretor::Complete(const Standard_CString line)
529{
530 Standard_PCharacter pLine;
531 //
532 pLine=(Standard_PCharacter)line;
dde68833 533 return Tcl_CommandComplete (pLine) != 0;
7fd59977 534}
535
536//=======================================================================
537//function : Destroy
538//purpose :
539//=======================================================================
540
dda67c1c 541Draw_Interpretor::~Draw_Interpretor()
7fd59977 542{
543 // MKV 01.02.05
544#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
545 try {
546 OCC_CATCH_SIGNALS
547 Tcl_Exit(0);
548 }
549 catch (Standard_Failure) {
0797d9d3 550#ifdef OCCT_DEBUG
7fd59977 551 cout <<"Tcl_Exit have an exeption" << endl;
552#endif
553 }
554#else
57c28b61 555#ifdef _WIN32
7fd59977 556 Tcl_Exit(0);
557#endif
558#endif
559}
560
561//=======================================================================
562//function : Interp
563//purpose :
564//=======================================================================
565
566Draw_PInterp Draw_Interpretor::Interp() const
567{
568 Standard_DomainError_Raise_if (myInterp==NULL , "No call for Draw_Interpretor::Init()");
569 return myInterp;
570}
571
572void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
573{
574 if (isAllocated)
575 Tcl_DeleteInterp(myInterp);
576 isAllocated = Standard_False;
577 myInterp = PIntrp;
578}
aa02980d 579
580//=======================================================================
581//function : Logging
582//purpose :
583//=======================================================================
584
585void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
586{
587 myDoLog = doLog;
588}
589
590void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
591{
592 myDoEcho = doEcho;
593}
594
595Standard_Boolean Draw_Interpretor::GetDoLog () const
596{
597 return myDoLog;
598}
599
600Standard_Boolean Draw_Interpretor::GetDoEcho () const
601{
602 return myDoEcho;
603}
604
605Standard_SStream& Draw_Interpretor::Log ()
606{
607 return myLog;
60be1f9b 608}