-// File: Draw_Interpretor.cxx
-// Created: Thu Feb 23 17:53:09 1995
-// Author: Remi LEQUETTE
-// <rle@bravox>
-
+// Created on: 1995-02-23
+// Created by: Remi LEQUETTE
+// Copyright (c) 1995-1999 Matra Datavision
+// Copyright (c) 1999-2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
-#include <Draw_Interpretor.ixx>
+#include <Draw_Interpretor.hxx>
#include <Draw_Appli.hxx>
#include <Standard_SStream.hxx>
#include <Standard_RangeError.hxx>
#include <TCollection_AsciiString.hxx>
#include <TCollection_ExtendedString.hxx>
+#include <OSD_Process.hxx>
+#include <OSD_Path.hxx>
+#include <OSD.hxx>
+#include <OSD_File.hxx>
#include <string.h>
-
#include <tcl.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+// for capturing of cout and cerr (dup(), dup2())
+#ifdef _WIN32
+#include <io.h>
+#endif
+
+#if ! defined(STDOUT_FILENO)
+#define STDOUT_FILENO fileno(stdout)
+#endif
+#if ! defined(STDERR_FILENO)
+#define STDERR_FILENO fileno(stderr)
+#endif
#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 1)))
#define TCL_USES_UTF8
#endif
-//
-// Auxiliary tool to convert strings in command arguments from UTF-8
-// (Tcl internal encoding since Tcl 8.1) to system local encoding,
-// normally extended Ascii as expected by OCC commands
-//
-class TclUTFToLocalStringSentry {
- public:
+// logging helpers
+namespace {
+ void dumpArgs (Standard_OStream& os, int argc, const char *argv[])
+ {
+ for (int i=0; i < argc; i++)
+ os << argv[i] << " ";
+ os << endl;
+ }
-#ifdef TCL_USES_UTF8
- TclUTFToLocalStringSentry (int argc, const char **argv) :
- nb(0),
- TclArgv(new Tcl_DString[argc]),
- Argv(new char*[argc])
+ void flush_standard_streams ()
{
- for (; nb < argc; nb++ ) {
- Tcl_UtfToExternalDString ( NULL, argv[nb], -1, &TclArgv[nb] );
- Argv[nb] = Tcl_DStringValue ( &TclArgv[nb] );
- }
+ fflush (stderr);
+ fflush (stdout);
+ cerr << flush;
+ cout << flush;
}
-
- ~TclUTFToLocalStringSentry ()
+
+ int capture_start (OSD_File& theTmpFile, int std_fd)
{
- delete[] Argv;
- while ( nb-- >0 ) Tcl_DStringFree ( &TclArgv[nb] );
- delete[] TclArgv;
+ theTmpFile.BuildTemporary();
+ if (theTmpFile.Failed())
+ {
+ cerr << "Error: cannot create temporary file for capturing console output" << endl;
+ return -1;
+ }
+
+ // remember current file descriptors of standard stream, and replace it by temporary
+ return theTmpFile.Capture(std_fd);
}
-#else
- TclUTFToLocalStringSentry (int, const char **argv) : Argv((char**)argv) {}
-#endif
- const char **GetArgv () const { return (const char **)Argv; }
-
- private:
- int nb;
- Tcl_DString *TclArgv;
- char **Argv;
-};
+ void capture_end (OSD_File* tmp_file, int std_fd, int save_fd, Standard_OStream &log, Standard_Boolean doEcho)
+ {
+ if (!tmp_file)
+ 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)
+ {
+ log << buf;
+ if (doEcho)
+ cout << buf;
+ }
+ // close temporary file
+ tmp_file->Close();
-//
-// Call backs for TCL
-//
+ // remove temporary file if this is not done by the system
+ if (tmp_file->Exists())
+ tmp_file->Remove();
+ }
-struct CData {
- CData(Draw_CommandFunction ff, Draw_Interpretor* ii) : f(ff), i(ii) {}
- Draw_CommandFunction f;
- Draw_Interpretor* i;
-};
+} // 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 clientData, Tcl_Interp *interp,
+(ClientData theClientData, Tcl_Interp *interp,
Standard_Integer argc, const char* argv[])
#else
static Standard_Integer CommandCmd
-(ClientData clientData, Tcl_Interp *interp,
+(ClientData theClientData, Tcl_Interp *interp,
Standard_Integer argc, char* argv[])
#endif
{
static Standard_Integer code;
code = TCL_OK;
- CData* C = (CData*) clientData;
+ Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
+ Draw_Interpretor& di = *(aCallback->myDI);
+
+ // log command execution, except commands manipulating log itself and echo
+ Standard_Boolean isLogManipulation = (strcmp (argv[0], "dlog") == 0 ||
+ 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;
+ if (doLog)
+ {
+ fd_out_save = capture_start (aFile_out, STDOUT_FILENO);
+ fd_err_save = capture_start (aFile_err, STDERR_FILENO);
+ }
+ // run command
try {
OCC_CATCH_SIGNALS
- // OCC63: Convert strings from UTF-8 to local encoding, normally expected by OCC commands
- TclUTFToLocalStringSentry anArgs ( argc, (const char**)argv );
+ // get exception if control-break has been pressed
+ OSD::ControlBreak();
+
+ // OCC680: Transfer UTF-8 directly to OCC commands without locale usage
- Draw_Interpretor& di = *(C->i);
- Standard_Integer fres = C->f ( di, argc, anArgs.GetArgv() );
+ Standard_Integer fres = aCallback->Invoke ( di, argc, argv /*anArgs.GetArgv()*/ );
if (fres != 0)
code = TCL_ERROR;
}
cout << "An exception was caught " << E << endl;
- if (cc && atoi(cc)) {
-#ifdef WNT
+ if (cc && Draw::Atoi(cc)) {
+#ifdef _WIN32
Tcl_Exit(0);
#else
Tcl_Eval(interp,"exit");
// get the error message
Standard_SStream ss;
- ss << "** Exception ** " << E << ends ;
-#ifdef USE_STL_STREAM
+ ss << "** Exception ** " << E << ends;
Tcl_SetResult(interp,(char*)(ss.str().c_str()),TCL_VOLATILE);
-#else
- Tcl_SetResult(interp,(char*)(ss.str()),TCL_VOLATILE);
-#endif
code = TCL_ERROR;
}
-
+
+ // flush streams
+ flush_standard_streams();
+
+ // end capturing cout and cerr
+ if (doLog)
+ {
+ capture_end (&aFile_err, STDERR_FILENO, fd_err_save, di.Log(), doEcho);
+ capture_end (&aFile_out, STDOUT_FILENO, fd_out_save, di.Log(), doEcho);
+ }
+
+ // log command result
+ const char* aResultStr = NULL;
+ if (doLog)
+ {
+ aResultStr = Tcl_GetStringResult (interp);
+ if (aResultStr != 0 && aResultStr[0] != '\0' )
+ di.Log() << Tcl_GetStringResult (interp) << endl;
+ }
+ if (doEcho)
+ {
+ if (aResultStr == NULL)
+ aResultStr = Tcl_GetStringResult (interp);
+ if (aResultStr != 0 && aResultStr[0] != '\0' )
+ cout << Tcl_GetStringResult (interp) << endl;
+ }
+
return code;
}
-
-static void CommandDelete (ClientData clientData)
+static void CommandDelete (ClientData theClientData)
{
- CData *C = (CData*) clientData;
- delete C;
+ Draw_Interpretor::CallBackData* aCallback = (Draw_Interpretor::CallBackData* )theClientData;
+ delete aCallback;
}
//=======================================================================
//=======================================================================
Draw_Interpretor::Draw_Interpretor() :
- isAllocated(Standard_False)
+ isAllocated(Standard_False), myDoLog(Standard_False), myDoEcho(Standard_False)
{
// The tcl interpreter is not created immediately as it is kept
// by a global variable and created and deleted before the main().
Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
isAllocated(Standard_False),
- myInterp(p)
+ myInterp(p),
+ myDoLog(Standard_False),
+ myDoEcho(Standard_False)
{
}
//=======================================================================
-//function : Add
-//purpose :
+//function : add
+//purpose :
//=======================================================================
-//#ifdef WNT
-void Draw_Interpretor::Add(const Standard_CString n,
- const Standard_CString help,
- const Draw_CommandFunction f,
- const Standard_CString group)
-//#else
-//void Draw_Interpretor::Add(const Standard_CString n,
-// const Standard_CString help,
-// const Draw_CommandFunction& f,
-// const Standard_CString group)
-//#endif
+void Draw_Interpretor::add (const Standard_CString theCommandName,
+ const Standard_CString theHelp,
+ const Standard_CString theFileName,
+ Draw_Interpretor::CallBackData* theCallback,
+ const Standard_CString theGroup)
{
- Standard_PCharacter pN, pHelp, pGroup;
- //
- pN=(Standard_PCharacter)n;
- pHelp=(Standard_PCharacter)help;
- pGroup=(Standard_PCharacter)group;
- //
- if (myInterp==NULL) Init();
-
- CData* C = new CData(f,this);
-
- Tcl_CreateCommand(myInterp, pN ,CommandCmd, (ClientData) C, CommandDelete);
-
- // add the help
- Tcl_SetVar2(myInterp,"Draw_Helps", pN, pHelp, TCL_GLOBAL_ONLY);
- Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
- TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
-}
-//=======================================================================
-//function : Add
-//purpose :
-//=======================================================================
-void Draw_Interpretor::Add(const Standard_CString n,
- const Standard_CString help,
- const Standard_CString file_name,
- const Draw_CommandFunction f,
- const Standard_CString group)
-{
- Standard_PCharacter pN, pHelp, pGroup, pFileName;
- //
- pN=(Standard_PCharacter)n;
- pHelp=(Standard_PCharacter)help;
- pGroup=(Standard_PCharacter)group;
- pFileName=(Standard_PCharacter)file_name;
- //
- if (myInterp==NULL) Init();
+ if (myInterp == NULL)
+ {
+ Init();
+ }
- CData* C = new CData(f,this);
- Standard_Integer length, num_slashes, ii, jj, kk;
- Tcl_CreateCommand(myInterp,pN,CommandCmd, (ClientData) C, CommandDelete);
+ Standard_PCharacter aName = (Standard_PCharacter )theCommandName;
+ Standard_PCharacter aHelp = (Standard_PCharacter )theHelp;
+ Standard_PCharacter aGroup = (Standard_PCharacter )theGroup;
+ Tcl_CreateCommand (myInterp, aName, CommandCmd, (ClientData )theCallback, CommandDelete);
// add the help
- Tcl_SetVar2(myInterp,"Draw_Helps",pN,pHelp,TCL_GLOBAL_ONLY);
- Tcl_SetVar2(myInterp,"Draw_Groups",pGroup,pN,
- TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
- length = strlen(pFileName) ;
- char * a_string =
- new char[length + 1] ;
- jj = 0 ;
- num_slashes = 0 ;
- ii = length ;
- while (num_slashes < 3 && ii >= 0) {
- if (file_name[ii] == '/') {
- num_slashes += 1 ;
- }
- ii -= 1 ;
- }
- jj = 0 ;
- for (kk = ii+2 , jj =0 ; kk < length ; kk++) {
- a_string[jj] = file_name[kk] ;
- jj += 1 ;
- }
- a_string[jj] = '\0' ;
-
- Tcl_SetVar2(myInterp,"Draw_Files",pN,a_string,TCL_GLOBAL_ONLY);
+ Tcl_SetVar2 (myInterp, "Draw_Helps", aName, aHelp, TCL_GLOBAL_ONLY);
+ Tcl_SetVar2 (myInterp, "Draw_Groups", aGroup, aName,
+ TCL_GLOBAL_ONLY | TCL_APPEND_VALUE | TCL_LIST_ELEMENT);
- delete [] a_string;
+ // add path to source file (keep not more than two last subdirectories)
+ if (theFileName == NULL
+ || *theFileName == '\0')
+ {
+ return;
+ }
+ OSD_Path aPath (theFileName);
+ Standard_Integer nbTrek = aPath.TrekLength();
+ for (Standard_Integer i = 2; i < nbTrek; ++i)
+ {
+ aPath.RemoveATrek (1);
+ }
+ aPath.SetDisk ("");
+ aPath.SetNode ("");
+ TCollection_AsciiString aSrcPath;
+ aPath.SystemName (aSrcPath);
+ Tcl_SetVar2 (myInterp, "Draw_Files", aName, aSrcPath.ToCString(), TCL_GLOBAL_ONLY);
}
-
//=======================================================================
//function : Remove
//purpose :
Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
{
char c[100];
- sprintf(c,"%d",i);
+ Sprintf(c,"%d",i);
Tcl_AppendResult(myInterp,c,(Standard_CString)0);
return *this;
}
Draw_Interpretor& Draw_Interpretor::Append(const Standard_Real r)
{
char s[100];
- sprintf(s,"%.17g",r);
+ Sprintf(s,"%.17g",r);
Tcl_AppendResult(myInterp,s,(Standard_CString)0);
return *this;
}
Draw_Interpretor& Draw_Interpretor::Append(const Standard_SStream& s)
{
-#ifdef USE_STL_STREAM
return Append (s.str().c_str());
-#else
- // Note: use dirty tricks -- unavoidable with old streams
- TCollection_AsciiString aStr (((Standard_SStream&)AReason).str(), AReason.pcount());
- ((Standard_SStream&)AReason).freeze (false);
- return Append (aStr.ToCString());
-#endif
}
//=======================================================================
return Tcl_EvalFile(myInterp,pfname);
}
+//=======================================================================
+//function : PrintHelp
+//purpose :
+//=======================================================================
+
+Standard_Integer Draw_Interpretor::PrintHelp (const Standard_CString theCommandName)
+{
+ TCollection_AsciiString aCmd = TCollection_AsciiString ("help ") + theCommandName;
+ Standard_PCharacter aLinePtr = (Standard_PCharacter )aCmd.ToCString();
+ return Tcl_Eval (myInterp, aLinePtr);
+}
+
//=======================================================================
//function :Complete
//purpose :
Standard_PCharacter pLine;
//
pLine=(Standard_PCharacter)line;
- return Tcl_CommandComplete(pLine);
+ return Tcl_CommandComplete (pLine) != 0;
}
//=======================================================================
//purpose :
//=======================================================================
-void Draw_Interpretor::Destroy()
+Draw_Interpretor::~Draw_Interpretor()
{
// MKV 01.02.05
#if ((TCL_MAJOR_VERSION > 8) || ((TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION >= 4)))
Tcl_Exit(0);
}
catch (Standard_Failure) {
-#ifdef DEB
+#ifdef OCCT_DEBUG
cout <<"Tcl_Exit have an exeption" << endl;
#endif
}
#else
-#ifdef WNT
+#ifdef _WIN32
Tcl_Exit(0);
#endif
#endif
isAllocated = Standard_False;
myInterp = PIntrp;
}
+
+//=======================================================================
+//function : Logging
+//purpose :
+//=======================================================================
+
+void Draw_Interpretor::SetDoLog (Standard_Boolean doLog)
+{
+ myDoLog = doLog;
+}
+
+void Draw_Interpretor::SetDoEcho (Standard_Boolean doEcho)
+{
+ myDoEcho = doEcho;
+}
+
+Standard_Boolean Draw_Interpretor::GetDoLog () const
+{
+ return myDoLog;
+}
+
+Standard_Boolean Draw_Interpretor::GetDoEcho () const
+{
+ return myDoEcho;
+}
+
+Standard_SStream& Draw_Interpretor::Log ()
+{
+ return myLog;
+}