[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