Storm
A Modern Probabilistic Model Checker
Loading...
Searching...
No Matches
SettingsManager.cpp
Go to the documentation of this file.
2
3#include <boost/algorithm/string.hpp>
4#include <boost/io/ios_state.hpp>
5#include <cstring>
6#include <fstream>
7#include <iomanip>
8#include <mutex>
9#include <regex>
10#include <set>
11
14#include "storm/io/file.h"
47
48namespace storm {
49namespace settings {
50
51SettingsManager::SettingsManager() : modules(), longNameToOptions(), shortNameToOptions(), moduleOptions() {}
52
53SettingsManager::~SettingsManager() {
54 // Intentionally left empty.
55}
56
57SettingsManager& SettingsManager::manager() {
58 static SettingsManager settingsManager;
59 return settingsManager;
60}
61
62void SettingsManager::setName(std::string const& name, std::string const& executableName) {
63 this->name = name;
64 this->executableName = executableName;
65}
66
67void SettingsManager::setFromCommandLine(int const argc, char const* const argv[]) {
68 // We convert the arguments to a vector of strings and strip off the first element since it refers to the
69 // name of the program.
70 std::vector<std::string> argumentVector(argc - 1);
71 for (int i = 1; i < argc; ++i) {
72 argumentVector[i - 1] = std::string(argv[i]);
73 }
74
75 this->setFromExplodedString(argumentVector);
76}
77
78void SettingsManager::setFromString(std::string const& commandLineString) {
79 if (commandLineString.empty()) {
80 this->setFromExplodedString({});
81 } else {
82 std::vector<std::string> argumentVector;
83 boost::split(argumentVector, commandLineString, boost::is_any_of("\t "));
84 this->setFromExplodedString(argumentVector);
85 }
86}
87
88void SettingsManager::handleUnknownOption(std::string const& optionName, bool isShort) const {
89 std::string optionNameWithDashes = (isShort ? "-" : "--") + optionName;
90 storm::utility::string::SimilarStrings similarStrings(optionNameWithDashes, 0.6, false);
91 std::map<std::string, std::vector<std::string>> similarOptionNames;
92 for (auto const& longOption : longNameToOptions) {
93 if (similarStrings.add("--" + longOption.first)) {
94 similarOptionNames["--" + longOption.first].push_back(longOption.first);
95 }
96 }
97 for (auto const& shortOption : shortNameToOptions) {
98 if (similarStrings.add("-" + shortOption.first)) {
99 for (auto const& option : shortOption.second) {
100 similarOptionNames["-" + shortOption.first].push_back(option->getLongName());
101 }
102 }
103 }
104 std::string errorMessage = "Unknown option '" + optionNameWithDashes + "'.";
105 if (!similarOptionNames.empty()) {
106 errorMessage += " " + similarStrings.toDidYouMeanString() + "\n\n";
107 std::vector<std::string> sortedSimilarOptionNames;
108 auto similarStringsList = similarStrings.toList();
109 for (auto const& s : similarStringsList) {
110 for (auto const& longOptionName : similarOptionNames.at(s)) {
111 sortedSimilarOptionNames.push_back(longOptionName);
112 }
113 }
114 errorMessage += getHelpForSelection({}, sortedSimilarOptionNames, "", "##### Suggested options:");
115 }
116 STORM_LOG_THROW(false, storm::exceptions::OptionParserException, errorMessage);
117}
118
119void SettingsManager::setFromExplodedString(std::vector<std::string> const& commandLineArguments) {
120 // In order to assign the parsed arguments to an option, we need to keep track of the "active" option's name.
121 bool optionActive = false;
122 bool activeOptionIsShortName = false;
123 std::string activeOptionName = "";
124 std::vector<std::string> argumentCache;
125
126 // Walk through all arguments.
127 for (uint_fast64_t i = 0; i < commandLineArguments.size(); ++i) {
128 std::string const& currentArgument = commandLineArguments[i];
129
130 // Check if the given argument is a new option or belongs to a previously given option.
131 if (!currentArgument.empty() && currentArgument.at(0) == '-') {
132 if (optionActive) {
133 // At this point we know that a new option is about to come. Hence, we need to assign the current
134 // cache content to the option that was active until now.
135 setOptionsArguments(activeOptionName, activeOptionIsShortName ? this->shortNameToOptions : this->longNameToOptions, argumentCache);
136
137 // After the assignment, the argument cache needs to be cleared.
138 argumentCache.clear();
139 } else {
140 optionActive = true;
141 }
142
143 if (currentArgument.at(1) == '-') {
144 // In this case, the argument has to be the long name of an option. Try to get all options that
145 // match the long name.
146 std::string optionName = currentArgument.substr(2);
147 auto optionIterator = this->longNameToOptions.find(optionName);
148 if (optionIterator == this->longNameToOptions.end()) {
149 handleUnknownOption(optionName, false);
150 }
151 activeOptionIsShortName = false;
152 activeOptionName = optionName;
153 } else {
154 // In this case, the argument has to be the short name of an option. Try to get all options that
155 // match the short name.
156 std::string optionName = currentArgument.substr(1);
157 auto optionIterator = this->shortNameToOptions.find(optionName);
158 if (optionIterator == this->shortNameToOptions.end()) {
159 handleUnknownOption(optionName, true);
160 }
161 activeOptionIsShortName = true;
162 activeOptionName = optionName;
163 }
164 } else if (optionActive) {
165 // Add the current argument to the list of arguments for the currently active options.
166 argumentCache.push_back(currentArgument);
167 } else {
168 STORM_LOG_THROW(false, storm::exceptions::OptionParserException,
169 "Found stray argument '" << currentArgument << "' that is not preceeded by a matching option.");
170 }
171 }
172
173 // If an option is still active at this point, we need to set it.
174 if (optionActive) {
175 setOptionsArguments(activeOptionName, activeOptionIsShortName ? this->shortNameToOptions : this->longNameToOptions, argumentCache);
176 }
177
178 // Include the options from a possibly specified configuration file, but don't overwrite existing settings.
181 this->setFromConfigurationFile(storm::settings::getModule<storm::settings::modules::GeneralSettings>().getConfigFilename());
182 }
183
184 // Finally, check whether all modules are okay with the current settings.
185 this->finalizeAllModules();
186}
187
188void SettingsManager::setFromConfigurationFile(std::string const& configFilename) {
189 std::map<std::string, std::vector<std::string>> configurationFileSettings = parseConfigFile(configFilename);
190
191 for (auto const& optionArgumentsPair : configurationFileSettings) {
192 auto options = this->longNameToOptions.find(optionArgumentsPair.first);
193
194 // We don't need to check whether this option exists or not, because this is already checked when
195 // parsing the configuration file.
196
197 // Now go through all the matching options and set them according to the values.
198 for (auto option : options->second) {
199 if (option->getHasOptionBeenSet()) {
200 // If the option was already set from the command line, we issue a warning and ignore the
201 // settings from the configuration file.
202 STORM_LOG_WARN("The option '" << option->getLongName() << "' of module '" << option->getModuleName()
203 << "' has been set in the configuration file '" << configFilename
204 << "', but was overwritten on the command line.\n");
205 } else {
206 // If, however, the option has not been set yet, we try to assign values ot its arguments
207 // based on the argument strings.
208 setOptionArguments(optionArgumentsPair.first, option, optionArgumentsPair.second);
209 }
210 }
211 }
212 // Finally, check whether all modules are okay with the current settings.
213 this->finalizeAllModules();
214}
215
216void SettingsManager::printHelp(std::string const& filter) const {
217 STORM_PRINT("usage: " << executableName << " [options]\n\n");
218
219 if (filter == "frequent" || filter == "all") {
220 bool includeAdvanced = (filter == "all");
221 // Find longest option name.
222 uint_fast64_t maxLength = getPrintLengthOfLongestOption(includeAdvanced);
223
224 std::vector<std::string> invisibleModules;
225 uint64_t numHidden = 0;
226 for (auto const& moduleName : this->moduleNames) {
227 // Only print for visible modules.
228 if (hasModule(moduleName, true)) {
229 STORM_PRINT(getHelpForModule(moduleName, maxLength, includeAdvanced));
230 // collect 'hidden' options
231 if (!includeAdvanced) {
232 auto moduleIterator = moduleOptions.find(moduleName);
233 if (moduleIterator != this->moduleOptions.end()) {
234 bool allAdvanced = true;
235 for (auto const& option : moduleIterator->second) {
236 if (!option->getIsAdvanced()) {
237 allAdvanced = false;
238 } else {
239 ++numHidden;
240 }
241 }
242 if (!moduleIterator->second.empty() && allAdvanced) {
243 invisibleModules.push_back(moduleName);
244 }
245 }
246 }
247 }
248 }
249 if (!includeAdvanced) {
250 if (numHidden == 1) {
251 STORM_PRINT(numHidden << " hidden option.\n");
252 } else {
253 STORM_PRINT(numHidden << " hidden options.\n");
254 }
255 if (!invisibleModules.empty()) {
256 if (invisibleModules.size() == 1) {
257 STORM_PRINT(invisibleModules.size() << " hidden module (" << boost::join(invisibleModules, ", ") << ").\n");
258 } else {
259 STORM_PRINT(invisibleModules.size() << " hidden modules (" << boost::join(invisibleModules, ", ") << ").\n");
260 }
261 }
262 STORM_PRINT("\nType '" + executableName + " --help modulename' to display all options of a specific module.\n");
263 STORM_PRINT("Type '" + executableName + " --help all' to display a complete list of options.\n");
264 }
265 } else {
266 // Create a regular expression from the input hint.
267 std::regex hintRegex(filter, std::regex_constants::ECMAScript | std::regex_constants::icase);
268
269 // Try to match the regular expression against the known modules.
270 std::vector<std::string> matchingModuleNames;
271 for (auto const& moduleName : this->moduleNames) {
272 if (std::regex_search(moduleName, hintRegex)) {
273 if (hasModule(moduleName, true)) {
274 matchingModuleNames.push_back(moduleName);
275 }
276 }
277 }
278
279 // Try to match the regular expression against the known options.
280 std::vector<std::string> matchingOptionNames;
281 for (auto const& optionName : this->longOptionNames) {
282 if (std::regex_search(optionName, hintRegex)) {
283 matchingOptionNames.push_back(optionName);
284 }
285 }
286
287 std::string optionList = getHelpForSelection(matchingModuleNames, matchingOptionNames,
288 "Matching modules for filter '" + filter + "':", "Matching options for filter '" + filter + "':");
289 if (optionList.empty()) {
290 STORM_PRINT("Filter '" << filter << "' did not match any modules or options.\n");
291 } else {
292 STORM_PRINT(optionList);
293 }
294 }
295}
296
297std::string SettingsManager::getHelpForSelection(std::vector<std::string> const& selectedModuleNames, std::vector<std::string> const& selectedLongOptionNames,
298 std::string modulesHeader, std::string optionsHeader) const {
299 std::stringstream stream;
300
301 // Remember which options we printed, so we don't display options twice.
302 std::set<std::shared_ptr<Option>> printedOptions;
303
304 // Try to match the regular expression against the known modules.
305 uint_fast64_t maxLengthModules = 0;
306 for (auto const& moduleName : selectedModuleNames) {
307 maxLengthModules = std::max(maxLengthModules, getPrintLengthOfLongestOption(moduleName, true));
308 // Add all options of this module to the list of printed options so we don't print them twice.
309 auto optionIterator = this->moduleOptions.find(moduleName);
310 STORM_LOG_ASSERT(optionIterator != this->moduleOptions.end(), "Unable to find selected module " << moduleName << ".");
311 printedOptions.insert(optionIterator->second.begin(), optionIterator->second.end());
312 }
313
314 // Try to match the regular expression against the known options.
315 std::vector<std::shared_ptr<Option>> matchingOptions;
316 uint_fast64_t maxLengthOptions = 0;
317 for (auto const& optionName : selectedLongOptionNames) {
318 auto optionIterator = this->longNameToOptions.find(optionName);
319 STORM_LOG_ASSERT(optionIterator != this->longNameToOptions.end(), "Unable to find selected option " << optionName << ".");
320 for (auto const& option : optionIterator->second) {
321 // Only add the option if we have not already added it to the list of options that is going
322 // to be printed anyway.
323 if (printedOptions.find(option) == printedOptions.end()) {
324 maxLengthOptions = std::max(maxLengthOptions, option->getPrintLength());
325 matchingOptions.push_back(option);
326 printedOptions.insert(option);
327 }
328 }
329 }
330
331 // Print the matching modules.
332 uint_fast64_t maxLength = std::max(maxLengthModules, maxLengthOptions);
333 if (selectedModuleNames.size() > 0) {
334 if (modulesHeader != "") {
335 stream << modulesHeader << '\n';
336 }
337 for (auto const& matchingModuleName : selectedModuleNames) {
338 stream << getHelpForModule(matchingModuleName, maxLength, true);
339 }
340 }
341
342 // Print the matching options.
343 if (matchingOptions.size() > 0) {
344 if (optionsHeader != "") {
345 stream << optionsHeader << '\n';
346 }
347 for (auto const& option : matchingOptions) {
348 stream << std::setw(maxLength) << std::left << *option << '\n';
349 }
350 }
351 return stream.str();
352}
353
354std::string SettingsManager::getHelpForModule(std::string const& moduleName, uint_fast64_t maxLength, bool includeAdvanced) const {
355 auto moduleIterator = moduleOptions.find(moduleName);
356 if (moduleIterator == this->moduleOptions.end()) {
357 return "";
358 }
359 // STORM_LOG_THROW(moduleIterator != moduleOptions.end(), storm::exceptions::IllegalFunctionCallException, "Cannot print help for unknown module '" <<
360 // moduleName << "'.");
361
362 // Check whether there is at least one (enabled) option in this module
363 uint64_t numOfOptions = 0;
364 for (auto const& option : moduleIterator->second) {
365 if (includeAdvanced || !option->getIsAdvanced()) {
366 ++numOfOptions;
367 }
368 }
369
370 std::stringstream stream;
371 if (numOfOptions > 0) {
372 std::string displayedModuleName = "'" + moduleName + "'";
373 if (!includeAdvanced) {
374 displayedModuleName += " (" + std::to_string(numOfOptions) + "/" + std::to_string(moduleIterator->second.size()) + " shown)";
375 }
376 stream << "##### Module " << displayedModuleName << " " << std::string(std::min(maxLength, maxLength - displayedModuleName.length() - 14), '#') << '\n';
377
378 // Save the flags for std::cout so we can manipulate them and be sure they will be restored as soon as this
379 // stream goes out of scope.
380 boost::io::ios_flags_saver out(std::cout);
381
382 for (auto const& option : moduleIterator->second) {
383 if (includeAdvanced || !option->getIsAdvanced()) {
384 stream << std::setw(maxLength) << std::left << *option << '\n';
385 }
386 }
387 stream << '\n';
388 }
389 return stream.str();
390}
391
392uint_fast64_t SettingsManager::getPrintLengthOfLongestOption(bool includeAdvanced) const {
393 uint_fast64_t length = 0;
394 for (auto const& moduleName : this->moduleNames) {
395 length = std::max(getPrintLengthOfLongestOption(moduleName, includeAdvanced), length);
396 }
397 return length;
398}
399
400uint_fast64_t SettingsManager::getPrintLengthOfLongestOption(std::string const& moduleName, bool includeAdvanced) const {
401 auto moduleIterator = modules.find(moduleName);
402 STORM_LOG_THROW(moduleIterator != modules.end(), storm::exceptions::IllegalFunctionCallException,
403 "Unable to retrieve option length of unknown module '" << moduleName << "'.");
404 return moduleIterator->second->getPrintLengthOfLongestOption(includeAdvanced);
405}
406
407void SettingsManager::addModule(std::unique_ptr<modules::ModuleSettings>&& moduleSettings, bool doRegister) {
408 auto moduleIterator = this->modules.find(moduleSettings->getModuleName());
409 STORM_LOG_THROW(moduleIterator == this->modules.end(), storm::exceptions::IllegalFunctionCallException,
410 "Unable to register module '" << moduleSettings->getModuleName() << "' because a module with the same name already exists.");
411
412 // Take over the module settings object.
413 std::string moduleName = moduleSettings->getModuleName();
414 this->moduleNames.push_back(moduleName);
415 this->modules.emplace(moduleSettings->getModuleName(), std::move(moduleSettings));
416 auto iterator = this->modules.find(moduleName);
417 std::unique_ptr<modules::ModuleSettings> const& settings = iterator->second;
418
419 if (doRegister) {
420 this->moduleOptions.emplace(moduleName, std::vector<std::shared_ptr<Option>>());
421 // Now register the options of the module.
422 for (auto const& option : settings->getOptions()) {
423 this->addOption(option);
424 }
425 }
426}
427
428void SettingsManager::addOption(std::shared_ptr<Option> const& option) {
429 // First, we register to which module the given option belongs.
430 auto moduleOptionIterator = this->moduleOptions.find(option->getModuleName());
431 STORM_LOG_THROW(moduleOptionIterator != this->moduleOptions.end(), storm::exceptions::IllegalFunctionCallException,
432 "Cannot add option for unknown module '" << option->getModuleName() << "'.");
433 moduleOptionIterator->second.emplace_back(option);
434
435 // Then, we add the option's name (and possibly short name) to the registered options. If a module prefix is
436 // not required for this option, we have to add both versions to our mappings, the prefixed one and the
437 // non-prefixed one.
438 if (!option->getRequiresModulePrefix()) {
439 bool isCompatible = this->isCompatible(option, option->getLongName(), this->longNameToOptions);
440 STORM_LOG_THROW(isCompatible, storm::exceptions::IllegalFunctionCallException,
441 "Unable to add option '" << option->getLongName() << "', because an option with the same name is incompatible with it.");
442 addOptionToMap(option->getLongName(), option, this->longNameToOptions);
443 }
444 // For the prefixed name, we don't need a compatibility check, because a module is not allowed to register the same option twice.
445 addOptionToMap(option->getModuleName() + ":" + option->getLongName(), option, this->longNameToOptions);
446 longOptionNames.push_back(option->getModuleName() + ":" + option->getLongName());
447
448 if (option->getHasShortName()) {
449 if (!option->getRequiresModulePrefix()) {
450 bool isCompatible = this->isCompatible(option, option->getShortName(), this->shortNameToOptions);
451 STORM_LOG_THROW(isCompatible, storm::exceptions::IllegalFunctionCallException,
452 "Unable to add option '" << option->getLongName() << "', because an option with the same name is incompatible with it.");
453 addOptionToMap(option->getShortName(), option, this->shortNameToOptions);
454 }
455 addOptionToMap(option->getModuleName() + ":" + option->getShortName(), option, this->shortNameToOptions);
456 }
457}
458
459bool SettingsManager::hasModule(std::string const& moduleName, bool checkHidden) const {
460 if (checkHidden) {
461 return this->moduleOptions.find(moduleName) != this->moduleOptions.end();
462 } else {
463 return this->modules.find(moduleName) != this->modules.end();
464 }
465}
466
467modules::ModuleSettings const& SettingsManager::getModule(std::string const& moduleName) const {
468 auto moduleIterator = this->modules.find(moduleName);
469 STORM_LOG_THROW(moduleIterator != this->modules.end(), storm::exceptions::IllegalFunctionCallException,
470 "Cannot retrieve unknown module '" << moduleName << "'.");
471 return *moduleIterator->second;
472}
473
474modules::ModuleSettings& SettingsManager::getModule(std::string const& moduleName) {
475 auto moduleIterator = this->modules.find(moduleName);
476 STORM_LOG_THROW(moduleIterator != this->modules.end(), storm::exceptions::IllegalFunctionCallException,
477 "Cannot retrieve unknown module '" << moduleName << "'.");
478 return *moduleIterator->second;
479}
480
481bool SettingsManager::isCompatible(std::shared_ptr<Option> const& option, std::string const& optionName,
482 std::unordered_map<std::string, std::vector<std::shared_ptr<Option>>> const& optionMap) {
483 auto optionIterator = optionMap.find(optionName);
484 if (optionIterator != optionMap.end()) {
485 for (auto const& otherOption : optionIterator->second) {
486 bool locallyCompatible = option->isCompatibleWith(*otherOption);
487 if (!locallyCompatible) {
488 return false;
489 }
490 }
491 }
492 return true;
493}
494
495void SettingsManager::setOptionArguments(std::string const& optionName, std::shared_ptr<Option> option, std::vector<std::string> const& argumentCache) {
496 STORM_LOG_THROW(argumentCache.size() <= option->getArgumentCount(), storm::exceptions::OptionParserException,
497 "Too many arguments for option '" << optionName << "'.");
498 STORM_LOG_THROW(!option->getHasOptionBeenSet(), storm::exceptions::OptionParserException, "Option '" << optionName << "' is set multiple times.");
499
500 // Now set the provided argument values one by one.
501 for (uint_fast64_t i = 0; i < argumentCache.size(); ++i) {
502 ArgumentBase& argument = option->getArgument(i);
503 bool conversionOk = argument.setFromStringValue(argumentCache[i]);
504 STORM_LOG_THROW(conversionOk, storm::exceptions::OptionParserException,
505 "Value '" << argumentCache[i] << "' is invalid for argument <" << argument.getName() << "> of option:\n"
506 << *option);
507 }
508
509 // In case there are optional arguments that were not set, we set them to their default value.
510 for (uint_fast64_t i = argumentCache.size(); i < option->getArgumentCount(); ++i) {
511 ArgumentBase& argument = option->getArgument(i);
512 STORM_LOG_THROW(argument.getIsOptional(), storm::exceptions::OptionParserException,
513 "Non-optional argument <" << argument.getName() << "> of option:\n"
514 << *option);
515 argument.setFromDefaultValue();
516 }
517
518 option->setHasOptionBeenSet();
519 if (optionName != option->getLongName() && optionName != option->getShortName() && boost::starts_with(optionName, option->getModuleName())) {
520 option->setHasOptionBeenSetWithModulePrefix();
521 }
522}
523
524void SettingsManager::setOptionsArguments(std::string const& optionName, std::unordered_map<std::string, std::vector<std::shared_ptr<Option>>> const& optionMap,
525 std::vector<std::string> const& argumentCache) {
526 auto optionIterator = optionMap.find(optionName);
527 STORM_LOG_THROW(optionIterator != optionMap.end(), storm::exceptions::OptionParserException, "Unknown option '" << optionName << "'.");
528
529 // Iterate over all options and set the arguments.
530 for (auto& option : optionIterator->second) {
531 setOptionArguments(optionName, option, argumentCache);
532 }
533}
534
535void SettingsManager::addOptionToMap(std::string const& name, std::shared_ptr<Option> const& option,
536 std::unordered_map<std::string, std::vector<std::shared_ptr<Option>>>& optionMap) {
537 auto optionIterator = optionMap.find(name);
538 if (optionIterator == optionMap.end()) {
539 std::vector<std::shared_ptr<Option>> optionVector;
540 optionVector.push_back(option);
541 optionMap.emplace(name, optionVector);
542 } else {
543 optionIterator->second.push_back(option);
544 }
545}
546
547void SettingsManager::finalizeAllModules() {
548 for (auto const& nameModulePair : this->modules) {
549 nameModulePair.second->finalize();
550 nameModulePair.second->check();
551 }
552}
553
554std::map<std::string, std::vector<std::string>> SettingsManager::parseConfigFile(std::string const& filename) const {
555 std::map<std::string, std::vector<std::string>> result;
556
557 std::ifstream input;
558 storm::io::openFile(filename, input);
559
560 bool globalScope = true;
561 std::string activeModule = "";
562 uint_fast64_t lineNumber = 1;
563 for (std::string line; storm::io::getline(input, line); ++lineNumber) {
564 // If the first character of the line is a "[", we expect the settings of a new module to start and
565 // the line to be of the shape [<module>].
566 if (line.at(0) == '[') {
568 line.at(0) == '[' && line.find("]") == line.length() - 1 && line.find("[", 1) == line.npos, storm::exceptions::OptionParserException,
569 "Illegal module name header in configuration file '" << filename << " in line " << std::to_string(lineNumber)
570 << ". Expected [<module>] where <module> is a placeholder for a known module.");
571
572 // Extract the module name and check whether it's a legal one.
573 std::string moduleName = line.substr(1, line.length() - 2);
574 STORM_LOG_THROW(moduleName != "" && (moduleName == "global" || (this->modules.find(moduleName) != this->modules.end())),
575 storm::exceptions::OptionParserException,
576 "Module header in configuration file '" << filename << " in line " << std::to_string(lineNumber) << " refers to unknown module '"
577 << moduleName << ".");
578
579 // If the module name is "global", we unset the currently active module and treat all options to follow as unprefixed.
580 if (moduleName == "global") {
581 globalScope = true;
582 } else {
583 activeModule = moduleName;
584 globalScope = false;
585 }
586 } else {
587 // In this case, we expect the line to be of the shape o or o=a b c, where o is an option and a, b
588 // and c are the values that are supposed to be assigned to the arguments of the option.
589 std::size_t assignmentSignIndex = line.find("=");
590 bool containsAssignment = false;
591 if (assignmentSignIndex != line.npos) {
592 containsAssignment = true;
593 }
594
595 std::string optionName;
596 if (containsAssignment) {
597 optionName = line.substr(0, assignmentSignIndex);
598 } else {
599 optionName = line;
600 }
601
602 if (globalScope) {
603 STORM_LOG_THROW(this->longNameToOptions.find(optionName) != this->longNameToOptions.end(), storm::exceptions::OptionParserException,
604 "Option assignment in configuration file '" << filename << " in line " << lineNumber << " refers to unknown option '"
605 << optionName << "'.");
606 } else {
607 STORM_LOG_THROW(this->longNameToOptions.find(activeModule + ":" + optionName) != this->longNameToOptions.end(),
608 storm::exceptions::OptionParserException,
609 "Option assignment in configuration file '" << filename << " in line " << lineNumber << " refers to unknown option '"
610 << activeModule << ":" << optionName << "'.");
611 }
612
613 std::string fullOptionName = (!globalScope ? activeModule + ":" : "") + optionName;
614 STORM_LOG_WARN_COND(result.find(fullOptionName) == result.end(), "Option '" << fullOptionName << "' is set in line " << lineNumber
615 << " of configuration file " << filename
616 << ", but has been set before.");
617
618 // If the current line is an assignment, split the right-hand side of the assignment into parts
619 // enclosed by quotation marks.
620 if (containsAssignment) {
621 std::string assignedValues = line.substr(assignmentSignIndex + 1);
622 std::vector<std::string> argumentCache;
623
624 // As horrible as it may look, this regular expression matches either a quoted string (possibly
625 // containing escaped quotes) or a simple word (without whitespaces and quotes).
626 std::regex argumentRegex("\"(([^\\\\\"]|((\\\\\\\\)*\\\\\")|\\\\[^\"])*)\"|(([^ \\\\\"]|((\\\\\\\\)*\\\\\")|\\\\[^\"])+)");
627 boost::algorithm::trim_left(assignedValues);
628
629 while (!assignedValues.empty()) {
630 std::smatch match;
631 bool hasMatch = std::regex_search(assignedValues, match, argumentRegex);
632
633 // If the input could not be matched, we have a parsing error.
635 hasMatch, storm::exceptions::OptionParserException,
636 "Parsing error in configuration file '" << filename << "' in line " << lineNumber << ". Unexpected input '" << assignedValues << "'.");
637
638 // Extract the matched argument and cut off the quotation marks if necessary.
639 std::string matchedArgument = std::string(match[0].first, match[0].second);
640 if (matchedArgument.at(0) == '"') {
641 matchedArgument = matchedArgument.substr(1, matchedArgument.length() - 2);
642 }
643 argumentCache.push_back(matchedArgument);
644
645 assignedValues = assignedValues.substr(match.length());
646 boost::algorithm::trim_left(assignedValues);
647 }
648
649 // After successfully parsing the argument values, we store them in the result map.
650 result.emplace(fullOptionName, argumentCache);
651 } else {
652 // In this case, we can just insert the option to indicate it should be set (without arguments).
653 result.emplace(fullOptionName, std::vector<std::string>());
654 }
655 }
656 }
657
659 return result;
660}
661
663 return SettingsManager::manager();
664}
665
667 return SettingsManager::manager();
668}
669
673
677
678void initializeAll(std::string const& name, std::string const& executableName) {
679 storm::settings::mutableManager().setName(name, executableName);
680
681 // Register all known settings modules.
711}
712
713} // namespace settings
714} // namespace storm
Provides the central API for the registration of command line options and parsing the options from th...
void setName(std::string const &name, std::string const &executableName)
Sets the name of the tool.
modules::ModuleSettings const & getModule(std::string const &moduleName) const
Retrieves the settings of the module with the given name.
This class represents the settings for the abstraction procedures.
This is the base class of the settings for a particular module.
bool add(std::string const &string)
Adds the given string to the set of similar strings (if it is similar)
Definition string.cpp:18
std::string toDidYouMeanString() const
Returns a "Did you mean abc?" string.
Definition string.cpp:34
std::vector< std::string > toList() const
Gets a list of all added strings that are similar to the reference string.
Definition string.cpp:26
#define STORM_LOG_WARN(message)
Definition logging.h:30
#define STORM_LOG_ASSERT(cond, message)
Definition macros.h:11
#define STORM_LOG_WARN_COND(cond, message)
Definition macros.h:38
#define STORM_LOG_THROW(cond, exception, message)
Definition macros.h:30
#define STORM_PRINT(message)
Define the macros that print information and optionally also log it.
Definition macros.h:62
std::basic_istream< CharT, Traits > & getline(std::basic_istream< CharT, Traits > &input, std::basic_string< CharT, Traits, Allocator > &str)
Overloaded getline function which handles different types of newline ( and \r).
Definition file.h:80
void closeFile(std::ofstream &stream)
Close the given file after writing.
Definition file.h:47
void openFile(std::string const &filepath, std::ofstream &filestream, bool append=false, bool silent=false)
Open the given file for writing.
Definition file.h:18
storm::settings::modules::BuildSettings & mutableBuildSettings()
Retrieves the build settings in a mutable form.
storm::settings::modules::AbstractionSettings & mutableAbstractionSettings()
Retrieves the abstraction settings in a mutable form.
bool hasModule()
Returns true if the given module is registered.
SettingsType const & getModule()
Get module.
void initializeAll(std::string const &name, std::string const &executableName)
Initialize the settings manager with all available modules.
SettingsManager const & manager()
Retrieves the settings manager.
SettingsManager & mutableManager()
Retrieves the settings manager.
LabParser.cpp.
Definition cli.cpp:18