mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-08-18 06:55:48 +03:00
Fix for SpartanJ/ecode#461. Used CreateProcess is the Unicode version ("CreateProcessW"), and binary paths are now resolved as absolute paths in Windows.
This commit is contained in:
@@ -134,10 +134,10 @@ bool Process::create( const std::string& command, const std::vector<std::string>
|
||||
if ( mProcess )
|
||||
return false;
|
||||
std::vector<const char*> strings;
|
||||
std::string rcommand;
|
||||
mProcess = eeMalloc( sizeof( subprocess_s ) );
|
||||
memset( mProcess, 0, sizeof( subprocess_s ) );
|
||||
if ( !environment.empty() ) {
|
||||
std::string rcommand;
|
||||
if ( FileSystem::fileExists( command ) ) {
|
||||
rcommand = command;
|
||||
} else {
|
||||
@@ -188,7 +188,16 @@ bool Process::create( const std::string& command, const std::vector<std::string>
|
||||
return ret;
|
||||
}
|
||||
|
||||
strings.push_back( command.c_str() );
|
||||
if ( ( options & UseAbsolutePath ) && command.find_first_of( "\\/" ) == std::string::npos ) {
|
||||
rcommand = Sys::which( command );
|
||||
if ( !rcommand.empty() )
|
||||
strings.push_back( rcommand.c_str() );
|
||||
else
|
||||
strings.push_back( command.c_str() );
|
||||
} else {
|
||||
strings.push_back( command.c_str() );
|
||||
}
|
||||
|
||||
for ( size_t i = 0; i < cmdArr.size(); ++i )
|
||||
strings.push_back( cmdArr[i].c_str() );
|
||||
strings.push_back( NULL );
|
||||
|
||||
212
src/thirdparty/subprocess/subprocess.h
vendored
212
src/thirdparty/subprocess/subprocess.h
vendored
@@ -39,6 +39,7 @@
|
||||
/* disable warning: '__cplusplus' is not defined as a preprocessor macro,
|
||||
* replacing with '0' for '#if/#elif' */
|
||||
#pragma warning(disable : 4668)
|
||||
#define _WINBASE_
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -282,9 +283,9 @@ struct subprocess_security_attributes_s {
|
||||
|
||||
struct subprocess_startup_info_s {
|
||||
unsigned long cb;
|
||||
char *lpReserved;
|
||||
char *lpDesktop;
|
||||
char *lpTitle;
|
||||
wchar_t* lpReserved;
|
||||
wchar_t* lpDesktop;
|
||||
wchar_t* lpTitle;
|
||||
unsigned long dwX;
|
||||
unsigned long dwY;
|
||||
unsigned long dwXSize;
|
||||
@@ -301,6 +302,48 @@ struct subprocess_startup_info_s {
|
||||
void *hStdError;
|
||||
};
|
||||
|
||||
typedef unsigned char BYTE;
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD;
|
||||
typedef int BOOL;
|
||||
typedef wchar_t* LPWSTR;
|
||||
typedef const wchar_t* LPCWSTR;
|
||||
typedef unsigned char* LPBYTE;
|
||||
typedef void* HANDLE;
|
||||
typedef void* LPVOID;
|
||||
typedef char CHAR;
|
||||
|
||||
#define OFS_MAXPATHNAME 128
|
||||
typedef struct _OFSTRUCT {
|
||||
BYTE cBytes;
|
||||
BYTE fFixedDisk;
|
||||
WORD nErrCode;
|
||||
WORD Reserved1;
|
||||
WORD Reserved2;
|
||||
CHAR szPathName[OFS_MAXPATHNAME];
|
||||
} OFSTRUCT, *LPOFSTRUCT, *POFSTRUCT;
|
||||
|
||||
typedef struct _STARTUPINFOW {
|
||||
DWORD cb;
|
||||
LPWSTR lpReserved;
|
||||
LPWSTR lpDesktop;
|
||||
LPWSTR lpTitle;
|
||||
DWORD dwX;
|
||||
DWORD dwY;
|
||||
DWORD dwXSize;
|
||||
DWORD dwYSize;
|
||||
DWORD dwXCountChars;
|
||||
DWORD dwYCountChars;
|
||||
DWORD dwFillAttribute;
|
||||
DWORD dwFlags;
|
||||
WORD wShowWindow;
|
||||
WORD cbReserved2;
|
||||
LPBYTE lpReserved2;
|
||||
HANDLE hStdInput;
|
||||
HANDLE hStdOutput;
|
||||
HANDLE hStdError;
|
||||
} STARTUPINFOW, *LPSTARTUPINFOW;
|
||||
|
||||
struct subprocess_overlapped_s {
|
||||
uintptr_t Internal;
|
||||
uintptr_t InternalHigh;
|
||||
@@ -354,6 +397,74 @@ __declspec(dllimport) int __stdcall GetOverlappedResult(void *, LPOVERLAPPED,
|
||||
unsigned long *, int);
|
||||
__declspec(dllimport) int __stdcall FlushFileBuffers(void *);
|
||||
|
||||
__declspec(dllimport) int __stdcall CreateProcessW(
|
||||
const wchar_t* lpApplicationName, wchar_t* lpCommandLine,
|
||||
LPSECURITY_ATTRIBUTES lpProcessAttributes, LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
BOOL bInheritHandles,
|
||||
DWORD dwCreationFlags,
|
||||
LPVOID lpEnvironment,
|
||||
const wchar_t* lpCurrentDirectory,
|
||||
LPSTARTUPINFOW lpStartupInfo,
|
||||
LPPROCESS_INFORMATION lpProcessInformation );
|
||||
|
||||
#ifndef CP_UTF8
|
||||
#define CP_UTF8 65001 // UTF-8 translation
|
||||
#endif
|
||||
|
||||
#ifndef MB_ERR_INVALID_CHARS
|
||||
#define MB_ERR_INVALID_CHARS 0x00000008 // error for invalid chars
|
||||
#endif
|
||||
|
||||
#ifndef CREATE_UNICODE_ENVIRONMENT
|
||||
#define CREATE_UNICODE_ENVIRONMENT 0x00000400
|
||||
#endif
|
||||
|
||||
__declspec( dllimport ) int __stdcall MultiByteToWideChar(
|
||||
unsigned int CodePage, // UINT
|
||||
unsigned long dwFlags, // DWORD
|
||||
const char* lpMultiByteStr, // LPCCH -> const char*
|
||||
int cbMultiByte,
|
||||
wchar_t* lpWideCharStr, // LPWSTR -> wchar_t*
|
||||
int cchWideChar );
|
||||
|
||||
wchar_t* Utf8ToUtf16_C( const char* utf8Str ) {
|
||||
if ( utf8Str == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int wideCharCount = MultiByteToWideChar(
|
||||
CP_UTF8,
|
||||
MB_ERR_INVALID_CHARS,
|
||||
utf8Str,
|
||||
-1,
|
||||
NULL,
|
||||
0
|
||||
);
|
||||
|
||||
if ( wideCharCount == 0 ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wchar_t* wideStr = (wchar_t*)malloc( wideCharCount * sizeof( wchar_t ) );
|
||||
if ( wideStr == NULL ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int result = MultiByteToWideChar( CP_UTF8,
|
||||
MB_ERR_INVALID_CHARS, // Use same flags
|
||||
utf8Str, -1,
|
||||
wideStr, // Destination buffer
|
||||
wideCharCount // Size of destination buffer in WCHARs
|
||||
);
|
||||
|
||||
if ( result == 0 ) {
|
||||
free( wideStr );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return wideStr;
|
||||
}
|
||||
|
||||
#if defined(_DLL)
|
||||
#define SUBPROCESS_DLLIMPORT __declspec(dllimport)
|
||||
#else
|
||||
@@ -500,15 +611,15 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
||||
subprocess_size_t len;
|
||||
int i, j;
|
||||
int need_quoting;
|
||||
unsigned long flags = 0;
|
||||
unsigned long flags = CREATE_UNICODE_ENVIRONMENT;
|
||||
const unsigned long startFUseStdHandles = 0x00000100;
|
||||
const unsigned long handleFlagInherit = 0x00000001;
|
||||
const unsigned long createNoWindow = 0x08000000;
|
||||
struct subprocess_subprocess_information_s processInfo;
|
||||
struct subprocess_security_attributes_s saAttr = {sizeof(saAttr),
|
||||
SUBPROCESS_NULL, 1};
|
||||
char *used_environment = SUBPROCESS_NULL;
|
||||
struct subprocess_startup_info_s startInfo = {0,
|
||||
wchar_t *used_environment = SUBPROCESS_NULL;
|
||||
STARTUPINFOW startInfo = { 0,
|
||||
SUBPROCESS_NULL,
|
||||
SUBPROCESS_NULL,
|
||||
SUBPROCESS_NULL,
|
||||
@@ -537,36 +648,57 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
||||
if (subprocess_option_inherit_environment !=
|
||||
(options & subprocess_option_inherit_environment)) {
|
||||
if (SUBPROCESS_NULL == environment) {
|
||||
used_environment = SUBPROCESS_CONST_CAST(char *, "\0\0");
|
||||
used_environment = SUBPROCESS_NULL;
|
||||
} else {
|
||||
// We always end with two null terminators.
|
||||
len = 2;
|
||||
if ( environment[0] == NULL ) {
|
||||
used_environment = SUBPROCESS_NULL;
|
||||
} else {
|
||||
size_t total_wchars_for_env = 0;
|
||||
for ( i = 0; environment[i] != NULL; i++ ) {
|
||||
int wchars_for_str = MultiByteToWideChar( CP_UTF8, 0, environment[i], -1, NULL, 0 );
|
||||
if ( wchars_for_str == 0 ) {
|
||||
if ( environment[i][0] != '\0' )
|
||||
return -1;
|
||||
wchars_for_str = 1;
|
||||
}
|
||||
total_wchars_for_env += wchars_for_str;
|
||||
}
|
||||
total_wchars_for_env += 1;
|
||||
|
||||
for (i = 0; environment[i]; i++) {
|
||||
for (j = 0; '\0' != environment[i][j]; j++) {
|
||||
len++;
|
||||
}
|
||||
used_environment = (wchar_t*)malloc( total_wchars_for_env * sizeof( wchar_t ) );
|
||||
if ( !used_environment )
|
||||
return -1;
|
||||
|
||||
// For the null terminator too.
|
||||
len++;
|
||||
}
|
||||
wchar_t* current_env_ptr = used_environment;
|
||||
size_t remaining_wchar_capacity = total_wchars_for_env;
|
||||
for ( i = 0; environment[i] != NULL; i++ ) {
|
||||
int wchars_for_str = MultiByteToWideChar( CP_UTF8, 0, environment[i], -1, NULL, 0 );
|
||||
if ( wchars_for_str == 0 ) {
|
||||
if ( environment[i][0] != '\0' )
|
||||
return -1;
|
||||
wchars_for_str = 1;
|
||||
}
|
||||
|
||||
used_environment = SUBPROCESS_CAST(char *, _alloca(len));
|
||||
if ( wchars_for_str > remaining_wchar_capacity ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Re-use len for the insertion position
|
||||
len = 0;
|
||||
int wchars_written = MultiByteToWideChar(
|
||||
CP_UTF8, 0, environment[i], -1, current_env_ptr, remaining_wchar_capacity );
|
||||
if ( wchars_written == 0 ||
|
||||
wchars_written != wchars_for_str ) {
|
||||
return -1;
|
||||
}
|
||||
current_env_ptr += wchars_written;
|
||||
remaining_wchar_capacity -= wchars_written;
|
||||
}
|
||||
|
||||
for (i = 0; environment[i]; i++) {
|
||||
for (j = 0; '\0' != environment[i][j]; j++) {
|
||||
used_environment[len++] = environment[i][j];
|
||||
}
|
||||
|
||||
used_environment[len++] = '\0';
|
||||
}
|
||||
|
||||
// End with the two null terminators.
|
||||
used_environment[len++] = '\0';
|
||||
used_environment[len++] = '\0';
|
||||
if ( remaining_wchar_capacity > 0 ) {
|
||||
*current_env_ptr = L'\0';
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (SUBPROCESS_NULL != environment) {
|
||||
@@ -744,20 +876,30 @@ int subprocess_create_ex(const char *const commandLine[], int options,
|
||||
|
||||
commandLineCombined[len] = '\0';
|
||||
|
||||
if (!CreateProcessA(
|
||||
wchar_t* commandLineCombinedW = Utf8ToUtf16_C( commandLineCombined );
|
||||
wchar_t* working_directoryW = Utf8ToUtf16_C( working_directory );
|
||||
|
||||
if (!CreateProcessW(
|
||||
SUBPROCESS_NULL,
|
||||
commandLineCombined, // command line
|
||||
commandLineCombinedW, // command line
|
||||
SUBPROCESS_NULL, // process security attributes
|
||||
SUBPROCESS_NULL, // primary thread security attributes
|
||||
1, // handles are inherited
|
||||
flags, // creation flags
|
||||
used_environment, // used environment
|
||||
working_directory, // set process working directory
|
||||
SUBPROCESS_PTR_CAST(LPSTARTUPINFOA,
|
||||
used_environment, // used environment
|
||||
working_directoryW, // set process working directory
|
||||
SUBPROCESS_PTR_CAST( LPSTARTUPINFOW,
|
||||
&startInfo), // STARTUPINFO pointer
|
||||
SUBPROCESS_PTR_CAST(LPPROCESS_INFORMATION, &processInfo))) {
|
||||
free( commandLineCombinedW );
|
||||
free( used_environment );
|
||||
free( working_directoryW );
|
||||
return -1;
|
||||
}
|
||||
|
||||
free( commandLineCombinedW );
|
||||
free( used_environment );
|
||||
free( working_directoryW );
|
||||
|
||||
out_process->hProcess = processInfo.hProcess;
|
||||
|
||||
|
||||
@@ -40,10 +40,13 @@ int Git::git( const std::string& args, const std::string& projectDir, std::strin
|
||||
Clock clock;
|
||||
buf.clear();
|
||||
Process p;
|
||||
p.create( mGitPath, args,
|
||||
if ( !p.create( mGitPath, args,
|
||||
Process::CombinedStdoutStderr | Process::Options::NoWindow |
|
||||
Process::Options::EnableAsync | Process::Options::InheritEnvironment,
|
||||
{ { "LC_ALL", "en_US.UTF-8" } }, projectDir.empty() ? mProjectPath : projectDir );
|
||||
{ { "LC_ALL", "en_US.UTF-8" } },
|
||||
projectDir.empty() ? mProjectPath : projectDir ) ) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
p.readAllStdOut( buf );
|
||||
int retCode = 0;
|
||||
p.join( &retCode );
|
||||
|
||||
@@ -1310,8 +1310,11 @@ bool LSPClientServer::start() {
|
||||
}
|
||||
|
||||
if ( !cmd.empty() ) {
|
||||
bool ret = mProcess.create( cmd, Process::getDefaultOptions() | Process::EnableAsync,
|
||||
mLSP.env, mRootPath );
|
||||
auto flags = Process::getDefaultOptions() | Process::EnableAsync;
|
||||
#if EE_PLATFORM == EE_PLATFORM_WIN
|
||||
flags |= Process::UseAbsolutePath;
|
||||
#endif
|
||||
bool ret = mProcess.create( cmd, flags, mLSP.env, mRootPath );
|
||||
if ( ret ) {
|
||||
if ( mProcess.isAlive() ) {
|
||||
mUsingProcess = true;
|
||||
|
||||
Reference in New Issue
Block a user