[cmake-developers] [PATCH v5] For Windows encode process output to internally used encoding
Dāvis Mosāns
davispuh at gmail.com
Thu Jul 21 13:22:56 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 | 3 ++
Source/cmExecuteProcessCommand.cxx | 11 ++++-
Source/cmProcessTools.cxx | 9 +++-
Source/cmSystemTools.cxx | 11 ++++-
Source/kwsys/CMakeLists.txt | 2 +-
Source/kwsys/ProcessOutput.hxx.in | 94 ++++++++++++++++++++++++++++++++++++++
Source/kwsys/SystemInformation.cxx | 4 ++
bootstrap | 1 +
8 files changed, 128 insertions(+), 7 deletions(-)
create mode 100644 Source/kwsys/ProcessOutput.hxx.in
diff --git a/Source/cmExecProgramCommand.cxx b/Source/cmExecProgramCommand.cxx
index 58bbc31..217cda1 100644
--- a/Source/cmExecProgramCommand.cxx
+++ b/Source/cmExecProgramCommand.cxx
@@ -14,6 +14,7 @@
#include "cmSystemTools.h"
#include <cmsys/Process.h>
+#include <cmsys/ProcessOutput.hxx>
// cmExecProgramCommand
bool cmExecProgramCommand::InitialPass(std::vector<std::string> const& args,
@@ -219,6 +220,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
int length;
char* data;
int p;
+ cmsys::ProcessOutput processOutput;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
if (p == cmsysProcess_Pipe_STDOUT || p == cmsysProcess_Pipe_STDERR) {
if (verbose) {
@@ -230,6 +232,7 @@ bool cmExecProgramCommand::RunCommand(const char* command, std::string& output,
// All output has been read. Wait for the process to exit.
cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ processOutput.DecodeText(output, output);
// Check the result of running the process.
std::string msg;
diff --git a/Source/cmExecuteProcessCommand.cxx b/Source/cmExecuteProcessCommand.cxx
index d97b25f..bdefa8b 100644
--- a/Source/cmExecuteProcessCommand.cxx
+++ b/Source/cmExecuteProcessCommand.cxx
@@ -14,6 +14,7 @@
#include "cmSystemTools.h"
#include <cmsys/Process.h>
+#include <cmsys/ProcessOutput.hxx>
#include <ctype.h> /* isspace */
@@ -228,17 +229,21 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
int length;
char* data;
int p;
+ cmsys::ProcessOutput processOutput;
+ std::string strdata;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
// Put the output in the right place.
if (p == cmsysProcess_Pipe_STDOUT && !output_quiet) {
if (output_variable.empty()) {
- cmSystemTools::Stdout(data, length);
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stdout(strdata.c_str(), strdata.size());
} else {
cmExecuteProcessCommandAppend(tempOutput, data, length);
}
} else if (p == cmsysProcess_Pipe_STDERR && !error_quiet) {
if (error_variable.empty()) {
- cmSystemTools::Stderr(data, length);
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stderr(strdata.c_str(), strdata.size());
} else {
cmExecuteProcessCommandAppend(tempError, data, length);
}
@@ -247,6 +252,8 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
// All output has been read. Wait for the process to exit.
cmsysProcess_WaitForExit(cp, CM_NULLPTR);
+ processOutput.DecodeText(tempOutput, tempOutput);
+ processOutput.DecodeText(tempError, tempError);
// Fix the text in the output strings.
cmExecuteProcessCommandFixText(tempOutput, output_strip_trailing_whitespace);
diff --git a/Source/cmProcessTools.cxx b/Source/cmProcessTools.cxx
index 34b8df2..fdfa276 100644
--- a/Source/cmProcessTools.cxx
+++ b/Source/cmProcessTools.cxx
@@ -12,6 +12,7 @@
#include "cmProcessTools.h"
#include <cmsys/Process.h>
+#include <cmsys/ProcessOutput.hxx>
void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
OutputParser* err)
@@ -20,14 +21,18 @@ void cmProcessTools::RunProcess(struct cmsysProcess_s* cp, OutputParser* out,
char* data = CM_NULLPTR;
int length = 0;
int p;
+ cmsys::ProcessOutput processOutput;
+ std::string strdata;
while ((out || err) &&
(p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
if (out && p == cmsysProcess_Pipe_STDOUT) {
- if (!out->Process(data, length)) {
+ processOutput.DecodeText(data, length, strdata);
+ if (!out->Process(strdata.c_str(), int(strdata.size()))) {
out = CM_NULLPTR;
}
} else if (err && p == cmsysProcess_Pipe_STDERR) {
- if (!err->Process(data, length)) {
+ processOutput.DecodeText(data, length, strdata);
+ if (!err->Process(strdata.c_str(), int(strdata.size()))) {
err = CM_NULLPTR;
}
}
diff --git a/Source/cmSystemTools.cxx b/Source/cmSystemTools.cxx
index 9740ef7..ca92646 100644
--- a/Source/cmSystemTools.cxx
+++ b/Source/cmSystemTools.cxx
@@ -26,6 +26,7 @@
#include <cmsys/Glob.hxx>
#include <cmsys/RegularExpression.hxx>
#include <cmsys/System.h>
+#include <cmsys/ProcessOutput.hxx>
#if defined(CMAKE_BUILD_WITH_CMAKE)
#include "cmArchiveWrite.h"
#include "cmLocale.h"
@@ -612,6 +613,8 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
char* data;
int length;
int pipe;
+ cmsys::ProcessOutput processOutput;
+ std::string strdata;
if (outputflag != OUTPUT_PASSTHROUGH &&
(captureStdOut || captureStdErr || outputflag != OUTPUT_NONE)) {
while ((pipe = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR)) >
@@ -627,14 +630,16 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
if (pipe == cmsysProcess_Pipe_STDOUT) {
if (outputflag != OUTPUT_NONE) {
- cmSystemTools::Stdout(data, length);
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stdout(strdata.c_str(), strdata.size());
}
if (captureStdOut) {
tempStdOut.insert(tempStdOut.end(), data, data + length);
}
} else if (pipe == cmsysProcess_Pipe_STDERR) {
if (outputflag != OUTPUT_NONE) {
- cmSystemTools::Stderr(data, length);
+ processOutput.DecodeText(data, length, strdata);
+ cmSystemTools::Stderr(strdata.c_str(), strdata.size());
}
if (captureStdErr) {
tempStdErr.insert(tempStdErr.end(), data, data + length);
@@ -646,9 +651,11 @@ bool cmSystemTools::RunSingleCommand(std::vector<std::string> const& command,
cmsysProcess_WaitForExit(cp, CM_NULLPTR);
if (captureStdOut) {
captureStdOut->assign(tempStdOut.begin(), tempStdOut.end());
+ processOutput.DecodeText(*captureStdOut, *captureStdOut);
}
if (captureStdErr) {
captureStdErr->assign(tempStdErr.begin(), tempStdErr.end());
+ processOutput.DecodeText(*captureStdErr, *captureStdErr);
}
bool result = true;
diff --git a/Source/kwsys/CMakeLists.txt b/Source/kwsys/CMakeLists.txt
index 87f6048..5fce50f 100644
--- a/Source/kwsys/CMakeLists.txt
+++ b/Source/kwsys/CMakeLists.txt
@@ -666,7 +666,7 @@ ENDIF()
# selected components. Initialize with required components.
SET(KWSYS_CLASSES)
SET(KWSYS_H_FILES Configure SharedForward)
-SET(KWSYS_HXX_FILES Configure String
+SET(KWSYS_HXX_FILES Configure String ProcessOutput
hashtable hash_fun hash_map hash_set
)
diff --git a/Source/kwsys/ProcessOutput.hxx.in b/Source/kwsys/ProcessOutput.hxx.in
new file mode 100644
index 0000000..a662bed
--- /dev/null
+++ b/Source/kwsys/ProcessOutput.hxx.in
@@ -0,0 +1,94 @@
+/*============================================================================
+ KWSys - Kitware System Library
+ Copyright 2000-2016 Kitware, Inc., Insight Software Consortium
+
+ Distributed under the OSI-approved BSD License (the "License");
+ see accompanying file Copyright.txt for details.
+
+ This software is distributed WITHOUT ANY WARRANTY; without even the
+ implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ See the License for more information.
+============================================================================*/
+#ifndef @KWSYS_NAMESPACE at _ProcessOutput_hxx
+#define @KWSYS_NAMESPACE at _ProcessOutput_hxx
+
+#include <string>
+#include <vector>
+#if defined(_WIN32)
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN 1
+# endif
+# include <windows.h>
+#endif
+
+namespace @KWSYS_NAMESPACE@
+{
+ class ProcessOutput
+ {
+ public:
+#if defined(_WIN32)
+ static const UINT defaultCodepage = @KWSYS_ENCODING_DEFAULT_CODEPAGE@;
+#endif
+ ProcessOutput()
+ {
+#if defined(_WIN32)
+ codepage = GetConsoleCP();
+ if (!codepage) {
+ codepage = GetACP();
+ }
+#endif
+ }
+
+ ~ProcessOutput()
+ {
+ }
+
+ bool DecodeText(std::string raw, std::string& decoded)
+ {
+ bool success = true;
+ decoded = raw;
+#if defined(_WIN32)
+ if (raw.size() > 0 && codepage != defaultCodepage) {
+ success = false;
+ const int wlength = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), NULL, 0);
+ wchar_t* wdata = new wchar_t[wlength];
+ int r = MultiByteToWideChar(codepage, 0, raw.c_str(), int(raw.size()), wdata, wlength);
+ if (r > 0) {
+ int length = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, NULL, 0, NULL, NULL);
+ char *data = new char[length + 1];
+ r = WideCharToMultiByte(defaultCodepage, 0, wdata, wlength, data, length, NULL, NULL);
+ if (r > 0) {
+ data[length] = '\0';
+ decoded = data;
+ success = true;
+ }
+ delete[] data;
+ }
+ delete[] wdata;
+ }
+#endif
+ return success;
+ }
+
+ bool DecodeText(const char* data, size_t length, std::string& decoded)
+ {
+ return DecodeText(std::string(data, length), decoded);
+ }
+
+ bool DecodeText(std::vector<char> raw, std::vector<char>& decoded)
+ {
+ std::string str;
+ const bool success = DecodeText(std::string(raw.begin(), raw.end()), str);
+ decoded.assign(str.begin(), str.end());
+ return success;
+ }
+
+ private:
+#if defined(_WIN32)
+ UINT codepage;
+#endif
+ };
+}
+
+#endif
+
diff --git a/Source/kwsys/SystemInformation.cxx b/Source/kwsys/SystemInformation.cxx
index 81fb2f9..d5495de 100644
--- a/Source/kwsys/SystemInformation.cxx
+++ b/Source/kwsys/SystemInformation.cxx
@@ -37,12 +37,14 @@
#include "kwsysPrivate.h"
#include KWSYS_HEADER(SystemInformation.hxx)
#include KWSYS_HEADER(Process.h)
+#include KWSYS_HEADER(ProcessOutput.hxx)
// Work-around CMake dependency scanning limitation. This must
// duplicate the above list of headers.
#if 0
# include "SystemInformation.hxx.in"
# include "Process.h.in"
+# include "ProcessOutput.hxx.in"
#endif
#include <iostream>
@@ -4631,6 +4633,7 @@ std::string SystemInformationImplementation::RunProcess(std::vector<const char*>
int length;
double timeout = 255;
int pipe; // pipe id as returned by kwsysProcess_WaitForData()
+ ProcessOutput processOutput;
while( ( static_cast<void>(pipe = kwsysProcess_WaitForData(gp,&data,&length,&timeout)),
(pipe == kwsysProcess_Pipe_STDOUT || pipe == kwsysProcess_Pipe_STDERR) ) ) // wait for 1s
@@ -4638,6 +4641,7 @@ std::string SystemInformationImplementation::RunProcess(std::vector<const char*>
buffer.append(data, length);
}
kwsysProcess_WaitForExit(gp, 0);
+ processOutput.DecodeText(buffer, buffer);
int result = 0;
switch(kwsysProcess_GetState(gp))
diff --git a/bootstrap b/bootstrap
index 742fa2b..aa7307d 100755
--- a/bootstrap
+++ b/bootstrap
@@ -371,6 +371,7 @@ KWSYS_FILES="\
FStream.hxx \
Glob.hxx \
Process.h \
+ ProcessOutput.hxx \
RegularExpression.hxx \
String.h \
String.hxx \
--
2.9.0
More information about the cmake-developers
mailing list