/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * CommandLineParser.cpp * * Created on: May 8, 2010 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "CodePatterns/MemDebug.hpp" #include #include #include #include #include #include #include "Actions/Action.hpp" #include "Actions/ActionRegistry.hpp" #include "Actions/ActionTrait.hpp" #include "Actions/OptionRegistry.hpp" #include "Actions/OptionTrait.hpp" #include "Actions/Values.hpp" #include "CodePatterns/Log.hpp" #include "CodePatterns/Verbose.hpp" #include "CommandLineParser.hpp" #include "CommandLineParser_validate.hpp" #include "CodePatterns/Singleton_impl.hpp" using namespace MoleCuilder; class element; /** Constructor of class CommandLineParser. * */ CommandLineParser::CommandLineParser() : analysis("Analysis options"), atom("Atom options"), command("Command options"), fill("fill options"), fragmentation("Fragmentation options"), graph("Graph options"), molecule("Molecule options"), options("Secondary options"), parser("Parser options"), selection("Selection options"), tesselation("Tesselation options"), world("World options") { // put all options lists into a lookup CmdParserLookup["analysis"] = &analysis; CmdParserLookup["atom"] = &atom; CmdParserLookup["command"] = &command; CmdParserLookup["edit"] = &edit; CmdParserLookup["fill"] = &fill; CmdParserLookup["fragmentation"] = &fragmentation; CmdParserLookup["graph"] = &graph; CmdParserLookup["options"] = &options; CmdParserLookup["molecule"] = &molecule; CmdParserLookup["parser"] = &parser; CmdParserLookup["selection"] = &selection; CmdParserLookup["tesselation"] = &tesselation; CmdParserLookup["world"] = &world; } /** Destructor of class CommandLineParser. * */ CommandLineParser::~CommandLineParser() {} /** Initializes command arguments to accept. * Goes through ActionRegistry and puts all actions therein into the map. */ void CommandLineParser::InitializeCommandArguments() { // we need a list of already added options, otherwise we get ambigious exceptions std::set AlreadyAddedOptionNames; ActionRegistry &AR = ActionRegistry::getInstance(); bool ActionAlreadyAdded_flag = false; for (ActionRegistry::const_iterator actioniter = AR.getBeginIter(); actioniter != AR.getEndIter(); ++actioniter) { ActionAlreadyAdded_flag = false; Action* const currentAction = actioniter->second; //std::cout << "Current Action to initialize is: " << actioniter->first << std::endl; for (ActionTrait::options_const_iterator optioniter = currentAction->Traits.getBeginIter(); optioniter != currentAction->Traits.getEndIter(); ++optioniter) { if (optioniter->first == actioniter->first) ActionAlreadyAdded_flag = true; ASSERT( OptionRegistry::getInstance().isOptionPresentByName(optioniter->first), "CommandLineParser::Init() - Option "+optioniter->first+" not present in OptionRegistry." ); const OptionTrait* const currentOption = OptionRegistry::getInstance().getOptionByName(optioniter->first); if (AlreadyAddedOptionNames.find(optioniter->first) == AlreadyAddedOptionNames.end()) { // add the option // std::cout << "Registering Option " // << currentOption->getName() // << " with type '" << currentOption->getTypeName() << "' " // << " with description '" << currentOption->getDescription() << "' "; // if (currentOption->hasShortForm()) // std::cout << ", with short form " << currentOption->getShortForm(); // else // std::cout << ", with no short form "; // if (currentOption->hasDefaultValue()) // std::cout << ", with default value " << currentOption->getDefaultValue(); // else // std::cout << ", with no default value "; // std::cout << std::endl; AddOptionToParser(currentOption, (CmdParserLookup["options"])); AlreadyAddedOptionNames.insert(optioniter->first); } else { // std::cout << "Option " << currentOption->getName() << " already registered." << std::endl; } } if (!ActionAlreadyAdded_flag) { // add the action // std::cout << "Registering Action " // << currentAction->Traits.getName() // << " in menu " << currentAction->Traits.getMenuName() // << " with type '" << currentAction->Traits.getTypeName() << "' " // << " with description '" << currentAction->Traits.getDescription() << "' "; // if (currentAction->Traits.hasShortForm()) // std::cout << ", with short form " << currentAction->Traits.getShortForm(); // else // std::cout << ", with no short form "; // if (currentAction->Traits.hasDefaultValue()) // std::cout << ", with default value " << currentAction->Traits.getDefaultValue(); // else // std::cout << ", with no default value "; // std::cout << std::endl; ASSERT(CmdParserLookup.find(currentAction->Traits.getMenuName()) != CmdParserLookup.end(), "CommandLineParser: boost::program_options::options_description for this Action not present."); AddOptionToParser(dynamic_cast(&(currentAction->Traits)),(CmdParserLookup[currentAction->Traits.getMenuName()])); } } // note: positioning is not important on the command line } /** Adds an Action or Option to the CommandLineParser. * Note that Action is derived from Option(Trait) * * This ugly switch function is necessary because of the compile-time problem: * po::value has to be instantiated at compile-time however we do know the type not until run-time. * Not even a templated function like po::value getProgramOptionValuefromType() does help, specialized * to each available type, as the signatures of all the functions differ. Hence, they cannot not put into * one type_info -> po::value map ... * * \param *currentOption pointer to Action/Option to add * \param *OptionList program_options list to add to */ void CommandLineParser::AddOptionToParser(const OptionTrait * const currentOption, po::options_description* OptionList) { // check whether dynamic_cast in Init() suceeded ASSERT(currentOption != NULL, "CommandLineParser::AddOptionToParser() - currentOption is NULL!"); // add other options // std::cout << "Adding Action " << currentOption->getName() << " with type " // << currentOption->getType()->name() << ", " << (currentOption->hasDefaultValue() ? "with" : "without") // << " default value, and KeyandShortform " << currentOption->getKeyAndShortForm() // << " to CommandLineParser." << std::endl; switch(TypeToEnums.getEnumforType(currentOption->getType())) { default: case TypeEnumContainer::NoneType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::BooleanType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < bool >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < bool >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::FileType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < boost::filesystem::path >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < boost::filesystem::path >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfFilesType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::IntegerType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < int >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < int >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfIntegersType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::UnsignedIntegerType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < unsigned int >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < unsigned int >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfUnsignedIntegersType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::DoubleType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < double >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < double >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfDoublesType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::StringType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < std::string >()->default_value(currentOption->getDefaultValue()) : po::value < std::string >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfStringsType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::VectorType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < VectorValue >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < VectorValue >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfVectorsType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::MoleculeType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < const molecule * >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < int >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfMoleculesType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::AtomType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < int >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < int >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfAtomsType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ElementType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < const element * >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < int >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfElementsType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < std::vector >()->default_value(boost::lexical_cast< std::vector >(currentOption->getDefaultValue().c_str())) : po::value < std::vector >()->multitoken(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::RandomNumberDistribution_ParametersType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? po::value < std::string >()->default_value(boost::lexical_cast< std::string >(currentOption->getDefaultValue().c_str())) : po::value < std::string >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::RealSpaceMatrixType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), // currentOption->hasDefaultValue() ? // po::value < RealSpaceMatrixValue >()->default_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : po::value < RealSpaceMatrixValue >(), currentOption->getDescription().c_str()) ; break; } } /** States whether there are command line arguments. * \return true - there are none, false - there is at least one command line argument */ bool CommandLineParser::isEmpty() { return vm.empty(); } /** Sets the options. * \param _argc arg count from main() * \param **_argv argument array from main() */ void CommandLineParser::setOptions(int _argc, char **_argv) { argc = _argc; argv = _argv; config_file_options.add(options); // append all option_descriptions to both cmdline_options and visible for (CmdParserLookupMap::iterator iter = CmdParserLookup.begin(); iter != CmdParserLookup.end(); ++iter) { cmdline_options.add(*(iter->second)); visible.add(*(iter->second)); } } /** Parses the command line arguments. * Calls program_options::store() and program_options::notify() */ void CommandLineParser::Parse() { po::store(po::command_line_parser(argc,argv).options(cmdline_options).run(), vm); std::ifstream input; input.open("example.cfg"); if (!input.fail()) po::store(po::parse_config_file(input, config_file_options), vm); input.close(); po::notify(vm); } /** Scan the argument list for -a or --arguments and store their order for later use. */ void CommandLineParser::scanforSequenceOfArguments() { std::map ShortFormToActionMap = getShortFormToActionMap(); LOG(0, "Scanning command line arguments and recognizing Actions."); // go through all arguments for (int i=1;i '9')) && ((argv[i][1] != '.'))) { std::map ::iterator iter = ShortFormToActionMap.find(&(argv[i][1])); if (iter != ShortFormToActionMap.end()) { LOG(1, "Putting " << iter->second << " for " << iter->first << " into the sequence."); SequenceOfActions.push_back(iter->second); } } } } } /** Makes the Parser parse the command line options with current known options. * \param _argc arg count from main() * \param **_argv argument array from main() */ void CommandLineParser::Run(int _argc, char **_argv) { setOptions(_argc,_argv); Parse(); scanforSequenceOfArguments(); } /** Go through all Actions and create a map from short form to their token. * \return map from Action's ShortForm to token. */ std::map CommandLineParser::getShortFormToActionMap() const { std::map result; ActionRegistry &AR = ActionRegistry::getInstance(); for (ActionRegistry::const_iterator iter = AR.getBeginIter(); iter != AR.getEndIter(); ++iter) if ((iter->second)->Traits.hasShortForm()) { ASSERT(result.find((iter->second)->Traits.getShortForm()) == result.end(), "Short form "+toString((iter->second)->Traits.getShortForm())+ " for action "+toString(iter->first)+" already present from "+ std::string(result[(iter->second)->Traits.getShortForm()])+"!"); result[(iter->second)->Traits.getShortForm()] = (iter->second)->getName(); } return result; } CONSTRUCT_SINGLETON(CommandLineParser)