--- ScriptHappy.cpp.cvs	Sat Mar 16 06:35:54 2002
+++ ScriptHappy.cpp	Sun Mar 17 05:55:23 2002
@@ -38,6 +38,13 @@
 
 #include "ut_Script.h"
 
+#ifdef WIN32
+#define SETENV_MISSING
+#include <windows.h>
+HANDLE hnd_popen(char *command);
+void preProcessLine(char *data, int len, int bufSize);
+#endif
+
 /*!
  * This plugin doesn't actually do anything... well, ok maybe it does
  * This plugin exports 2 editmethods that other plugins can call
@@ -104,6 +111,7 @@
       {
 	mErrorMsg = "ScriptHappy not installed" ;
 	UT_DEBUGMSG(("DOM: scriptHappy_Capture not installed??\n"));
+	    return UT_ERROR ;
       }
   }
 
@@ -222,7 +230,7 @@
   UT_String var ( key ) ;
   var += "=" ;
   var += value ;
-  putenv ( var ) ;
+  putenv ( var.c_str() ) ;
 #else
   setenv ( key, value, 1 ) ;
 #endif
@@ -345,8 +353,13 @@
       UT_DEBUGMSG(("DOM: trying to capture '%s'\n",command));
       
       // open up a pipe for reading
+#ifdef WIN32
+      HANDLE hPipe = hnd_popen( command );
+      if (hPipe == INVALID_HANDLE_VALUE)
+#else
       FILE * pipe = popen ( command, "r" ) ;
       if ( !pipe )
+#endif
 	{
 	  UT_DEBUGMSG(("Couldn't execute pipe\n"));
 	  DELETEPV ( command );
@@ -354,16 +367,29 @@
 	}
       DELETEPV ( command ) ;      
             
+#ifdef WIN32
+      char script_output[ 1024 ];
+      DWORD bytesRead;
+#else
       char script_output [ 64 ] = "" ;
 
       // prime the buffer - not sure why this is needed, it just doesn't
       // work without this pre-read
       fgets ( script_output, sizeof(script_output), pipe ) ;
+#endif
 
       // suck in our data
+#ifdef WIN32
+      while ( ReadFile(hPipe, script_output, sizeof(script_output)-1, &bytesRead, NULL) && bytesRead)
+#else
       while ( fgets ( script_output, sizeof ( script_output ), pipe ) != NULL )
+#endif
 	{
 	  int howMany = 0 ;
+#ifdef WIN32
+	  // note we require sizeof(script_output) to <= MAX_SIGNED_INT, and assume we read at least 1 less bytes
+	  preProcessLine(script_output, (int)bytesRead, sizeof(script_output));
+#endif
 	  UT_UCSChar * script_ucsdata = ScriptHappy_asciiToUcs ( script_output, howMany ) ;
 	  if ( howMany )
             view->cmdCharInsert ( script_ucsdata, howMany );
@@ -371,7 +397,11 @@
 	}
       
       // close the pipe
+#ifdef WIN32
+      CloseHandle(hPipe);
+#else
       pclose ( pipe ) ;
+#endif
       
       return true ;
     }
@@ -439,3 +469,172 @@
   UT_ScriptLibrary::instance().registerScript ( mSniffer ) ;
   UT_DEBUGMSG(("DOM: registered script!\n"));
 }
+
+
+// Windows utility functions
+#ifdef WIN32
+
+// spawn specified command and inherit handles [stdout]
+static bool CreateChildProcess(char * appName, char *cmdline, HANDLE hChildStdIn, HANDLE hChildStdOut, HANDLE hChildStdErr, WORD showWnd=0)
+{
+	PROCESS_INFORMATION procInfo; 
+	STARTUPINFO startInfo; 
+
+	//initialize structures used to return info
+	ZeroMemory( &procInfo, sizeof(PROCESS_INFORMATION) ); 
+	ZeroMemory( &startInfo, sizeof(STARTUPINFO) ); 
+	startInfo.cb = sizeof(STARTUPINFO); 
+      startInfo.dwFlags = STARTF_USESTDHANDLES;
+	if (showWnd) startInfo.dwFlags |= STARTF_USESHOWWINDOW;
+	startInfo.wShowWindow = showWnd;  /* eg SW_HIDE */
+
+      startInfo.hStdOutput = hChildStdOut;
+      startInfo.hStdInput  = hChildStdIn;
+      startInfo.hStdError  = hChildStdErr;
+
+	// Create the child process. 
+	return (CreateProcess(
+			appName,    // application module to execute
+			cmdline,    // command line 
+			NULL,       // process security attributes 
+			NULL,       // primary thread security attributes 
+			TRUE,       // handles are inherited  ***
+			0,          // creation flags 
+			NULL,       // use parent's environment 
+			NULL,       // use parent's current directory 
+			&startInfo, // STARTUPINFO pointer 
+			&procInfo   // receives PROCESS_INFORMATION 
+	) != 0);
+} 
+
+// Win32 popen-ish read mode for spawned process, ie returns HANDLE to child's stdout
+// Only those Windows programs that actually write to standard output will work as expected.
+// based on MS Win32 docs
+HANDLE hnd_popen(char *command)
+{ 
+	HANDLE hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup, hSaveStdout; 
+ 
+	SECURITY_ATTRIBUTES saAttr; 
+	bool fSuccess; 
+ 
+	// Set the bInheritHandle flag so pipe handles are inherited. 
+	saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); 
+	saAttr.bInheritHandle = TRUE; 
+	saAttr.lpSecurityDescriptor = NULL; 
+ 
+	// The steps for redirecting child process's STDOUT: 
+	//     1. Save current STDOUT, to be restored later. 
+	//     2. Create anonymous pipe to be STDOUT for child process. 
+	//     3. Set STDOUT of the parent process to be write handle to 
+	//        the pipe, so it is inherited by the child process. 
+	//     4. Create a noninheritable duplicate of the read handle and
+	//        close the inheritable read handle. 
+ 
+
+	// Save the handle to the current STDOUT. 
+	hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE); 
+ 
+	// Create a pipe for the child process's STDOUT. 
+	if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
+	{
+		UT_DEBUGMSG(("KJD: Stdout pipe creation failed\n"));
+		return INVALID_HANDLE_VALUE;
+	}
+ 
+	// Set a write handle to the pipe to be STDOUT. 
+	if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
+	{
+		UT_DEBUGMSG(("KJD: Redirecting STDOUT failed\n"));
+		CloseHandle(hChildStdoutRd);
+		CloseHandle(hChildStdoutWr);
+		return INVALID_HANDLE_VALUE;
+	}
+ 
+	// Create noninheritable read handle and close the inheritable read handle. 
+	if (DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
+		GetCurrentProcess(), &hChildStdoutRdDup , 0,
+		FALSE, DUPLICATE_SAME_ACCESS) == 0)
+	{
+		UT_DEBUGMSG(("KJD: DuplicateHandle failed\n"));
+		if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
+		{
+			UT_DEBUGMSG(("KJD: Restoring Stdout failed\n"));
+		}
+		CloseHandle(hChildStdoutRd);
+		CloseHandle(hChildStdoutWr);
+		return INVALID_HANDLE_VALUE;
+	}
+	CloseHandle(hChildStdoutRd);
+ 
+	// Now create the child process. 
+	// TODO: popen runs /bin/sh 'command', perhaps we should do something similar 
+	//       or at least change it to call associated program, eg active perl for *.pl files
+	//       currently only *.exe, *.com, & *.bat work
+	if (! (fSuccess = CreateChildProcess(NULL, command, NULL, hChildStdoutWr, NULL) ))
+	{
+		UT_DEBUGMSG(("KJD: Create process failed\n"));
+	}
+ 
+	// After process creation, restore the saved STDOUT. 
+	if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout)) 
+	{
+		UT_DEBUGMSG(("KJD: Restoring Stdout failed. (postSpawn)\n"));
+		fSuccess = false;
+	}
+
+	CloseHandle(hChildStdoutWr);
+	if (!fSuccess)
+	{
+		CloseHandle(hChildStdoutRdDup);
+		return INVALID_HANDLE_VALUE;
+	}
+	else
+	{
+		return hChildStdoutRdDup;
+	}
+} 
+
+
+// converts \r\n or \n\r to just \n
+// ensure's '\0' terminated (if adjusted_len==bufSize then last character lost)
+// convert any OEM data to something displayable (instead of blocks[])
+void preProcessLine(char *data, int len, int bufSize)
+{
+	if (data==NULL) return;
+	char *buffer = new char[bufSize];
+	if (buffer == NULL) return;
+
+	int j = 0;
+	for (register int i = 0; i < len; i++, j++)
+	{
+		register char value = data[i];
+		switch (value)
+		{
+			case '\n':
+			case '\r':
+			{
+				register char lookingfor = (value == '\r')?'\n':'\r';
+				if ((i+1 < len) && (data[i+1] == lookingfor))
+					i++; // skip next character
+
+				buffer[j] = '\n';
+				break;
+			}
+			default:
+			{
+				buffer[j] = value;
+				break;
+			}	
+		}
+	}
+
+	len = (j < bufSize)?j:j-1;
+	buffer[len] = '\0'; // ensure '\0' terminated
+	memcpy(data, buffer, len+1);
+	delete[] buffer;
+
+	// a better approach of course would be to map to unicode equivalent during conversion to UCS
+	OemToCharA(data, data);
+}
+
+#endif  /* WIN32 */