From 7af4ac428234c28930edb0964317235d8a29c47a Mon Sep 17 00:00:00 2001 From: Reijo Tomperi Date: Sat, 5 Sep 2009 22:01:49 +0300 Subject: [PATCH] New command line argument added --template Fix ticket #462 (Allow using template to customize output format) http://sourceforge.net/apps/trac/cppcheck/ticket/462 --- man/cppcheck.1.xml | 7 ++++++ src/cppcheck.cpp | 20 +++++++++++++++- src/cppcheckexecutor.cpp | 2 +- src/errorlogger.cpp | 51 +++++++++++++++++++++++++++++++++------- src/errorlogger.h | 16 ++++++++++++- src/settings.h | 4 ++++ test/testcppcheck.cpp | 15 ++++++++++++ 7 files changed, 104 insertions(+), 11 deletions(-) diff --git a/man/cppcheck.1.xml b/man/cppcheck.1.xml index e766ed252..9e009599c 100644 --- a/man/cppcheck.1.xml +++ b/man/cppcheck.1.xml @@ -111,6 +111,7 @@ man(1), man(7), http://www.tldp.org/HOWTO/Man-Page/ + @@ -200,6 +201,12 @@ files, this is not needed. Check coding style. + + + + Format the error messages. E.g. '{file}:{line},{severity},{id},{message}' or '{file}({line}):({severity}) {message}' + + diff --git a/src/cppcheck.cpp b/src/cppcheck.cpp index 76da83c09..f488c8164 100644 --- a/src/cppcheck.cpp +++ b/src/cppcheck.cpp @@ -172,7 +172,22 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[]) _settings._includePaths.push_back(path); } -// Include paths + + // Output formatter + else if (strcmp(argv[i], "--template") == 0) + { + // "--template path/" + if (strcmp(argv[i], "--template") == 0) + { + ++i; + if (i >= argc) + return "cppcheck: argument to '--template' is missing\n"; + + _settings._outputFormat = argv[i]; + } + } + + // Include paths else if (strcmp(argv[i], "-j") == 0 || strncmp(argv[i], "-j", 2) == 0) { @@ -308,6 +323,9 @@ std::string CppCheck::parseFromArgs(int argc, const char* const argv[]) " -j [jobs] Start [jobs] threads to do the checking simultaneously.\n" " -q, --quiet Only print error messages\n" " -s, --style Check coding style\n" + " --template '[text]' Format the error messages. E.g.\n" + " '{file}:{line},{severity},{id},{message}' or\n" + " '{file}({line}):({severity}) {message}'\n" " --unused-functions Check if there are unused functions\n" " -v, --verbose More detailed error reports\n" " --version Print out version number\n" diff --git a/src/cppcheckexecutor.cpp b/src/cppcheckexecutor.cpp index 3707b807d..509a08a50 100644 --- a/src/cppcheckexecutor.cpp +++ b/src/cppcheckexecutor.cpp @@ -112,6 +112,6 @@ void CppCheckExecutor::reportErr(const ErrorLogger::ErrorMessage &msg) } else { - reportErr(msg.toText()); + reportErr(msg.toText(_settings._outputFormat)); } } diff --git a/src/errorlogger.cpp b/src/errorlogger.cpp index 2a22fe3d2..2164b3fb7 100644 --- a/src/errorlogger.cpp +++ b/src/errorlogger.cpp @@ -158,15 +158,50 @@ std::string ErrorLogger::ErrorMessage::toXML() const return xml.str(); } -std::string ErrorLogger::ErrorMessage::toText() const +void ErrorLogger::ErrorMessage::findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith) { - std::ostringstream text; - if (!_callStack.empty()) - text << callStackToString(_callStack) << ": "; - if (!_severity.empty()) - text << "(" << _severity << ") "; - text << _msg; - return text.str(); + std::string::size_type index = 0; + while ((index = source.find(searchFor, index)) != std::string::npos) + { + source.replace(index, searchFor.length(), replaceWith); + index += replaceWith.length() - searchFor.length() + 1; + } +} + +std::string ErrorLogger::ErrorMessage::toText(const std::string &outputFormat) const +{ + if (outputFormat.length() == 0) + { + std::ostringstream text; + if (!_callStack.empty()) + text << callStackToString(_callStack) << ": "; + if (!_severity.empty()) + text << "(" << _severity << ") "; + text << _msg; + return text.str(); + } + else + { + std::string result = outputFormat; + findAndReplace(result, "{id}", _id); + findAndReplace(result, "{severity}", _severity); + findAndReplace(result, "{message}", _msg); + + if (!_callStack.empty()) + { + std::ostringstream oss; + oss << _callStack.back().line; + findAndReplace(result, "{line}", oss.str()); + findAndReplace(result, "{file}", _callStack.back().getfile()); + } + else + { + findAndReplace(result, "{file}", ""); + findAndReplace(result, "{line}", ""); + } + + return result; + } } void ErrorLogger::_writemsg(const Tokenizer *tokenizer, const Token *tok, const char severity[], const std::string &msg, const std::string &id) diff --git a/src/errorlogger.h b/src/errorlogger.h index adbc8646d..35b042794 100644 --- a/src/errorlogger.h +++ b/src/errorlogger.h @@ -66,7 +66,21 @@ public: static std::string getXMLHeader(); static std::string getXMLFooter(); - std::string toText() const; + /** + * Format the error message into a string. + * @param outputFormat Empty string to use default output format + * or template to be used. E.g. "{file}:{line},{severity},{id},{message}" + */ + std::string toText(const std::string &outputFormat = "") const; + + /** + * Replace all occurances of searchFor with replaceWith in the + * given source. + * @param source The string to modify + * @param searchFor What should be searched for + * @param replaceWith What will replace the found item + */ + static void findAndReplace(std::string &source, const std::string &searchFor, const std::string &replaceWith); std::string serialize() const; bool deserialize(const std::string &data); std::list _callStack; diff --git a/src/settings.h b/src/settings.h index 4ff8bad01..57acb255f 100644 --- a/src/settings.h +++ b/src/settings.h @@ -65,6 +65,10 @@ public: Default value is 0. */ int _exitCode; + /** The output format in which the errors are printed in text mode, + e.g. "{severity} {file}:{line} {message} {id}" */ + std::string _outputFormat; + #ifdef __GNUC__ /** show timing information */ bool _showtime; diff --git a/test/testcppcheck.cpp b/test/testcppcheck.cpp index f2911b9a6..46100a39d 100644 --- a/test/testcppcheck.cpp +++ b/test/testcppcheck.cpp @@ -53,6 +53,7 @@ private: TEST_CASE(xml); TEST_CASE(include); + TEST_CASE(templateFormat); } void linenumbers() @@ -104,6 +105,20 @@ private: ASSERT_EQUALS("[ab/ef.h:0]: ", errmsg.toText()); } + void templateFormat() + { + ErrorLogger::ErrorMessage errmsg; + ErrorLogger::ErrorMessage::FileLocation loc; + loc.file = "some/{file}file.cpp"; + loc.line = 10; + errmsg._callStack.push_back(loc); + errmsg._id = "testId"; + errmsg._severity = "testSeverity"; + errmsg._msg = "long testMessage"; + ASSERT_EQUALS("", errmsg.toXML()); + ASSERT_EQUALS("[some/{file}file.cpp:10]: (testSeverity) long testMessage", errmsg.toText()); + ASSERT_EQUALS("testId-some/{file}file.cpp,testSeverity.10?{long testMessage}", errmsg.toText("{id}-{file},{severity}.{line}?{{message}}")); + } }; REGISTER_TEST(TestCppcheck)