Index: vcdiff.c =================================================================== --- vcdiff.c (revision 2263) +++ vcdiff.c (working copy) @@ -36,6 +36,34 @@ #include "project.h" #include "pluginmacros.h" +#ifdef G_OS_WIN32 +#include +#include + +#define BUFSIZE 4096 + +struct _geany_win32_spawn +{ + HANDLE hChildStdinRd; + HANDLE hChildStdinWr; + HANDLE hChildStdoutRd; + HANDLE hChildStdoutWr; + HANDLE hChildStderrRd; + HANDLE hChildStderrWr; + HANDLE hInputFile; + HANDLE hStdout; + HANDLE hStderr; +}; +typedef struct _geany_win32_spawn geany_win32_spawn; + +gboolean geany_w32_spawn_sync(gchar *cmdline, gchar *dir, gchar **std_out, gchar **std_err); +gboolean GetContentFromHandle(HANDLE hFile, gchar **content); +HANDLE getTempFileHandle(); +gboolean CreateChildProcess(geany_win32_spawn *gw_spawn, TCHAR *szCmdline, TCHAR *dir); +VOID ReadFromPipe(HANDLE hRead, HANDLE hWrite, HANDLE hFile); +VOID ErrorExit(LPSTR); +#endif + PluginFields *plugin_fields; GeanyData *geany_data; @@ -167,7 +195,6 @@ return ret; } - static void* find_cmd_env(gint cmd_type, gboolean cmd, const gchar* filename) { guint i; @@ -186,7 +213,7 @@ } -static void* get_cmd_env(gint cmd_type, gboolean cmd, const gchar* filename) +static void* get_cmd_env(gint cmd_type, gboolean cmd, const gchar* filename, int *size) { int i; gint len = 0; @@ -234,6 +261,9 @@ else ret[i] = g_strdup(argv[i]); } + + *size = len; + g_free(dir); g_free(base_filename); return ret; @@ -307,17 +337,27 @@ g_free(filename); } - static gchar *make_diff(const gchar *filename, gint cmd) { gchar *std_output = NULL; gchar *std_error = NULL; - gint exit_code; gchar *text = NULL; gchar *dir; - gchar **env = get_cmd_env(cmd, FALSE, filename); - gchar **argv = get_cmd_env(cmd, TRUE, filename); + gint argc = 0; + gint i; + gchar **env = get_cmd_env(cmd, FALSE, filename, &argc); + gchar **argv = get_cmd_env(cmd, TRUE, filename, &argc); +#ifdef G_OS_WIN32 + TCHAR buffer[MAX_PATH]=TEXT(""); + TCHAR cmdline[MAX_PATH] = TEXT(""); + TCHAR* lpPart[MAX_PATH]={NULL}; + DWORD retval=0; + +#else + gint exit_code; +#endif + if (!argv) { if (env) @@ -334,6 +374,32 @@ dir = g_path_get_dirname(filename); } +#ifdef G_OS_WIN32 + retval = SearchPath(NULL, + argv[0], ".exe", MAX_PATH, buffer, lpPart); + sprintf(cmdline, "\"%s\"", buffer); + for (i = 1; i < argc; i++) { + sprintf(cmdline, "%s %s", cmdline, argv[i]); + //MessageBox(NULL, cmdline, cmdline, MB_OK); + } + + if (geany_w32_spawn_sync(cmdline, dir, &std_output, &std_error)) + { + if (NZV(std_output)) + { + text = std_output; + } + else + { + p_ui->set_statusbar(FALSE, _("No changes were made.")); + } + } + else + { + p_ui->set_statusbar(FALSE, _("Something went really wrong.")); + } + +#else if (g_spawn_sync(dir, argv, env, G_SPAWN_SEARCH_PATH, NULL, NULL, &std_output, &std_error, &exit_code, NULL)) { // CVS dump stuff to stderr when diff nested dirs @@ -356,6 +422,8 @@ p_ui->set_statusbar(FALSE, _("Something went really wrong.")); } +#endif + g_free(dir); g_free(std_error); g_strfreev(env); @@ -530,3 +598,255 @@ // remove the menu item added in init() gtk_widget_destroy(plugin_fields->menu_item); } + +#ifdef G_OS_WIN32 +gboolean geany_w32_spawn_sync(gchar *cmdline, gchar *dir, gchar **std_out, gchar **std_err) +{ + SECURITY_ATTRIBUTES saAttr; + BOOL fSuccess; + geany_win32_spawn gw_spawn; + + /* Temp file */ + HANDLE hStdoutTempFile, hStderrTempFile; + + gchar *stdout_content = NULL; + gchar *stderr_content = NULL; + + hStderrTempFile = getTempFileHandle(); + if (hStderrTempFile == INVALID_HANDLE_VALUE) + { + printf("Second CreateFile failed (%d)\n", GetLastError()); + return FALSE; + } + + hStdoutTempFile = getTempFileHandle(); + if (hStdoutTempFile == INVALID_HANDLE_VALUE) + { + printf("Second CreateFile failed (%d)\n", GetLastError()); + return FALSE; + } + + /* Set the bInheritHandle flag so pipe handles are inherited. */ + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + /* Get the handle to the current STDOUT and STDERR. */ + gw_spawn.hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + gw_spawn.hStderr = GetStdHandle(STD_ERROR_HANDLE); + + + /* Create a pipe for the child process's STDOUT. */ + if (!CreatePipe(&(gw_spawn.hChildStdoutRd), &(gw_spawn.hChildStdoutWr), &saAttr, 0)) + { + ErrorExit("Stdout pipe creation failed\n"); + return FALSE; + } + + /* Ensure that the read handle to the child process's pipe for STDOUT is not inherited.*/ + SetHandleInformation(gw_spawn.hChildStdoutRd, HANDLE_FLAG_INHERIT, 0); + + + /* Create a pipe for the child process's STDERR. */ + if (!CreatePipe(&(gw_spawn.hChildStderrRd), &(gw_spawn.hChildStderrWr), &saAttr, 0)) + { + ErrorExit("Stdout pipe creation failed\n"); + return FALSE; + } + + /* Ensure that the read handle to the child process's pipe for STDOUT is not inherited.*/ + SetHandleInformation(gw_spawn.hChildStderrRd, HANDLE_FLAG_INHERIT, 0); + + + /* Create a pipe for the child process's STDIN. */ + if (! CreatePipe(&(gw_spawn.hChildStdinRd), &(gw_spawn.hChildStdinWr), &saAttr, 0)) + { + ErrorExit("Stdin pipe creation failed\n"); + return FALSE; + } + + /* Ensure that the write handle to the child process's pipe for STDIN is not inherited. */ + SetHandleInformation(gw_spawn.hChildStdinWr, HANDLE_FLAG_INHERIT, 0); + + + /* Now create the child process. */ + fSuccess = CreateChildProcess(&gw_spawn, cmdline, dir); + if (! fSuccess) + { + ErrorExit("Create process failed with"); + return FALSE; + } + + /* Read from pipe that is the standard output for child process. */ + ReadFromPipe(gw_spawn.hChildStdoutRd, gw_spawn.hChildStdoutWr, hStdoutTempFile); + GetContentFromHandle(hStdoutTempFile, &stdout_content); + + ReadFromPipe(gw_spawn.hChildStderrRd, gw_spawn.hChildStderrWr, hStderrTempFile); + GetContentFromHandle(hStderrTempFile, &stderr_content); + + *std_out = stdout_content; + *std_err = stderr_content; + return TRUE; +} + +gboolean GetContentFromHandle(HANDLE hFile, gchar **content) +{ + DWORD filesize; + gchar * buffer; + DWORD dwRead; + + filesize = GetFileSize(hFile, NULL); + if (filesize<1) { + *content = NULL; + return TRUE; + } + + buffer = g_malloc(sizeof(gchar*) * (filesize+1)); + if (!buffer) + { + ErrorExit("Alloc failed"); + return FALSE; + } + + SetFilePointer(hFile,0, NULL, FILE_BEGIN); + if( !ReadFile(hFile, buffer, filesize, &dwRead, + NULL) || dwRead == 0) + { + ErrorExit("Cannot read tempfile"); + return FALSE; + } + + if (!CloseHandle (hFile)) + { + printf ("CloseHandle failed (%d)\n", GetLastError()); + g_free(buffer); + *content = NULL; + return FALSE; + } + *content = buffer; + return TRUE; +} + +gboolean CreateChildProcess(geany_win32_spawn *gw_spawn, TCHAR *szCmdline, TCHAR *dir) +{ + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + BOOL bFuncRetn = FALSE; + + /* Set up members of the PROCESS_INFORMATION structure. */ + ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); + + /* Set up members of the STARTUPINFO structure.*/ + ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); + + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = gw_spawn->hChildStderrWr; + siStartInfo.hStdOutput = gw_spawn->hChildStdoutWr; + siStartInfo.hStdInput = gw_spawn->hChildStdinRd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + /* Create the child process. */ + bFuncRetn = CreateProcess(NULL, + szCmdline, /* command line */ + NULL, /* process security attributes */ + NULL, /* primary thread security attributes */ + TRUE, /* handles are inherited */ + CREATE_NO_WINDOW, /* creation flags */ + NULL, /* use parent's environment */ + dir, /* use parent's current directory */ + &siStartInfo, /* STARTUPINFO pointer */ + &piProcInfo); /* receives PROCESS_INFORMATION */ + + if (bFuncRetn == 0) + { + ErrorExit("CreateProcess failed\n"); + return FALSE; + } + else + { + CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + return bFuncRetn; + } + return FALSE; +} + +VOID ReadFromPipe(HANDLE hRead, HANDLE hWrite, HANDLE hFile) +{ + DWORD dwRead, dwWritten; + CHAR chBuf[BUFSIZE]; + + /* Close the write end of the pipe before reading from the + read end of the pipe. */ + if (!CloseHandle(hWrite)) + { + ErrorExit("Closing handle failed"); + return; + } + + /* Read output from the child process, and write to parent's STDOUT. */ + for (;;) + { + if( !ReadFile(hRead, chBuf, BUFSIZE, &dwRead, + NULL) || dwRead == 0) break; + + if (!WriteFile(hFile, chBuf, dwRead, &dwWritten, NULL)) + break; + } +} + + +HANDLE getTempFileHandle() +{ + /* Temp file */ + DWORD dwBufSize=BUFSIZE; + UINT uRetVal; + TCHAR szTempName[BUFSIZE]; + TCHAR lpPathBuffer[BUFSIZE]; + DWORD dwRetVal; + HANDLE hTempFile; + + /* Get the temp path. */ + dwRetVal = GetTempPath(dwBufSize, /* length of the buffer*/ + lpPathBuffer); /* buffer for path */ + + if (dwRetVal > dwBufSize || (dwRetVal == 0)) + { + printf ("GetTempPath failed (%d)\n", GetLastError()); + return NULL; + } + + /* Create a temporary file for STDOUT. */ + uRetVal = GetTempFileName(lpPathBuffer, /* directory for tmp files */ + TEXT("GEANY_VCDIFF_"), /* temp file name prefix */ + 0, /* create unique name */ + szTempName); /* buffer for name */ + if (uRetVal == 0) + { + printf ("GetTempFileName failed (%d)\n", GetLastError()); + return NULL; + } + + hTempFile = CreateFile((LPTSTR) szTempName, /* file name */ + GENERIC_READ | GENERIC_WRITE, /* open r-w */ + 0, /* do not share */ + NULL, /* default security */ + CREATE_ALWAYS, /* overwrite existing */ + FILE_ATTRIBUTE_NORMAL,/* normal file */ + NULL); /* no template */ + + if (hTempFile == INVALID_HANDLE_VALUE) + { + printf("Second CreateFile failed (%d)\n", GetLastError()); + return NULL; + } + return hTempFile; +} + + +VOID ErrorExit (LPSTR lpszMessage) +{ + p_dialogs->show_msgbox(1, _("%s."), lpszMessage); +} +#endif +