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@_ProcessOutput_hxx +#define @KWSYS_NAMESPACE@_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 -- Powered by www.kitware.com Please keep messages on-topic and check the CMake FAQ at: http://www.cmake.org/Wiki/CMake_FAQ Kitware offers various services to support the CMake community. For more information on each offering, please visit: CMake Support: http://cmake.org/cmake/help/support.html CMake Consulting: http://cmake.org/cmake/help/consulting.html CMake Training Courses: http://cmake.org/cmake/help/training.html Visit other Kitware open-source projects at http://www.kitware.com/opensource/opensource.html Follow this link to subscribe/unsubscribe: http://public.kitware.com/mailman/listinfo/cmake-developers