Fixed #439 (Patch: Cppcheck reports wrong filename for filenames containing 8-bit ASCII)

This commit is contained in:
Heiko Eißfeldt 2017-08-21 12:52:15 +02:00 committed by Daniel Marjamäki
parent bce1d83550
commit 04bcc86d59
3 changed files with 125 additions and 3 deletions

View File

@ -197,6 +197,11 @@ int CppCheckExecutor::check(int argc, const char* const argv[])
} }
} }
void CppCheckExecutor::setSettings(const Settings &settings)
{
_settings = &settings;
}
/** /**
* Simple helper function: * Simple helper function:
* \return size of array * \return size of array
@ -937,6 +942,29 @@ int CppCheckExecutor::check_internal(CppCheck& cppcheck, int /*argc*/, const cha
return 0; 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<WCHAR> wcContainer(msg.length());
std::vector<char> 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) void CppCheckExecutor::reportErr(const std::string &errmsg)
{ {
// Alert only about unique errors // Alert only about unique errors
@ -947,12 +975,12 @@ void CppCheckExecutor::reportErr(const std::string &errmsg)
if (errorOutput) if (errorOutput)
*errorOutput << errmsg << std::endl; *errorOutput << errmsg << std::endl;
else else
std::cerr << errmsg << std::endl; std::cerr << ansiToOEM(errmsg, _settings ? !_settings->xml : true) << std::endl;
} }
void CppCheckExecutor::reportOut(const std::string &outmsg) 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) void CppCheckExecutor::reportProgress(const std::string &filename, const char stage[], const std::size_t value)

View File

@ -125,6 +125,12 @@ protected:
*/ */
bool parseFromArgs(CppCheck *cppcheck, int argc, const char* const argv[]); 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: private:
/** /**

View File

@ -1,4 +1,4 @@
/* /*
* Cppcheck - A tool for static C/C++ code analysis * Cppcheck - A tool for static C/C++ code analysis
* Copyright (C) 2007-2016 Cppcheck team. * Copyright (C) 2007-2016 Cppcheck team.
* *
@ -17,6 +17,8 @@
*/ */
#include "cppcheckexecutor.h" #include "cppcheckexecutor.h"
#include "errorlogger.h"
#include "cppcheck.h"
#include "filelister.h" #include "filelister.h"
#include "path.h" #include "path.h"
#include "pathmatch.h" #include "pathmatch.h"
@ -44,6 +46,7 @@ private:
void run() { void run() {
TEST_CASE(runSamples); TEST_CASE(runSamples);
TEST_CASE(runConsoleCodePageTranslationOnWindows);
} }
void runSamples() const { void runSamples() const {
@ -90,6 +93,91 @@ private:
delete[] path; delete[] path;
} }
} }
class CppCheckExecutor2 : public CppCheckExecutor {
public:
void settings(const Settings &set) {
setSettings(set);
}
};
void runConsoleCodePageTranslationOnWindows() const {
REDIRECT;
std::vector<std::string> 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<std::string>::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) REGISTER_TEST(TestSamples)