carl  24.04
Computer ARithmetic Library
SettingsParser.cpp
Go to the documentation of this file.
1 #include "SettingsParser.h"
2 
3 #include "settings_utils.h"
4 
5 #include <boost/any.hpp>
6 #if __has_include(<filesystem>)
7 #include <filesystem>
8 namespace fs = std::filesystem;
9 #else
10 #include <experimental/filesystem>
11 namespace fs = std::experimental::filesystem;
12 #endif
13 #include <algorithm>
14 
15 namespace carl::settings {
16 
17 std::ostream& operator<<(std::ostream& os, const boost::any& val) {
18  if (val.empty()) {
19  return os << "<empty>";
20  } else if (boost::any_cast<bool>(&val) != nullptr) {
21  return os << std::boolalpha << boost::any_cast<bool>(val);
22  } else if (boost::any_cast<std::size_t>(&val) != nullptr) {
23  return os << boost::any_cast<std::size_t>(val);
24  } else if (boost::any_cast<std::string>(&val) != nullptr) {
25  return os << boost::any_cast<std::string>(val);
26  } else if (boost::any_cast<carl::settings::duration>(&val) != nullptr) {
27  return os << boost::any_cast<carl::settings::duration>(val);
28  } else if (boost::any_cast<carl::settings::binary_quantity>(&val) != nullptr) {
29  return os << boost::any_cast<carl::settings::binary_quantity>(val);
30  } else if (boost::any_cast<carl::settings::metric_quantity>(&val) != nullptr) {
31  return os << boost::any_cast<carl::settings::metric_quantity>(val);
32  }
33  return os << "Unknown type";
34 }
35 
36 
37 std::ostream& operator<<(std::ostream& os, OptionPrinter op) {
38  if (op.parser.argv_zero == nullptr) {
39  os << "Usage: <binary> [options]";
40  } else {
41  os << "Usage: " << op.parser.argv_zero << " [options]";
42  }
43  for (unsigned i = 0; i < op.parser.mPositional.max_total_count(); ++i) {
44  os << " " << op.parser.mPositional.name_for_position(i);
45  }
46  os << std::endl;
47  return os << op.parser.mAllOptions;
48 }
49 std::ostream& operator<<(std::ostream& os, SettingsPrinter sp) {
50  for (const auto& option: sp.parser.mAllOptions.options()) {
51  auto value = sp.parser.mValues[option->canonical_display_name()];
52  os << option->canonical_display_name() << " = " << value.value() << std::endl;
53  }
54  return os;
55 }
56 
57 void SettingsParser::warn_for_unrecognized(const po::parsed_options& parsed) const {
58  auto res = po::collect_unrecognized(parsed.options, po::exclude_positional);
59  for (const auto& s: res) {
61  }
62 }
63 
64 void SettingsParser::parse_command_line(int argc, char* argv[], bool allow_unregistered) {
65  auto parser = po::command_line_parser(argc, argv).options(mAllOptions).positional(mPositional);
66  if (allow_unregistered) {
67  parser.allow_unregistered();
68  }
69  auto parsed = parser.run();
70  if (allow_unregistered) {
71  warn_for_unrecognized(parsed);
72  }
73  po::store(parsed, mValues);
74 }
75 
76 void SettingsParser::parse_config_file(bool allow_unregistered) {
77  fs::path configfile(mValues[this->name_of_config_file()].as<std::string>());
78  if (fs::is_regular_file(configfile)) {
79  auto parsed = po::parse_config_file<char>(configfile.c_str(), mAllOptions, allow_unregistered);
80  if (allow_unregistered) {
81  warn_for_unrecognized(parsed);
82  }
83  po::store(parsed, mValues);
84  } else {
85  warn_config_file(configfile);
86  }
87 }
88 
90  return std::any_of(mFinalizer.begin(), mFinalizer.end(),
91  [](const auto& f){ return f(); }
92  );
93 }
94 
96  for (const auto& po: mOptions) {
97  mAllOptions.add(po);
98  }
99 }
100 
101 void SettingsParser::parse_options(int argc, char* argv[], bool allow_unregistered) {
102  argv_zero = argv[0];
103  parse_command_line(argc, argv, allow_unregistered);
104  if (mValues.count(this->name_of_config_file()) != 0) {
105  parse_config_file(allow_unregistered);
106  }
107  po::notify(mValues);
108  if (finalize_settings()) {
109  po::notify(mValues);
110  }
111 }
112 
113 }
std::ostream & operator<<(std::ostream &os, const duration &d)
Streaming operator for duration. Auto-detects proper time suffix.
Helper class to nicely print the options that are available.
const SettingsParser & parser
Reference to parser.
Helper class to nicely print the settings that were parsed.
const SettingsParser & parser
Reference to parser.
void parse_options(int argc, char *argv[], bool allow_unregistered=true)
Parse the options.
void finalize()
Finalizes the parser.
bool finalize_settings()
Calls the finalizer functions.
std::vector< po::options_description > mOptions
Stores the individual options until the parser is finalized.
void parse_config_file(bool allow_unregistered)
Parses the config file if one was configured.
virtual void warn_config_file(const std::string &file) const
Prints a warning if loading the config file failed. Can be overridden.
po::options_description mAllOptions
Accumulates all available options.
po::positional_options_description mPositional
Stores the positional arguments.
virtual void warn_for_unrecognized_option(const std::string &s) const
Prints a warning if an option was unrecognized. Can be overridden.
virtual std::string name_of_config_file() const
Gives the option name for the config file name. Can be overridden.
po::variables_map mValues
Stores the parsed values.
void warn_for_unrecognized(const po::parsed_options &parsed) const
Checks for unrecognized options that were found.
void parse_command_line(int argc, char *argv[], bool allow_unregistered)
Parses the command line.
std::vector< std::function< bool()> > mFinalizer
Stores hooks for setting object finalizer functions.
char * argv_zero
Stores the name of the current binary.