Commit 2ed473b3 authored by Dāvis Mosāns's avatar Dāvis Mosāns Committed by Brad King
Browse files

execute_process: Add ENCODING option for Windows child process output

Different applications can use different output encodings.
parent 076aef8e
......@@ -18,7 +18,8 @@ Execute one or more child processes.
[OUTPUT_QUIET]
[ERROR_QUIET]
[OUTPUT_STRIP_TRAILING_WHITESPACE]
[ERROR_STRIP_TRAILING_WHITESPACE])
[ERROR_STRIP_TRAILING_WHITESPACE]
[ENCODING <name>])
Runs the given sequence of one or more commands in parallel with the standard
output of each process piped to the standard input of the next.
......@@ -66,6 +67,14 @@ Options:
``OUTPUT_QUIET``, ``ERROR_QUIET``
The standard output or standard error results will be quietly ignored.
``ENCODING <name>``
On Windows, the encoding that is used to decode output from the process.
Ignored on other platforms.
Valid encoding names are: ``AUTO`` (the default), ``NONE``, ``UTF8``,
``ANSI`` and ``OEM``.
``AUTO`` encoding means current active console's codepage will be used
or if that isn't available then ``ANSI`` codepage will be used.
If more than one ``OUTPUT_*`` or ``ERROR_*`` option is given for the
same pipe the precedence is not specified.
If no ``OUTPUT_*`` or ``ERROR_*`` options are given the output will
......
execute_process-encoding
------------------------
* The :command:`execute_process` command gained an ``ENCODING`` option to
specify on Windows which encoding is used for output from child process.
......@@ -47,6 +47,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
std::string error_variable;
std::string result_variable;
std::string working_directory;
cmProcessOutput::Encoding encoding = cmProcessOutput::Auto;
for (size_t i = 0; i < args.size(); ++i) {
if (args[i] == "COMMAND") {
doing_command = true;
......@@ -128,6 +129,14 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
} else if (args[i] == "ERROR_STRIP_TRAILING_WHITESPACE") {
doing_command = false;
error_strip_trailing_whitespace = true;
} else if (args[i] == "ENCODING") {
doing_command = false;
if (++i < args.size()) {
encoding = cmProcessOutput::FindEncoding(args[i]);
} else {
this->SetError(" called with no value for ENCODING.");
return false;
}
} else if (doing_command) {
cmds[command_index].push_back(args[i].c_str());
} else {
......@@ -223,7 +232,7 @@ bool cmExecuteProcessCommand::InitialPass(std::vector<std::string> const& args,
int length;
char* data;
int p;
cmProcessOutput processOutput;
cmProcessOutput processOutput(encoding);
std::string strdata;
while ((p = cmsysProcess_WaitForData(cp, &data, &length, CM_NULLPTR), p)) {
// Put the output in the right place.
......
......@@ -9,6 +9,21 @@ unsigned int cmProcessOutput::defaultCodepage =
KWSYS_ENCODING_DEFAULT_CODEPAGE;
#endif
cmProcessOutput::Encoding cmProcessOutput::FindEncoding(std::string name)
{
Encoding encoding = Auto;
if (name == "UTF8") {
encoding = UTF8;
} else if (name == "NONE") {
encoding = None;
} else if (name == "ANSI") {
encoding = ANSI;
} else if (name == "OEM") {
encoding = OEM;
}
return encoding;
}
cmProcessOutput::cmProcessOutput(Encoding encoding, unsigned int maxSize)
{
#if defined(_WIN32)
......
......@@ -27,6 +27,13 @@ public:
OEM
};
/**
* Find encoding enum value for given encoding \a name.
* \param name a encoding name.
* \return encoding enum value or Auto if \a name was not found.
*/
static Encoding FindEncoding(std::string name);
/// The code page that is used as internal encoding to which we will encode.
static unsigned int defaultCodepage;
......
......@@ -31,6 +31,9 @@ create_test_sourcelist(CMakeLib_TEST_SRCS CMakeLibTests.cxx ${CMakeLib_TESTS})
add_executable(CMakeLibTests ${CMakeLib_TEST_SRCS})
target_link_libraries(CMakeLibTests CMakeLib)
add_executable(testEncoding testEncoding.cxx)
target_link_libraries(testEncoding cmsys)
# Xcode 2.x forgets to create the output directory before linking
# the individual architectures.
if(CMAKE_OSX_ARCHITECTURES AND XCODE
......
#include <fstream>
#include <iostream>
#include <string>
#include <cmsys/ConsoleBuf.hxx>
#ifdef _WIN32
void setEncoding(cmsys::ConsoleBuf::Manager& buf, UINT codepage)
{
cmsys::ConsoleBuf* cb = buf.GetConsoleBuf();
if (cb) {
cb->input_pipe_codepage = codepage;
cb->output_pipe_codepage = codepage;
cb->input_file_codepage = codepage;
cb->output_file_codepage = codepage;
cb->activateCodepageChange();
}
}
#endif
int main(int argc, char* argv[])
{
#ifdef _WIN32
cmsys::ConsoleBuf::Manager consoleOut(std::cout);
#endif
if (argc <= 2) {
std::cout << "Usage: testEncoding <encoding> <file>" << std::endl;
return 1;
}
const std::string encoding(argv[1]);
#ifdef _WIN32
if (encoding == "UTF8") {
setEncoding(consoleOut, CP_UTF8);
} else if (encoding == "ANSI") {
setEncoding(consoleOut, CP_ACP);
} else if (encoding == "OEM") {
setEncoding(consoleOut, CP_OEMCP);
} // else AUTO
#endif
std::ifstream file(argv[2]);
if (!file.is_open()) {
std::cout << "Failed to open file: " << argv[2] << std::endl;
return 2;
}
std::string text((std::istreambuf_iterator<char>(file)),
std::istreambuf_iterator<char>());
std::cout << text;
return 0;
}
......@@ -179,6 +179,9 @@ add_RunCMake_test(add_custom_target)
add_RunCMake_test(add_dependencies)
add_RunCMake_test(add_subdirectory)
add_RunCMake_test(build_command)
if(NOT CMake_TEST_EXTERNAL_CMAKE)
set(execute_process_ARGS -DTEST_ENCODING_EXE=$<TARGET_FILE:testEncoding>)
endif()
add_RunCMake_test(execute_process)
add_RunCMake_test(export)
add_RunCMake_test(cmake_minimum_required)
......
......@@ -75,6 +75,7 @@ function(run_cmake test)
OUTPUT_VARIABLE actual_stdout
ERROR_VARIABLE ${actual_stderr_var}
RESULT_VARIABLE actual_result
ENCODING UTF8
${maybe_timeout}
)
else()
......@@ -90,6 +91,7 @@ function(run_cmake test)
OUTPUT_VARIABLE actual_stdout
ERROR_VARIABLE ${actual_stderr_var}
RESULT_VARIABLE actual_result
ENCODING UTF8
${maybe_timeout}
)
endif()
......
cmake_minimum_required(VERSION 3.7)
project(${RunCMake_TEST} NONE)
include(${RunCMake_TEST}.cmake)
execute_process(
COMMAND ${TEST_ENCODING_EXE} ${TEST_ENCODING} ${CMAKE_CURRENT_LIST_DIR}/EncodingUTF8-stderr.txt
OUTPUT_VARIABLE out
ENCODING ${TEST_ENCODING}
)
message("${out}")
^CMake Error at EncodingMissing.cmake:[0-9]+ \(execute_process\):
execute_process called with no value for ENCODING.
Call Stack \(most recent call first\):
CMakeLists.txt:[0-9]+ \(include\)$
यूनिकोड είναι very здорово!
......@@ -6,3 +6,8 @@ unset(RunCMake_TEST_OUTPUT_MERGE)
run_cmake_command(MergeOutputFile ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputFile.cmake)
run_cmake_command(MergeOutputVars ${CMAKE_COMMAND} -P ${RunCMake_SOURCE_DIR}/MergeOutputVars.cmake)
run_cmake(EncodingMissing)
if(TEST_ENCODING_EXE)
run_cmake_command(EncodingUTF8 ${CMAKE_COMMAND} -DTEST_ENCODING=UTF8 -DTEST_ENCODING_EXE=${TEST_ENCODING_EXE} -P ${RunCMake_SOURCE_DIR}/Encoding.cmake)
endif()
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment