LCOV - code coverage report
Current view: top level - cli - cmdlineparser.cpp (source / functions) Hit Total Coverage
Test: lcov.info Lines: 660 806 81.9 %
Date: 2024-04-28 12:00:40 Functions: 17 24 70.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Cppcheck - A tool for static C/C++ code analysis
       3             :  * Copyright (C) 2007-2024 Cppcheck team.
       4             :  *
       5             :  * This program is free software: you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation, either version 3 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful,
      11             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13             :  * GNU General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License
      16             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      17             :  */
      18             : 
      19             : #include "cmdlineparser.h"
      20             : 
      21             : #include "addoninfo.h"
      22             : #include "check.h"
      23             : #include "color.h"
      24             : #include "config.h"
      25             : #include "cppcheck.h"
      26             : #include "cppcheckexecutor.h"
      27             : #include "errorlogger.h"
      28             : #include "errortypes.h"
      29             : #include "filelister.h"
      30             : #include "filesettings.h"
      31             : #include "importproject.h"
      32             : #include "library.h"
      33             : #include "path.h"
      34             : #include "pathmatch.h"
      35             : #include "platform.h"
      36             : #include "settings.h"
      37             : #include "standards.h"
      38             : #include "suppressions.h"
      39             : #include "timer.h"
      40             : #include "utils.h"
      41             : 
      42             : #include <algorithm>
      43             : #include <cassert>
      44             : #include <climits>
      45             : #include <cstdint>
      46             : #include <cstdio>
      47             : #include <cstdlib> // EXIT_FAILURE
      48             : #include <cstring>
      49             : #include <fstream>
      50             : #include <iostream>
      51             : #include <iterator>
      52             : #include <list>
      53             : #include <set>
      54             : #include <sstream>
      55             : #include <unordered_set>
      56             : #include <utility>
      57             : 
      58             : #ifdef HAVE_RULES
      59             : // xml is used for rules
      60             : #include "xml.h"
      61             : #endif
      62             : 
      63           4 : static bool addFilesToList(const std::string& fileList, std::vector<std::string>& pathNames)
      64             : {
      65             :     std::istream *files;
      66           8 :     std::ifstream infile;
      67           4 :     if (fileList == "-") { // read from stdin
      68           2 :         files = &std::cin;
      69             :     } else {
      70           2 :         infile.open(fileList);
      71           2 :         if (!infile.is_open())
      72           1 :             return false;
      73           1 :         files = &infile;
      74             :     }
      75           3 :     if (files && *files) {
      76           6 :         std::string fileName;
      77             :         // cppcheck-suppress accessMoved - FP
      78           9 :         while (std::getline(*files, fileName)) { // next line
      79             :             // cppcheck-suppress accessMoved - FP
      80           6 :             if (!fileName.empty()) {
      81           6 :                 pathNames.emplace_back(std::move(fileName));
      82             :             }
      83             :         }
      84             :     }
      85           3 :     return true;
      86             : }
      87             : 
      88           4 : static bool addIncludePathsToList(const std::string& fileList, std::list<std::string>& pathNames)
      89             : {
      90           8 :     std::ifstream files(fileList);
      91           4 :     if (files) {
      92           2 :         std::string pathName;
      93             :         // cppcheck-suppress accessMoved - FP
      94           6 :         while (std::getline(files, pathName)) { // next line
      95           4 :             if (!pathName.empty()) {
      96           4 :                 pathName = Path::removeQuotationMarks(std::move(pathName));
      97           4 :                 pathName = Path::fromNativeSeparators(std::move(pathName));
      98             : 
      99             :                 // If path doesn't end with / or \, add it
     100           4 :                 if (!endsWith(pathName, '/'))
     101           4 :                     pathName += '/';
     102             : 
     103           4 :                 pathNames.emplace_back(std::move(pathName));
     104             :             }
     105             :         }
     106           2 :         return true;
     107             :     }
     108           2 :     return false;
     109             : }
     110             : 
     111           2 : static bool addPathsToSet(const std::string& fileName, std::set<std::string>& set)
     112             : {
     113           4 :     std::list<std::string> templist;
     114           2 :     if (!addIncludePathsToList(fileName, templist))
     115           1 :         return false;
     116           1 :     set.insert(templist.cbegin(), templist.cend());
     117           1 :     return true;
     118             : }
     119             : 
     120             : namespace {
     121             :     class XMLErrorMessagesLogger : public ErrorLogger
     122             :     {
     123         936 :         void reportOut(const std::string & outmsg, Color /*c*/ = Color::Reset) override
     124             :         {
     125         936 :             std::cout << outmsg << std::endl;
     126         936 :         }
     127             : 
     128         936 :         void reportErr(const ErrorMessage &msg) override
     129             :         {
     130         936 :             reportOut(msg.toXML());
     131         936 :         }
     132             : 
     133           0 :         void reportProgress(const std::string & /*filename*/, const char /*stage*/[], const std::size_t /*value*/) override
     134           0 :         {}
     135             :     };
     136             : }
     137             : 
     138         277 : CmdLineParser::CmdLineParser(CmdLineLogger &logger, Settings &settings, Suppressions &suppressions)
     139             :     : mLogger(logger)
     140             :     , mSettings(settings)
     141         277 :     , mSuppressions(suppressions)
     142         277 : {}
     143             : 
     144          27 : bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
     145             : {
     146          27 :     const Result result = parseFromArgs(argc, argv);
     147             : 
     148          27 :     switch (result) {
     149          27 :     case Result::Success:
     150          27 :         break;
     151           0 :     case Result::Exit:
     152           0 :         Settings::terminate();
     153           0 :         return true;
     154           0 :     case Result::Fail:
     155           0 :         return false;
     156             :     }
     157             : 
     158             :     // Libraries must be loaded before FileLister is executed to ensure markup files will be
     159             :     // listed properly.
     160          27 :     if (!loadLibraries(mSettings))
     161           1 :         return false;
     162             : 
     163          26 :     if (!loadAddons(mSettings))
     164           1 :         return false;
     165             : 
     166             :     // Check that all include paths exist
     167             :     {
     168          25 :         for (std::list<std::string>::iterator iter = mSettings.includePaths.begin();
     169          25 :              iter != mSettings.includePaths.end();
     170             :              ) {
     171           0 :             const std::string path(Path::toNativeSeparators(*iter));
     172           0 :             if (Path::isDirectory(path))
     173           0 :                 ++iter;
     174             :             else {
     175             :                 // TODO: this bypasses the template format and other settings
     176             :                 // If the include path is not found, warn user and remove the non-existing path from the list.
     177           0 :                 if (mSettings.severity.isEnabled(Severity::information))
     178           0 :                     std::cout << "(information) Couldn't find path given by -I '" << path << '\'' << std::endl;
     179           0 :                 iter = mSettings.includePaths.erase(iter);
     180             :             }
     181             :         }
     182             :     }
     183             : 
     184             :     // Output a warning for the user if he tries to exclude headers
     185          25 :     const std::vector<std::string>& ignored = getIgnoredPaths();
     186          25 :     const bool warn = std::any_of(ignored.cbegin(), ignored.cend(), [](const std::string& i) {
     187           0 :         return Path::isHeader2(i);
     188             :     });
     189          25 :     if (warn) {
     190           0 :         mLogger.printMessage("filename exclusion does not apply to header (.h and .hpp) files.");
     191           0 :         mLogger.printMessage("Please use --suppress for ignoring results from the header files.");
     192             :     }
     193             : 
     194          25 :     const std::vector<std::string>& pathnamesRef = getPathNames();
     195          25 :     const std::list<FileSettings>& fileSettingsRef = getFileSettings();
     196             : 
     197             :     // the inputs can only be used exclusively - CmdLineParser should already handle this
     198          25 :     assert(!(!pathnamesRef.empty() && !fileSettingsRef.empty()));
     199             : 
     200          25 :     if (!fileSettingsRef.empty()) {
     201             :         // TODO: de-duplicate
     202             : 
     203           0 :         std::list<FileSettings> fileSettings;
     204           0 :         if (!mSettings.fileFilters.empty()) {
     205             :             // filter only for the selected filenames from all project files
     206           0 :             std::copy_if(fileSettingsRef.cbegin(), fileSettingsRef.cend(), std::back_inserter(fileSettings), [&](const FileSettings &fs) {
     207           0 :                 return matchglobs(mSettings.fileFilters, fs.filename());
     208           0 :             });
     209           0 :             if (fileSettings.empty()) {
     210           0 :                 mLogger.printError("could not find any files matching the filter.");
     211           0 :                 return false;
     212             :             }
     213             :         }
     214             :         else {
     215           0 :             fileSettings = fileSettingsRef;
     216             :         }
     217             : 
     218           0 :         mFileSettings.clear();
     219             : 
     220             :         // sort the markup last
     221           0 :         std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
     222           0 :             return !mSettings.library.markupFile(fs.filename()) || !mSettings.library.processMarkupAfterCode(fs.filename());
     223           0 :         });
     224             : 
     225           0 :         std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
     226           0 :             return mSettings.library.markupFile(fs.filename()) && mSettings.library.processMarkupAfterCode(fs.filename());
     227           0 :         });
     228             : 
     229           0 :         if (mFileSettings.empty()) {
     230           0 :             mLogger.printError("could not find or open any of the paths given.");
     231           0 :             return false;
     232             :         }
     233             :     }
     234             : 
     235          25 :     if (!pathnamesRef.empty()) {
     236          25 :         std::list<FileWithDetails> filesResolved;
     237             :         // TODO: this needs to be inlined into PathMatch as it depends on the underlying filesystem
     238             : #if defined(_WIN32)
     239             :         // For Windows we want case-insensitive path matching
     240             :         const bool caseSensitive = false;
     241             : #else
     242          25 :         const bool caseSensitive = true;
     243             : #endif
     244             :         // Execute recursiveAddFiles() to each given file parameter
     245             :         // TODO: verbose log which files were ignored?
     246          25 :         const PathMatch matcher(ignored, caseSensitive);
     247          50 :         for (const std::string &pathname : pathnamesRef) {
     248          75 :             const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher);
     249          25 :             if (!err.empty()) {
     250             :                 // TODO: bail out?
     251           0 :                 mLogger.printMessage(err);
     252             :             }
     253             :         }
     254             : 
     255          25 :         if (filesResolved.empty()) {
     256           0 :             mLogger.printError("could not find or open any of the paths given.");
     257             :             // TODO: PathMatch should provide the information if files were ignored
     258           0 :             if (!ignored.empty())
     259           0 :                 mLogger.printMessage("Maybe all paths were ignored?");
     260           0 :             return false;
     261             :         }
     262             : 
     263             :         // de-duplicate files
     264             :         {
     265          25 :             auto it = filesResolved.begin();
     266          50 :             while (it != filesResolved.end()) {
     267          25 :                 const std::string& name = it->path();
     268             :                 // TODO: log if duplicated files were dropped
     269          25 :                 filesResolved.erase(std::remove_if(std::next(it), filesResolved.end(), [&](const FileWithDetails& entry) {
     270           0 :                     return entry.path() == name;
     271          25 :                 }), filesResolved.end());
     272          25 :                 ++it;
     273             :             }
     274             :         }
     275             : 
     276          25 :         std::list<FileWithDetails> files;
     277          25 :         if (!mSettings.fileFilters.empty()) {
     278           0 :             std::copy_if(filesResolved.cbegin(), filesResolved.cend(), std::inserter(files, files.end()), [&](const FileWithDetails& entry) {
     279           0 :                 return matchglobs(mSettings.fileFilters, entry.path());
     280           0 :             });
     281           0 :             if (files.empty()) {
     282           0 :                 mLogger.printError("could not find any files matching the filter.");
     283           0 :                 return false;
     284             :             }
     285             :         }
     286             :         else {
     287          25 :             files = std::move(filesResolved);
     288             :         }
     289             : 
     290             :         // sort the markup last
     291          50 :         std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
     292          25 :             return !mSettings.library.markupFile(entry.path()) || !mSettings.library.processMarkupAfterCode(entry.path());
     293          25 :         });
     294             : 
     295          50 :         std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
     296          25 :             return mSettings.library.markupFile(entry.path()) && mSettings.library.processMarkupAfterCode(entry.path());
     297          25 :         });
     298             : 
     299          25 :         if (mFiles.empty()) {
     300           0 :             mLogger.printError("could not find or open any of the paths given.");
     301           0 :             return false;
     302             :         }
     303             :     }
     304             : 
     305          25 :     return true;
     306             : }
     307             : 
     308             : // TODO: normalize/simplify/native all path parameters
     309             : // TODO: error out on all missing given files/paths
     310         277 : CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const argv[])
     311             : {
     312         277 :     mSettings.exename = Path::getCurrentExecutablePath(argv[0]);
     313             : 
     314             :     // default to --check-level=normal from CLI for now
     315         277 :     mSettings.setCheckLevel(Settings::CheckLevel::normal);
     316             : 
     317         277 :     if (argc <= 1) {
     318           1 :         printHelp();
     319           1 :         return Result::Exit;
     320             :     }
     321             : 
     322             :     // check for exclusive options
     323        1137 :     for (int i = 1; i < argc; i++) {
     324             :         // documentation..
     325         875 :         if (std::strcmp(argv[i], "--doc") == 0) {
     326           2 :             std::ostringstream doc;
     327             :             // Get documentation..
     328          54 :             for (const Check * it : Check::instances()) {
     329          52 :                 const std::string& name(it->name());
     330         104 :                 const std::string info(it->classInfo());
     331          52 :                 if (!name.empty() && !info.empty())
     332             :                     doc << "## " << name << " ##\n"
     333          52 :                         << info << "\n";
     334             :             }
     335             : 
     336           2 :             mLogger.printRaw(doc.str());
     337           2 :             return Result::Exit;
     338             :         }
     339             : 
     340             :         // print all possible error messages..
     341         873 :         if (std::strcmp(argv[i], "--errorlist") == 0) {
     342           4 :             if (!loadCppcheckCfg())
     343           1 :                 return Result::Fail;
     344             :             {
     345           0 :                 XMLErrorMessagesLogger xmlLogger;
     346           3 :                 std::cout << ErrorMessage::getXMLHeader(mSettings.cppcheckCfgProductName);
     347           3 :                 CppCheck::getErrorMessages(xmlLogger);
     348           3 :                 std::cout << ErrorMessage::getXMLFooter() << std::endl;
     349             :             }
     350           3 :             return Result::Exit;
     351             :         }
     352             : 
     353             :         // Print help
     354         869 :         if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) {
     355           4 :             printHelp();
     356           4 :             return Result::Exit;
     357             :         }
     358             : 
     359         865 :         if (std::strcmp(argv[i], "--version") == 0) {
     360           4 :             if (!loadCppcheckCfg())
     361           1 :                 return Result::Fail;
     362           3 :             const std::string version = getVersion();
     363           3 :             mLogger.printRaw(version);
     364           3 :             return Result::Exit;
     365             :         }
     366             :     }
     367             : 
     368         262 :     bool def = false;
     369         262 :     bool maxconfigs = false;
     370             : 
     371         524 :     ImportProject project;
     372             : 
     373         262 :     bool executorAuto = true;
     374         262 :     int8_t logMissingInclude{0};
     375             : 
     376         947 :     for (int i = 1; i < argc; i++) {
     377         765 :         if (argv[i][0] == '-') {
     378             :             // User define
     379         587 :             if (std::strncmp(argv[i], "-D", 2) == 0) {
     380           8 :                 std::string define;
     381             : 
     382             :                 // "-D define"
     383           8 :                 if (std::strcmp(argv[i], "-D") == 0) {
     384           4 :                     ++i;
     385           4 :                     if (i >= argc || argv[i][0] == '-') {
     386           3 :                         mLogger.printError("argument to '-D' is missing.");
     387           3 :                         return Result::Fail;
     388             :                     }
     389             : 
     390           1 :                     define = argv[i];
     391             :                 }
     392             :                 // "-Ddefine"
     393             :                 else {
     394           4 :                     define = 2 + argv[i];
     395             :                 }
     396             : 
     397             :                 // No "=", append a "=1"
     398           5 :                 if (define.find('=') == std::string::npos)
     399           4 :                     define += "=1";
     400             : 
     401           5 :                 if (!mSettings.userDefines.empty())
     402           1 :                     mSettings.userDefines += ";";
     403           5 :                 mSettings.userDefines += define;
     404             : 
     405           5 :                 def = true;
     406             :             }
     407             : 
     408             :             // -E
     409         579 :             else if (std::strcmp(argv[i], "-E") == 0) {
     410           0 :                 mSettings.preprocessOnly = true;
     411           0 :                 mSettings.quiet = true;
     412             :             }
     413             : 
     414             :             // Include paths
     415         579 :             else if (std::strncmp(argv[i], "-I", 2) == 0) {
     416           7 :                 std::string path;
     417             : 
     418             :                 // "-I path/"
     419           7 :                 if (std::strcmp(argv[i], "-I") == 0) {
     420           6 :                     ++i;
     421           6 :                     if (i >= argc || argv[i][0] == '-') {
     422           1 :                         mLogger.printError("argument to '-I' is missing.");
     423           1 :                         return Result::Fail;
     424             :                     }
     425           5 :                     path = argv[i];
     426             :                 }
     427             : 
     428             :                 // "-Ipath/"
     429             :                 else {
     430           1 :                     path = 2 + argv[i];
     431             :                 }
     432           6 :                 path = Path::removeQuotationMarks(std::move(path));
     433           6 :                 path = Path::fromNativeSeparators(std::move(path));
     434             : 
     435             :                 // If path doesn't end with / or \, add it
     436           6 :                 if (!endsWith(path,'/'))
     437           2 :                     path += '/';
     438             : 
     439           6 :                 mSettings.includePaths.emplace_back(std::move(path));
     440             :             }
     441             : 
     442             :             // User undef
     443         572 :             else if (std::strncmp(argv[i], "-U", 2) == 0) {
     444           6 :                 std::string undef;
     445             : 
     446             :                 // "-U undef"
     447           6 :                 if (std::strcmp(argv[i], "-U") == 0) {
     448           3 :                     ++i;
     449           3 :                     if (i >= argc || argv[i][0] == '-') {
     450           3 :                         mLogger.printError("argument to '-U' is missing.");
     451           3 :                         return Result::Fail;
     452             :                     }
     453             : 
     454           0 :                     undef = argv[i];
     455             :                 }
     456             :                 // "-Uundef"
     457             :                 else {
     458           3 :                     undef = 2 + argv[i];
     459             :                 }
     460             : 
     461           3 :                 mSettings.userUndefs.insert(std::move(undef));
     462             :             }
     463             : 
     464         566 :             else if (std::strncmp(argv[i], "--addon=", 8) == 0)
     465           2 :                 mSettings.addons.emplace(argv[i]+8);
     466             : 
     467         564 :             else if (std::strncmp(argv[i],"--addon-python=", 15) == 0)
     468           0 :                 mSettings.addonPython.assign(argv[i]+15);
     469             : 
     470             :             // Check configuration
     471         564 :             else if (std::strcmp(argv[i], "--check-config") == 0)
     472           1 :                 mSettings.checkConfiguration = true;
     473             : 
     474             :             // Check level
     475         563 :             else if (std::strncmp(argv[i], "--check-level=", 14) == 0) {
     476          28 :                 Settings::CheckLevel level = Settings::CheckLevel::normal;
     477          28 :                 const std::string level_s(argv[i] + 14);
     478          28 :                 if (level_s == "normal")
     479           1 :                     level = Settings::CheckLevel::normal;
     480          27 :                 else if (level_s == "exhaustive")
     481          26 :                     level = Settings::CheckLevel::exhaustive;
     482             :                 else {
     483           1 :                     mLogger.printError("unknown '--check-level' value '" + level_s + "'.");
     484           1 :                     return Result::Fail;
     485             :                 }
     486             : 
     487          27 :                 mSettings.setCheckLevel(level);
     488             :             }
     489             : 
     490             :             // Check library definitions
     491         535 :             else if (std::strcmp(argv[i], "--check-library") == 0) {
     492          25 :                 mSettings.checkLibrary = true;
     493             :             }
     494             : 
     495         510 :             else if (std::strncmp(argv[i], "--check-version=", 16) == 0) {
     496           2 :                 if (!loadCppcheckCfg())
     497           1 :                     return Result::Fail;
     498           2 :                 const std::string actualVersion = getVersion();
     499           2 :                 const std::string wantedVersion = argv[i] + 16;
     500           2 :                 if (actualVersion != wantedVersion) {
     501           1 :                     mLogger.printError("--check-version check failed. Aborting.");
     502           1 :                     return Result::Fail;
     503             :                 }
     504             :             }
     505             : 
     506         508 :             else if (std::strncmp(argv[i], "--checkers-report=", 18) == 0)
     507           0 :                 mSettings.checkersReportFilename = argv[i] + 18;
     508             : 
     509         508 :             else if (std::strncmp(argv[i], "--checks-max-time=", 18) == 0) {
     510           3 :                 if (!parseNumberArg(argv[i], 18, mSettings.checksMaxTime, true))
     511           2 :                     return Result::Fail;
     512             :             }
     513             : 
     514         505 :             else if (std::strcmp(argv[i], "--clang") == 0) {
     515           1 :                 mSettings.clang = true;
     516             :             }
     517             : 
     518         504 :             else if (std::strncmp(argv[i], "--clang=", 8) == 0) {
     519           1 :                 mSettings.clang = true;
     520           1 :                 mSettings.clangExecutable = argv[i] + 8;
     521             :             }
     522             : 
     523         503 :             else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) {
     524           0 :                 mSettings.configExcludePaths.insert(Path::fromNativeSeparators(argv[i] + 17));
     525             :             }
     526             : 
     527         503 :             else if (std::strncmp(argv[i], "--config-excludes-file=", 23) == 0) {
     528             :                 // open this file and read every input file (1 file name per line)
     529           2 :                 const std::string cfgExcludesFile(23 + argv[i]);
     530           2 :                 if (!addPathsToSet(cfgExcludesFile, mSettings.configExcludePaths)) {
     531           1 :                     mLogger.printError("unable to open config excludes file at '" + cfgExcludesFile + "'");
     532           1 :                     return Result::Fail;
     533             :                 }
     534             :             }
     535             : 
     536         501 :             else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) {
     537           3 :                 mSettings.buildDir = Path::fromNativeSeparators(argv[i] + 21);
     538           3 :                 if (endsWith(mSettings.buildDir, '/'))
     539           0 :                     mSettings.buildDir.pop_back();
     540             : 
     541           3 :                 if (!Path::isDirectory(mSettings.buildDir)) {
     542           2 :                     mLogger.printError("Directory '" + mSettings.buildDir + "' specified by --cppcheck-build-dir argument has to be existent.");
     543           2 :                     return Result::Fail;
     544             :                 }
     545             :             }
     546             : 
     547             :             // Show --debug output after the first simplifications
     548         498 :             else if (std::strcmp(argv[i], "--debug") == 0 ||
     549         498 :                      std::strcmp(argv[i], "--debug-normal") == 0)
     550           0 :                 mSettings.debugnormal = true;
     551             : 
     552             :             // Flag used for various purposes during debugging
     553         498 :             else if (std::strcmp(argv[i], "--debug-simplified") == 0)
     554           1 :                 mSettings.debugSimplified = true;
     555             : 
     556             :             // Show template information
     557         497 :             else if (std::strcmp(argv[i], "--debug-template") == 0)
     558           0 :                 mSettings.debugtemplate = true;
     559             : 
     560             :             // Show debug warnings
     561         497 :             else if (std::strcmp(argv[i], "--debug-warnings") == 0)
     562          26 :                 mSettings.debugwarnings = true;
     563             : 
     564         471 :             else if (std::strncmp(argv[i], "--disable=", 10) == 0) {
     565          70 :                 const std::string errmsg = mSettings.removeEnabled(argv[i] + 10);
     566          35 :                 if (!errmsg.empty()) {
     567           3 :                     mLogger.printError(errmsg);
     568           3 :                     return Result::Fail;
     569             :                 }
     570          32 :                 if (std::string(argv[i] + 10).find("missingInclude") != std::string::npos) {
     571          27 :                     --logMissingInclude;
     572             :                 }
     573             :             }
     574             : 
     575             :             // dump cppcheck data
     576         436 :             else if (std::strcmp(argv[i], "--dump") == 0)
     577           0 :                 mSettings.dump = true;
     578             : 
     579         436 :             else if (std::strncmp(argv[i], "--enable=", 9) == 0) {
     580          47 :                 const std::string enable_arg = argv[i] + 9;
     581          47 :                 const std::string errmsg = mSettings.addEnabled(enable_arg);
     582          47 :                 if (!errmsg.empty()) {
     583           3 :                     mLogger.printError(errmsg);
     584           3 :                     return Result::Fail;
     585             :                 }
     586             :                 // when "style" is enabled, also enable "warning", "performance" and "portability"
     587          44 :                 if (enable_arg.find("style") != std::string::npos) {
     588          27 :                     mSettings.addEnabled("warning");
     589          27 :                     mSettings.addEnabled("performance");
     590          27 :                     mSettings.addEnabled("portability");
     591             :                 }
     592          44 :                 if (enable_arg.find("information") != std::string::npos && logMissingInclude == 0) {
     593          28 :                     ++logMissingInclude;
     594          28 :                     mSettings.addEnabled("missingInclude");
     595             :                 }
     596          44 :                 if (enable_arg.find("missingInclude") != std::string::npos) {
     597           5 :                     --logMissingInclude;
     598             :                 }
     599             :             }
     600             : 
     601             :             // --error-exitcode=1
     602         389 :             else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) {
     603          28 :                 if (!parseNumberArg(argv[i], 17, mSettings.exitCode))
     604           2 :                     return Result::Fail;
     605             :             }
     606             : 
     607             :             // Exception handling inside cppcheck client
     608         361 :             else if (std::strcmp(argv[i], "--exception-handling") == 0) {
     609             : #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
     610           1 :                 mSettings.exceptionHandling = true;
     611             : #else
     612             :                 mLogger.printError("Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled.");
     613             :                 return Result::Fail;
     614             : #endif
     615             :             }
     616             : 
     617             :             // Exception handling inside cppcheck client
     618         360 :             else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) {
     619             : #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
     620           3 :                 const std::string exceptionOutfilename = argv[i] + 21;
     621           3 :                 if (exceptionOutfilename != "stderr" && exceptionOutfilename != "stdout") {
     622           1 :                     mLogger.printError("invalid '--exception-handling' argument");
     623           1 :                     return Result::Fail;
     624             :                 }
     625           2 :                 mSettings.exceptionHandling = true;
     626           2 :                 CppCheckExecutor::setExceptionOutput((exceptionOutfilename == "stderr") ? stderr : stdout);
     627             : #else
     628             :                 mLogger.printError("Option --exception-handling is not supported since Cppcheck has not been built with any exception handling enabled.");
     629             :                 return Result::Fail;
     630             : #endif
     631             :             }
     632             : 
     633         357 :             else if (std::strncmp(argv[i], "--executor=", 11) == 0) {
     634           6 :                 const std::string type = 11 + argv[i];
     635           6 :                 if (type == "auto") {
     636           2 :                     executorAuto = true;
     637           2 :                     mSettings.executor = Settings::defaultExecutor();
     638             :                 }
     639           4 :                 else if (type == "thread") {
     640             : #if defined(HAS_THREADING_MODEL_THREAD)
     641           2 :                     executorAuto = false;
     642           2 :                     mSettings.executor = Settings::ExecutorType::Thread;
     643             : #else
     644             :                     mLogger.printError("executor type 'thread' cannot be used as Cppcheck has not been built with a respective threading model.");
     645             :                     return Result::Fail;
     646             : #endif
     647             :                 }
     648           2 :                 else if (type == "process") {
     649             : #if defined(HAS_THREADING_MODEL_FORK)
     650           2 :                     executorAuto = false;
     651           2 :                     mSettings.executor = Settings::ExecutorType::Process;
     652             : #else
     653             :                     mLogger.printError("executor type 'process' cannot be used as Cppcheck has not been built with a respective threading model.");
     654             :                     return Result::Fail;
     655             : #endif
     656             :                 }
     657             :                 else {
     658           0 :                     mLogger.printError("unknown executor: '" + type + "'.");
     659           0 :                     return Result::Fail;
     660             :                 }
     661             :             }
     662             : 
     663             :             // Filter errors
     664         351 :             else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) {
     665             :                 // exitcode-suppressions=filename.txt
     666           1 :                 std::string filename = 24 + argv[i];
     667             : 
     668           1 :                 std::ifstream f(filename);
     669           1 :                 if (!f.is_open()) {
     670           0 :                     mLogger.printError("couldn't open the file: \"" + filename + "\".");
     671           0 :                     return Result::Fail;
     672             :                 }
     673           1 :                 const std::string errmsg(mSuppressions.nofail.parseFile(f));
     674           1 :                 if (!errmsg.empty()) {
     675           0 :                     mLogger.printError(errmsg);
     676           0 :                     return Result::Fail;
     677             :                 }
     678             :             }
     679             : 
     680             :             // use a file filter
     681         350 :             else if (std::strncmp(argv[i], "--file-filter=", 14) == 0) {
     682           1 :                 const char *filter = argv[i] + 14;
     683           1 :                 if (std::strcmp(filter, "-") == 0) {
     684           1 :                     if (!addFilesToList(filter, mSettings.fileFilters)) {
     685           0 :                         mLogger.printError("Failed: --file-filter=-");
     686           0 :                         return Result::Fail;
     687             :                     }
     688             :                 } else {
     689           0 :                     mSettings.fileFilters.emplace_back(filter);
     690             :                 }
     691             :             }
     692             : 
     693             :             // file list specified
     694         349 :             else if (std::strncmp(argv[i], "--file-list=", 12) == 0) {
     695             :                 // open this file and read every input file (1 file name per line)
     696           3 :                 const std::string fileList = argv[i] + 12;
     697           3 :                 if (!addFilesToList(fileList, mPathNames)) {
     698           1 :                     mLogger.printError("couldn't open the file: \"" + fileList + "\".");
     699           1 :                     return Result::Fail;
     700             :                 }
     701             :             }
     702             : 
     703             :             // Force checking of files that have "too many" configurations
     704         346 :             else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0)
     705          28 :                 mSettings.force = true;
     706             : 
     707         318 :             else if (std::strcmp(argv[i], "--fsigned-char") == 0)
     708           3 :                 mSettings.platform.defaultSign = 's';
     709             : 
     710         315 :             else if (std::strcmp(argv[i], "--funsigned-char") == 0)
     711           3 :                 mSettings.platform.defaultSign = 'u';
     712             : 
     713             :             // Ignored paths
     714         312 :             else if (std::strncmp(argv[i], "-i", 2) == 0) {
     715          10 :                 std::string path;
     716             : 
     717             :                 // "-i path/"
     718          10 :                 if (std::strcmp(argv[i], "-i") == 0) {
     719           5 :                     ++i;
     720           5 :                     if (i >= argc || argv[i][0] == '-') {
     721           1 :                         mLogger.printError("argument to '-i' is missing.");
     722           1 :                         return Result::Fail;
     723             :                     }
     724           4 :                     path = argv[i];
     725             :                 }
     726             : 
     727             :                 // "-ipath/"
     728             :                 else {
     729           5 :                     path = 2 + argv[i];
     730             :                 }
     731             : 
     732           9 :                 if (!path.empty()) {
     733           9 :                     path = Path::removeQuotationMarks(std::move(path));
     734           9 :                     path = Path::fromNativeSeparators(std::move(path));
     735           9 :                     path = Path::simplifyPath(std::move(path));
     736             : 
     737           9 :                     if (Path::isDirectory(path)) {
     738             :                         // If directory name doesn't end with / or \, add it
     739           0 :                         if (!endsWith(path, '/'))
     740           0 :                             path += '/';
     741             :                     }
     742           9 :                     mIgnoredPaths.emplace_back(std::move(path));
     743             :                 }
     744             :             }
     745             : 
     746         302 :             else if (std::strncmp(argv[i], "--include=", 10) == 0) {
     747           0 :                 mSettings.userIncludes.emplace_back(Path::fromNativeSeparators(argv[i] + 10));
     748             :             }
     749             : 
     750         302 :             else if (std::strncmp(argv[i], "--includes-file=", 16) == 0) {
     751             :                 // open this file and read every input file (1 file name per line)
     752           2 :                 const std::string includesFile(16 + argv[i]);
     753           2 :                 if (!addIncludePathsToList(includesFile, mSettings.includePaths)) {
     754           1 :                     mLogger.printError("unable to open includes file at '" + includesFile + "'");
     755           1 :                     return Result::Fail;
     756             :                 }
     757             :             }
     758             : 
     759             :             // Inconclusive checking
     760         300 :             else if (std::strcmp(argv[i], "--inconclusive") == 0)
     761          26 :                 mSettings.certainty.enable(Certainty::inconclusive);
     762             : 
     763             :             // Enables inline suppressions.
     764         274 :             else if (std::strcmp(argv[i], "--inline-suppr") == 0)
     765          26 :                 mSettings.inlineSuppressions = true;
     766             : 
     767             :             // Checking threads
     768         248 :             else if (std::strncmp(argv[i], "-j", 2) == 0) {
     769           9 :                 std::string numberString;
     770             : 
     771             :                 // "-j 3"
     772           9 :                 if (std::strcmp(argv[i], "-j") == 0) {
     773           3 :                     ++i;
     774           3 :                     if (i >= argc || argv[i][0] == '-') {
     775           0 :                         mLogger.printError("argument to '-j' is missing.");
     776           0 :                         return Result::Fail;
     777             :                     }
     778             : 
     779           3 :                     numberString = argv[i];
     780             :                 }
     781             : 
     782             :                 // "-j3"
     783             :                 else
     784           6 :                     numberString = argv[i]+2;
     785             : 
     786             :                 unsigned int tmp;
     787           9 :                 std::string err;
     788           9 :                 if (!strToInt(numberString, tmp, &err)) {
     789           2 :                     mLogger.printError("argument to '-j' is not valid - " +  err + ".");
     790           2 :                     return Result::Fail;
     791             :                 }
     792           7 :                 if (tmp == 0) {
     793             :                     // TODO: implement get CPU logical core count and use that.
     794             :                     // Usually, -j 0 would mean "use all available cores," but
     795             :                     // if we get a 0, we just stall and don't do any work.
     796           1 :                     mLogger.printError("argument for '-j' must be greater than 0.");
     797           1 :                     return Result::Fail;
     798             :                 }
     799           6 :                 if (tmp > 1024) {
     800             :                     // Almost nobody has 1024 logical cores, but somebody out
     801             :                     // there does.
     802           1 :                     mLogger.printError("argument for '-j' is allowed to be 1024 at max.");
     803           1 :                     return Result::Fail;
     804             :                 }
     805           5 :                 mSettings.jobs = tmp;
     806             :             }
     807             : 
     808         239 :             else if (std::strncmp(argv[i], "-l", 2) == 0) {
     809             : #ifdef HAS_THREADING_MODEL_FORK
     810           3 :                 std::string numberString;
     811             : 
     812             :                 // "-l 3"
     813           3 :                 if (std::strcmp(argv[i], "-l") == 0) {
     814           2 :                     ++i;
     815           2 :                     if (i >= argc || argv[i][0] == '-') {
     816           0 :                         mLogger.printError("argument to '-l' is missing.");
     817           0 :                         return Result::Fail;
     818             :                     }
     819             : 
     820           2 :                     numberString = argv[i];
     821             :                 }
     822             : 
     823             :                 // "-l3"
     824             :                 else
     825           1 :                     numberString = argv[i]+2;
     826             : 
     827             :                 int tmp;
     828           3 :                 std::string err;
     829           3 :                 if (!strToInt(numberString, tmp, &err)) {
     830           1 :                     mLogger.printError("argument to '-l' is not valid - " + err + ".");
     831           1 :                     return Result::Fail;
     832             :                 }
     833           2 :                 mSettings.loadAverage = tmp;
     834             : #else
     835             :                 mLogger.printError("Option -l cannot be used as Cppcheck has not been built with fork threading model.");
     836             :                 return Result::Fail;
     837             : #endif
     838             :             }
     839             : 
     840             :             // Enforce language (--language=, -x)
     841         236 :             else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) {
     842           6 :                 std::string str;
     843           6 :                 if (argv[i][2]) {
     844           3 :                     str = argv[i]+11;
     845             :                 } else {
     846           3 :                     i++;
     847           3 :                     if (i >= argc || argv[i][0] == '-') {
     848           2 :                         mLogger.printError("no language given to '-x' option.");
     849           2 :                         return Result::Fail;
     850             :                     }
     851           1 :                     str = argv[i];
     852             :                 }
     853             : 
     854           4 :                 if (str == "c")
     855           1 :                     mSettings.enforcedLang = Standards::Language::C;
     856           3 :                 else if (str == "c++")
     857           2 :                     mSettings.enforcedLang = Standards::Language::CPP;
     858             :                 else {
     859           1 :                     mLogger.printError("unknown language '" + str + "' enforced.");
     860           1 :                     return Result::Fail;
     861           3 :                 }
     862             :             }
     863             : 
     864             :             // --library
     865         230 :             else if (std::strncmp(argv[i], "--library=", 10) == 0) {
     866          25 :                 mSettings.libraries.emplace_back(argv[i] + 10);
     867             :             }
     868             : 
     869             :             // Set maximum number of #ifdef configurations to check
     870         205 :             else if (std::strncmp(argv[i], "--max-configs=", 14) == 0) {
     871             :                 int tmp;
     872           4 :                 if (!parseNumberArg(argv[i], 14, tmp))
     873           3 :                     return Result::Fail;
     874           2 :                 if (tmp < 1) {
     875           1 :                     mLogger.printError("argument to '--max-configs=' must be greater than 0.");
     876           1 :                     return Result::Fail;
     877             :                 }
     878             : 
     879           1 :                 mSettings.maxConfigs = tmp;
     880           1 :                 mSettings.force = false;
     881           1 :                 maxconfigs = true;
     882             :             }
     883             : 
     884             :             // max ctu depth
     885         201 :             else if (std::strncmp(argv[i], "--max-ctu-depth=", 16) == 0) {
     886           2 :                 if (!parseNumberArg(argv[i], 16, mSettings.maxCtuDepth))
     887           1 :                     return Result::Fail;
     888             :             }
     889             : 
     890             :             // Write results in file
     891         199 :             else if (std::strncmp(argv[i], "--output-file=", 14) == 0)
     892           0 :                 mSettings.outputFile = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 14));
     893             : 
     894             :             // Experimental: limit execution time for extended valueflow analysis. basic valueflow analysis
     895             :             // is always executed.
     896         199 :             else if (std::strncmp(argv[i], "--performance-valueflow-max-time=", 33) == 0) {
     897           2 :                 if (!parseNumberArg(argv[i], 33, mSettings.performanceValueFlowMaxTime, true))
     898           1 :                     return Result::Fail;
     899             :             }
     900             : 
     901         197 :             else if (std::strncmp(argv[i], "--performance-valueflow-max-if-count=", 37) == 0) {
     902           2 :                 if (!parseNumberArg(argv[i], 37, mSettings.performanceValueFlowMaxIfCount, true))
     903           1 :                     return Result::Fail;
     904             :             }
     905             : 
     906             :             // Specify platform
     907         195 :             else if (std::strncmp(argv[i], "--platform=", 11) == 0) {
     908          42 :                 const std::string platform(11+argv[i]);
     909             : 
     910          42 :                 std::string errstr;
     911         168 :                 const std::vector<std::string> paths = {argv[0]};
     912          42 :                 if (!mSettings.platform.set(platform, errstr, paths)) {
     913           1 :                     mLogger.printError(errstr);
     914           1 :                     return Result::Fail;
     915             :                 }
     916             : 
     917             :                 // TODO: remove
     918             :                 // these are loaded via external files and thus have Settings::PlatformFile set instead.
     919             :                 // override the type so they behave like the regular platforms.
     920          41 :                 if (platform == "unix32-unsigned")
     921           1 :                     mSettings.platform.type = Platform::Type::Unix32;
     922          40 :                 else if (platform == "unix64-unsigned")
     923           1 :                     mSettings.platform.type = Platform::Type::Unix64;
     924             :             }
     925             : 
     926             :             // Write results in results.plist
     927         153 :             else if (std::strncmp(argv[i], "--plist-output=", 15) == 0) {
     928           2 :                 mSettings.plistOutput = Path::simplifyPath(Path::fromNativeSeparators(argv[i] + 15));
     929           2 :                 if (mSettings.plistOutput.empty())
     930           1 :                     mSettings.plistOutput = ".";
     931             : 
     932           2 :                 const std::string plistOutput = Path::toNativeSeparators(mSettings.plistOutput);
     933           2 :                 if (!Path::isDirectory(plistOutput)) {
     934           1 :                     std::string message("plist folder does not exist: '");
     935           1 :                     message += plistOutput;
     936           1 :                     message += "'.";
     937           1 :                     mLogger.printError(message);
     938           1 :                     return Result::Fail;
     939             :                 }
     940             : 
     941           1 :                 if (!endsWith(mSettings.plistOutput,'/'))
     942           1 :                     mSettings.plistOutput += '/';
     943             :             }
     944             : 
     945             :             // Special Cppcheck Premium options
     946         151 :             else if (std::strncmp(argv[i], "--premium=", 10) == 0 && isCppcheckPremium()) {
     947             :                 const std::set<std::string> valid{
     948             :                     "autosar",
     949             :                     "cert-c-2016",
     950             :                     "cert-c++-2016",
     951             :                     "cert-cpp-2016",
     952             :                     "misra-c-2012",
     953             :                     "misra-c-2023",
     954             :                     "misra-c++-2008",
     955             :                     "misra-cpp-2008",
     956             :                     "misra-c++-2023",
     957             :                     "misra-cpp-2023",
     958             :                     "bughunting",
     959         120 :                     "safety"};
     960             : 
     961           8 :                 if (std::strcmp(argv[i], "--premium=safety") == 0)
     962           2 :                     mSettings.safety = true;
     963           8 :                 if (!mSettings.premiumArgs.empty())
     964           0 :                     mSettings.premiumArgs += " ";
     965           8 :                 const std::string p(argv[i] + 10);
     966           8 :                 if (!valid.count(p) && !startsWith(p, "cert-c-int-precision=")) {
     967           2 :                     mLogger.printError("invalid --premium option '" + p + "'.");
     968           2 :                     return Result::Fail;
     969             :                 }
     970           6 :                 mSettings.premiumArgs += "--" + p;
     971           6 :                 if (p == "misra-c-2012" || p == "misra-c-2023")
     972           1 :                     mSettings.addons.emplace("misra");
     973           6 :                 if (startsWith(p, "autosar") || startsWith(p, "cert") || startsWith(p, "misra")) {
     974             :                     // All checkers related to the coding standard should be enabled. The coding standards
     975             :                     // do not all undefined behavior or portability issues.
     976           4 :                     mSettings.addEnabled("warning");
     977           4 :                     mSettings.addEnabled("portability");
     978             :                 }
     979             :             }
     980             : 
     981             :             // --project
     982         143 :             else if (std::strncmp(argv[i], "--project=", 10) == 0) {
     983           7 :                 if (project.projectType != ImportProject::Type::NONE)
     984             :                 {
     985           1 :                     mLogger.printError("multiple --project options are not supported.");
     986           3 :                     return Result::Fail;
     987             :                 }
     988             : 
     989           6 :                 mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force
     990           6 :                 std::string projectFile = argv[i]+10;
     991           6 :                 ImportProject::Type projType = project.import(projectFile, &mSettings);
     992           6 :                 project.projectType = projType;
     993           6 :                 if (projType == ImportProject::Type::CPPCHECK_GUI) {
     994           4 :                     for (const std::string &lib : project.guiProject.libraries)
     995           0 :                         mSettings.libraries.emplace_back(lib);
     996             : 
     997           4 :                     const auto& excludedPaths = project.guiProject.excludedPaths;
     998           4 :                     std::copy(excludedPaths.cbegin(), excludedPaths.cend(), std::back_inserter(mIgnoredPaths));
     999             : 
    1000           4 :                     std::string platform(project.guiProject.platform);
    1001             : 
    1002             :                     // keep existing platform from command-line intact
    1003           4 :                     if (!platform.empty()) {
    1004           0 :                         std::string errstr;
    1005           0 :                         const std::vector<std::string> paths = {projectFile, argv[0]};
    1006           0 :                         if (!mSettings.platform.set(platform, errstr, paths)) {
    1007           0 :                             mLogger.printError(errstr);
    1008           0 :                             return Result::Fail;
    1009             :                         }
    1010             :                     }
    1011             : 
    1012           4 :                     const auto& projectFileGui = project.guiProject.projectFile;
    1013           4 :                     if (!projectFileGui.empty()) {
    1014             :                         // read underlying project
    1015           0 :                         projectFile = projectFileGui;
    1016           0 :                         projType = project.import(projectFileGui, &mSettings);
    1017             :                     }
    1018             :                 }
    1019           6 :                 if (projType == ImportProject::Type::VS_SLN || projType == ImportProject::Type::VS_VCXPROJ) {
    1020           0 :                     if (project.guiProject.analyzeAllVsConfigs == "false")
    1021           0 :                         project.selectOneVsConfig(mSettings.platform.type);
    1022           0 :                     mSettings.libraries.emplace_back("windows");
    1023             :                 }
    1024           6 :                 if (projType == ImportProject::Type::MISSING) {
    1025           2 :                     mLogger.printError("failed to open project '" + projectFile + "'. The file does not exist.");
    1026           2 :                     return Result::Fail;
    1027             :                 }
    1028           4 :                 if (projType == ImportProject::Type::UNKNOWN) {
    1029           0 :                     mLogger.printError("failed to load project '" + projectFile + "'. The format is unknown.");
    1030           0 :                     return Result::Fail;
    1031             :                 }
    1032           4 :                 if (projType == ImportProject::Type::FAILURE) {
    1033           0 :                     mLogger.printError("failed to load project '" + projectFile + "'. An error occurred.");
    1034           0 :                     return Result::Fail;
    1035             :                 }
    1036             :             }
    1037             : 
    1038             :             // --project-configuration
    1039         136 :             else if (std::strncmp(argv[i], "--project-configuration=", 24) == 0) {
    1040           0 :                 mVSConfig = argv[i] + 24;
    1041           0 :                 if (!mVSConfig.empty() && (project.projectType == ImportProject::Type::VS_SLN || project.projectType == ImportProject::Type::VS_VCXPROJ))
    1042           0 :                     project.ignoreOtherConfigs(mVSConfig);
    1043             :             }
    1044             : 
    1045             :             // Only print something when there are errors
    1046         136 :             else if (std::strcmp(argv[i], "-q") == 0 || std::strcmp(argv[i], "--quiet") == 0)
    1047           2 :                 mSettings.quiet = true;
    1048             : 
    1049             :             // Output relative paths
    1050         134 :             else if (std::strcmp(argv[i], "-rp") == 0 || std::strcmp(argv[i], "--relative-paths") == 0)
    1051           2 :                 mSettings.relativePaths = true;
    1052         132 :             else if (std::strncmp(argv[i], "-rp=", 4) == 0 || std::strncmp(argv[i], "--relative-paths=", 17) == 0) {
    1053           2 :                 mSettings.relativePaths = true;
    1054           2 :                 if (argv[i][argv[i][3]=='='?4:17] != 0) {
    1055           4 :                     std::string paths = argv[i]+(argv[i][3]=='='?4:17);
    1056             :                     for (;;) {
    1057           4 :                         const std::string::size_type pos = paths.find(';');
    1058           4 :                         if (pos == std::string::npos) {
    1059           2 :                             mSettings.basePaths.emplace_back(Path::fromNativeSeparators(paths));
    1060           2 :                             break;
    1061             :                         }
    1062           2 :                         mSettings.basePaths.emplace_back(Path::fromNativeSeparators(paths.substr(0, pos)));
    1063           2 :                         paths.erase(0, pos + 1);
    1064           2 :                     }
    1065             :                 } else {
    1066           0 :                     mLogger.printError("no paths specified for the '" + std::string(argv[i]) + "' option.");
    1067           0 :                     return Result::Fail;
    1068           2 :                 }
    1069             :             }
    1070             : 
    1071             :             // Report progress
    1072         130 :             else if (std::strcmp(argv[i], "--report-progress") == 0) {
    1073           1 :                 mSettings.reportProgress = 10;
    1074             :             }
    1075             : 
    1076         129 :             else if (std::strncmp(argv[i], "--report-progress=", 18) == 0) {
    1077             :                 int tmp;
    1078           4 :                 if (!parseNumberArg(argv[i], 18, tmp, true))
    1079           2 :                     return Result::Fail;
    1080           2 :                 mSettings.reportProgress = tmp;
    1081             :             }
    1082             : 
    1083             :             // Rule given at command line
    1084         125 :             else if (std::strncmp(argv[i], "--rule=", 7) == 0) {
    1085             : #ifdef HAVE_RULES
    1086             :                 Settings::Rule rule;
    1087             :                 rule.pattern = 7 + argv[i];
    1088             : 
    1089             :                 if (rule.pattern.empty()) {
    1090             :                     mLogger.printError("no rule pattern provided.");
    1091             :                     return Result::Fail;
    1092             :                 }
    1093             : 
    1094             :                 mSettings.rules.emplace_back(std::move(rule));
    1095             : #else
    1096           1 :                 mLogger.printError("Option --rule cannot be used as Cppcheck has not been built with rules support.");
    1097           1 :                 return Result::Fail;
    1098             : #endif
    1099             :             }
    1100             : 
    1101             :             // Rule file
    1102         124 :             else if (std::strncmp(argv[i], "--rule-file=", 12) == 0) {
    1103             : #ifdef HAVE_RULES
    1104             :                 // TODO: improved error handling - wrong root node, etc.
    1105             :                 // TODO: consume unused "version" attribute
    1106             :                 const std::string ruleFile = argv[i] + 12;
    1107             :                 tinyxml2::XMLDocument doc;
    1108             :                 const tinyxml2::XMLError err = doc.LoadFile(ruleFile.c_str());
    1109             :                 if (err == tinyxml2::XML_SUCCESS) {
    1110             :                     const tinyxml2::XMLElement *node = doc.FirstChildElement();
    1111             :                     // check if it is a single or multi rule configuration
    1112             :                     if (node && strcmp(node->Value(), "rules") == 0)
    1113             :                         node = node->FirstChildElement("rule");
    1114             :                     for (; node && strcmp(node->Value(), "rule") == 0; node = node->NextSiblingElement()) {
    1115             :                         Settings::Rule rule;
    1116             : 
    1117             :                         for (const tinyxml2::XMLElement *subnode = node->FirstChildElement(); subnode; subnode = subnode->NextSiblingElement()) {
    1118             :                             const char * const subtext = subnode->GetText();
    1119             :                             if (std::strcmp(subnode->Name(), "tokenlist") == 0) {
    1120             :                                 rule.tokenlist = empty_if_null(subtext);
    1121             :                             }
    1122             :                             else if (std::strcmp(subnode->Name(), "pattern") == 0) {
    1123             :                                 rule.pattern = empty_if_null(subtext);
    1124             :                             }
    1125             :                             else if (std::strcmp(subnode->Name(), "message") == 0) {
    1126             :                                 for (const tinyxml2::XMLElement *msgnode = subnode->FirstChildElement(); msgnode; msgnode = msgnode->NextSiblingElement()) {
    1127             :                                     const char * const msgtext = msgnode->GetText();
    1128             :                                     if (std::strcmp(msgnode->Name(), "severity") == 0) {
    1129             :                                         rule.severity = severityFromString(empty_if_null(msgtext));
    1130             :                                     }
    1131             :                                     else if (std::strcmp(msgnode->Name(), "id") == 0) {
    1132             :                                         rule.id = empty_if_null(msgtext);
    1133             :                                     }
    1134             :                                     else if (std::strcmp(msgnode->Name(), "summary") == 0) {
    1135             :                                         rule.summary = empty_if_null(msgtext);
    1136             :                                     }
    1137             :                                     else {
    1138             :                                         mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + msgnode->Name() + "' encountered in 'message'.");
    1139             :                                         return Result::Fail;
    1140             :                                     }
    1141             :                                 }
    1142             :                             }
    1143             :                             else {
    1144             :                                 mLogger.printError("unable to load rule-file '" + ruleFile + "' - unknown element '" + subnode->Name() + "' encountered in 'rule'.");
    1145             :                                 return Result::Fail;
    1146             :                             }
    1147             :                         }
    1148             : 
    1149             :                         if (rule.pattern.empty()) {
    1150             :                             mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule is lacking a pattern.");
    1151             :                             return Result::Fail;
    1152             :                         }
    1153             : 
    1154             :                         if (rule.id.empty()) {
    1155             :                             mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule is lacking an id.");
    1156             :                             return Result::Fail;
    1157             :                         }
    1158             : 
    1159             :                         if (rule.tokenlist.empty()) {
    1160             :                             mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule is lacking a tokenlist.");
    1161             :                             return Result::Fail;
    1162             :                         }
    1163             : 
    1164             :                         if (rule.tokenlist != "normal" && rule.tokenlist != "define" && rule.tokenlist != "raw") {
    1165             :                             mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule is using the unsupported tokenlist '" + rule.tokenlist + "'.");
    1166             :                             return Result::Fail;
    1167             :                         }
    1168             : 
    1169             :                         if (rule.severity == Severity::none) {
    1170             :                             mLogger.printError("unable to load rule-file '" + ruleFile + "' - a rule has an invalid severity.");
    1171             :                             return Result::Fail;
    1172             :                         }
    1173             : 
    1174             :                         mSettings.rules.emplace_back(std::move(rule));
    1175             :                     }
    1176             :                 } else {
    1177             :                     mLogger.printError("unable to load rule-file '" + ruleFile + "' (" + tinyxml2::XMLDocument::ErrorIDToName(err) + ").");
    1178             :                     return Result::Fail;
    1179             :                 }
    1180             : #else
    1181           1 :                 mLogger.printError("Option --rule-file cannot be used as Cppcheck has not been built with rules support.");
    1182           1 :                 return Result::Fail;
    1183             : #endif
    1184             :             }
    1185             : 
    1186             :             // Safety certified behavior
    1187         123 :             else if (std::strcmp(argv[i], "--safety") == 0)
    1188           0 :                 mSettings.safety = true;
    1189             : 
    1190             :             // show timing information..
    1191         123 :             else if (std::strncmp(argv[i], "--showtime=", 11) == 0) {
    1192           8 :                 const std::string showtimeMode = argv[i] + 11;
    1193           8 :                 if (showtimeMode == "file")
    1194           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_FILE;
    1195           7 :                 else if (showtimeMode == "file-total")
    1196           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_FILE_TOTAL;
    1197           6 :                 else if (showtimeMode == "summary")
    1198           0 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_SUMMARY;
    1199           6 :                 else if (showtimeMode == "top5") {
    1200           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_FILE;
    1201           1 :                     mLogger.printMessage("--showtime=top5 is deprecated and will be removed in Cppcheck 2.14. Please use --showtime=top5_file or --showtime=top5_summary instead.");
    1202             :                 }
    1203           5 :                 else if (showtimeMode == "top5_file")
    1204           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_FILE;
    1205           4 :                 else if (showtimeMode == "top5_summary")
    1206           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_TOP5_SUMMARY;
    1207           3 :                 else if (showtimeMode == "none")
    1208           1 :                     mSettings.showtime = SHOWTIME_MODES::SHOWTIME_NONE;
    1209           2 :                 else if (showtimeMode.empty()) {
    1210           1 :                     mLogger.printError("no mode provided for --showtime");
    1211           1 :                     return Result::Fail;
    1212             :                 }
    1213             :                 else {
    1214           1 :                     mLogger.printError("unrecognized --showtime mode: '" + showtimeMode + "'. Supported modes: file, file-total, summary, top5, top5_file, top5_summary.");
    1215           1 :                     return Result::Fail;
    1216             :                 }
    1217             :             }
    1218             : 
    1219             :             // --std
    1220         115 :             else if (std::strncmp(argv[i], "--std=", 6) == 0) {
    1221           4 :                 const std::string std = argv[i] + 6;
    1222             :                 // TODO: print error when standard is unknown
    1223           4 :                 if (std::strncmp(std.c_str(), "c++", 3) == 0) {
    1224           1 :                     mSettings.standards.cpp = Standards::getCPP(std);
    1225             :                 }
    1226           3 :                 else if (std::strncmp(std.c_str(), "c", 1) == 0) {
    1227           2 :                     mSettings.standards.c = Standards::getC(std);
    1228             :                 }
    1229             :                 else {
    1230           1 :                     mLogger.printError("unknown --std value '" + std + "'");
    1231           1 :                     return Result::Fail;
    1232             :                 }
    1233             :             }
    1234             : 
    1235         111 :             else if (std::strncmp(argv[i], "--suppress=", 11) == 0) {
    1236          30 :                 const std::string suppression = argv[i]+11;
    1237          30 :                 const std::string errmsg(mSuppressions.nomsg.addSuppressionLine(suppression));
    1238          30 :                 if (!errmsg.empty()) {
    1239           1 :                     mLogger.printError(errmsg);
    1240           1 :                     return Result::Fail;
    1241             :                 }
    1242             :             }
    1243             : 
    1244             :             // Filter errors
    1245          81 :             else if (std::strncmp(argv[i], "--suppressions-list=", 20) == 0) {
    1246           4 :                 std::string filename = argv[i]+20;
    1247           4 :                 std::ifstream f(filename);
    1248           4 :                 if (!f.is_open()) {
    1249           3 :                     std::string message("couldn't open the file: \"");
    1250           3 :                     message += filename;
    1251           3 :                     message += "\".";
    1252           5 :                     if (std::count(filename.cbegin(), filename.cend(), ',') > 0 ||
    1253           5 :                         std::count(filename.cbegin(), filename.cend(), '.') > 1) {
    1254             :                         // If user tried to pass multiple files (we can only guess that)
    1255             :                         // e.g. like this: --suppressions-list=a.txt,b.txt
    1256             :                         // print more detailed error message to tell user how he can solve the problem
    1257           2 :                         message += "\nIf you want to pass two files, you can do it e.g. like this:";
    1258           2 :                         message += "\n    cppcheck --suppressions-list=a.txt --suppressions-list=b.txt file.cpp";
    1259             :                     }
    1260             : 
    1261           3 :                     mLogger.printError(message);
    1262           3 :                     return Result::Fail;
    1263             :                 }
    1264           1 :                 const std::string errmsg(mSuppressions.nomsg.parseFile(f));
    1265           1 :                 if (!errmsg.empty()) {
    1266           0 :                     mLogger.printError(errmsg);
    1267           0 :                     return Result::Fail;
    1268             :                 }
    1269             :             }
    1270             : 
    1271          77 :             else if (std::strncmp(argv[i], "--suppress-xml=", 15) == 0) {
    1272           5 :                 const char * filename = argv[i] + 15;
    1273           5 :                 const std::string errmsg(mSuppressions.nomsg.parseXmlFile(filename));
    1274           5 :                 if (!errmsg.empty()) {
    1275           4 :                     mLogger.printError(errmsg);
    1276           4 :                     return Result::Fail;
    1277             :                 }
    1278             :             }
    1279             : 
    1280             :             // Output formatter
    1281          72 :             else if (std::strncmp(argv[i], "--template=", 11) == 0) {
    1282          35 :                 mSettings.templateFormat = argv[i] + 11;
    1283             :                 // TODO: bail out when no template is provided?
    1284             : 
    1285          35 :                 if (mSettings.templateFormat == "gcc") {
    1286           1 :                     mSettings.templateFormat = "{bold}{file}:{line}:{column}: {magenta}warning:{default} {message} [{id}]{reset}\\n{code}";
    1287           1 :                     mSettings.templateLocation = "{bold}{file}:{line}:{column}: {dim}note:{reset} {info}\\n{code}";
    1288          34 :                 } else if (mSettings.templateFormat == "daca2") {
    1289           1 :                     mSettings.daca = true;
    1290           1 :                     mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]";
    1291           1 :                     mSettings.templateLocation = "{file}:{line}:{column}: note: {info}";
    1292          33 :                 } else if (mSettings.templateFormat == "vs")
    1293           1 :                     mSettings.templateFormat = "{file}({line}): {severity}: {message}";
    1294          32 :                 else if (mSettings.templateFormat == "edit")
    1295           1 :                     mSettings.templateFormat = "{file} +{line}: {severity}: {message}";
    1296          31 :                 else if (mSettings.templateFormat == "cppcheck1")
    1297           1 :                     mSettings.templateFormat = "{callstack}: ({severity}{inconclusive:, inconclusive}) {message}";
    1298          30 :                 else if (mSettings.templateFormat == "selfcheck") {
    1299           1 :                     mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}";
    1300           1 :                     mSettings.templateLocation = "{file}:{line}:{column}: note: {info}\\n{code}";
    1301           1 :                     mSettings.daca = true;
    1302          29 :                 } else if (mSettings.templateFormat == "simple") {
    1303           1 :                     mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]";
    1304           1 :                     mSettings.templateLocation = "";
    1305             :                 }
    1306             :                 // TODO: bail out when no placeholders are found?
    1307             :             }
    1308             : 
    1309          37 :             else if (std::strncmp(argv[i], "--template-location=", 20) == 0) {
    1310           2 :                 mSettings.templateLocation = argv[i] + 20;
    1311             :                 // TODO: bail out when no template is provided?
    1312             :                 // TODO: bail out when no placeholders are found?
    1313             :             }
    1314             : 
    1315          35 :             else if (std::strncmp(argv[i], "--template-max-time=", 20) == 0) {
    1316           5 :                 if (!parseNumberArg(argv[i], 20, mSettings.templateMaxTime))
    1317           2 :                     return Result::Fail;
    1318             :             }
    1319             : 
    1320          30 :             else if (std::strncmp(argv[i], "--typedef-max-time=", 19) == 0) {
    1321           3 :                 if (!parseNumberArg(argv[i], 19, mSettings.typedefMaxTime))
    1322           2 :                     return Result::Fail;
    1323             :             }
    1324             : 
    1325          27 :             else if (std::strncmp(argv[i], "--valueflow-max-iterations=", 27) == 0) {
    1326           4 :                 if (!parseNumberArg(argv[i], 27, mSettings.valueFlowMaxIterations))
    1327           2 :                     return Result::Fail;
    1328             :             }
    1329             : 
    1330          23 :             else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0)
    1331           3 :                 mSettings.verbose = true;
    1332             : 
    1333             :             // Write results in results.xml
    1334          20 :             else if (std::strcmp(argv[i], "--xml") == 0)
    1335           5 :                 mSettings.xml = true;
    1336             : 
    1337             :             // Define the XML file version (and enable XML output)
    1338          15 :             else if (std::strncmp(argv[i], "--xml-version=", 14) == 0) {
    1339             :                 int tmp;
    1340           5 :                 if (!parseNumberArg(argv[i], 14, tmp))
    1341           2 :                     return Result::Fail;
    1342           4 :                 if (tmp != 2) {
    1343             :                     // We only have xml version 2
    1344           1 :                     mLogger.printError("'--xml-version' can only be 2.");
    1345           1 :                     return Result::Fail;
    1346             :                 }
    1347             : 
    1348           3 :                 mSettings.xml_version = tmp;
    1349             :                 // Enable also XML if version is set
    1350           3 :                 mSettings.xml = true;
    1351             :             }
    1352             : 
    1353             :             else {
    1354          10 :                 std::string message("unrecognized command line option: \"");
    1355          10 :                 message += argv[i];
    1356          10 :                 message += "\".";
    1357          10 :                 mLogger.printError(message);
    1358          10 :                 return Result::Fail;
    1359             :             }
    1360             :         }
    1361             : 
    1362             :         else {
    1363         178 :             mPathNames.emplace_back(Path::fromNativeSeparators(Path::removeQuotationMarks(argv[i])));
    1364             :         }
    1365             :     }
    1366             : 
    1367         182 :     if (logMissingInclude == 1)
    1368           1 :         mLogger.printMessage("'--enable=information' will no longer implicitly enable 'missingInclude' starting with 2.16. Please enable it explicitly if you require it.");
    1369             : 
    1370         182 :     if (!loadCppcheckCfg())
    1371           1 :         return Result::Fail;
    1372             : 
    1373             :     // TODO: bail out?
    1374         181 :     if (!executorAuto && mSettings.useSingleJob())
    1375           2 :         mLogger.printMessage("'--executor' has no effect as only a single job will be used.");
    1376             : 
    1377             :     // Default template format..
    1378         181 :     if (mSettings.templateFormat.empty()) {
    1379         147 :         mSettings.templateFormat = "{bold}{file}:{line}:{column}: {red}{inconclusive:{magenta}}{severity}:{inconclusive: inconclusive:}{default} {message} [{id}]{reset}\\n{code}";
    1380         147 :         if (mSettings.templateLocation.empty())
    1381         147 :             mSettings.templateLocation = "{bold}{file}:{line}:{column}: {dim}note:{reset} {info}\\n{code}";
    1382             :     }
    1383             :     // replace static parts of the templates
    1384         181 :     substituteTemplateFormatStatic(mSettings.templateFormat);
    1385         181 :     substituteTemplateLocationStatic(mSettings.templateLocation);
    1386             : 
    1387         181 :     if (mSettings.force || maxconfigs)
    1388          28 :         mSettings.checkAllConfigurations = true;
    1389             : 
    1390         181 :     if (mSettings.force)
    1391          27 :         mSettings.maxConfigs = INT_MAX;
    1392             : 
    1393         154 :     else if ((def || mSettings.preprocessOnly) && !maxconfigs)
    1394           4 :         mSettings.maxConfigs = 1U;
    1395             : 
    1396         181 :     if (mSettings.checks.isEnabled(Checks::unusedFunction) && mSettings.jobs > 1 && mSettings.buildDir.empty()) {
    1397             :         // TODO: bail out
    1398           0 :         mLogger.printMessage("unusedFunction check can't be used with '-j' option. Disabling unusedFunction check.");
    1399             :     }
    1400             : 
    1401         181 :     if (!mPathNames.empty() && project.projectType != ImportProject::Type::NONE) {
    1402           1 :         mLogger.printError("--project cannot be used in conjunction with source files.");
    1403           1 :         return Result::Fail;
    1404             :     }
    1405             : 
    1406             :     // Print error only if we have "real" command and expect files
    1407         180 :     if (mPathNames.empty() && project.guiProject.pathNames.empty() && project.fileSettings.empty()) {
    1408             :         // TODO: this message differs from the one reported in fillSettingsFromArgs()
    1409           3 :         mLogger.printError("no C or C++ source files found.");
    1410           3 :         return Result::Fail;
    1411             :     }
    1412             : 
    1413         177 :     if (!project.guiProject.pathNames.empty())
    1414           1 :         mPathNames = project.guiProject.pathNames;
    1415             : 
    1416         177 :     if (!project.fileSettings.empty()) {
    1417           0 :         project.ignorePaths(mIgnoredPaths);
    1418           0 :         if (project.fileSettings.empty()) {
    1419           0 :             mLogger.printError("no C or C++ source files found.");
    1420           0 :             mLogger.printMessage("all paths were ignored"); // TODO: log this differently?
    1421           0 :             return Result::Fail;
    1422             :         }
    1423           0 :         mFileSettings = project.fileSettings;
    1424             :     }
    1425             : 
    1426             :     // Use paths _pathnames if no base paths for relative path output are given
    1427         177 :     if (mSettings.basePaths.empty() && mSettings.relativePaths)
    1428           2 :         mSettings.basePaths = mPathNames;
    1429             : 
    1430         177 :     return Result::Success;
    1431             : }
    1432             : 
    1433           5 : void CmdLineParser::printHelp() const
    1434             : {
    1435           5 :     const std::string manualUrl(isCppcheckPremium() ?
    1436             :                                 "https://cppcheck.sourceforge.io/manual.pdf" :
    1437          15 :                                 "https://files.cppchecksolutions.com/manual.pdf");
    1438             : 
    1439           5 :     std::ostringstream oss;
    1440             :     oss << "Cppcheck - A tool for static C/C++ code analysis\n"
    1441             :         "\n"
    1442             :         "Syntax:\n"
    1443             :         "    cppcheck [OPTIONS] [files or paths]\n"
    1444             :         "\n"
    1445             :         "If a directory is given instead of a filename, *.cpp, *.cxx, *.cc, *.c++, *.c, *.ipp,\n"
    1446             :         "*.ixx, *.tpp, and *.txx files are checked recursively from the given directory.\n\n"
    1447             :         "Options:\n"
    1448             :         "    --addon=<addon>\n"
    1449             :         "                         Execute addon. i.e. --addon=misra. If options must be\n"
    1450             :         "                         provided a json configuration is needed.\n"
    1451             :         "    --addon-python=<python interpreter>\n"
    1452             :         "                         You can specify the python interpreter either in the\n"
    1453             :         "                         addon json files or through this command line option.\n"
    1454             :         "                         If not present, Cppcheck will try \"python3\" first and\n"
    1455             :         "                         then \"python\".\n"
    1456             :         "    --cppcheck-build-dir=<dir>\n"
    1457             :         "                         Cppcheck work folder. Advantages:\n"
    1458             :         "                          * whole program analysis\n"
    1459             :         "                          * faster analysis; Cppcheck will reuse the results if\n"
    1460             :         "                            the hash for a file is unchanged.\n"
    1461             :         "                          * some useful debug information, i.e. commands used to\n"
    1462             :         "                            execute clang/clang-tidy/addons.\n"
    1463             :         "    --check-config       Check cppcheck configuration. The normal code\n"
    1464             :         "                         analysis is disabled by this flag.\n"
    1465             :         "    --check-level=<level>\n"
    1466             :         "                         Configure how much checking you want:\n"
    1467             :         "                          * normal: Cppcheck uses some compromises in the checking so\n"
    1468             :         "                            the checking will finish in reasonable time.\n"
    1469             :         "                          * exhaustive: deeper analysis that you choose when you can\n"
    1470             :         "                            wait.\n"
    1471             :         "                         The default choice is 'normal'.\n"
    1472             :         "    --check-library      Show information messages when library files have\n"
    1473             :         "                         incomplete info.\n"
    1474             :         "    --checkers-report=<file>\n"
    1475             :         "                         Write a report of all the active checkers to the given file.\n"
    1476             :         "    --clang=<path>       Experimental: Use Clang parser instead of the builtin Cppcheck\n"
    1477             :         "                         parser. Takes the executable as optional parameter and\n"
    1478             :         "                         defaults to `clang`. Cppcheck will run the given Clang\n"
    1479             :         "                         executable, import the Clang AST and convert it into\n"
    1480             :         "                         Cppcheck data. After that the normal Cppcheck analysis is\n"
    1481             :         "                         used. You must have the executable in PATH if no path is\n"
    1482             :         "                         given.\n"
    1483             :         "    --config-exclude=<dir>\n"
    1484             :         "                         Path (prefix) to be excluded from configuration\n"
    1485             :         "                         checking. Preprocessor configurations defined in\n"
    1486             :         "                         headers (but not sources) matching the prefix will not\n"
    1487             :         "                         be considered for evaluation.\n"
    1488             :         "    --config-excludes-file=<file>\n"
    1489             :         "                         A file that contains a list of config-excludes\n"
    1490             :         "    --disable=<id>       Disable individual checks.\n"
    1491             :         "                         Please refer to the documentation of --enable=<id>\n"
    1492             :         "                         for further details.\n"
    1493             :         "    --dump               Dump xml data for each translation unit. The dump\n"
    1494             :         "                         files have the extension .dump and contain ast,\n"
    1495             :         "                         tokenlist, symboldatabase, valueflow.\n"
    1496             :         "    -D<ID>               Define preprocessor symbol. Unless --max-configs or\n"
    1497             :         "                         --force is used, Cppcheck will only check the given\n"
    1498             :         "                         configuration when -D is used.\n"
    1499             :         "                         Example: '-DDEBUG=1 -D__cplusplus'.\n"
    1500             :         "    -E                   Print preprocessor output on stdout and don't do any\n"
    1501             :         "                         further processing.\n"
    1502             :         "    --enable=<id>        Enable additional checks. The available ids are:\n"
    1503             :         "                          * all\n"
    1504             :         "                                  Enable all checks. It is recommended to only\n"
    1505             :         "                                  use --enable=all when the whole program is\n"
    1506             :         "                                  scanned, because this enables unusedFunction.\n"
    1507             :         "                          * warning\n"
    1508             :         "                                  Enable warning messages\n"
    1509             :         "                          * style\n"
    1510             :         "                                  Enable all coding style checks. All messages\n"
    1511             :         "                                  with the severities 'style', 'warning',\n"
    1512             :         "                                  'performance' and 'portability' are enabled.\n"
    1513             :         "                          * performance\n"
    1514             :         "                                  Enable performance messages\n"
    1515             :         "                          * portability\n"
    1516             :         "                                  Enable portability messages\n"
    1517             :         "                          * information\n"
    1518             :         "                                  Enable information messages\n"
    1519             :         "                          * unusedFunction\n"
    1520             :         "                                  Check for unused functions. It is recommended\n"
    1521             :         "                                  to only enable this when the whole program is\n"
    1522             :         "                                  scanned.\n"
    1523             :         "                          * missingInclude\n"
    1524             :         "                                  Warn if there are missing includes.\n"
    1525             :         "                         Several ids can be given if you separate them with\n"
    1526             :         "                         commas. See also --std\n"
    1527             :         "    --error-exitcode=<n> If errors are found, integer [n] is returned instead of\n"
    1528           5 :         "                         the default '0'. '" << EXIT_FAILURE << "' is returned\n"
    1529             :         "                         if arguments are not valid or if no input files are\n"
    1530             :         "                         provided. Note that your operating system can modify\n"
    1531             :         "                         this value, e.g. '256' can become '0'.\n"
    1532             :         "    --errorlist          Print a list of all the error messages in XML format.\n"
    1533             :         "    --exitcode-suppressions=<file>\n"
    1534             :         "                         Used when certain messages should be displayed but\n"
    1535             :         "                         should not cause a non-zero exitcode.\n"
    1536             :         "    --file-filter=<str>  Analyze only those files matching the given filter str\n"
    1537             :         "                         Can be used multiple times\n"
    1538             :         "                         Example: --file-filter=*bar.cpp analyzes only files\n"
    1539             :         "                                  that end with bar.cpp.\n"
    1540             :         "    --file-list=<file>   Specify the files to check in a text file. Add one\n"
    1541             :         "                         filename per line. When file is '-,' the file list will\n"
    1542             :         "                         be read from standard input.\n"
    1543             :         "    -f, --force          Force checking of all configurations in files. If used\n"
    1544             :         "                         together with '--max-configs=', the last option is the\n"
    1545             :         "                         one that is effective.\n"
    1546             :         "    --fsigned-char       Treat char type as signed.\n"
    1547             :         "    --funsigned-char     Treat char type as unsigned.\n"
    1548             :         "    -h, --help           Print this help.\n"
    1549             :         "    -I <dir>             Give path to search for include files. Give several -I\n"
    1550             :         "                         parameters to give several paths. First given path is\n"
    1551             :         "                         searched for contained header files first. If paths are\n"
    1552             :         "                         relative to source files, this is not needed.\n"
    1553             :         "    --includes-file=<file>\n"
    1554             :         "                         Specify directory paths to search for included header\n"
    1555             :         "                         files in a text file. Add one include path per line.\n"
    1556             :         "                         First given path is searched for contained header\n"
    1557             :         "                         files first. If paths are relative to source files,\n"
    1558             :         "                         this is not needed.\n"
    1559             :         "    --include=<file>\n"
    1560             :         "                         Force inclusion of a file before the checked file.\n"
    1561             :         "    -i <dir or file>     Give a source file or source file directory to exclude\n"
    1562             :         "                         from the check. This applies only to source files so\n"
    1563             :         "                         header files included by source files are not matched.\n"
    1564             :         "                         Directory name is matched to all parts of the path.\n"
    1565             :         "    --inconclusive       Allow that Cppcheck reports even though the analysis is\n"
    1566             :         "                         inconclusive.\n"
    1567             :         "                         There are false positives with this option. Each result\n"
    1568             :         "                         must be carefully investigated before you know if it is\n"
    1569             :         "                         good or bad.\n"
    1570             :         "    --inline-suppr       Enable inline suppressions. Use them by placing one or\n"
    1571             :         "                         more comments, like: '// cppcheck-suppress warningId'\n"
    1572             :         "                         on the lines before the warning to suppress.\n"
    1573             :         "    -j <jobs>            Start <jobs> threads to do the checking simultaneously.\n"
    1574             :         "    -l <load>            Specifies that no new threads should be started if\n"
    1575             :         "                         there are other threads running and the load average is\n"
    1576             :         "                         at least <load>.\n"
    1577             :         "    --language=<language>, -x <language>\n"
    1578             :         "                         Forces cppcheck to check all files as the given\n"
    1579             :         "                         language. Valid values are: c, c++\n"
    1580             :         "    --library=<cfg>      Load file <cfg> that contains information about types\n"
    1581             :         "                         and functions. With such information Cppcheck\n"
    1582             :         "                         understands your code better and therefore you\n"
    1583             :         "                         get better results. The std.cfg file that is\n"
    1584             :         "                         distributed with Cppcheck is loaded automatically.\n"
    1585             :         "                         For more information about library files, read the\n"
    1586             :         "                         manual.\n"
    1587             :         "    --max-configs=<limit>\n"
    1588             :         "                         Maximum number of configurations to check in a file\n"
    1589             :         "                         before skipping it. Default is '12'. If used together\n"
    1590             :         "                         with '--force', the last option is the one that is\n"
    1591             :         "                         effective.\n"
    1592             :         "    --max-ctu-depth=N    Max depth in whole program analysis. The default value\n"
    1593             :         "                         is 2. A larger value will mean more errors can be found\n"
    1594             :         "                         but also means the analysis will be slower.\n"
    1595             :         "    --output-file=<file> Write results to file, rather than standard error.\n"
    1596             :         "    --platform=<type>, --platform=<file>\n"
    1597             :         "                         Specifies platform specific types and sizes. The\n"
    1598             :         "                         available builtin platforms are:\n"
    1599             :         "                          * unix32\n"
    1600             :         "                                 32 bit unix variant\n"
    1601             :         "                          * unix64\n"
    1602             :         "                                 64 bit unix variant\n"
    1603             :         "                          * win32A\n"
    1604             :         "                                 32 bit Windows ASCII character encoding\n"
    1605             :         "                          * win32W\n"
    1606             :         "                                 32 bit Windows UNICODE character encoding\n"
    1607             :         "                          * win64\n"
    1608             :         "                                 64 bit Windows\n"
    1609             :         "                          * avr8\n"
    1610             :         "                                 8 bit AVR microcontrollers\n"
    1611             :         "                          * elbrus-e1cp\n"
    1612             :         "                                 Elbrus e1c+ architecture\n"
    1613             :         "                          * pic8\n"
    1614             :         "                                 8 bit PIC microcontrollers\n"
    1615             :         "                                 Baseline and mid-range architectures\n"
    1616             :         "                          * pic8-enhanced\n"
    1617             :         "                                 8 bit PIC microcontrollers\n"
    1618             :         "                                 Enhanced mid-range and high end (PIC18) architectures\n"
    1619             :         "                          * pic16\n"
    1620             :         "                                 16 bit PIC microcontrollers\n"
    1621             :         "                          * mips32\n"
    1622             :         "                                 32 bit MIPS microcontrollers\n"
    1623             :         "                          * native\n"
    1624             :         "                                 Type sizes of host system are assumed, but no\n"
    1625             :         "                                 further assumptions.\n"
    1626             :         "                          * unspecified\n"
    1627             :         "                                 Unknown type sizes\n"
    1628             :         "    --plist-output=<path>\n"
    1629           5 :         "                         Generate Clang-plist output files in folder.\n";
    1630             : 
    1631           5 :     if (isCppcheckPremium()) {
    1632             :         oss <<
    1633             :             "    --premium=<option>\n"
    1634             :             "                         Coding standards:\n"
    1635             :             "                          * autosar           Autosar (partial)\n"
    1636             :             "                          * cert-c-2016       Cert C 2016 checking\n"
    1637             :             "                          * cert-c++-2016     Cert C++ 2016 checking\n"
    1638             :             "                          * misra-c-2012      Misra C 2012\n"
    1639             :             "                          * misra-c-2023      Misra C 2023\n"
    1640             :             "                          * misra-c++-2008    Misra C++ 2008\n"
    1641             :             "                         Other:\n"
    1642             :             "                          * bughunting        Soundy analysis\n"
    1643             :             "                          * cert-c-int-precision=BITS  Integer precision to use in Cert C analysis.\n"
    1644           0 :             "                          * safety            Safe mode\n";
    1645             :     }
    1646             : 
    1647             :     oss <<
    1648             :         "    --project=<file>     Run Cppcheck on project. The <file> can be a Visual\n"
    1649             :         "                         Studio Solution (*.sln), Visual Studio Project\n"
    1650             :         "                         (*.vcxproj), compile database (compile_commands.json),\n"
    1651             :         "                         or Borland C++ Builder 6 (*.bpr). The files to analyse,\n"
    1652             :         "                         include paths, defines, platform and undefines in\n"
    1653             :         "                         the specified file will be used.\n"
    1654             :         "    --project-configuration=<config>\n"
    1655             :         "                         If used together with a Visual Studio Solution (*.sln)\n"
    1656             :         "                         or Visual Studio Project (*.vcxproj) you can limit\n"
    1657             :         "                         the configuration cppcheck should check.\n"
    1658             :         "                         For example: '--project-configuration=Release|Win32'\n"
    1659             :         "    -q, --quiet          Do not show progress reports.\n"
    1660             :         "                         Note that this option is not mutually exclusive with --verbose.\n"
    1661             :         "    -rp=<paths>, --relative-paths=<paths>\n"
    1662             :         "                         Use relative paths in output. When given, <paths> are\n"
    1663             :         "                         used as base. You can separate multiple paths by ';'.\n"
    1664             :         "                         Otherwise path where source files are searched is used.\n"
    1665             :         "                         We use string comparison to create relative paths, so\n"
    1666             :         "                         using e.g. ~ for home folder does not work. It is\n"
    1667             :         "                         currently only possible to apply the base paths to\n"
    1668             :         "                         files that are on a lower level in the directory tree.\n"
    1669             :         "    --report-progress    Report progress messages while checking a file (single job only).\n"
    1670             :         "    --rule=<rule>        Match regular expression.\n"
    1671             :         "    --rule-file=<file>   Use given rule file. For more information, see:\n"
    1672             :         "                         http://sourceforge.net/projects/cppcheck/files/Articles/\n"
    1673             :         "    --showtime=<mode>    Show timing information.\n"
    1674             :         "                         The available modes are:\n"
    1675             :         "                          * none\n"
    1676             :         "                                 Show nothing (default)\n"
    1677             :         "                          * file\n"
    1678             :         "                                 Show for each processed file\n"
    1679             :         "                          * file-total\n"
    1680             :         "                                 Show total time only for each processed file\n"
    1681             :         "                          * summary\n"
    1682             :         "                                 Show a summary at the end\n"
    1683             :         "                          * top5_file\n"
    1684             :         "                                 Show the top 5 for each processed file\n"
    1685             :         "                          * top5_summary\n"
    1686             :         "                                 Show the top 5 summary at the end\n"
    1687             :         "                          * top5\n"
    1688             :         "                                 Alias for top5_file (deprecated)\n"
    1689             :         "    --std=<id>           Set standard.\n"
    1690             :         "                         The available options are:\n"
    1691             :         "                          * c89\n"
    1692             :         "                                 C code is C89 compatible\n"
    1693             :         "                          * c99\n"
    1694             :         "                                 C code is C99 compatible\n"
    1695             :         "                          * c11\n"
    1696             :         "                                 C code is C11 compatible (default)\n"
    1697             :         "                          * c++03\n"
    1698             :         "                                 C++ code is C++03 compatible\n"
    1699             :         "                          * c++11\n"
    1700             :         "                                 C++ code is C++11 compatible\n"
    1701             :         "                          * c++14\n"
    1702             :         "                                 C++ code is C++14 compatible\n"
    1703             :         "                          * c++17\n"
    1704             :         "                                 C++ code is C++17 compatible\n"
    1705             :         "                          * c++20\n"
    1706             :         "                                 C++ code is C++20 compatible (default)\n"
    1707             :         "    --suppress=<spec>    Suppress warnings that match <spec>. The format of\n"
    1708             :         "                         <spec> is:\n"
    1709             :         "                         [error id]:[filename]:[line]\n"
    1710             :         "                         The [filename] and [line] are optional. If [error id]\n"
    1711             :         "                         is a wildcard '*', all error ids match.\n"
    1712             :         "    --suppressions-list=<file>\n"
    1713             :         "                         Suppress warnings listed in the file. Each suppression\n"
    1714             :         "                         is in the same format as <spec> above.\n"
    1715             :         "    --suppress-xml=<file>\n"
    1716             :         "                         Suppress warnings listed in a xml file. XML file should\n"
    1717             :         "                         follow the manual.pdf format specified in section.\n"
    1718             :         "                         `6.4 XML suppressions` .\n"
    1719             :         "    --template='<text>'  Format the error messages. Available fields:\n"
    1720             :         "                           {file}              file name\n"
    1721             :         "                           {line}              line number\n"
    1722             :         "                           {column}            column number\n"
    1723             :         "                           {callstack}         show a callstack. Example:\n"
    1724             :         "                                                 [file.c:1] -> [file.c:100]\n"
    1725             :         "                           {inconclusive:text} if warning is inconclusive, text\n"
    1726             :         "                                               is written\n"
    1727             :         "                           {severity}          severity\n"
    1728             :         "                           {message}           warning message\n"
    1729             :         "                           {id}                warning id\n"
    1730             :         "                           {cwe}               CWE id (Common Weakness Enumeration)\n"
    1731             :         "                           {code}              show the real code\n"
    1732             :         "                           \\t                 insert tab\n"
    1733             :         "                           \\n                 insert newline\n"
    1734             :         "                           \\r                 insert carriage return\n"
    1735             :         "                         Example formats:\n"
    1736             :         "                         '{file}:{line},{severity},{id},{message}' or\n"
    1737             :         "                         '{file}({line}):({severity}) {message}' or\n"
    1738             :         "                         '{callstack} {message}'\n"
    1739             :         "                         Pre-defined templates: gcc (default), cppcheck1 (old default), vs, edit.\n"
    1740             :         // Note: template daca2 also exists, but is for internal use (cppcheck scripts).
    1741             :         "    --template-location='<text>'\n"
    1742             :         "                         Format error message location. If this is not provided\n"
    1743             :         "                         then no extra location info is shown.\n"
    1744             :         "                         Available fields:\n"
    1745             :         "                           {file}      file name\n"
    1746             :         "                           {line}      line number\n"
    1747             :         "                           {column}    column number\n"
    1748             :         "                           {info}      location info\n"
    1749             :         "                           {code}      show the real code\n"
    1750             :         "                           \\t         insert tab\n"
    1751             :         "                           \\n         insert newline\n"
    1752             :         "                           \\r         insert carriage return\n"
    1753             :         "                         Example format (gcc-like):\n"
    1754             :         "                         '{file}:{line}:{column}: note: {info}\\n{code}'\n"
    1755             :         "    -U<ID>               Undefine preprocessor symbol. Use -U to explicitly\n"
    1756             :         "                         hide certain #ifdef <ID> code paths from checking.\n"
    1757             :         "                         Example: '-UDEBUG'\n"
    1758             :         "    -v, --verbose        Output more detailed error information.\n"
    1759             :         "                         Note that this option is not mutually exclusive with --quiet.\n"
    1760             :         "    --version            Print out version number.\n"
    1761             :         "    --xml                Write results in xml format to error stream (stderr).\n"
    1762             :         "\n"
    1763             :         "Example usage:\n"
    1764             :         "  # Recursively check the current folder. Print the progress on the screen and\n"
    1765             :         "  # write errors to a file:\n"
    1766             :         "  cppcheck . 2> err.txt\n"
    1767             :         "\n"
    1768             :         "  # Recursively check ../myproject/ and don't print progress:\n"
    1769             :         "  cppcheck --quiet ../myproject/\n"
    1770             :         "\n"
    1771             :         "  # Check test.cpp, enable all checks:\n"
    1772             :         "  cppcheck --enable=all --inconclusive --library=posix test.cpp\n"
    1773             :         "\n"
    1774             :         "  # Check f.cpp and search include files from inc1/ and inc2/:\n"
    1775             :         "  cppcheck -I inc1/ -I inc2/ f.cpp\n"
    1776             :         "\n"
    1777             :         "For more information:\n"
    1778             :         "    " << manualUrl << "\n"
    1779             :         "\n"
    1780             :         "Many thanks to the 3rd party libraries we use:\n"
    1781             :         " * tinyxml2 -- loading project/library/ctu files.\n"
    1782             :         " * picojson -- loading compile database.\n"
    1783             :         " * pcre -- rules.\n"
    1784           5 :         " * qt -- used in GUI\n";
    1785             : 
    1786           5 :     mLogger.printRaw(oss.str());
    1787           5 : }
    1788             : 
    1789           6 : std::string CmdLineParser::getVersion() const {
    1790           6 :     if (!mSettings.cppcheckCfgProductName.empty())
    1791           1 :         return mSettings.cppcheckCfgProductName;
    1792           5 :     const char * const extraVersion = CppCheck::extraVersion();
    1793           5 :     if (*extraVersion != '\0')
    1794           0 :         return std::string("Cppcheck ") + CppCheck::version() + " ("+ extraVersion + ')';
    1795          10 :     return std::string("Cppcheck ") + CppCheck::version();
    1796             : }
    1797             : 
    1798          18 : bool CmdLineParser::isCppcheckPremium() const {
    1799          18 :     if (mSettings.cppcheckCfgProductName.empty())
    1800          10 :         Settings::loadCppcheckCfg(mSettings, mSettings.supprs);
    1801          18 :     return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
    1802             : }
    1803             : 
    1804          51 : bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
    1805             : {
    1806         102 :     const Library::Error err = destination.load(basepath.c_str(), filename);
    1807             : 
    1808          51 :     if (err.errorcode == Library::ErrorCode::UNKNOWN_ELEMENT)
    1809           0 :         mLogger.printMessage("Found unknown elements in configuration file '" + std::string(filename) + "': " + err.reason); // TODO: print as errors
    1810          51 :     else if (err.errorcode != Library::ErrorCode::OK) {
    1811           2 :         std::string msg = "Failed to load library configuration file '" + std::string(filename) + "'. ";
    1812           1 :         switch (err.errorcode) {
    1813           0 :         case Library::ErrorCode::OK:
    1814           0 :             break;
    1815           1 :         case Library::ErrorCode::FILE_NOT_FOUND:
    1816           1 :             msg += "File not found";
    1817           1 :             break;
    1818           0 :         case Library::ErrorCode::BAD_XML:
    1819           0 :             msg += "Bad XML";
    1820           0 :             break;
    1821           0 :         case Library::ErrorCode::UNKNOWN_ELEMENT:
    1822           0 :             msg += "Unexpected element";
    1823           0 :             break;
    1824           0 :         case Library::ErrorCode::MISSING_ATTRIBUTE:
    1825           0 :             msg +="Missing attribute";
    1826           0 :             break;
    1827           0 :         case Library::ErrorCode::BAD_ATTRIBUTE_VALUE:
    1828           0 :             msg += "Bad attribute value";
    1829           0 :             break;
    1830           0 :         case Library::ErrorCode::UNSUPPORTED_FORMAT:
    1831           0 :             msg += "File is of unsupported format version";
    1832           0 :             break;
    1833           0 :         case Library::ErrorCode::DUPLICATE_PLATFORM_TYPE:
    1834           0 :             msg += "Duplicate platform type";
    1835           0 :             break;
    1836           0 :         case Library::ErrorCode::PLATFORM_TYPE_REDEFINED:
    1837           0 :             msg += "Platform type redefined";
    1838           0 :             break;
    1839           0 :         case Library::ErrorCode::DUPLICATE_DEFINE:
    1840           0 :             msg += "Duplicate define";
    1841           0 :             break;
    1842             :         }
    1843           1 :         if (!err.reason.empty())
    1844           0 :             msg += " '" + err.reason + "'";
    1845           1 :         mLogger.printMessage(msg); // TODO: print as errors
    1846           1 :         return false;
    1847             :     }
    1848          50 :     return true;
    1849             : }
    1850             : 
    1851          27 : bool CmdLineParser::loadLibraries(Settings& settings)
    1852             : {
    1853          27 :     if (!tryLoadLibrary(settings.library, settings.exename, "std.cfg")) {
    1854           0 :         const std::string msg("Failed to load std.cfg. Your Cppcheck installation is broken, please re-install.");
    1855             : #ifdef FILESDIR
    1856             :         const std::string details("The Cppcheck binary was compiled with FILESDIR set to \""
    1857             :                                   FILESDIR "\" and will therefore search for "
    1858             :                                   "std.cfg in " FILESDIR "/cfg.");
    1859             : #else
    1860           0 :         const std::string cfgfolder(Path::fromNativeSeparators(Path::getPathFromFilename(settings.exename)) + "cfg");
    1861             :         const std::string details("The Cppcheck binary was compiled without FILESDIR set. Either the "
    1862           0 :                                   "std.cfg should be available in " + cfgfolder + " or the FILESDIR "
    1863           0 :                                   "should be configured.");
    1864             : #endif
    1865           0 :         mLogger.printRaw(msg + " " + details); // TODO: do not print as raw?
    1866           0 :         return false;
    1867             :     }
    1868             : 
    1869          27 :     bool result = true;
    1870          51 :     for (const auto& lib : settings.libraries) {
    1871          24 :         if (!tryLoadLibrary(settings.library, settings.exename, lib.c_str())) {
    1872           1 :             result = false;
    1873             :         }
    1874             :     }
    1875          27 :     return result;
    1876             : }
    1877             : 
    1878          26 : bool CmdLineParser::loadAddons(Settings& settings)
    1879             : {
    1880          26 :     bool result = true;
    1881          27 :     for (const std::string &addon: settings.addons) {
    1882           1 :         AddonInfo addonInfo;
    1883           1 :         const std::string failedToGetAddonInfo = addonInfo.getAddonInfo(addon, settings.exename);
    1884           1 :         if (!failedToGetAddonInfo.empty()) {
    1885           1 :             mLogger.printRaw(failedToGetAddonInfo); // TODO: do not print as raw
    1886           1 :             result = false;
    1887           1 :             continue;
    1888             :         }
    1889           0 :         settings.addonInfos.emplace_back(std::move(addonInfo));
    1890             :     }
    1891          26 :     return result;
    1892             : }
    1893             : 
    1894         192 : bool CmdLineParser::loadCppcheckCfg()
    1895             : {
    1896         384 :     const std::string cfgErr = Settings::loadCppcheckCfg(mSettings, mSuppressions);
    1897         192 :     if (!cfgErr.empty()) {
    1898           3 :         mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
    1899           3 :         return false;
    1900             :     }
    1901         189 :     return true;
    1902             : }
    1903             : 

Generated by: LCOV version 1.14