0024275: Cppcheck warnings on uninitialized class members
[occt.git] / src / Draw / Draw_Interpretor.cxx
index 51e796e..2a258a2 100755 (executable)
@@ -1,7 +1,23 @@
-// 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-2012 OPEN CASCADE SAS
+//
+// The content of this file is subject to the Open CASCADE Technology Public
+// License Version 6.5 (the "License"). You may not use the content of this file
+// except in compliance with the License. Please obtain a copy of the License
+// at http://www.opencascade.org and read it completely before using this file.
+//
+// The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
+// main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
+//
+// The Original Code and all software distributed under the License is
+// distributed on an "AS IS" basis, without warranty of any kind, and the
+// Initial Developer hereby disclaims all such warranties, including without
+// limitation, any warranties of merchantability, fitness for a particular
+// purpose or non-infringement. Please see the License for the specific terms
+// and conditions governing the rights and limitations under the License.
+
 
 
 #include <Draw_Interpretor.ixx>
 
 #include <TCollection_AsciiString.hxx>
 #include <TCollection_ExtendedString.hxx>
+#include <OSD_Process.hxx>
+#include <OSD_Path.hxx>
+#include <OSD.hxx>
 
 #include <string.h>
-
 #include <tcl.h>
 
+// for capturing of cout and cerr (dup(), dup2())
+#ifdef _MSC_VER
+#include <io.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.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
@@ -49,7 +82,11 @@ class TclUTFToLocalStringSentry {
     delete[] TclArgv;
   }
 #else
-  TclUTFToLocalStringSentry (int, const char **argv) : Argv((char**)argv) {}
+  TclUTFToLocalStringSentry (int, const char **argv) : 
+          nb(0),
+       TclArgv(NULL),
+          Argv((char**)argv)
+  {}
 #endif
 
   const char **GetArgv () const { return (const char **)Argv; }
@@ -71,6 +108,84 @@ struct CData {
   Draw_Interpretor*    i;
 };
 
+// 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;
+  }
+
+  void flush_standard_streams ()
+  {
+    fflush (stderr);
+    fflush (stdout);
+    cerr << flush;
+    cout << flush;
+  }
+
+  FILE* capture_start (int std_fd, int *save_fd, char*& tmp_name)
+  {
+    *save_fd = 0;
+
+    // open temporary files
+  #if defined(_WIN32)
+    // use _tempnam() to decrease chances of failure (tmpfile() creates 
+    // file in root folder and will fail if it is write protected), see #24132
+    static const char* tmpdir = getenv("TEMP");
+    static char prefix[256] = ""; // prefix for temporary files, initialize once per process using pid
+    if (prefix[0] == '\0')
+      sprintf (prefix, "drawtmp%d_", (int)OSD_Process().ProcessId());
+    tmp_name = _tempnam (tmpdir, prefix);
+    FILE* aTmpFile = (tmp_name != NULL ? fopen (tmp_name, "w+b") : tmpfile());
+  #else
+    tmp_name = NULL;
+    FILE* aTmpFile = tmpfile();
+  #endif
+    int fd_tmp = (aTmpFile != NULL ? fileno (aTmpFile) : -1);
+    if (fd_tmp < 0)
+    {
+      cerr << "Error: cannot create temporary file for capturing console output" << endl;
+      fclose (aTmpFile);
+      return NULL;
+    }
+
+    // remember current file descriptors of standard stream, and replace it by temporary
+    (*save_fd) = dup(std_fd);
+    dup2(fd_tmp, std_fd);
+    return aTmpFile;
+  }
+
+  void capture_end (FILE* tmp_file, int std_fd, int save_fd, char* tmp_name, Standard_OStream &log, Standard_Boolean doEcho)
+  {
+    if (! tmp_file)
+      return;
+
+    // restore normal descriptors of console stream
+    dup2 (save_fd, std_fd);
+    close(save_fd);
+
+    // extract all output and copy it to log and optionally to cout
+    const int BUFSIZE = 2048;
+    char buf[BUFSIZE];
+    rewind(tmp_file);
+    while (fgets (buf, BUFSIZE, tmp_file) != NULL)
+    {
+      log << buf;
+      if (doEcho) 
+        cout << buf;
+    }
+
+    // close temporary file
+    fclose (tmp_file);
+
+    // remove temporary file if this is not done by the system
+    if (tmp_name)
+      remove (tmp_name);
+  }
+};
+
 // 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 
@@ -85,14 +200,43 @@ static Standard_Integer CommandCmd
   static Standard_Integer code;
   code = TCL_OK;
   CData* C = (CData*) clientData;
+  Draw_Interpretor& di = *(C->i);
+
+  // 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
+  char *err_name = NULL, *out_name = NULL;
+  FILE * aFile_err = NULL;
+  FILE * aFile_out = NULL;
+  int fd_err_save = 0;
+  int fd_out_save = 0;
+  if (doLog)
+  {
+    aFile_out = capture_start (STDOUT_FILENO, &fd_out_save, out_name);
+    aFile_err = capture_start (STDERR_FILENO, &fd_err_save, err_name);
+  }
 
+  // run command
   try {
     OCC_CATCH_SIGNALS
 
+    // get exception if control-break has been pressed 
+    OSD::ControlBreak();
+
     // OCC63: Convert strings from UTF-8 to local encoding, normally expected by OCC commands
     TclUTFToLocalStringSentry anArgs ( argc, (const char**)argv );
       
-    Draw_Interpretor& di = *(C->i);
     Standard_Integer fres = C->f ( di, argc, anArgs.GetArgv() );
     if (fres != 0) 
       code = TCL_ERROR;
@@ -113,7 +257,7 @@ static Standard_Integer CommandCmd
 
     cout << "An exception was caught " << E << endl;
 
-    if (cc && atoi(cc)) {
+    if (cc && Draw::Atoi(cc)) {
 #ifdef WNT
       Tcl_Exit(0);
 #else      
@@ -131,7 +275,33 @@ static Standard_Integer CommandCmd
 #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, err_name, di.Log(), doEcho);
+    capture_end (aFile_out, STDOUT_FILENO, fd_out_save, out_name, 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;
 }
 
@@ -148,7 +318,7 @@ static void CommandDelete (ClientData clientData)
 //=======================================================================
 
 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().
@@ -175,7 +345,9 @@ void Draw_Interpretor::Init()
 
 Draw_Interpretor::Draw_Interpretor(const Draw_PInterp& p) :
   isAllocated(Standard_False),
-  myInterp(p)
+  myInterp(p),
+  myDoLog(Standard_False),
+  myDoEcho(Standard_False)
 {
 }
 
@@ -232,34 +404,23 @@ void Draw_Interpretor::Add(const Standard_CString n,
   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);
 
   // 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);
 
+  // add path to source file (keep not more than two last subdirectories)
+  OSD_Path aPath (pFileName);
+  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",pN,aSrcPath.ToCString(),TCL_GLOBAL_ONLY);
 }
 
 
@@ -360,7 +521,7 @@ Draw_Interpretor& Draw_Interpretor::Append(const TCollection_ExtendedString& the
 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;
 }
@@ -373,7 +534,7 @@ Draw_Interpretor& Draw_Interpretor::Append(const Standard_Integer i)
 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;
 }
@@ -517,3 +678,33 @@ void Draw_Interpretor::Set(const Draw_PInterp& PIntrp)
   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;
+}