[cmake-developers] [PATCH v6] For Windows encode process output to internally used encoding

2016-08-13 Thread Dāvis Mosāns
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/CMakeLists.txt  |   2 +
 Source/ProcessOutput.hxx.in| 160 +
 Source/cmExecProgramCommand.cxx|   3 +
 Source/cmExecuteProcessCommand.cxx |  11 ++-
 Source/cmProcessTools.cxx  |   9 ++-
 Source/cmSystemTools.cxx   |  11 ++-
 bootstrap  |   3 +
 7 files changed, 193 insertions(+), 6 deletions(-)
 create mode 100644 Source/ProcessOutput.hxx.in

diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt
index a790994..eb51683 100644
--- a/Source/CMakeLists.txt
+++ b/Source/CMakeLists.txt
@@ -419,6 +419,8 @@ foreach(command_file
 endforeach()
 configure_file(cmCommands.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/cmCommands.cxx 
@ONLY)
 
+configure_file(ProcessOutput.hxx.in 
${CMAKE_CURRENT_BINARY_DIR}/ProcessOutput.hxx)
+
 # Kdevelop only works on UNIX and not windows
 if(UNIX)
   set(SRCS ${SRCS} cmGlobalKdevelopGenerator.cxx)
diff --git a/Source/ProcessOutput.hxx.in b/Source/ProcessOutput.hxx.in
new file mode 100644
index 000..ea7b881
--- /dev/null
+++ b/Source/ProcessOutput.hxx.in
@@ -0,0 +1,160 @@
+/*
+  CMake - Cross Platform Makefile Generator
+  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 ProcessOutput_hxx
+#define ProcessOutput_hxx
+
+#include 
+#include 
+#if defined(_WIN32)
+#  ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#  endif
+#  include 
+#endif
+
+  class ProcessOutput
+  {
+public:
+#if defined(_WIN32)
+  static const UINT defaultCodepage = @KWSYS_ENCODING_DEFAULT_CODEPAGE@;
+#endif
+  // must match to KWSYSPE_PIPE_BUFFER_SIZE
+  ProcessOutput(unsigned int maxSize = 1024)
+  {
+#if defined(_WIN32)
+bufferSize = maxSize;
+codepage = GetConsoleCP();
+if (!codepage) {
+  codepage = GetACP();
+}
+#else
+static_cast(maxSize);
+#endif
+  }
+
+  ~ProcessOutput()
+  {
+  }
+
+  bool DecodeText(std::string raw, std::string& decoded, size_t id = 0)
+  {
+bool success = true;
+decoded = raw;
+#if defined(_WIN32)
+if (id > 0) {
+  if (rawparts.size() < id) {
+rawparts.reserve(id);
+while (rawparts.size() < id) rawparts.push_back(std::string());
+  }
+  raw = rawparts[id - 1] + raw;
+  rawparts[id - 1].clear();
+  decoded = raw;
+}
+if (raw.size() > 0 && codepage != defaultCodepage) {
+  success = false;
+  CPINFOEXW cpinfo;
+  if (id > 0 && raw.size() == bufferSize && GetCPInfoExW(codepage, 0, 
&cpinfo) == 1 && cpinfo.MaxCharSize > 1) {
+if (cpinfo.MaxCharSize == 2 && cpinfo.LeadByte[0] != 0) {
+  LPSTR prevChar = CharPrevExA(codepage, raw.c_str(), raw.c_str() 
+ raw.size(), 0);
+  bool isLeadByte = (*(prevChar + 1) == 0) && 
IsDBCSLeadByteEx(codepage, *prevChar);
+  if (isLeadByte) {
+rawparts[id - 1] += *(raw.end() - 1);
+raw.resize(raw.size() - 1);
+  }
+  success = DoDecodeText(raw, decoded, NULL);
+} else {
+  bool restoreDecoded = false;
+  std::string firstDecoded = decoded;
+  wchar_t lastChar = 0;
+  for (UINT i = 0; i < cpinfo.MaxCharSize; i++) {
+success = DoDecodeText(raw, decoded, &lastChar);
+if (success && lastChar != 0) {
+  if (i == 0) {
+firstDecoded = decoded;
+  }
+  if (lastChar == cpinfo.UnicodeDefaultChar) {
+restoreDecoded = true;
+rawparts[id - 1] = *(raw.end() - 1) + rawparts[id - 1];
+raw.resize(raw.size() - 1);
+  } else {
+restoreDecoded = false;
+break;
+  }
+} else {
+  break;
+}
+  }
+  if (restoreDecoded) {
+decoded = firstDecoded;
+rawparts[id - 1].clear();
+  }
+}
+  } else {
+success = DoDecodeText(raw, decoded, NULL);
+  }
+}
+#else
+static_cast(id);
+#endif
+return success;
+  }
+
+  b

Re: [cmake-developers] [PATCH v6] For Windows encode process output to internally used encoding

2016-08-15 Thread Brad King
On 08/13/2016 08:18 PM, Dāvis Mosāns wrote:
>  Source/ProcessOutput.hxx.in| 160 
> +
[snip]
> +  static const UINT defaultCodepage = @KWSYS_ENCODING_DEFAULT_CODEPAGE@;

Thanks.  Overall the approach looks good now.  I'd like to avoid
having to configure this header just for the default codepage value.
Also I'd like to avoid having to include `windows.h` publicly.
Please move the implementation into a .cxx file to hide these
parts away from includers.

Thanks,
-Brad

-- 

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