#include <string.h>
#include <tcl.h>
+#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#endif
// for capturing of cout and cerr (dup(), dup2())
#ifdef _WIN32
#include <io.h>
+#include <sys/stat.h>
#endif
#if ! defined(STDOUT_FILENO)
cout << flush;
}
- int capture_start (OSD_File& theTmpFile, int std_fd)
+ int capture_start (int theFDStd, int theFDLog)
{
- theTmpFile.BuildTemporary();
- if (theTmpFile.Failed())
+ Standard_ASSERT_RETURN (theFDLog >= 0, "Invalid descriptor of log file", -1);
+
+ // Duplicate a file descriptor of the standard stream to be able to restore output to it later
+ int aFDSave = dup (theFDStd);
+ if (aFDSave < 0)
{
- cerr << "Error: cannot create temporary file for capturing console output" << endl;
+ perror ("Error capturing standard stream to log: dup() returned");
return -1;
}
- // remember current file descriptors of standard stream, and replace it by temporary
- return theTmpFile.Capture(std_fd);
+ // Redirect the stream to the log file
+ if (dup2 (theFDLog, theFDStd) < 0)
+ {
+ close (aFDSave);
+ perror ("Error capturing standard stream to log: dup2() returned");
+ return -1;
+ }
+
+ // remember saved file descriptor of standard stream
+ return aFDSave;
}
- void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
+ void capture_end (int theFDStd, int& theFDSave)
{
- if (!tmp_file)
+ if (theFDSave < 0)
return;
// restore normal descriptors of console stream
- #ifdef _WIN32
- _dup2(save_fd, std_fd);
- _close(save_fd);
- #else
- dup2(save_fd, std_fd);
- close(save_fd);
- #endif
-
- // extract all output and copy it to log and optionally to cout
- const int BUFSIZE = 2048;
- TCollection_AsciiString buf;
- tmp_file->Rewind();
- while (tmp_file->ReadLine (buf, BUFSIZE) > 0)
+ if (dup2(theFDSave, theFDStd) < 0)
{
- log << buf;
- if (doEcho)
- cout << buf;
+ perror ("Error returning capturing standard stream to log: dup2() returned");
+ return;
}
- // close temporary file
- tmp_file->Close();
-
- // remove temporary file if this is not done by the system
- if (tmp_file->Exists())
- tmp_file->Remove();
+ // close saved file descriptor
+ close(theFDSave);
+ theFDSave = -1;
}
} // anonymous namespace
-// MKV 29.03.05
-#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
-static Standard_Integer CommandCmd
-(ClientData theClientData, Tcl_Interp *interp,
- Standard_Integer argc, const char* argv[])
-#else
-static Standard_Integer CommandCmd
-(ClientData theClientData, Tcl_Interp *interp,
- Standard_Integer argc, char* argv[])
-#endif
+static Standard_Integer CommandCmd (ClientData theClientData, Tcl_Interp* interp, Standard_Integer argc, const char* argv[])
{
static Standard_Integer code;
code = TCL_OK;
strcmp (argv[0], "decho") == 0);
Standard_Boolean doLog = (di.GetDoLog() && ! isLogManipulation);
Standard_Boolean doEcho = (di.GetDoEcho() && ! isLogManipulation);
- if (doLog)
- dumpArgs (di.Log(), argc, argv);
- if (doEcho)
- dumpArgs (cout, argc, argv);
// flush cerr and cout
flush_standard_streams();
// capture cout and cerr to log
- OSD_File aFile_out, aFile_err;
- int fd_err_save = -1;
- int fd_out_save = -1;
+ int aFDstdout = STDOUT_FILENO;
+ int aFDstderr = STDERR_FILENO;
+ int aFDerr_save = -1;
+ int aFDout_save = -1;
if (doLog)
{
- fd_out_save = capture_start (aFile_out, STDOUT_FILENO);
- fd_err_save = capture_start (aFile_err, STDERR_FILENO);
+ aFDout_save = capture_start (aFDstdout, di.GetLogFileDescriptor());
+ aFDerr_save = capture_start (aFDstderr, di.GetLogFileDescriptor());
}
+ if (doEcho || doLog)
+ dumpArgs (cout, argc, argv);
+
// run command
try {
OCC_CATCH_SIGNALS
if (fres != 0)
code = TCL_ERROR;
}
- catch (Standard_Failure) {
-
- Handle(Standard_Failure) E = Standard_Failure::Caught();
-
+ catch (Standard_Failure const& anException) {
// fail if Draw_ExitOnCatch is set
- // MKV 29.03.05
-#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4))) && !defined(USE_NON_CONST)
- const char* cc = Tcl_GetVar(interp,
- "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
-#else
- char* const cc = Tcl_GetVar(interp,
- "Draw_ExitOnCatch",TCL_GLOBAL_ONLY);
-#endif
-
- cout << "An exception was caught " << E << endl;
-
- if (cc && Draw::Atoi(cc)) {
+ std::cout << "An exception was caught " << anException << std::endl;
+ const char* toExitOnCatch = Tcl_GetVar (interp, "Draw_ExitOnCatch", TCL_GLOBAL_ONLY);
+ if (toExitOnCatch != NULL && Draw::Atoi (toExitOnCatch))
+ {
#ifdef _WIN32
Tcl_Exit(0);
#else
// get the error message
Standard_SStream ss;
- ss << "** Exception ** " << E << ends;
+ ss << "** Exception ** " << anException << ends;
Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
code = TCL_ERROR;
}
+ catch (std::exception const& theStdException)
+ {
+ std::cout << "An exception was caught " << theStdException.what() << " [" << typeid(theStdException).name() << "]" << std::endl;
+ const char* toExitOnCatch = Tcl_GetVar (interp, "Draw_ExitOnCatch", TCL_GLOBAL_ONLY);
+ if (toExitOnCatch != NULL && Draw::Atoi (toExitOnCatch))
+ {
+ #ifdef _WIN32
+ Tcl_Exit (0);
+ #else
+ Tcl_Eval (interp, "exit");
+ #endif
+ }
- // flush streams
- flush_standard_streams();
-
- // end capturing cout and cerr
- if (doLog)
+ // get the error message
+ Standard_SStream ss;
+ ss << "** Exception ** " << theStdException.what() << " [" << typeid(theStdException).name() << "]" << ends;
+ Tcl_SetResult (interp, (char*)(ss.str().c_str()), TCL_VOLATILE);
+ code = TCL_ERROR;
+ }
+ catch (...)
{
- capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
- capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
+ std::cout << "UNKNOWN exception was caught " << std::endl;
+ const char* toExitOnCatch = Tcl_GetVar (interp, "Draw_ExitOnCatch", TCL_GLOBAL_ONLY);
+ if (toExitOnCatch != NULL && Draw::Atoi (toExitOnCatch))
+ {
+ #ifdef _WIN32
+ Tcl_Exit (0);
+ #else
+ Tcl_Eval (interp,"exit");
+ #endif
+ }
+
+ // get the error message
+ Standard_SStream ss;
+ ss << "** Exception ** UNKNOWN" << ends;
+ Tcl_SetResult (interp, (char* )(ss.str().c_str()), TCL_VOLATILE);
+ code = TCL_ERROR;
}
// log command result
- const char* aResultStr = NULL;
- if (doLog)
+ if (doLog || doEcho)
{
- aResultStr = Tcl_GetStringResult (interp);
+ const char* aResultStr = Tcl_GetStringResult (interp);
if (aResultStr != 0 && aResultStr[0] != '\0' )
- di.Log() << Tcl_GetStringResult (interp) << endl;
+ {
+ std::cout << aResultStr << std::endl;
+ }
}
- if (doEcho)
+
+ // flush streams
+ flush_standard_streams();
+
+ // end capturing cout and cerr
+ if (doLog)
{
- if (aResultStr == NULL)
- aResultStr = Tcl_GetStringResult (interp);
- if (aResultStr != 0 && aResultStr[0] != '\0' )
- cout << Tcl_GetStringResult (interp) << endl;
+ capture_end (aFDstderr, aFDerr_save);
+ capture_end (aFDstdout, aFDout_save);
}
return code;
//=======================================================================
Draw_Interpretor::Draw_Interpretor() :
- isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
+ isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False), myFDLog(-1)
{
// The tcl interpreter is not created immediately as it is kept
// by a global variable and created and deleted before the main().
Draw_Interpretor::CallBackData* theCallback,
const Standard_CString theGroup)
{
- if (myInterp == NULL)
- {
- Init();
- }
+ Standard_ASSERT_RAISE (myInterp != NULL, "Attempt to add command to Null interpretor");
Standard_PCharacter aName = (Standard_PCharacter )theCommandName;
Standard_PCharacter aHelp = (Standard_PCharacter )theHelp;
aPath.SetNode ("");
TCollection_AsciiString aSrcPath;
aPath.SystemName (aSrcPath);
+ if (aSrcPath.Value(1) == '/')
+ aSrcPath.Remove(1);
Tcl_SetVar2 (myInterp, "Draw_Files", aName, aSrcPath.ToCString(), TCL_GLOBAL_ONLY);
}
Standard_Integer Draw_Interpretor::Eval(const Standard_CString line)
{
- Standard_PCharacter pLine;
- //
- pLine=(Standard_PCharacter)line;
- //
- return Tcl_Eval(myInterp,pLine);
+ return Tcl_Eval(myInterp,line);
}
Standard_Integer Draw_Interpretor::RecordAndEval(const Standard_CString line,
const Standard_Integer flags)
{
- Standard_PCharacter pLine;
- //
- pLine=(Standard_PCharacter)line;
- return Tcl_RecordAndEval(myInterp,pLine,flags);
+ return Tcl_RecordAndEval(myInterp,line,flags);
}
//=======================================================================
Standard_Integer Draw_Interpretor::EvalFile(const Standard_CString fname)
{
- Standard_PCharacter pfname;
- //
- pfname=(Standard_PCharacter)fname;
- return Tcl_EvalFile(myInterp,pfname);
+ return Tcl_EvalFile(myInterp,fname);
}
//=======================================================================
Draw_Interpretor::~Draw_Interpretor()
{
+ SetDoLog (Standard_False);
+ if (myFDLog >=0)
+ {
+ close (myFDLog);
+ myFDLog = 0;
+ }
+
// MKV 01.02.05
#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
try {
void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
{
+ if (myDoLog == doLog)
+ return;
+
+ // create log file if not opened yet
+ if (doLog && myFDLog < 0)
+ {
+#ifdef _WIN32
+ char tmpfile[L_tmpnam + 1];
+ tmpnam(tmpfile);
+ myFDLog = open (tmpfile, O_RDWR | O_CREAT | O_EXCL | O_TEMPORARY, S_IREAD | S_IWRITE);
+#else
+ // according to Linux Filesystem Hierarchy Standard, 3.17,
+ // /tmp/ is the right directory for temporary files
+ char tmpfile[256] = "/tmp/occt_draw_XXXXXX";
+ myFDLog = mkstemp (tmpfile);
+ if (myFDLog >= 0)
+ {
+// printf ("Tmp file: %s\n", tmpfile);
+ unlink (tmpfile); // make sure the file will be deleted on close
+ }
+#endif
+ if (myFDLog < 0)
+ {
+ perror ("Error creating temporary file for capturing console output");
+ printf ("path: %s\n", tmpfile);
+ return;
+ }
+ }
+
myDoLog = doLog;
}
return myDoEcho;
}
-Standard_SStream& Draw_Interpretor::Log ()
+void Draw_Interpretor::ResetLog ()
{
- return myLog;
+ if (myFDLog < 0)
+ return;
+
+ // flush cerr and cout, for the case if they are bound to the log
+ flush_standard_streams();
+
+ lseek (myFDLog, 0, SEEK_SET);
+
+#ifdef _WIN32
+ if (_chsize_s (myFDLog, 0) != 0)
+#else
+ if (ftruncate (myFDLog, 0) != 0)
+#endif
+ {
+ perror ("Error truncating the console log");
+ }
+}
+
+void Draw_Interpretor::AddLog (const Standard_CString theStr)
+{
+ if (myFDLog < 0 || ! theStr || ! theStr[0])
+ return;
+
+ // flush cerr and cout, for the case if they are bound to the log
+ flush_standard_streams();
+
+ // write as plain bytes
+ if (write (myFDLog, theStr, (unsigned int)strlen(theStr)) <0)
+ {
+ perror ("Error writing to console log");
+ }
+}
+
+TCollection_AsciiString Draw_Interpretor::GetLog ()
+{
+ TCollection_AsciiString aLog;
+ if (myFDLog < 0)
+ return aLog;
+
+ // flush cerr and cout
+ flush_standard_streams();
+
+ // rewind the file to its start
+ lseek (myFDLog, 0, SEEK_SET);
+
+ // read the whole log to string; this implementation
+ // is not optimized but should be sufficient
+ const int BUFSIZE = 4096;
+ char buffer[BUFSIZE + 1];
+ for (;;)
+ {
+ int nbRead = read (myFDLog, buffer, BUFSIZE);
+ if (nbRead <= 0)
+ {
+ break;
+ }
+ buffer[nbRead] = '\0';
+ aLog.AssignCat (buffer);
+ }
+
+ return aLog;
}