[cmake-developers] [PATCH v4 4/4] For Windows encode process output to internally used encoding
Dāvis Mosāns
davispuh at gmail.com
Thu Jul 7 17:54:06 EDT 2016
Typically Windows applications (eg. MSVC compiler) use current console's
codepage for output to pipes so we need to encode that to internally used
encoding (KWSYS_ENCODING_DEFAULT_CODEPAGE).
---
Source/cmExecProgramCommand.cxx | 1 +
Source/cmExecuteProcessCommand.cxx | 1 +
Source/cmProcessTools.cxx | 2 ++
Source/cmSystemTools.cxx | 3 +++
Source/kwsys/CMakeLists.txt | 2 ++
Source/kwsys/Process.h.in | 13 +++++++++++++
Source/kwsys/ProcessUNIX.c | 6 ++++++
Source/kwsys/ProcessWin32.c | 33 ++++++++++++++++++++++++++++++++-
Source/kwsys/SystemInformation.cxx | 1 +
9 files changed, 61 insertions(+), 1 deletion(-)
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 58bbc31..92b89fc 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -220,6 +220,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
char* data;
int p;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
+ cmsysProcess_DecodeTextOutput(cp, &data, &length);
if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
if (verbose) {
cmSystemTools::Stdout(data, length);
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index d97b25f..b13fb2e 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -229,6 +229,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
char* data;
int p;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
+ cmsysProcess_DecodeTextOutput(cp, &data, &length);
// Put the output in the right place.
if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
if (output_variable.empty()) {
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index 34b8df2..8ab8070 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -23,10 +23,12 @@ void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
while ((out || err) &&
(p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
if (out && p == cmsysProcess_Pipe_STDOUT) {
+ cmsysProcess_DecodeTextOutput(cp, &data, &length);
if (!out->Process(data, length)) {
out = CM_NULLPTR;
}
} else if (err && p == cmsysProcess_Pipe_STDERR) {
+ cmsysProcess_DecodeTextOutput(cp, &data, &length);
if (!err->Process(data, length)) {
err = CM_NULLPTR;
}
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 9740ef7..aeb5471 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -616,6 +616,7 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
(captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) >
0) {
+ cmsysProcess_DecodeTextOutput(cp, &data, &length);
// Translate NULL characters in the output into valid text.
// Visual Studio 7 puts these characters in the output of its
// build process.
@@ -1689,11 +1690,13 @@ int cmSystemTools::WaitForLine(cmsysProcess* process, std::string& line,
return pipe;
} else if (pipe == cmsysProcess_Pipe_STDOUT) {
// Append to the stdout buffer.
+ cmsysProcess_DecodeTextOutput(process, &data, &length);
std::vector<char>::size_type size = out.size();
out.insert(out.end(), data, data + length);
outiter = out.begin() + size;
} else if (pipe == cmsysProcess_Pipe_STDERR) {
// Append to the stderr buffer.
+ cmsysProcess_DecodeTextOutput(process, &data, &length);
std::vector<char>::size_type size = err.size();
err.insert(err.end(), data, data + length);
erriter = err.begin() + size;
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 39b03b3..65203c0 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -708,6 +708,8 @@ IF(KWSYS_USE_Process)
IF(NOT UNIX)
# Use the Windows implementation.
SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessWin32.c)
+ SET_PROPERTY(SOURCE ProcessWin32.c APPEND PROPERTY COMPILE_DEFINITIONS
+ KWSYS_ENCODING_DEFAULT_CODEPAGE=${KWSYS_ENCODING_DEFAULT_CODEPAGE})
ELSE()
# Use the UNIX implementation.
SET(KWSYS_C_SRCS ${KWSYS_C_SRCS} ProcessUNIX.c)
diff --git a/Source/kwsys/Process.h.in b/Source/kwsys/Process.h.in
index 96563a2..0c79b47 100644
--- a/Source/kwsys/Process.h.in
+++ b/Source/kwsys/Process.h.in
@@ -67,6 +67,7 @@
# define kwsysProcess_Execute kwsys_ns(Process_Execute)
# define kwsysProcess_Disown kwsys_ns(Process_Disown)
# define kwsysProcess_WaitForData kwsys_ns(Process_WaitForData)
+# define kwsysProcess_DecodeTextOutput kwsys_ns(Process_DecodeTextOutput)
# define kwsysProcess_Pipes_e kwsys_ns(Process_Pipes_e)
# define kwsysProcess_Pipe_None kwsys_ns(Process_Pipe_None)
# define kwsysProcess_Pipe_STDIN kwsys_ns(Process_Pipe_STDIN)
@@ -356,6 +357,18 @@ enum kwsysProcess_Pipes_e
};
/**
+ * Decode pipe's text output from external encoding to internal.
+ *
+ * data = Must be a pointer to the same data buffer that WaitForData
+ returned.
+ * length = Pointer to the length of data, also must be same as returned
+ * from WaitForData.
+ *
+ * Returns 1 if data was succesfully decoded or 0 in case of error.
+ */
+kwsysEXPORT int kwsysProcess_DecodeTextOutput(kwsysProcess* cp, char** data, int* length);
+
+/**
* Block until the child process terminates or the given timeout
* expires. If no process is running, returns immediatly. The
* argument is:
diff --git a/Source/kwsys/ProcessUNIX.c b/Source/kwsys/ProcessUNIX.c
index b577982..a357b22 100644
--- a/Source/kwsys/ProcessUNIX.c
+++ b/Source/kwsys/ProcessUNIX.c
@@ -1187,6 +1187,12 @@ int kwsysProcess_WaitForData(kwsysProcess* cp, char** data, int* length,
}
/*--------------------------------------------------------------------------*/
+int kwsysProcess_DecodeTextOutput(kwsysProcess* cp, char** data, int* length)
+{
+ return 1;
+}
+
+/*--------------------------------------------------------------------------*/
static int kwsysProcessWaitForPipe(kwsysProcess* cp, char** data, int* length,
kwsysProcessWaitData* wd)
{
diff --git a/Source/kwsys/ProcessWin32.c b/Source/kwsys/ProcessWin32.c
index 2b93e69..6424969 100644
--- a/Source/kwsys/ProcessWin32.c
+++ b/Source/kwsys/ProcessWin32.c
@@ -69,6 +69,7 @@ a UNIX-style select system call.
/* The maximum amount to read from a pipe at a time. */
#define KWSYSPE_PIPE_BUFFER_SIZE 1024
+#define KWSYSPE_PIPE_ACTUAL_BUFFER_SIZE (KWSYSPE_PIPE_BUFFER_SIZE * 2)
/* Debug output macro. */
#if 0
@@ -181,7 +182,7 @@ struct kwsysProcessPipeData_s
/* ------------- Data managed per call to Execute ------------- */
/* Buffer for data read in this pipe's thread. */
- char DataBuffer[KWSYSPE_PIPE_BUFFER_SIZE];
+ char DataBuffer[KWSYSPE_PIPE_ACTUAL_BUFFER_SIZE];
/* The length of the data stored in the buffer. */
DWORD DataLength;
@@ -319,6 +320,9 @@ struct kwsysProcess_s
/* Own handles for the child's ends of the pipes in the parent process.
Used temporarily during process creation. */
HANDLE PipeChildStd[3];
+
+ /* Console's active codepage */
+ UINT codepage;
};
/*--------------------------------------------------------------------------*/
@@ -1645,6 +1649,28 @@ void kwsysProcessPipeThreadReadPipe(kwsysProcess* cp, kwsysProcessPipeData* td)
}
/*--------------------------------------------------------------------------*/
+int kwsysProcess_DecodeTextOutput(kwsysProcess* cp, char** data, int* length)
+{
+ int success = 1;
+ if (cp && data && length && *length > 0 &&
+ cp->codepage != KWSYS_ENCODING_DEFAULT_CODEPAGE) {
+ success = 0;
+ const int wlength = MultiByteToWideChar(cp->codepage, 0, *data, *length, NULL, 0);
+ wchar_t* wdata = malloc(wlength * sizeof(wchar_t));
+ int r = MultiByteToWideChar(cp->codepage, 0, *data, *length, wdata, wlength);
+ if (r > 0) {
+ r = WideCharToMultiByte(KWSYS_ENCODING_DEFAULT_CODEPAGE, 0, wdata, wlength, *data, KWSYSPE_PIPE_ACTUAL_BUFFER_SIZE, NULL, NULL);
+ if (r > 0) {
+ *length = r;
+ success = 1;
+ }
+ }
+ free(wdata);
+ }
+ return success;
+}
+
+/*--------------------------------------------------------------------------*/
/*
Function executed for each pipe's thread. Argument is a pointer to
@@ -1761,6 +1787,11 @@ int kwsysProcessInitialize(kwsysProcess* cp)
}
}
+ cp->codepage = GetConsoleCP();
+ if (!cp->codepage) {
+ cp->codepage = GetACP();
+ }
+
return 1;
}
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index c84d71f..f3e5a50 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -4637,6 +4637,7 @@ std::string SystemInformationImplementation::RunProcess(std::vector<const char*>
while( ( static_cast<void>(pipe = kwsysProcess_WaitForData(gp,&data,&length,&timeout)),
(pipe == kwsysProcess_Pipe_STDOUT || pipe == kwsysProcess_Pipe_STDERR) ) ) // wait for 1s
{
+ kwsysProcess_DecodeTextOutput(gp, &data, &length);
buffer.append(data, length);
}
kwsysProcess_WaitForExit(gp, 0);
--
2.9.0
More information about the cmake-developers
mailing list