diff --git a/README.md b/README.md index 0f50408..6721fdc 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,7 @@ The configuration file is written in json, as **run-cppcheck-config.json**. It i and `%LOCALAPPDATA%\run-cppcheck` on Windows. The log file may provide more information than the editor plugin if analysis fails. - **enable_logging**: Default is `true`. - **extra_args**: Extra arguments to pass to cppcheck. Example: `["--enable=style"]`. + +**NOTE:** Some plugins use the `--version` flag to determine the version of cppcheck. For these plugin, you need +to place a run-cppcheck-config.json in the directory where the plugin runs the command, providing the **cppcheck** field. +If this configuration is not found, run-cppcheck tries to find cppcheck in PATH. diff --git a/config.cpp b/config.cpp index 08659a9..6f1effe 100644 --- a/config.cpp +++ b/config.cpp @@ -95,23 +95,27 @@ std::string Config::command() const cmd += "\"" + m_cppcheck + "\""; - for (const auto &arg : m_args) { - // If arg contains double quotes, escape them - std::string escapedArg = arg; - size_t pos = 0; - while ((pos = escapedArg.find("\"", pos)) != std::string::npos) { - escapedArg.replace(pos, 1, "\\\""); - pos += 2; - } - cmd += " \"" + escapedArg + "\""; + if (m_printVersion) { + cmd += " \"--version\""; + } else { + for (const auto &arg : m_args) { + // If arg contains double quotes, escape them + std::string escapedArg = arg; + size_t pos = 0; + while ((pos = escapedArg.find("\"", pos)) != std::string::npos) { + escapedArg.replace(pos, 1, "\\\""); + pos += 2; + } + cmd += " \"" + escapedArg + "\""; - } + } - if (!m_projectFilePath.empty()) { - cmd += " \"--project=" + m_projectFilePath.string() + "\" \"--file-filter=" + m_filename.string() + "\""; - } else { - cmd += " \"" + m_filename.string() + "\""; + if (!m_projectFilePath.empty()) { + cmd += " \"--project=" + m_projectFilePath.string() + "\" \"--file-filter=" + m_filename.string() + "\""; + } else { + cmd += " \"" + m_filename.string() + "\""; + } } cmd += " 2>&1"; @@ -185,6 +189,15 @@ std::string Config::matchFilenameFromCompileCommand() return ""; } +static bool fileExists(const std::filesystem::path &path) +{ +#ifdef _WIN32 + return !_access(path.string().c_str(), 0); +#else + return !access(path.string().c_str(), F_OK); +#endif +} + std::string Config::parseArgs(int argc, char **argv) { (void) argc; @@ -204,6 +217,11 @@ std::string Config::parseArgs(int argc, char **argv) continue; } + if (std::string(arg) == "--version") { + m_printVersion = true; + continue; + } + if (arg[0] == '-') { m_args.push_back(arg); continue; @@ -215,35 +233,51 @@ std::string Config::parseArgs(int argc, char **argv) m_filename = arg; } - if (m_filename.empty()) - return "Missing filename"; + if (!m_printVersion) { + if (m_filename.empty()) + return "Missing filename"; - if (m_logFilePath.empty()) { - const std::string error = getDefaultLogFilePath(m_logFilePath); - if (!error.empty()) - return error; - } - if (m_configPath.empty()) - m_configPath = findFile(m_filename, "run-cppcheck-config.json"); + if (m_logFilePath.empty()) { + const std::string error = getDefaultLogFilePath(m_logFilePath); + if (!error.empty()) + return error; + } - if (m_configPath.empty()) - return "Failed to find 'run-cppcheck-config.json' in any parent directory of analyzed file"; + if (m_configPath.empty()) + m_configPath = findFile(m_filename, "run-cppcheck-config.json"); - std::string err = load(m_configPath); - if (!err.empty()) - return "Failed to load '" + m_configPath.string() + "': " + err; + if (m_configPath.empty()) + return "Failed to find 'run-cppcheck-config.json' in any parent directory of analyzed file"; - if (!m_projectFilePath.empty() && m_projectFilePath.is_relative()) - m_projectFilePath = m_configPath.parent_path() / m_projectFilePath; + std::string err = load(m_configPath); + if (!err.empty()) + return "Failed to load '" + m_configPath.string() + "': " + err; - if (m_filename.is_relative()) - m_filename = normalizePath(std::filesystem::current_path() / m_filename); + if (!m_projectFilePath.empty() && m_projectFilePath.is_relative()) + m_projectFilePath = m_configPath.parent_path() / m_projectFilePath; - err = matchFilenameFromCompileCommand(); + if (m_filename.is_relative()) + m_filename = normalizePath(std::filesystem::current_path() / m_filename); - // Only warn if compile_commands.json is corrupted - if (!err.empty()) - return "Failed to process compile_commands.json: " + err; + err = matchFilenameFromCompileCommand(); + + // Only warn if compile_commands.json is corrupted + if (!err.empty()) + return "Failed to process compile_commands.json: " + err; + } else { + + // If --version is used there is no input file, so check for config + // in current working directory + if (m_configPath.empty()) + m_configPath = std::filesystem::current_path() / "run-cppcheck-config.json"; + + if (!fileExists(m_configPath)) + return ""; + + std::string err = load(m_configPath); + if (!err.empty()) + return "Failed to load '" + m_configPath.string() + "': " + err; + } return ""; } diff --git a/config.h b/config.h index 2fa9fff..8d22af9 100644 --- a/config.h +++ b/config.h @@ -15,6 +15,7 @@ class Config { , m_cppcheck("cppcheck") , m_filename("") , m_args({}) + , m_printVersion(false) { } @@ -41,6 +42,11 @@ class Config { return m_configPath; } + bool printVersion() const + { + return m_printVersion; + } + private: static std::filesystem::path findFile(const std::filesystem::path &input_path, const std::string &filename); static std::string getDefaultLogFilePath(std::filesystem::path &path); @@ -53,6 +59,7 @@ class Config { std::string m_cppcheck; std::filesystem::path m_filename; std::vector m_args; + bool m_printVersion; }; #endif diff --git a/main.cpp b/main.cpp index fc58504..9f538ae 100644 --- a/main.cpp +++ b/main.cpp @@ -82,7 +82,10 @@ int main(int argc, char** argv) { std::string output; int res = executeCommand(cmd, output); - std::cerr << output; + if (config.printVersion()) + std::cout << output; + else + std::cerr << output; logfile << output; return res;