diff --git a/cli/cppcheckexecutor.cpp b/cli/cppcheckexecutor.cpp index 43756cc0a..8760c2bbe 100644 --- a/cli/cppcheckexecutor.cpp +++ b/cli/cppcheckexecutor.cpp @@ -197,6 +197,11 @@ int CppCheckExecutor::check(int argc, const char* const argv[]) } } +void CppCheckExecutor::setSettings(const Settings &settings) +{ + _settings = &settings; +} + /** * Simple helper function: * \return size of array @@ -937,6 +942,29 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha return 0; } +#ifdef _WIN32 +// fix trac ticket #439 'Cppcheck reports wrong filename for filenames containing 8-bit ASCII' +static const std::string ansiToOEM(std::string msg, bool doConvert) +{ + if (doConvert) { + // convert ANSI strings to OEM strings in two steps + std::vector wcContainer(msg.length()); + std::vector cContainer(msg.begin(), msg.end()); + + // ansi code page characters to wide characters + MultiByteToWideChar(CP_ACP, 0, cContainer.data(), msg.length(), wcContainer.data(), msg.length()); + // wide characters to oem codepage characters + WideCharToMultiByte(CP_OEMCP, 0, wcContainer.data(), msg.length(), cContainer.data(), msg.length(), NULL, NULL); + + msg.assign(cContainer.begin(), cContainer.end()); + } + return msg; +} +#else +// no performance regression on non-windows systems +#define ansiToOEM(msg, doConvert) msg +#endif + void CppCheckExecutor::reportErr(const std::string &errmsg) { // Alert only about unique errors @@ -947,12 +975,12 @@ void CppCheckExecutor::reportErr(const std::string &errmsg) if (errorOutput) *errorOutput << errmsg << std::endl; else - std::cerr << errmsg << std::endl; + std::cerr << ansiToOEM(errmsg, _settings ? !_settings->xml : true) << std::endl; } void CppCheckExecutor::reportOut(const std::string &outmsg) { - std::cout << outmsg << std::endl; + std::cout << ansiToOEM(outmsg, true) << std::endl; } void CppCheckExecutor::reportProgress(const std::string &filename, const char stage[], const std::size_t value) diff --git a/cli/cppcheckexecutor.h b/cli/cppcheckexecutor.h index 1707b4af9..79a1aa25c 100644 --- a/cli/cppcheckexecutor.h +++ b/cli/cppcheckexecutor.h @@ -125,6 +125,12 @@ protected: */ bool parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[]); + /** + * Helper function to supply settings. This can be used for testing. + * @param settings Reference to an Settings instance + */ + void setSettings(const Settings &); + private: /** diff --git a/test/testsamples.cpp b/test/testsamples.cpp index 2cec0e67d..4f51fc2cc 100644 --- a/test/testsamples.cpp +++ b/test/testsamples.cpp @@ -1,4 +1,4 @@ -/* +/* * Cppcheck - A tool for static C/C++ code analysis * Copyright (C) 2007-2016 Cppcheck team. * @@ -17,6 +17,8 @@ */ #include "cppcheckexecutor.h" +#include "errorlogger.h" +#include "cppcheck.h" #include "filelister.h" #include "path.h" #include "pathmatch.h" @@ -44,6 +46,7 @@ private: void run() { TEST_CASE(runSamples); + TEST_CASE(runConsoleCodePageTranslationOnWindows); } void runSamples() const { @@ -90,6 +93,91 @@ private: delete[] path; } } + + class CppCheckExecutor2 : public CppCheckExecutor { + public: + void settings(const Settings &set) { + setSettings(set); + } + + }; + + void runConsoleCodePageTranslationOnWindows() const { + REDIRECT; + + std::vector msgs; + msgs.push_back("ASCII"); // first entry should be using only ASCII + msgs.push_back("kääk"); + msgs.push_back("Português"); +// msgs.push_back("日本語"); +// msgs.push_back("한국어"); +// msgs.push_back("Русский"); +// msgs.push_back("中文"); + + Settings set1; + Settings setXML; + setXML.xml = true; + setXML.xml_version = 2; + CppCheckExecutor2 exec; + exec.settings(set1); + CppCheckExecutor2 execXML; + execXML.settings(setXML); + + for (std::vector::const_iterator i = msgs.begin(); i != msgs.end(); ++i) { + CLEAR_REDIRECT_OUTPUT; + CLEAR_REDIRECT_ERROUT; + + exec.reportOut(*i); + + ErrorLogger::ErrorMessage errMessage; + errMessage.setmsg(*i); + + // no xml option + exec.reportInfo(errMessage); + +#ifdef _WIN32 + // expect changes through code page translation except for the 'ASCII' case + if (i == msgs.begin()) { + ASSERT_EQUALS(*i + "\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(*i + "\n", GET_REDIRECT_ERROUT); + } else { + ASSERT(*i + "\n" != GET_REDIRECT_OUTPUT); + ASSERT(*i + "\n" != GET_REDIRECT_ERROUT); + } +#else + // do not expect any code page translation + ASSERT_EQUALS(*i + "\n", GET_REDIRECT_OUTPUT); + ASSERT_EQUALS(*i + "\n", GET_REDIRECT_ERROUT); +#endif + + CLEAR_REDIRECT_ERROUT; + // possible change of msg for xml option + // with ErrorLogger::ErrorMessage::fixInvalidChars(), plus additional XML formatting + execXML.reportInfo(errMessage); + // undo the effects of "ErrorLogger::ErrorMessage::fixInvalidChars()" + // replacing octal constants with characters + std::string myErr; + std::string myErrOrg = GET_REDIRECT_ERROUT; + std::string::const_iterator from = myErrOrg.begin(); + while (from != myErrOrg.end()) { + if (*from == '\\') { + ++from; + unsigned c; + // expect three digits + std::istringstream es(std::string(from, from + 3)); + es >> std::oct >> c; + ++from; + ++from; + myErr.push_back(c); + } else { + myErr.push_back(*from); + } + ++from; + } + + ASSERT(std::string::npos != myErr.find(*i)); + } + } }; REGISTER_TEST(TestSamples)