diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index 9df82766a..f6710c010 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -120,6 +120,8 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) bool def = false; bool maxconfigs = false; + mSettings->exename = argv[0]; + for (int i = 1; i < argc; i++) { if (argv[i][0] == '-') { if (std::strcmp(argv[i], "--version") == 0) { diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index 3f6a8cac4..61a903145 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -59,12 +59,14 @@ static const CWE CWE398(398U); // Indicator of Poor Code Quality namespace { struct AddonInfo { - std::string script; + std::string name; + std::string scriptFile; std::string args; - std::string getAddonInfo(const std::string &fileName) { + std::string getAddonInfo(const std::string &fileName, const std::string &exename) { if (!endsWith(fileName, ".json", 5)) { - script = fileName; + name = fileName; + scriptFile = Path::getPathFromFilename(exename) + "/addons/" + fileName + ".py"; return ""; } std::ifstream fin(fileName); @@ -81,12 +83,32 @@ namespace { for (const picojson::value &v : obj["args"].get()) args += " " + v.get(); } - script = obj["script"].get(); + name = obj["script"].get(); + scriptFile = Path::getPathFromFilename(exename) + "/addons/" + fileName + ".py"; return ""; } }; } +static std::string executeAddon(const AddonInfo &addonInfo, const std::string &dumpFile) +{ + const std::string cmd = "python " + addonInfo.scriptFile + " --cli" + addonInfo.args + " " + dumpFile; + +#ifdef _WIN32 + std::unique_ptr pipe(_popen(cmd.c_str(), "r"), _pclose); +#else + std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); +#endif + if (!pipe) + return ""; + char buffer[1024]; + std::string result; + while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) { + result += buffer; + } + return result; +} + static std::vector split(const std::string &str, const std::string &sep) { std::vector ret; @@ -553,12 +575,12 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string for (const std::string &addon : mSettings.addons) { struct AddonInfo addonInfo; - const std::string errmsg = addonInfo.getAddonInfo(addon); + const std::string errmsg = addonInfo.getAddonInfo(addon, mSettings.exename); if (!errmsg.empty()) { reportOut(errmsg); continue; } - const std::string &results = executeAddon(addonInfo.script, addonInfo.args, dumpFile); + const std::string &results = executeAddon(addonInfo, dumpFile); for (std::string::size_type pos = 0; pos < results.size();) { const std::string::size_type pos2 = results.find("\n", pos); if (pos2 == std::string::npos) @@ -597,7 +619,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string continue; // line must end with [addon-x] - const std::string::size_type id1 = line.rfind("[" + addonInfo.script + "-"); + const std::string::size_type id1 = line.rfind("[" + addonInfo.name + "-"); if (id1 == std::string::npos || id1 < sev2) continue; @@ -999,26 +1021,6 @@ void CppCheck::executeRules(const std::string &tokenlist, const Tokenizer &token #endif } -std::string CppCheck::executeAddon(const std::string &addon, const std::string &args, const std::string &dumpFile) -{ - const std::string addonFile = "addons/" + addon + ".py"; - const std::string cmd = "python " + addonFile + " --cli" + args + " " + dumpFile; - -#ifdef _WIN32 - std::unique_ptr pipe(_popen(cmd.c_str(), "r"), _pclose); -#else - std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); -#endif - if (!pipe) - return ""; - char buffer[1024]; - std::string result; - while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) { - result += buffer; - } - return result; -} - Settings &CppCheck::settings() { return mSettings; diff --git a/lib/cppcheck.h b/lib/cppcheck.h index e558c6729..0e27aa61d 100644 --- a/lib/cppcheck.h +++ b/lib/cppcheck.h @@ -179,12 +179,6 @@ private: */ void executeRules(const std::string &tokenlist, const Tokenizer &tokenizer); - /** - * @brief Execute a given addon - * @return results in std::string - */ - std::string executeAddon(const std::string &addon, const std::string &args, const std::string &dumpFile); - /** * @brief Errors and warnings are directed here. * diff --git a/lib/settings.h b/lib/settings.h index b7e1f3609..316ffad05 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -121,6 +121,9 @@ public: /** @brief Is --exception-handling given */ bool exceptionHandling; + // argv[0] + std::string exename; + /** @brief If errors are found, this value is returned from main(). Default value is 0. */ int exitCode; diff --git a/test/cli/test-helloworld.py b/test/cli/test-helloworld.py index b034dd067..8d856a228 100644 --- a/test/cli/test-helloworld.py +++ b/test/cli/test-helloworld.py @@ -37,6 +37,32 @@ def test_absolute_path(): assert stdout == 'Checking %s/main.c ...\n' % (prjpath) assert stderr == '[%s/main.c:5]: (error) Division by zero.\n' % (prjpath) +def test_addon_local_path(): + cwd = os.getcwd() + os.chdir('1-helloworld') + ret, stdout, stderr = cppcheck('--addon=misra .') + os.chdir(cwd) + assert ret == 0 + assert stdout == 'Checking main.c ...\n' + assert stderr == ('[main.c:5]: (error) Division by zero.\n' + '[main.c:1]: (style) misra violation (use --rule-texts= to get proper output)\n') + +def test_addon_absolute_path(): + prjpath = '%s/1-helloworld' % (os.getcwd()) + ret, stdout, stderr = cppcheck('--addon=misra %s' % (prjpath)) + assert ret == 0 + assert stdout == 'Checking %s/main.c ...\n' % (prjpath) + assert stderr == ('[%s/main.c:5]: (error) Division by zero.\n' + '[%s/main.c:1]: (style) misra violation (use --rule-texts= to get proper output)\n' % (prjpath, prjpath)) + +def test_addon_relative_path(): + prjpath = '1-helloworld' + ret, stdout, stderr = cppcheck('--addon=misra %s' % (prjpath)) + assert ret == 0 + assert stdout == 'Checking %s/main.c ...\n' % (prjpath) + assert stderr == ('[%s/main.c:5]: (error) Division by zero.\n' + '[%s/main.c:1]: (style) misra violation (use --rule-texts= to get proper output)\n' % (prjpath, prjpath)) + def test_basepath_relative_path(): prjpath = '1-helloworld' ret, stdout, stderr = cppcheck('%s -rp=%s' % (prjpath, prjpath))