0030377: DRAW, Windows - command executed via option -c fails on puts
authorabv <abv@opencascade.com>
Sun, 18 Nov 2018 16:53:10 +0000 (19:53 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 10 Jan 2019 13:35:02 +0000 (16:35 +0300)
When DRAW on Windows is launched with option -c, the command is now properly transferred to Tcl thread (separate thread that runs Tcl interpretor on Windows except when DRAW is run in batch mode) for execution, instead of being evaluated in the main thread.

Execution of DRAW in batch mode (option -b) is fixed by enabling proper initialization of the Tcl interpretor and replacement of backslashes in path to startup script by straight slashes on Windows in that mode.

Declaration of global variables used for communication of console command between threads is moved to Draw_Window.hxx to ensure consistency.
Function wscpy_s is used instead of memcpy to avoid possible buffer overrun.

src/Draw/CommandWindow.cxx
src/Draw/Draw.cxx
src/Draw/Draw_Window.cxx
src/Draw/Draw_Window.hxx

index 5e9909d..6d85fe9 100644 (file)
@@ -156,9 +156,6 @@ int GetCommand (HWND hWnd, wchar_t* theBuffer)
   return aNbChar;
 }
 
-extern console_semaphore_value volatile console_semaphore;
-extern wchar_t console_command[1000];
-
 /*--------------------------------------------------------*\
 |  EDIT WINDOW PROCEDURE
 \*--------------------------------------------------------*/
@@ -191,7 +188,7 @@ LRESULT APIENTRY EditProc(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam )
           //TCollection_AsciiString aCmdUtf8 (aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1);
           //Draw_Interprete (aCmdUtf8.ToCString());
           //if (toExit) { DestroyProc (hWnd); }
-          wcscpy (console_command, aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1);
+          wcscpy_s (console_command, aCmdBuffer + sizeof(THE_PROMPT) / sizeof(wchar_t) - 1);
           console_semaphore = HAS_CONSOLE_COMMAND;
           // Purge the buffer
           nbline = SendMessageW (hWnd, EM_GETLINECOUNT, 0l, 0l);
index e6292ae..81a4567 100644 (file)
@@ -66,8 +66,6 @@ filebuf Draw_Spyfile;
 
 static ostream spystream(&Draw_Spyfile);
 
-static   Standard_Boolean XLoop;
-
 static Handle(Draw_ProgressIndicator) PInd = NULL;
 
 Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
@@ -76,23 +74,20 @@ Standard_EXPORT Standard_Boolean Draw_Interprete(const char* command);
 // *******************************************************************
 // read an init file
 // *******************************************************************
-#ifdef _WIN32
-extern console_semaphore_value volatile console_semaphore;
-extern wchar_t console_command[1000];
-#endif
 
 static void ReadInitFile (const TCollection_AsciiString& theFileName)
 {
   TCollection_AsciiString aPath = theFileName;
 #ifdef _WIN32
+  aPath.ChangeAll('\\', '/');
   if (!Draw_Batch)
   {
     try
     {
-      aPath.ChangeAll ('\\', '/');
       {
-        const TCollection_ExtendedString aCmdWide = TCollection_ExtendedString ("source -encoding utf-8 \"") + TCollection_ExtendedString (aPath) + "\"";
-        memcpy (console_command, aCmdWide.ToWideString(), Min (aCmdWide.Length() + 1, 980) * sizeof(wchar_t));
+        TCollection_ExtendedString aCmdWide ("source -encoding utf-8 \"");
+        aCmdWide += TCollection_ExtendedString (aPath) + "\"";
+        wcscpy_s (console_command, aCmdWide.ToWideString());
       }
       console_semaphore = HAS_CONSOLE_COMMAND;
       while (console_semaphore == HAS_CONSOLE_COMMAND)
@@ -286,10 +281,13 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
     Draw_Batch=!Init_Appli();
 #endif
   else
+  {
     cout << "DRAW is running in batch mode" << endl;
+    theCommands.Init();
+    Tcl_Init(theCommands.Interp());
+  }
 
-  XLoop = !Draw_Batch;
-  if (XLoop)
+  if (! Draw_Batch)
   {
     // Default colors
     for (int i = 0; i < MAXCOLOR; ++i)
@@ -364,8 +362,21 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
   }
 
   // execute command from command line
-  if (!aCommand.IsEmpty()) {
-    Draw_Interprete (aCommand.ToCString());
+  if (!aCommand.IsEmpty())
+  {
+#ifdef _WIN32
+    if (!Draw_Batch)
+    {
+      // on Windows except batch mode, commands are executed in separate thread
+      while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
+      TCollection_ExtendedString aCmdWide(aCommand);
+      wcscpy_s(console_command, aCmdWide.ToWideString());
+      console_semaphore = HAS_CONSOLE_COMMAND;
+      while (console_semaphore == HAS_CONSOLE_COMMAND) Sleep(10);
+    }
+    else
+#endif
+    Draw_Interprete (aCommand.ToCString()); // Linux and Windows batch mode
     // provide a clean exit, this is useful for some analysis tools
     if ( ! isInteractiveForced )
 #ifndef _WIN32
@@ -378,7 +389,7 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
   // *****************************************************************
   // X loop
   // *****************************************************************
-  if (XLoop) {
+  if (! Draw_Batch) {
 #ifdef _WIN32
     Run_Appli(hWnd);
 #else
@@ -387,15 +398,15 @@ void Draw_Appli(int argc, char** argv, const FDraw_InitAppli Draw_InitAppli)
   }
   else
   {
-    char cmd[255];
-    for (;;)
+    const int MAXCMD = 2048;
+    char cmd[MAXCMD];
+    for (int ncmd = 1;; ++ncmd)
     {
-      cout << "Viewer>";
-      int i = -1;
-      do {
-        cin.get(cmd[++i]);
-      } while ((cmd[i] != '\n') && (!cin.fail()));
-      cmd[i] = '\0';
+      cout << "Draw[" << ncmd << "]> ";
+      if (cin.getline (cmd, MAXCMD).fail())
+      {
+        break;
+      }
       Draw_Interprete(cmd);
     }
   }
index 7aab0be..2ffd7ee 100644 (file)
@@ -30,6 +30,7 @@
 #include <Image_AlienPixMap.hxx>
 #include <NCollection_List.hxx>
 
+extern Standard_Boolean Draw_Batch;
 extern Standard_Boolean Draw_VirtualWindows;
 static Tcl_Interp *interp;        /* Interpreter for this application. */
 static NCollection_List<Draw_Window::FCallbackBeforeTerminate> MyCallbacks;
@@ -2021,8 +2022,7 @@ static Tk_Window mainWindow;
 //* threads sinchronization *//
 DWORD  dwMainThreadId;
 console_semaphore_value volatile console_semaphore = WAIT_CONSOLE_COMMAND;
-#define THE_COMMAND_SIZE 1000     /* Console Command size */
-wchar_t console_command[THE_COMMAND_SIZE];
+wchar_t console_command[DRAW_COMMAND_SIZE + 1];
 bool volatile isTkLoopStarted = false;
 
 /*--------------------------------------------------------*\
@@ -2051,6 +2051,7 @@ Standard_Boolean Init_Appli(HINSTANCE hInst,
                            &IDThread);
   if (!hThread) {
     cout << "Tcl/Tk main loop thread not created. Switching to batch mode..." << endl;
+    Draw_Batch = Standard_True;
 #ifdef _TK
     try {
       OCC_CATCH_SIGNALS
@@ -2125,7 +2126,7 @@ static DWORD WINAPI readStdinThreadFunc()
      && isConsoleInput)
     {
       DWORD aNbRead = 0;
-      if (ReadConsoleW (anStdIn, console_command, THE_COMMAND_SIZE, &aNbRead, NULL))
+      if (ReadConsoleW (anStdIn, console_command, DRAW_COMMAND_SIZE, &aNbRead, NULL))
       {
         console_command[aNbRead] = L'\0';
         console_semaphore = HAS_CONSOLE_COMMAND;
@@ -2145,7 +2146,7 @@ static DWORD WINAPI readStdinThreadFunc()
     }
 
     // fgetws() works only for characters within active locale (see setlocale())
-    if (fgetws (console_command, THE_COMMAND_SIZE, stdin))
+    if (fgetws (console_command, DRAW_COMMAND_SIZE, stdin))
     {
       console_semaphore = HAS_CONSOLE_COMMAND;
     }
@@ -2373,7 +2374,7 @@ static DWORD WINAPI tkLoop(VOID)
     }
   #ifdef _TK
     // We should not exit until the Main Tk window is closed
-    toLoop = (Tk_GetNumMainWindows() > 0) || Draw_VirtualWindows;
+    toLoop = (Draw_VirtualWindows || Tk_GetNumMainWindows() > 0);
   #endif
   }
   Tcl_Exit(0);
index 05ea549..2b9614c 100644 (file)
@@ -516,6 +516,13 @@ typedef enum {
   WAIT_CONSOLE_COMMAND,
   HAS_CONSOLE_COMMAND} console_semaphore_value;
 
+// global variable describing console state
+extern console_semaphore_value volatile console_semaphore;
+
+// Console command buffer
+#define DRAW_COMMAND_SIZE 1000
+extern wchar_t console_command[DRAW_COMMAND_SIZE + 1];
+
 // PROCEDURE DE DRAW WINDOW
 
 Standard_EXPORT Standard_Boolean Init_Appli(HINSTANCE,HINSTANCE,int,HWND&);