#include "Settings.h" #include #include #include #include "src/exceptions/OptionParserException.h" // Static Inits storm::settings::Destroyer storm::settings::Settings::destroyer; /*! * @brief Create new instance. * * Creates a new Settings instance and passes the arguments to the constructor of Settings. * * @param argc should be argc passed to main function * @param argv should be argv passed to main function * @param filename either NULL or name of config file * @return The new instance of Settings. */ void storm::settings::Settings::parse(int const argc, char const * const argv[]) { storm::settings::Settings* myInstance = storm::settings::Settings::getInstance(); myInstance->parseCommandLine(argc, argv); } bool storm::settings::Settings::hasAssignment(std::string const& option) { return (option.find_first_of('=', 0) != std::string::npos); } storm::settings::stringPair_t storm::settings::Settings::splitOptionString(std::string const& option) { size_t splitLocation = option.find_first_of('=', 0); if (splitLocation == std::string::npos) { // Second half is empty return std::make_pair(option, ""); } else if (splitLocation + 1 >= option.length()) { // Remove the = character return std::make_pair(option.substr(0, option.size() - 1), ""); } return std::make_pair(option.substr(0, splitLocation), option.substr(splitLocation + 1, std::string::npos)); } void storm::settings::Settings::handleAssignment(std::string const& longOptionName, std::vector arguments) { std::string optionName = storm::utility::StringHelper::stringToLower(longOptionName); Option* option = this->getPtrByLongName(optionName); // Mark as Set option->setHasOptionBeenSet(); uint_fast64_t givenArgsCount = arguments.size(); if (givenArgsCount > option->getArgumentCount()) { LOG4CPLUS_ERROR(logger, "Settings::handleAssignment: Unable to parse arguments for option \"" << longOptionName << "\": " << arguments.size() << " arguments given, but expected no more than " << option->getArgumentCount() << "."); throw storm::exceptions::OptionParserException() << "Unable to parse arguments for option \"" << longOptionName << "\": " << arguments.size() << " arguments given, but expected no more than " << option->getArgumentCount() << "."; } for (uint_fast64_t i = 0; i < option->getArgumentCount(); ++i) { if (i < givenArgsCount) { storm::settings::fromStringAssignmentResult_t assignmentResult = option->getArgument(i).fromStringValue(arguments.at(i)); if (!assignmentResult.first) { LOG4CPLUS_ERROR(logger, "Settings::handleAssignment: Unable to parse arguments for option \"" << longOptionName << "\": argument " << option->getArgument(i).getArgumentName() << " rejected the given value \"" << arguments.at(i) << "\" with message:\r\n" << assignmentResult.second << "."); throw storm::exceptions::OptionParserException() << "Unable to parse arguments for option \"" << longOptionName << "\": argument " << option->getArgument(i).getArgumentName() << " rejected the given value \"" << arguments.at(i) << "\" with message:\r\n" << assignmentResult.second << "."; } } else { // There is no given value for this argument, only optional if (!option->getArgument(i).getIsOptional()) { LOG4CPLUS_ERROR(logger, "Settings::handleAssignment: Unable to parse arguments for option \"" << longOptionName << "\": " << arguments.size() << " arguments given, but more arguments were expected."); throw storm::exceptions::OptionParserException() << "Unable to parse arguments for option \"" << longOptionName << "\": " << arguments.size() << " arguments given, but more arguments were expected."; } else { option->getArgument(i).setFromDefaultValue(); } } } } std::vector storm::settings::Settings::argvToStringArray(int const argc, char const * const argv[]) { // Ignore argv[0], it contains the program path and name std::vector result; for (int i = 1; i < argc; ++i) { result.push_back(std::string(argv[i])); } return result; } bool storm::settings::Settings::checkArgumentSyntaxForOption(std::string const& argvString) { if (argvString.size() < 2) { return false; } if ((argvString.at(0) != '-') || ((argvString.at(1) != '-') && !isalpha(argvString.at(1)))) { return false; } for (size_t i = 2; i < argvString.size(); ++i) { if (!isalpha(argvString.at(i))) { return false; } } return true; } std::vector storm::settings::Settings::scanForOptions(std::vector const& arguments) { std::vector result; result.reserve(arguments.size()); for (auto it = arguments.cbegin(); it != arguments.cend(); ++it) { result.push_back(checkArgumentSyntaxForOption(*it)); } return result; } void storm::settings::Settings::parseCommandLine(int const argc, char const * const argv[]) { LOG4CPLUS_DEBUG(logger, "Settings::parseCommandLine: Parsing " << argc << " arguments."); std::vector stringArgv = argvToStringArray(argc, argv); std::vector optionPositions = scanForOptions(stringArgv); bool optionActive = false; std::string longOptionName; std::vector argCache; for (size_t i = 0; i <= stringArgv.size(); ++i) { if (i == stringArgv.size()) { if (optionActive) { this->handleAssignment(longOptionName, argCache); argCache.clear(); } break; } else if (optionPositions.at(i)) { if (optionActive) { this->handleAssignment(longOptionName, argCache); argCache.clear(); } std::string const& nextOption = stringArgv.at(i); if (nextOption.at(0) == '-' && nextOption.at(1) != '-') { // Short Option std::string nextShortOptionName = storm::utility::StringHelper::stringToLower(nextOption.substr(1, nextOption.size() - 1)); if (!this->containsShortName(nextShortOptionName)) { LOG4CPLUS_ERROR(logger, "Settings::parseCommandLine: Unknown option name \"" << nextShortOptionName << "\"."); throw storm::exceptions::OptionParserException() << "Unknown option name \"" << nextShortOptionName << "\"."; } else { longOptionName = this->getByShortName(nextShortOptionName).getLongName(); optionActive = true; } } else { // Long Option std::string nextLongOptionName = storm::utility::StringHelper::stringToLower(nextOption.substr(2, nextOption.size() - 2)); if (!this->containsLongName(nextLongOptionName)) { LOG4CPLUS_ERROR(logger, "Settings::parseCommandLine: Unknown option name \"" << nextLongOptionName << "\"."); throw storm::exceptions::OptionParserException() << "Unknown option name \"" << nextLongOptionName << "\"."; } else { longOptionName = this->getByLongName(nextLongOptionName).getLongName(); optionActive = true; } } } else if (optionActive) { // Next argument for an Option found argCache.push_back(stringArgv.at(i)); } else { // No Option active and this is no option. LOG4CPLUS_ERROR(logger, "Settings::parseCommandLine: Found stray argument while parsing a given configuration, \"" << stringArgv.at(i) << "\" is neither a known option nor preceeded by an option."); throw storm::exceptions::OptionParserException() << "Found stray argument while parsing a given configuration; \"" << stringArgv.at(i) << "\" is neither a known option nor preceeded by an option."; } } for (auto it = this->options.cbegin(); it != this->options.cend(); ++it) { if (!it->second.get()->getHasOptionBeenSet()) { if (it->second.get()->getIsRequired()) { LOG4CPLUS_ERROR(logger, "Settings::parseCommandLine: Missing required option \"" << it->second.get()->getLongName() << "\"."); throw storm::exceptions::OptionParserException() << "Missing required option \"" << it->second.get()->getLongName() << "\"."; } else { // Set defaults on optional values for (uint_fast64_t i = 0; i < it->second.get()->getArgumentCount(); ++i) { if (it->second.get()->getArgument(i).getHasDefaultValue()) { it->second.get()->getArgument(i).setFromDefaultValue(); } } } } } } bool storm::settings::Settings::registerNewModule(ModuleRegistrationFunction_t registrationFunction) { Settings* myInstance = Settings::getInstance(); bool result = false; try { result = registrationFunction(myInstance); //LOG4CPLUS_DEBUG(logger, "Settings::registerNewModule: Successfully executed a registrationFunction"); } catch (storm::exceptions::IllegalArgumentException e) { //LOG4CPLUS_ERROR(logger, "Settings::registerNewModule: Internal Error while setting up available Options!" << std::endl << "IllegalArgumentException: " << e.what() << "."); std::cout << "Internal Error while setting up available options." << std::endl << "IllegalArgumentException: " << e.what() << "." << std::endl; return false; } catch (storm::exceptions::IllegalArgumentValueException e) { //LOG4CPLUS_ERROR(logger, "Settings::registerNewModule: Internal Error while setting up available Options!" << std::endl << "IllegalArgumentValueException: " << e.what() << "."); std::cout << "Internal Error while setting up available options." << std::endl << "IllegalArgumentValueException: " << e.what() << "." << std::endl; return false; } catch (storm::exceptions::IllegalFunctionCallException e) { //LOG4CPLUS_ERROR(logger, "Settings::registerNewModule: Internal Error while setting up available Options!" << std::endl << "IllegalFunctionCallException: " << e.what() << "."); std::cout << "Internal Error while setting up available options." << std::endl << "IllegalFunctionCallException: " << e.what() << "." << std::endl; return false; } catch (std::exception e) { //LOG4CPLUS_ERROR(logger, "Settings::registerNewModule: Internal Error while setting up available Options!" << std::endl << "std::exception: " << e.what() << "."); std::cout << "Internal Error while setting up available options." << std::endl << "std::exception: " << e.what() << "." << std::endl; return false; } return result; } storm::settings::Settings* storm::settings::Settings::getInstance() { // Usually, this would require double-checked locking. // But since C++11, this is the way to go: static storm::settings::Settings pInstance; return &pInstance; } storm::settings::Settings& storm::settings::Settings::addOption(Option* option) { // For automatic management of option's lifetime std::shared_ptr