Cppcheck
cmdlineparser.cpp
Go to the documentation of this file.
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 static bool addFilesToList(const std::string& fileList, std::vector<std::string>& pathNames)
64 {
65  std::istream *files;
66  std::ifstream infile;
67  if (fileList == "-") { // read from stdin
68  files = &std::cin;
69  } else {
70  infile.open(fileList);
71  if (!infile.is_open())
72  return false;
73  files = &infile;
74  }
75  if (files && *files) {
76  std::string fileName;
77  // cppcheck-suppress accessMoved - FP
78  while (std::getline(*files, fileName)) { // next line
79  // cppcheck-suppress accessMoved - FP
80  if (!fileName.empty()) {
81  pathNames.emplace_back(std::move(fileName));
82  }
83  }
84  }
85  return true;
86 }
87 
88 static bool addIncludePathsToList(const std::string& fileList, std::list<std::string>& pathNames)
89 {
90  std::ifstream files(fileList);
91  if (files) {
92  std::string pathName;
93  // cppcheck-suppress accessMoved - FP
94  while (std::getline(files, pathName)) { // next line
95  if (!pathName.empty()) {
96  pathName = Path::removeQuotationMarks(std::move(pathName));
97  pathName = Path::fromNativeSeparators(std::move(pathName));
98 
99  // If path doesn't end with / or \, add it
100  if (!endsWith(pathName, '/'))
101  pathName += '/';
102 
103  pathNames.emplace_back(std::move(pathName));
104  }
105  }
106  return true;
107  }
108  return false;
109 }
110 
111 static bool addPathsToSet(const std::string& fileName, std::set<std::string>& set)
112 {
113  std::list<std::string> templist;
114  if (!addIncludePathsToList(fileName, templist))
115  return false;
116  set.insert(templist.cbegin(), templist.cend());
117  return true;
118 }
119 
120 namespace {
121  class XMLErrorMessagesLogger : public ErrorLogger
122  {
123  void reportOut(const std::string & outmsg, Color /*c*/ = Color::Reset) override
124  {
125  std::cout << outmsg << std::endl;
126  }
127 
128  void reportErr(const ErrorMessage &msg) override
129  {
130  reportOut(msg.toXML());
131  }
132 
133  void reportProgress(const std::string & /*filename*/, const char /*stage*/[], const std::size_t /*value*/) override
134  {}
135  };
136 }
137 
139  : mLogger(logger)
140  , mSettings(settings)
141  , mSuppressions(suppressions)
142 {}
143 
144 bool CmdLineParser::fillSettingsFromArgs(int argc, const char* const argv[])
145 {
146  const Result result = parseFromArgs(argc, argv);
147 
148  switch (result) {
149  case Result::Success:
150  break;
151  case Result::Exit:
153  return true;
154  case Result::Fail:
155  return false;
156  }
157 
158  // Libraries must be loaded before FileLister is executed to ensure markup files will be
159  // listed properly.
160  if (!loadLibraries(mSettings))
161  return false;
162 
163  if (!loadAddons(mSettings))
164  return false;
165 
166  // Check that all include paths exist
167  {
168  for (std::list<std::string>::iterator iter = mSettings.includePaths.begin();
169  iter != mSettings.includePaths.end();
170  ) {
171  const std::string path(Path::toNativeSeparators(*iter));
172  if (Path::isDirectory(path))
173  ++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.
178  std::cout << "(information) Couldn't find path given by -I '" << path << '\'' << std::endl;
179  iter = mSettings.includePaths.erase(iter);
180  }
181  }
182  }
183 
184  // Output a warning for the user if he tries to exclude headers
185  const std::vector<std::string>& ignored = getIgnoredPaths();
186  const bool warn = std::any_of(ignored.cbegin(), ignored.cend(), [](const std::string& i) {
187  return Path::isHeader2(i);
188  });
189  if (warn) {
190  mLogger.printMessage("filename exclusion does not apply to header (.h and .hpp) files.");
191  mLogger.printMessage("Please use --suppress for ignoring results from the header files.");
192  }
193 
194  const std::vector<std::string>& pathnamesRef = getPathNames();
195  const std::list<FileSettings>& fileSettingsRef = getFileSettings();
196 
197  // the inputs can only be used exclusively - CmdLineParser should already handle this
198  assert(!(!pathnamesRef.empty() && !fileSettingsRef.empty()));
199 
200  if (!fileSettingsRef.empty()) {
201  // TODO: de-duplicate
202 
203  std::list<FileSettings> fileSettings;
204  if (!mSettings.fileFilters.empty()) {
205  // filter only for the selected filenames from all project files
206  std::copy_if(fileSettingsRef.cbegin(), fileSettingsRef.cend(), std::back_inserter(fileSettings), [&](const FileSettings &fs) {
207  return matchglobs(mSettings.fileFilters, fs.filename());
208  });
209  if (fileSettings.empty()) {
210  mLogger.printError("could not find any files matching the filter.");
211  return false;
212  }
213  }
214  else {
215  fileSettings = fileSettingsRef;
216  }
217 
218  mFileSettings.clear();
219 
220  // sort the markup last
221  std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
222  return !mSettings.library.markupFile(fs.filename()) || !mSettings.library.processMarkupAfterCode(fs.filename());
223  });
224 
225  std::copy_if(fileSettings.cbegin(), fileSettings.cend(), std::back_inserter(mFileSettings), [&](const FileSettings &fs) {
226  return mSettings.library.markupFile(fs.filename()) && mSettings.library.processMarkupAfterCode(fs.filename());
227  });
228 
229  if (mFileSettings.empty()) {
230  mLogger.printError("could not find or open any of the paths given.");
231  return false;
232  }
233  }
234 
235  if (!pathnamesRef.empty()) {
236  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  const bool caseSensitive = true;
243 #endif
244  // Execute recursiveAddFiles() to each given file parameter
245  // TODO: verbose log which files were ignored?
246  const PathMatch matcher(ignored, caseSensitive);
247  for (const std::string &pathname : pathnamesRef) {
248  const std::string err = FileLister::recursiveAddFiles(filesResolved, Path::toNativeSeparators(pathname), mSettings.library.markupExtensions(), matcher);
249  if (!err.empty()) {
250  // TODO: bail out?
251  mLogger.printMessage(err);
252  }
253  }
254 
255  if (filesResolved.empty()) {
256  mLogger.printError("could not find or open any of the paths given.");
257  // TODO: PathMatch should provide the information if files were ignored
258  if (!ignored.empty())
259  mLogger.printMessage("Maybe all paths were ignored?");
260  return false;
261  }
262 
263  // de-duplicate files
264  {
265  auto it = filesResolved.begin();
266  while (it != filesResolved.end()) {
267  const std::string& name = it->path();
268  // TODO: log if duplicated files were dropped
269  filesResolved.erase(std::remove_if(std::next(it), filesResolved.end(), [&](const FileWithDetails& entry) {
270  return entry.path() == name;
271  }), filesResolved.end());
272  ++it;
273  }
274  }
275 
276  std::list<FileWithDetails> files;
277  if (!mSettings.fileFilters.empty()) {
278  std::copy_if(filesResolved.cbegin(), filesResolved.cend(), std::inserter(files, files.end()), [&](const FileWithDetails& entry) {
279  return matchglobs(mSettings.fileFilters, entry.path());
280  });
281  if (files.empty()) {
282  mLogger.printError("could not find any files matching the filter.");
283  return false;
284  }
285  }
286  else {
287  files = std::move(filesResolved);
288  }
289 
290  // sort the markup last
291  std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
292  return !mSettings.library.markupFile(entry.path()) || !mSettings.library.processMarkupAfterCode(entry.path());
293  });
294 
295  std::copy_if(files.cbegin(), files.cend(), std::inserter(mFiles, mFiles.end()), [&](const FileWithDetails& entry) {
296  return mSettings.library.markupFile(entry.path()) && mSettings.library.processMarkupAfterCode(entry.path());
297  });
298 
299  if (mFiles.empty()) {
300  mLogger.printError("could not find or open any of the paths given.");
301  return false;
302  }
303  }
304 
305  return true;
306 }
307 
308 // TODO: normalize/simplify/native all path parameters
309 // TODO: error out on all missing given files/paths
310 CmdLineParser::Result CmdLineParser::parseFromArgs(int argc, const char* const argv[])
311 {
313 
314  // default to --check-level=normal from CLI for now
316 
317  if (argc <= 1) {
318  printHelp();
319  return Result::Exit;
320  }
321 
322  // check for exclusive options
323  for (int i = 1; i < argc; i++) {
324  // documentation..
325  if (std::strcmp(argv[i], "--doc") == 0) {
326  std::ostringstream doc;
327  // Get documentation..
328  for (const Check * it : Check::instances()) {
329  const std::string& name(it->name());
330  const std::string info(it->classInfo());
331  if (!name.empty() && !info.empty())
332  doc << "## " << name << " ##\n"
333  << info << "\n";
334  }
335 
336  mLogger.printRaw(doc.str());
337  return Result::Exit;
338  }
339 
340  // print all possible error messages..
341  if (std::strcmp(argv[i], "--errorlist") == 0) {
342  if (!loadCppcheckCfg())
343  return Result::Fail;
344  {
345  XMLErrorMessagesLogger xmlLogger;
347  CppCheck::getErrorMessages(xmlLogger);
348  std::cout << ErrorMessage::getXMLFooter() << std::endl;
349  }
350  return Result::Exit;
351  }
352 
353  // Print help
354  if (std::strcmp(argv[i], "-h") == 0 || std::strcmp(argv[i], "--help") == 0) {
355  printHelp();
356  return Result::Exit;
357  }
358 
359  if (std::strcmp(argv[i], "--version") == 0) {
360  if (!loadCppcheckCfg())
361  return Result::Fail;
362  const std::string version = getVersion();
363  mLogger.printRaw(version);
364  return Result::Exit;
365  }
366  }
367 
368  bool def = false;
369  bool maxconfigs = false;
370 
371  ImportProject project;
372 
373  bool executorAuto = true;
374  int8_t logMissingInclude{0};
375 
376  for (int i = 1; i < argc; i++) {
377  if (argv[i][0] == '-') {
378  // User define
379  if (std::strncmp(argv[i], "-D", 2) == 0) {
380  std::string define;
381 
382  // "-D define"
383  if (std::strcmp(argv[i], "-D") == 0) {
384  ++i;
385  if (i >= argc || argv[i][0] == '-') {
386  mLogger.printError("argument to '-D' is missing.");
387  return Result::Fail;
388  }
389 
390  define = argv[i];
391  }
392  // "-Ddefine"
393  else {
394  define = 2 + argv[i];
395  }
396 
397  // No "=", append a "=1"
398  if (define.find('=') == std::string::npos)
399  define += "=1";
400 
401  if (!mSettings.userDefines.empty())
402  mSettings.userDefines += ";";
403  mSettings.userDefines += define;
404 
405  def = true;
406  }
407 
408  // -E
409  else if (std::strcmp(argv[i], "-E") == 0) {
410  mSettings.preprocessOnly = true;
411  mSettings.quiet = true;
412  }
413 
414  // Include paths
415  else if (std::strncmp(argv[i], "-I", 2) == 0) {
416  std::string path;
417 
418  // "-I path/"
419  if (std::strcmp(argv[i], "-I") == 0) {
420  ++i;
421  if (i >= argc || argv[i][0] == '-') {
422  mLogger.printError("argument to '-I' is missing.");
423  return Result::Fail;
424  }
425  path = argv[i];
426  }
427 
428  // "-Ipath/"
429  else {
430  path = 2 + argv[i];
431  }
432  path = Path::removeQuotationMarks(std::move(path));
433  path = Path::fromNativeSeparators(std::move(path));
434 
435  // If path doesn't end with / or \, add it
436  if (!endsWith(path,'/'))
437  path += '/';
438 
439  mSettings.includePaths.emplace_back(std::move(path));
440  }
441 
442  // User undef
443  else if (std::strncmp(argv[i], "-U", 2) == 0) {
444  std::string undef;
445 
446  // "-U undef"
447  if (std::strcmp(argv[i], "-U") == 0) {
448  ++i;
449  if (i >= argc || argv[i][0] == '-') {
450  mLogger.printError("argument to '-U' is missing.");
451  return Result::Fail;
452  }
453 
454  undef = argv[i];
455  }
456  // "-Uundef"
457  else {
458  undef = 2 + argv[i];
459  }
460 
461  mSettings.userUndefs.insert(std::move(undef));
462  }
463 
464  else if (std::strncmp(argv[i], "--addon=", 8) == 0)
465  mSettings.addons.emplace(argv[i]+8);
466 
467  else if (std::strncmp(argv[i],"--addon-python=", 15) == 0)
468  mSettings.addonPython.assign(argv[i]+15);
469 
470  // Check configuration
471  else if (std::strcmp(argv[i], "--check-config") == 0)
473 
474  // Check level
475  else if (std::strncmp(argv[i], "--check-level=", 14) == 0) {
477  const std::string level_s(argv[i] + 14);
478  if (level_s == "normal")
480  else if (level_s == "exhaustive")
482  else {
483  mLogger.printError("unknown '--check-level' value '" + level_s + "'.");
484  return Result::Fail;
485  }
486 
487  mSettings.setCheckLevel(level);
488  }
489 
490  // Check library definitions
491  else if (std::strcmp(argv[i], "--check-library") == 0) {
492  mSettings.checkLibrary = true;
493  }
494 
495  else if (std::strncmp(argv[i], "--check-version=", 16) == 0) {
496  if (!loadCppcheckCfg())
497  return Result::Fail;
498  const std::string actualVersion = getVersion();
499  const std::string wantedVersion = argv[i] + 16;
500  if (actualVersion != wantedVersion) {
501  mLogger.printError("--check-version check failed. Aborting.");
502  return Result::Fail;
503  }
504  }
505 
506  else if (std::strncmp(argv[i], "--checkers-report=", 18) == 0)
507  mSettings.checkersReportFilename = argv[i] + 18;
508 
509  else if (std::strncmp(argv[i], "--checks-max-time=", 18) == 0) {
510  if (!parseNumberArg(argv[i], 18, mSettings.checksMaxTime, true))
511  return Result::Fail;
512  }
513 
514  else if (std::strcmp(argv[i], "--clang") == 0) {
515  mSettings.clang = true;
516  }
517 
518  else if (std::strncmp(argv[i], "--clang=", 8) == 0) {
519  mSettings.clang = true;
520  mSettings.clangExecutable = argv[i] + 8;
521  }
522 
523  else if (std::strncmp(argv[i], "--config-exclude=",17) ==0) {
525  }
526 
527  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  const std::string cfgExcludesFile(23 + argv[i]);
530  if (!addPathsToSet(cfgExcludesFile, mSettings.configExcludePaths)) {
531  mLogger.printError("unable to open config excludes file at '" + cfgExcludesFile + "'");
532  return Result::Fail;
533  }
534  }
535 
536  else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) {
538  if (endsWith(mSettings.buildDir, '/'))
539  mSettings.buildDir.pop_back();
540 
542  mLogger.printError("Directory '" + mSettings.buildDir + "' specified by --cppcheck-build-dir argument has to be existent.");
543  return Result::Fail;
544  }
545  }
546 
547  // Show --debug output after the first simplifications
548  else if (std::strcmp(argv[i], "--debug") == 0 ||
549  std::strcmp(argv[i], "--debug-normal") == 0)
550  mSettings.debugnormal = true;
551 
552  // Flag used for various purposes during debugging
553  else if (std::strcmp(argv[i], "--debug-simplified") == 0)
554  mSettings.debugSimplified = true;
555 
556  // Show template information
557  else if (std::strcmp(argv[i], "--debug-template") == 0)
558  mSettings.debugtemplate = true;
559 
560  // Show debug warnings
561  else if (std::strcmp(argv[i], "--debug-warnings") == 0)
562  mSettings.debugwarnings = true;
563 
564  else if (std::strncmp(argv[i], "--disable=", 10) == 0) {
565  const std::string errmsg = mSettings.removeEnabled(argv[i] + 10);
566  if (!errmsg.empty()) {
567  mLogger.printError(errmsg);
568  return Result::Fail;
569  }
570  if (std::string(argv[i] + 10).find("missingInclude") != std::string::npos) {
571  --logMissingInclude;
572  }
573  }
574 
575  // dump cppcheck data
576  else if (std::strcmp(argv[i], "--dump") == 0)
577  mSettings.dump = true;
578 
579  else if (std::strncmp(argv[i], "--enable=", 9) == 0) {
580  const std::string enable_arg = argv[i] + 9;
581  const std::string errmsg = mSettings.addEnabled(enable_arg);
582  if (!errmsg.empty()) {
583  mLogger.printError(errmsg);
584  return Result::Fail;
585  }
586  // when "style" is enabled, also enable "warning", "performance" and "portability"
587  if (enable_arg.find("style") != std::string::npos) {
588  mSettings.addEnabled("warning");
589  mSettings.addEnabled("performance");
590  mSettings.addEnabled("portability");
591  }
592  if (enable_arg.find("information") != std::string::npos && logMissingInclude == 0) {
593  ++logMissingInclude;
594  mSettings.addEnabled("missingInclude");
595  }
596  if (enable_arg.find("missingInclude") != std::string::npos) {
597  --logMissingInclude;
598  }
599  }
600 
601  // --error-exitcode=1
602  else if (std::strncmp(argv[i], "--error-exitcode=", 17) == 0) {
603  if (!parseNumberArg(argv[i], 17, mSettings.exitCode))
604  return Result::Fail;
605  }
606 
607  // Exception handling inside cppcheck client
608  else if (std::strcmp(argv[i], "--exception-handling") == 0) {
609 #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
610  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  else if (std::strncmp(argv[i], "--exception-handling=", 21) == 0) {
619 #if defined(USE_WINDOWS_SEH) || defined(USE_UNIX_SIGNAL_HANDLING)
620  const std::string exceptionOutfilename = argv[i] + 21;
621  if (exceptionOutfilename != "stderr" && exceptionOutfilename != "stdout") {
622  mLogger.printError("invalid '--exception-handling' argument");
623  return Result::Fail;
624  }
625  mSettings.exceptionHandling = true;
626  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  else if (std::strncmp(argv[i], "--executor=", 11) == 0) {
634  const std::string type = 11 + argv[i];
635  if (type == "auto") {
636  executorAuto = true;
638  }
639  else if (type == "thread") {
640 #if defined(HAS_THREADING_MODEL_THREAD)
641  executorAuto = false;
642  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  else if (type == "process") {
649 #if defined(HAS_THREADING_MODEL_FORK)
650  executorAuto = false;
651  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  mLogger.printError("unknown executor: '" + type + "'.");
659  return Result::Fail;
660  }
661  }
662 
663  // Filter errors
664  else if (std::strncmp(argv[i], "--exitcode-suppressions=", 24) == 0) {
665  // exitcode-suppressions=filename.txt
666  std::string filename = 24 + argv[i];
667 
668  std::ifstream f(filename);
669  if (!f.is_open()) {
670  mLogger.printError("couldn't open the file: \"" + filename + "\".");
671  return Result::Fail;
672  }
673  const std::string errmsg(mSuppressions.nofail.parseFile(f));
674  if (!errmsg.empty()) {
675  mLogger.printError(errmsg);
676  return Result::Fail;
677  }
678  }
679 
680  // use a file filter
681  else if (std::strncmp(argv[i], "--file-filter=", 14) == 0) {
682  const char *filter = argv[i] + 14;
683  if (std::strcmp(filter, "-") == 0) {
684  if (!addFilesToList(filter, mSettings.fileFilters)) {
685  mLogger.printError("Failed: --file-filter=-");
686  return Result::Fail;
687  }
688  } else {
689  mSettings.fileFilters.emplace_back(filter);
690  }
691  }
692 
693  // file list specified
694  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  const std::string fileList = argv[i] + 12;
697  if (!addFilesToList(fileList, mPathNames)) {
698  mLogger.printError("couldn't open the file: \"" + fileList + "\".");
699  return Result::Fail;
700  }
701  }
702 
703  // Force checking of files that have "too many" configurations
704  else if (std::strcmp(argv[i], "-f") == 0 || std::strcmp(argv[i], "--force") == 0)
705  mSettings.force = true;
706 
707  else if (std::strcmp(argv[i], "--fsigned-char") == 0)
709 
710  else if (std::strcmp(argv[i], "--funsigned-char") == 0)
712 
713  // Ignored paths
714  else if (std::strncmp(argv[i], "-i", 2) == 0) {
715  std::string path;
716 
717  // "-i path/"
718  if (std::strcmp(argv[i], "-i") == 0) {
719  ++i;
720  if (i >= argc || argv[i][0] == '-') {
721  mLogger.printError("argument to '-i' is missing.");
722  return Result::Fail;
723  }
724  path = argv[i];
725  }
726 
727  // "-ipath/"
728  else {
729  path = 2 + argv[i];
730  }
731 
732  if (!path.empty()) {
733  path = Path::removeQuotationMarks(std::move(path));
734  path = Path::fromNativeSeparators(std::move(path));
735  path = Path::simplifyPath(std::move(path));
736 
737  if (Path::isDirectory(path)) {
738  // If directory name doesn't end with / or \, add it
739  if (!endsWith(path, '/'))
740  path += '/';
741  }
742  mIgnoredPaths.emplace_back(std::move(path));
743  }
744  }
745 
746  else if (std::strncmp(argv[i], "--include=", 10) == 0) {
747  mSettings.userIncludes.emplace_back(Path::fromNativeSeparators(argv[i] + 10));
748  }
749 
750  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  const std::string includesFile(16 + argv[i]);
753  if (!addIncludePathsToList(includesFile, mSettings.includePaths)) {
754  mLogger.printError("unable to open includes file at '" + includesFile + "'");
755  return Result::Fail;
756  }
757  }
758 
759  // Inconclusive checking
760  else if (std::strcmp(argv[i], "--inconclusive") == 0)
762 
763  // Enables inline suppressions.
764  else if (std::strcmp(argv[i], "--inline-suppr") == 0)
766 
767  // Checking threads
768  else if (std::strncmp(argv[i], "-j", 2) == 0) {
769  std::string numberString;
770 
771  // "-j 3"
772  if (std::strcmp(argv[i], "-j") == 0) {
773  ++i;
774  if (i >= argc || argv[i][0] == '-') {
775  mLogger.printError("argument to '-j' is missing.");
776  return Result::Fail;
777  }
778 
779  numberString = argv[i];
780  }
781 
782  // "-j3"
783  else
784  numberString = argv[i]+2;
785 
786  unsigned int tmp;
787  std::string err;
788  if (!strToInt(numberString, tmp, &err)) {
789  mLogger.printError("argument to '-j' is not valid - " + err + ".");
790  return Result::Fail;
791  }
792  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  mLogger.printError("argument for '-j' must be greater than 0.");
797  return Result::Fail;
798  }
799  if (tmp > 1024) {
800  // Almost nobody has 1024 logical cores, but somebody out
801  // there does.
802  mLogger.printError("argument for '-j' is allowed to be 1024 at max.");
803  return Result::Fail;
804  }
805  mSettings.jobs = tmp;
806  }
807 
808  else if (std::strncmp(argv[i], "-l", 2) == 0) {
809 #ifdef HAS_THREADING_MODEL_FORK
810  std::string numberString;
811 
812  // "-l 3"
813  if (std::strcmp(argv[i], "-l") == 0) {
814  ++i;
815  if (i >= argc || argv[i][0] == '-') {
816  mLogger.printError("argument to '-l' is missing.");
817  return Result::Fail;
818  }
819 
820  numberString = argv[i];
821  }
822 
823  // "-l3"
824  else
825  numberString = argv[i]+2;
826 
827  int tmp;
828  std::string err;
829  if (!strToInt(numberString, tmp, &err)) {
830  mLogger.printError("argument to '-l' is not valid - " + err + ".");
831  return Result::Fail;
832  }
833  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  else if (std::strncmp(argv[i], "--language=", 11) == 0 || std::strcmp(argv[i], "-x") == 0) {
842  std::string str;
843  if (argv[i][2]) {
844  str = argv[i]+11;
845  } else {
846  i++;
847  if (i >= argc || argv[i][0] == '-') {
848  mLogger.printError("no language given to '-x' option.");
849  return Result::Fail;
850  }
851  str = argv[i];
852  }
853 
854  if (str == "c")
855  mSettings.enforcedLang = Standards::Language::C;
856  else if (str == "c++")
857  mSettings.enforcedLang = Standards::Language::CPP;
858  else {
859  mLogger.printError("unknown language '" + str + "' enforced.");
860  return Result::Fail;
861  }
862  }
863 
864  // --library
865  else if (std::strncmp(argv[i], "--library=", 10) == 0) {
866  mSettings.libraries.emplace_back(argv[i] + 10);
867  }
868 
869  // Set maximum number of #ifdef configurations to check
870  else if (std::strncmp(argv[i], "--max-configs=", 14) == 0) {
871  int tmp;
872  if (!parseNumberArg(argv[i], 14, tmp))
873  return Result::Fail;
874  if (tmp < 1) {
875  mLogger.printError("argument to '--max-configs=' must be greater than 0.");
876  return Result::Fail;
877  }
878 
879  mSettings.maxConfigs = tmp;
880  mSettings.force = false;
881  maxconfigs = true;
882  }
883 
884  // max ctu depth
885  else if (std::strncmp(argv[i], "--max-ctu-depth=", 16) == 0) {
886  if (!parseNumberArg(argv[i], 16, mSettings.maxCtuDepth))
887  return Result::Fail;
888  }
889 
890  // Write results in file
891  else if (std::strncmp(argv[i], "--output-file=", 14) == 0)
893 
894  // Experimental: limit execution time for extended valueflow analysis. basic valueflow analysis
895  // is always executed.
896  else if (std::strncmp(argv[i], "--performance-valueflow-max-time=", 33) == 0) {
897  if (!parseNumberArg(argv[i], 33, mSettings.performanceValueFlowMaxTime, true))
898  return Result::Fail;
899  }
900 
901  else if (std::strncmp(argv[i], "--performance-valueflow-max-if-count=", 37) == 0) {
903  return Result::Fail;
904  }
905 
906  // Specify platform
907  else if (std::strncmp(argv[i], "--platform=", 11) == 0) {
908  const std::string platform(11+argv[i]);
909 
910  std::string errstr;
911  const std::vector<std::string> paths = {argv[0]};
912  if (!mSettings.platform.set(platform, errstr, paths)) {
913  mLogger.printError(errstr);
914  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  if (platform == "unix32-unsigned")
921  mSettings.platform.type = Platform::Type::Unix32;
922  else if (platform == "unix64-unsigned")
923  mSettings.platform.type = Platform::Type::Unix64;
924  }
925 
926  // Write results in results.plist
927  else if (std::strncmp(argv[i], "--plist-output=", 15) == 0) {
929  if (mSettings.plistOutput.empty())
930  mSettings.plistOutput = ".";
931 
932  const std::string plistOutput = Path::toNativeSeparators(mSettings.plistOutput);
933  if (!Path::isDirectory(plistOutput)) {
934  std::string message("plist folder does not exist: '");
935  message += plistOutput;
936  message += "'.";
937  mLogger.printError(message);
938  return Result::Fail;
939  }
940 
941  if (!endsWith(mSettings.plistOutput,'/'))
942  mSettings.plistOutput += '/';
943  }
944 
945  // Special Cppcheck Premium options
946  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  "safety"};
960 
961  if (std::strcmp(argv[i], "--premium=safety") == 0)
962  mSettings.safety = true;
963  if (!mSettings.premiumArgs.empty())
964  mSettings.premiumArgs += " ";
965  const std::string p(argv[i] + 10);
966  if (!valid.count(p) && !startsWith(p, "cert-c-int-precision=")) {
967  mLogger.printError("invalid --premium option '" + p + "'.");
968  return Result::Fail;
969  }
970  mSettings.premiumArgs += "--" + p;
971  if (p == "misra-c-2012" || p == "misra-c-2023")
972  mSettings.addons.emplace("misra");
973  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  mSettings.addEnabled("warning");
977  mSettings.addEnabled("portability");
978  }
979  }
980 
981  // --project
982  else if (std::strncmp(argv[i], "--project=", 10) == 0) {
983  if (project.projectType != ImportProject::Type::NONE)
984  {
985  mLogger.printError("multiple --project options are not supported.");
986  return Result::Fail;
987  }
988 
989  mSettings.checkAllConfigurations = false; // Can be overridden with --max-configs or --force
990  std::string projectFile = argv[i]+10;
991  ImportProject::Type projType = project.import(projectFile, &mSettings);
992  project.projectType = projType;
993  if (projType == ImportProject::Type::CPPCHECK_GUI) {
994  for (const std::string &lib : project.guiProject.libraries)
995  mSettings.libraries.emplace_back(lib);
996 
997  const auto& excludedPaths = project.guiProject.excludedPaths;
998  std::copy(excludedPaths.cbegin(), excludedPaths.cend(), std::back_inserter(mIgnoredPaths));
999 
1000  std::string platform(project.guiProject.platform);
1001 
1002  // keep existing platform from command-line intact
1003  if (!platform.empty()) {
1004  std::string errstr;
1005  const std::vector<std::string> paths = {projectFile, argv[0]};
1006  if (!mSettings.platform.set(platform, errstr, paths)) {
1007  mLogger.printError(errstr);
1008  return Result::Fail;
1009  }
1010  }
1011 
1012  const auto& projectFileGui = project.guiProject.projectFile;
1013  if (!projectFileGui.empty()) {
1014  // read underlying project
1015  projectFile = projectFileGui;
1016  projType = project.import(projectFileGui, &mSettings);
1017  }
1018  }
1019  if (projType == ImportProject::Type::VS_SLN || projType == ImportProject::Type::VS_VCXPROJ) {
1020  if (project.guiProject.analyzeAllVsConfigs == "false")
1022  mSettings.libraries.emplace_back("windows");
1023  }
1024  if (projType == ImportProject::Type::MISSING) {
1025  mLogger.printError("failed to open project '" + projectFile + "'. The file does not exist.");
1026  return Result::Fail;
1027  }
1028  if (projType == ImportProject::Type::UNKNOWN) {
1029  mLogger.printError("failed to load project '" + projectFile + "'. The format is unknown.");
1030  return Result::Fail;
1031  }
1032  if (projType == ImportProject::Type::FAILURE) {
1033  mLogger.printError("failed to load project '" + projectFile + "'. An error occurred.");
1034  return Result::Fail;
1035  }
1036  }
1037 
1038  // --project-configuration
1039  else if (std::strncmp(argv[i], "--project-configuration=", 24) == 0) {
1040  mVSConfig = argv[i] + 24;
1042  project.ignoreOtherConfigs(mVSConfig);
1043  }
1044 
1045  // Only print something when there are errors
1046  else if (std::strcmp(argv[i], "-q") == 0 || std::strcmp(argv[i], "--quiet") == 0)
1047  mSettings.quiet = true;
1048 
1049  // Output relative paths
1050  else if (std::strcmp(argv[i], "-rp") == 0 || std::strcmp(argv[i], "--relative-paths") == 0)
1051  mSettings.relativePaths = true;
1052  else if (std::strncmp(argv[i], "-rp=", 4) == 0 || std::strncmp(argv[i], "--relative-paths=", 17) == 0) {
1053  mSettings.relativePaths = true;
1054  if (argv[i][argv[i][3]=='='?4:17] != 0) {
1055  std::string paths = argv[i]+(argv[i][3]=='='?4:17);
1056  for (;;) {
1057  const std::string::size_type pos = paths.find(';');
1058  if (pos == std::string::npos) {
1059  mSettings.basePaths.emplace_back(Path::fromNativeSeparators(paths));
1060  break;
1061  }
1062  mSettings.basePaths.emplace_back(Path::fromNativeSeparators(paths.substr(0, pos)));
1063  paths.erase(0, pos + 1);
1064  }
1065  } else {
1066  mLogger.printError("no paths specified for the '" + std::string(argv[i]) + "' option.");
1067  return Result::Fail;
1068  }
1069  }
1070 
1071  // Report progress
1072  else if (std::strcmp(argv[i], "--report-progress") == 0) {
1074  }
1075 
1076  else if (std::strncmp(argv[i], "--report-progress=", 18) == 0) {
1077  int tmp;
1078  if (!parseNumberArg(argv[i], 18, tmp, true))
1079  return Result::Fail;
1080  mSettings.reportProgress = tmp;
1081  }
1082 
1083  // Rule given at command line
1084  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  mLogger.printError("Option --rule cannot be used as Cppcheck has not been built with rules support.");
1097  return Result::Fail;
1098 #endif
1099  }
1100 
1101  // Rule file
1102  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  mLogger.printError("Option --rule-file cannot be used as Cppcheck has not been built with rules support.");
1182  return Result::Fail;
1183 #endif
1184  }
1185 
1186  // Safety certified behavior
1187  else if (std::strcmp(argv[i], "--safety") == 0)
1188  mSettings.safety = true;
1189 
1190  // show timing information..
1191  else if (std::strncmp(argv[i], "--showtime=", 11) == 0) {
1192  const std::string showtimeMode = argv[i] + 11;
1193  if (showtimeMode == "file")
1195  else if (showtimeMode == "file-total")
1197  else if (showtimeMode == "summary")
1199  else if (showtimeMode == "top5") {
1201  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  else if (showtimeMode == "top5_file")
1205  else if (showtimeMode == "top5_summary")
1207  else if (showtimeMode == "none")
1209  else if (showtimeMode.empty()) {
1210  mLogger.printError("no mode provided for --showtime");
1211  return Result::Fail;
1212  }
1213  else {
1214  mLogger.printError("unrecognized --showtime mode: '" + showtimeMode + "'. Supported modes: file, file-total, summary, top5, top5_file, top5_summary.");
1215  return Result::Fail;
1216  }
1217  }
1218 
1219  // --std
1220  else if (std::strncmp(argv[i], "--std=", 6) == 0) {
1221  const std::string std = argv[i] + 6;
1222  // TODO: print error when standard is unknown
1223  if (std::strncmp(std.c_str(), "c++", 3) == 0) {
1225  }
1226  else if (std::strncmp(std.c_str(), "c", 1) == 0) {
1228  }
1229  else {
1230  mLogger.printError("unknown --std value '" + std + "'");
1231  return Result::Fail;
1232  }
1233  }
1234 
1235  else if (std::strncmp(argv[i], "--suppress=", 11) == 0) {
1236  const std::string suppression = argv[i]+11;
1237  const std::string errmsg(mSuppressions.nomsg.addSuppressionLine(suppression));
1238  if (!errmsg.empty()) {
1239  mLogger.printError(errmsg);
1240  return Result::Fail;
1241  }
1242  }
1243 
1244  // Filter errors
1245  else if (std::strncmp(argv[i], "--suppressions-list=", 20) == 0) {
1246  std::string filename = argv[i]+20;
1247  std::ifstream f(filename);
1248  if (!f.is_open()) {
1249  std::string message("couldn't open the file: \"");
1250  message += filename;
1251  message += "\".";
1252  if (std::count(filename.cbegin(), filename.cend(), ',') > 0 ||
1253  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  message += "\nIf you want to pass two files, you can do it e.g. like this:";
1258  message += "\n cppcheck --suppressions-list=a.txt --suppressions-list=b.txt file.cpp";
1259  }
1260 
1261  mLogger.printError(message);
1262  return Result::Fail;
1263  }
1264  const std::string errmsg(mSuppressions.nomsg.parseFile(f));
1265  if (!errmsg.empty()) {
1266  mLogger.printError(errmsg);
1267  return Result::Fail;
1268  }
1269  }
1270 
1271  else if (std::strncmp(argv[i], "--suppress-xml=", 15) == 0) {
1272  const char * filename = argv[i] + 15;
1273  const std::string errmsg(mSuppressions.nomsg.parseXmlFile(filename));
1274  if (!errmsg.empty()) {
1275  mLogger.printError(errmsg);
1276  return Result::Fail;
1277  }
1278  }
1279 
1280  // Output formatter
1281  else if (std::strncmp(argv[i], "--template=", 11) == 0) {
1282  mSettings.templateFormat = argv[i] + 11;
1283  // TODO: bail out when no template is provided?
1284 
1285  if (mSettings.templateFormat == "gcc") {
1286  mSettings.templateFormat = "{bold}{file}:{line}:{column}: {magenta}warning:{default} {message} [{id}]{reset}\\n{code}";
1287  mSettings.templateLocation = "{bold}{file}:{line}:{column}: {dim}note:{reset} {info}\\n{code}";
1288  } else if (mSettings.templateFormat == "daca2") {
1289  mSettings.daca = true;
1290  mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]";
1291  mSettings.templateLocation = "{file}:{line}:{column}: note: {info}";
1292  } else if (mSettings.templateFormat == "vs")
1293  mSettings.templateFormat = "{file}({line}): {severity}: {message}";
1294  else if (mSettings.templateFormat == "edit")
1295  mSettings.templateFormat = "{file} +{line}: {severity}: {message}";
1296  else if (mSettings.templateFormat == "cppcheck1")
1297  mSettings.templateFormat = "{callstack}: ({severity}{inconclusive:, inconclusive}) {message}";
1298  else if (mSettings.templateFormat == "selfcheck") {
1299  mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]\\n{code}";
1300  mSettings.templateLocation = "{file}:{line}:{column}: note: {info}\\n{code}";
1301  mSettings.daca = true;
1302  } else if (mSettings.templateFormat == "simple") {
1303  mSettings.templateFormat = "{file}:{line}:{column}: {severity}:{inconclusive:inconclusive:} {message} [{id}]";
1305  }
1306  // TODO: bail out when no placeholders are found?
1307  }
1308 
1309  else if (std::strncmp(argv[i], "--template-location=", 20) == 0) {
1310  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  else if (std::strncmp(argv[i], "--template-max-time=", 20) == 0) {
1316  if (!parseNumberArg(argv[i], 20, mSettings.templateMaxTime))
1317  return Result::Fail;
1318  }
1319 
1320  else if (std::strncmp(argv[i], "--typedef-max-time=", 19) == 0) {
1321  if (!parseNumberArg(argv[i], 19, mSettings.typedefMaxTime))
1322  return Result::Fail;
1323  }
1324 
1325  else if (std::strncmp(argv[i], "--valueflow-max-iterations=", 27) == 0) {
1326  if (!parseNumberArg(argv[i], 27, mSettings.valueFlowMaxIterations))
1327  return Result::Fail;
1328  }
1329 
1330  else if (std::strcmp(argv[i], "-v") == 0 || std::strcmp(argv[i], "--verbose") == 0)
1331  mSettings.verbose = true;
1332 
1333  // Write results in results.xml
1334  else if (std::strcmp(argv[i], "--xml") == 0)
1335  mSettings.xml = true;
1336 
1337  // Define the XML file version (and enable XML output)
1338  else if (std::strncmp(argv[i], "--xml-version=", 14) == 0) {
1339  int tmp;
1340  if (!parseNumberArg(argv[i], 14, tmp))
1341  return Result::Fail;
1342  if (tmp != 2) {
1343  // We only have xml version 2
1344  mLogger.printError("'--xml-version' can only be 2.");
1345  return Result::Fail;
1346  }
1347 
1348  mSettings.xml_version = tmp;
1349  // Enable also XML if version is set
1350  mSettings.xml = true;
1351  }
1352 
1353  else {
1354  std::string message("unrecognized command line option: \"");
1355  message += argv[i];
1356  message += "\".";
1357  mLogger.printError(message);
1358  return Result::Fail;
1359  }
1360  }
1361 
1362  else {
1364  }
1365  }
1366 
1367  if (logMissingInclude == 1)
1368  mLogger.printMessage("'--enable=information' will no longer implicitly enable 'missingInclude' starting with 2.16. Please enable it explicitly if you require it.");
1369 
1370  if (!loadCppcheckCfg())
1371  return Result::Fail;
1372 
1373  // TODO: bail out?
1374  if (!executorAuto && mSettings.useSingleJob())
1375  mLogger.printMessage("'--executor' has no effect as only a single job will be used.");
1376 
1377  // Default template format..
1378  if (mSettings.templateFormat.empty()) {
1379  mSettings.templateFormat = "{bold}{file}:{line}:{column}: {red}{inconclusive:{magenta}}{severity}:{inconclusive: inconclusive:}{default} {message} [{id}]{reset}\\n{code}";
1380  if (mSettings.templateLocation.empty())
1381  mSettings.templateLocation = "{bold}{file}:{line}:{column}: {dim}note:{reset} {info}\\n{code}";
1382  }
1383  // replace static parts of the templates
1386 
1387  if (mSettings.force || maxconfigs)
1389 
1390  if (mSettings.force)
1391  mSettings.maxConfigs = INT_MAX;
1392 
1393  else if ((def || mSettings.preprocessOnly) && !maxconfigs)
1394  mSettings.maxConfigs = 1U;
1395 
1397  // TODO: bail out
1398  mLogger.printMessage("unusedFunction check can't be used with '-j' option. Disabling unusedFunction check.");
1399  }
1400 
1401  if (!mPathNames.empty() && project.projectType != ImportProject::Type::NONE) {
1402  mLogger.printError("--project cannot be used in conjunction with source files.");
1403  return Result::Fail;
1404  }
1405 
1406  // Print error only if we have "real" command and expect files
1407  if (mPathNames.empty() && project.guiProject.pathNames.empty() && project.fileSettings.empty()) {
1408  // TODO: this message differs from the one reported in fillSettingsFromArgs()
1409  mLogger.printError("no C or C++ source files found.");
1410  return Result::Fail;
1411  }
1412 
1413  if (!project.guiProject.pathNames.empty())
1414  mPathNames = project.guiProject.pathNames;
1415 
1416  if (!project.fileSettings.empty()) {
1417  project.ignorePaths(mIgnoredPaths);
1418  if (project.fileSettings.empty()) {
1419  mLogger.printError("no C or C++ source files found.");
1420  mLogger.printMessage("all paths were ignored"); // TODO: log this differently?
1421  return Result::Fail;
1422  }
1423  mFileSettings = project.fileSettings;
1424  }
1425 
1426  // Use paths _pathnames if no base paths for relative path output are given
1427  if (mSettings.basePaths.empty() && mSettings.relativePaths)
1429 
1430  return Result::Success;
1431 }
1432 
1434 {
1435  const std::string manualUrl(isCppcheckPremium() ?
1436  "https://cppcheck.sourceforge.io/manual.pdf" :
1437  "https://files.cppchecksolutions.com/manual.pdf");
1438 
1439  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  " 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  " Generate Clang-plist output files in folder.\n";
1630 
1631  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  " * 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  " * qt -- used in GUI\n";
1785 
1786  mLogger.printRaw(oss.str());
1787 }
1788 
1789 std::string CmdLineParser::getVersion() const {
1790  if (!mSettings.cppcheckCfgProductName.empty())
1792  const char * const extraVersion = CppCheck::extraVersion();
1793  if (*extraVersion != '\0')
1794  return std::string("Cppcheck ") + CppCheck::version() + " ("+ extraVersion + ')';
1795  return std::string("Cppcheck ") + CppCheck::version();
1796 }
1797 
1799  if (mSettings.cppcheckCfgProductName.empty())
1801  return startsWith(mSettings.cppcheckCfgProductName, "Cppcheck Premium");
1802 }
1803 
1804 bool CmdLineParser::tryLoadLibrary(Library& destination, const std::string& basepath, const char* filename)
1805 {
1806  const Library::Error err = destination.load(basepath.c_str(), filename);
1807 
1809  mLogger.printMessage("Found unknown elements in configuration file '" + std::string(filename) + "': " + err.reason); // TODO: print as errors
1810  else if (err.errorcode != Library::ErrorCode::OK) {
1811  std::string msg = "Failed to load library configuration file '" + std::string(filename) + "'. ";
1812  switch (err.errorcode) {
1814  break;
1816  msg += "File not found";
1817  break;
1819  msg += "Bad XML";
1820  break;
1822  msg += "Unexpected element";
1823  break;
1825  msg +="Missing attribute";
1826  break;
1828  msg += "Bad attribute value";
1829  break;
1831  msg += "File is of unsupported format version";
1832  break;
1834  msg += "Duplicate platform type";
1835  break;
1837  msg += "Platform type redefined";
1838  break;
1840  msg += "Duplicate define";
1841  break;
1842  }
1843  if (!err.reason.empty())
1844  msg += " '" + err.reason + "'";
1845  mLogger.printMessage(msg); // TODO: print as errors
1846  return false;
1847  }
1848  return true;
1849 }
1850 
1852 {
1853  if (!tryLoadLibrary(settings.library, settings.exename, "std.cfg")) {
1854  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  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  "std.cfg should be available in " + cfgfolder + " or the FILESDIR "
1863  "should be configured.");
1864 #endif
1865  mLogger.printRaw(msg + " " + details); // TODO: do not print as raw?
1866  return false;
1867  }
1868 
1869  bool result = true;
1870  for (const auto& lib : settings.libraries) {
1871  if (!tryLoadLibrary(settings.library, settings.exename, lib.c_str())) {
1872  result = false;
1873  }
1874  }
1875  return result;
1876 }
1877 
1879 {
1880  bool result = true;
1881  for (const std::string &addon: settings.addons) {
1882  AddonInfo addonInfo;
1883  const std::string failedToGetAddonInfo = addonInfo.getAddonInfo(addon, settings.exename);
1884  if (!failedToGetAddonInfo.empty()) {
1885  mLogger.printRaw(failedToGetAddonInfo); // TODO: do not print as raw
1886  result = false;
1887  continue;
1888  }
1889  settings.addonInfos.emplace_back(std::move(addonInfo));
1890  }
1891  return result;
1892 }
1893 
1895 {
1896  const std::string cfgErr = Settings::loadCppcheckCfg(mSettings, mSuppressions);
1897  if (!cfgErr.empty()) {
1898  mLogger.printError("could not load cppcheck.cfg - " + cfgErr);
1899  return false;
1900  }
1901  return true;
1902 }
1903 
Interface class that cppcheck uses to communicate with the checks.
Definition: check.h:59
static std::list< Check * > & instances()
List of registered check classes.
Definition: check.cpp:89
virtual void printMessage(const std::string &message)=0
print a regular message
virtual void printError(const std::string &message)=0
print an error message
virtual void printRaw(const std::string &message)=0
print to the output
bool parseNumberArg(const char *const arg, std::size_t offset, T &num, bool mustBePositive=false)
CmdLineParser(CmdLineLogger &logger, Settings &settings, Suppressions &suppressions)
The constructor.
const std::vector< std::string > & getPathNames() const
Return the path names user gave to command line.
Definition: cmdlineparser.h:80
bool tryLoadLibrary(Library &destination, const std::string &basepath, const char *filename)
Tries to load a library and prints warning/error messages.
std::vector< std::string > mPathNames
void printHelp() const
Print help text to the console.
bool loadLibraries(Settings &settings)
Load libraries.
std::string getVersion() const
Get Cppcheck version.
std::list< FileSettings > mFileSettings
bool fillSettingsFromArgs(int argc, const char *const argv[])
Parse command line args and fill settings and file lists from there.
Suppressions & mSuppressions
Settings & mSettings
std::list< FileWithDetails > mFiles
CmdLineLogger & mLogger
std::vector< std::string > mIgnoredPaths
bool isCppcheckPremium() const
Result parseFromArgs(int argc, const char *const argv[])
Parse given command line.
std::string mVSConfig
bool loadAddons(Settings &settings)
Load addons.
const std::vector< std::string > & getIgnoredPaths() const
Return a list of paths user wants to ignore.
const std::list< FileSettings > & getFileSettings() const
Return the file settings read from command line.
Definition: cmdlineparser.h:94
static void setExceptionOutput(FILE *exceptionOutput)
static void getErrorMessages(ErrorLogger &errorlogger)
Call all "getErrorMessages" in all registered Check classes.
Definition: cppcheck.cpp:1633
static const char * version()
Returns current version number as a string.
Definition: cppcheck.cpp:354
static const char * extraVersion()
Returns extra version info as a string.
Definition: cppcheck.cpp:359
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
virtual void reportOut(const std::string &outmsg, Color c=Color::Reset)=0
Information about progress is directed here.
virtual void reportProgress(const std::string &filename, const char stage[], const std::size_t value)
Report progress to client.
Definition: errorlogger.h:241
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
static std::string getXMLFooter()
static std::string getXMLHeader(std::string productName)
std::string toXML() const
Format the error message in XML format.
static std::string recursiveAddFiles(std::list< FileWithDetails > &files, const std::string &path, const PathMatch &ignored)
Recursively add source files to a map.
Definition: filelister.h:47
Importing project settings.
Definition: importproject.h:52
std::list< std::string > excludedPaths
Definition: importproject.h:88
std::list< FileSettings > fileSettings
Definition: importproject.h:70
struct ImportProject::@6 guiProject
void ignorePaths(const std::vector< std::string > &ipaths)
std::string analyzeAllVsConfigs
Definition: importproject.h:85
std::string projectFile
Definition: importproject.h:90
void selectOneVsConfig(Platform::Type platform)
void ignoreOtherConfigs(const std::string &cfg)
std::string platform
Definition: importproject.h:91
Type import(const std::string &filename, Settings *settings=nullptr)
std::vector< std::string > pathNames
Definition: importproject.h:86
std::list< std::string > libraries
Definition: importproject.h:87
ErrorCode errorcode
Definition: library.h:74
std::string reason
Definition: library.h:75
Library definitions handling.
Definition: library.h:52
const std::set< std::string > & markupExtensions() const
Definition: library.h:380
Error load(const char exename[], const char path[])
Definition: library.cpp:68
Simple path matching for ignoring paths in CLI.
Definition: pathmatch.h:33
static std::string simplifyPath(std::string originalPath)
Simplify path "foo/bar/.." => "foo".
Definition: path.cpp:83
static std::string fromNativeSeparators(std::string path)
Convert path to use internal path separators.
Definition: path.cpp:75
static std::string removeQuotationMarks(std::string path)
Remove quotation marks (") from the path.
Definition: path.cpp:103
static std::string getCurrentExecutablePath(const char *fallback)
Returns the absolute path to the current executable.
Definition: path.cpp:143
static std::string toNativeSeparators(std::string path)
Convert path to use native separators.
Definition: path.cpp:62
static std::string getPathFromFilename(const std::string &filename)
Lookup the path part from a filename (e.g., '/tmp/a.h' -> '/tmp/', 'a.h' -> '')
Definition: path.cpp:88
static bool isDirectory(const std::string &path)
Checks if a given path is a directory.
Definition: path.cpp:334
char defaultSign
Definition: platform.h:104
Type type
platform type
Definition: platform.h:118
bool set(Type t)
set the platform type for predefined platforms - deprecated use set(const std::string&,...
Definition: platform.cpp:36
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
std::set< std::string > userUndefs
undefines given by the user
Definition: settings.h:389
static void terminate(bool t=true)
Request termination of checking.
Definition: settings.h:444
bool debugtemplate
Is –debug-template given?
Definition: settings.h:180
static std::string loadCppcheckCfg(Settings &settings, Suppressions &suppressions)
Definition: settings.cpp:65
bool quiet
Is –quiet given?
Definition: settings.h:282
bool checkLibrary
Check for incomplete info in library files?
Definition: settings.h:135
std::string addEnabled(const std::string &str)
Enable extra checks by id.
Definition: settings.cpp:242
bool preprocessOnly
Using -E for debugging purposes.
Definition: settings.h:279
std::set< std::string > configExcludePaths
include paths excluded from checking the configuration
Definition: settings.h:162
int exitCode
If errors are found, this value is returned from main().
Definition: settings.h:214
std::size_t valueFlowMaxIterations
the maximum iterations of valueflow (–valueflow-max-iterations=T)
Definition: settings.h:395
bool checkAllConfigurations
check all configurations (false if -D or –max-configs is used
Definition: settings.h:124
std::vector< std::string > basePaths
Paths used as base for conversion to relative paths.
Definition: settings.h:118
int loadAverage
Load average value.
Definition: settings.h:240
int maxCtuDepth
–max-ctu-depth
Definition: settings.h:247
int reportProgress
–report-progress
Definition: settings.h:288
Suppressions supprs
suppressions
Definition: settings.h:369
std::string plistOutput
plist output (–plist-output=<dir>)
Definition: settings.h:270
std::string templateFormat
The output format in which the errors are printed in text mode, e.g.
Definition: settings.h:373
std::string clangExecutable
Custom Clang executable.
Definition: settings.h:153
Standards::Language enforcedLang
Name of the language that is enforced.
Definition: settings.h:190
std::string exename
Definition: settings.h:210
SimpleEnableGroup< Checks > checks
Definition: settings.h:360
bool xml
write XML results (–xml)
Definition: settings.h:401
bool checkConfiguration
Is the 'configuration checking' wanted?
Definition: settings.h:127
bool relativePaths
Use relative paths in output.
Definition: settings.h:285
std::unordered_set< std::string > addons
addons, either filename of python/json file or json data
Definition: settings.h:109
Library library
Library.
Definition: settings.h:237
bool clang
Use Clang.
Definition: settings.h:150
bool safety
Safety certified behavior Show checkers report when Cppcheck finishes Make cppcheck checking more str...
Definition: settings.h:313
std::size_t typedefMaxTime
The maximum time in seconds for the typedef simplification.
Definition: settings.h:383
std::string removeEnabled(const std::string &str)
Disable extra checks by id.
Definition: settings.cpp:247
std::string buildDir
–cppcheck-build-dir.
Definition: settings.h:121
std::string templateLocation
The output format in which the error locations are printed in text mode, e.g.
Definition: settings.h:377
std::string cppcheckCfgProductName
cppcheck.cfg: Custom product name
Definition: settings.h:165
std::string userDefines
defines given by the user
Definition: settings.h:386
std::vector< AddonInfo > addonInfos
the loaded addons infos
Definition: settings.h:112
std::string premiumArgs
Extra arguments for Cppcheck Premium addon.
Definition: settings.h:273
bool inlineSuppressions
Is –inline-suppr given?
Definition: settings.h:227
Platform platform
Definition: settings.h:255
bool dump
Is –dump given?
Definition: settings.h:186
void setCheckLevel(CheckLevel level)
Definition: settings.cpp:288
int performanceValueFlowMaxTime
Experimental: –performance-valueflow-max-time=T.
Definition: settings.h:258
int xml_version
XML version (–xml-version=..)
Definition: settings.h:404
int performanceValueFlowMaxIfCount
–performance-valueflow-max-if-count=C
Definition: settings.h:261
int checksMaxTime
The maximum time in seconds for the checks of a single file.
Definition: settings.h:138
std::string outputFile
write results (–output-file=<file>)
Definition: settings.h:253
bool useSingleJob() const
Definition: settings.h:457
static ExecutorType defaultExecutor()
Definition: settings.cpp:615
unsigned int jobs
How many processes/threads should do checking at the same time.
Definition: settings.h:231
bool debugnormal
Is –debug-normal given?
Definition: settings.h:174
bool force
Force checking the files with "too many" configurations (–force).
Definition: settings.h:220
bool daca
Are we running from DACA script?
Definition: settings.h:171
bool verbose
Is –verbose given?
Definition: settings.h:398
ExecutorType executor
Definition: settings.h:207
std::list< std::string > libraries
–library=
Definition: settings.h:234
std::list< std::string > includePaths
List of include paths, e.g.
Definition: settings.h:224
SimpleEnableGroup< Certainty > certainty
Definition: settings.h:359
SHOWTIME_MODES showtime
show timing information (–showtime=file|summary|top5)
Definition: settings.h:363
std::list< std::string > userIncludes
forced includes given by the user
Definition: settings.h:392
int maxConfigs
Maximum number of configurations to check before bailing.
Definition: settings.h:244
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
std::size_t templateMaxTime
The maximum time in seconds for the template instantiation.
Definition: settings.h:380
bool debugSimplified
Is –debug-simplified given?
Definition: settings.h:177
std::string checkersReportFilename
–checkers-report=<filename> : Generate report of executed checkers
Definition: settings.h:141
std::vector< std::string > fileFilters
List of –file-filter for analyzing special files.
Definition: settings.h:217
std::string addonPython
Path to the python interpreter to be used to run addons.
Definition: settings.h:115
bool debugwarnings
Is –debug-warnings given?
Definition: settings.h:183
Standards standards
Struct contains standards settings.
Definition: settings.h:366
bool isEnabled(T flag) const
Definition: settings.h:66
void enable(T flag)
Definition: settings.h:69
std::string addSuppressionLine(const std::string &line)
Don't show the given error.
std::string parseXmlFile(const char *filename)
Don't show errors listed in the file.
std::string parseFile(std::istream &istr)
Don't show errors listed in the file.
static bool addIncludePathsToList(const std::string &fileList, std::list< std::string > &pathNames)
static bool addFilesToList(const std::string &fileList, std::vector< std::string > &pathNames)
static bool addPathsToSet(const std::string &fileName, std::set< std::string > &set)
Color
Definition: color.h:27
void substituteTemplateFormatStatic(std::string &templateFormat)
replaces the static parts of the location template
void substituteTemplateLocationStatic(std::string &templateLocation)
replaces the static parts of the location template
Severity severityFromString(const std::string &severity)
Definition: errortypes.cpp:76
@ none
No severity (default value).
@ information
Checking information.
@ unusedFunction
std::string getAddonInfo(const std::string &fileName, const std::string &exename)
Definition: addoninfo.cpp:127
File settings.
Definition: filesettings.h:57
std::string getC() const
Definition: standards.h:64
enum Standards::cstd_t c
std::string getCPP() const
Definition: standards.h:103
enum Standards::cppstd_t cpp
SuppressionList nofail
suppress exitcode
Definition: suppressions.h:266
SuppressionList nomsg
suppress message (–suppressions)
Definition: suppressions.h:264
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
bool strToInt(const std::string &str, T &num, std::string *err=nullptr)
Definition: utils.h:211
bool endsWith(const std::string &str, char c)
Definition: utils.h:110
static T * empty_if_null(T *p)
Definition: utils.h:382