/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010-2012 University of Bonn. All rights reserved. * * * This file is part of MoleCuilder. * * MoleCuilder is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * MoleCuilder is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with MoleCuilder. If not, see . */ /* * 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/ActionQueue.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 "Parameters/Specifics/KeyValuePair.hpp" #include "World.hpp" #include "CodePatterns/Singleton_impl.hpp" using namespace MoleCuilder; class element; /** Constructor of class CommandLineParser. * */ CommandLineParser::CommandLineParser() : analysis("Analysis options"), atom("Atom options"), bond("Bond options"), command("Command options"), fill("fill options"), shape("shape options"), fragmentation("Fragmentation options"), geometry("Geometry options"), graph("Graph options"), molecule("Molecule options"), options("Secondary options"), parser("Parser options"), potential("Potential options"), selection("Selection options"), tesselation("Tesselation options"), world("World options") { // put all options lists into a lookup CmdParserLookup["analysis"] = &analysis; CmdParserLookup["atom"] = &atom; CmdParserLookup["bond"] = &bond; CmdParserLookup["command"] = &command; CmdParserLookup["edit"] = &edit; CmdParserLookup["fill"] = &fill; CmdParserLookup["shape"] = &shape; CmdParserLookup["fragmentation"] = &fragmentation; CmdParserLookup["geometry"] = &geometry; CmdParserLookup["graph"] = &graph; CmdParserLookup["options"] = &options; CmdParserLookup["molecule"] = &molecule; CmdParserLookup["parser"] = &parser; CmdParserLookup["potential"] = &potential; 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; bool ActionAlreadyAdded_flag = false; ActionQueue &AQ = ActionQueue::getInstance(); ActionQueue::ActionTokens_t tokens = AQ.getListOfActions(); for (ActionQueue::ActionTokens_t::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) { const ActionTrait &CurrentTrait = AQ.getActionsTrait(*iter); ActionAlreadyAdded_flag = false; //std::cout << "Current Action to initialize is: " << actioniter->first << std::endl; for (ActionTrait::options_const_iterator optioniter = CurrentTrait.getBeginIter(); optioniter != CurrentTrait.getEndIter(); ++optioniter) { if (optioniter->first == *iter) 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"]), (optioniter->first == *iter) ? true : false); 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(CurrentTrait.getMenuName()) != CmdParserLookup.end(), "CommandLineParser: boost::program_options::options_description for this Action not present."); AddOptionToParser( dynamic_cast(&CurrentTrait), (CmdParserLookup[CurrentTrait.getMenuName()]), false); } } // 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 * \param _DefaultAsImplicit whether to add a default value as default_value or * as implicit_value (default = option token present or not, implicit = option token present but not necessarily followed by argument) */ void CommandLineParser::AddOptionToParser( const OptionTrait * const currentOption, po::options_description* OptionList, const bool _DefaultAsImplicit) { // 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() ? (_DefaultAsImplicit ? po::value < bool >()->implicit_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : 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() ? (_DefaultAsImplicit ? po::value < int >()->implicit_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : 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() ? (_DefaultAsImplicit ? po::value < unsigned int >()->implicit_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : 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() ? (_DefaultAsImplicit ? po::value < double >()->implicit_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : 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() ? (_DefaultAsImplicit ? po::value < std::string >()->implicit_value(currentOption->getDefaultValue()) : 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() ? (_DefaultAsImplicit ? po::value < int >()->implicit_value(boost::lexical_cast(currentOption->getDefaultValue().c_str())) : 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 < std::string >(), 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::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; case TypeEnumContainer::KeyValueType: OptionList->add_options() (currentOption->getKeyAndShortForm().c_str(), currentOption->hasDefaultValue() ? (_DefaultAsImplicit ? po::value < KeyValuePair >()->implicit_value(boost::lexical_cast< KeyValuePair >(currentOption->getDefaultValue().c_str())) : po::value < KeyValuePair >()->default_value(boost::lexical_cast< KeyValuePair >(currentOption->getDefaultValue().c_str()))) : po::value < KeyValuePair >(), currentOption->getDescription().c_str()) ; break; case TypeEnumContainer::ListOfKeyValuesType: 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; } } /** 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() * * @return true - all is ok, false - command-line options could not be parsed * correctly */ bool CommandLineParser::Parse() { bool status = true; try { po::store(po::command_line_parser(argc,argv).options(cmdline_options).run(), vm); } catch (std::exception &e) { std::cerr << "Something went wrong with parsing the command-line arguments: " << e.what() << std::endl; World::getInstance().setExitFlag(134); #ifdef HAVE_ACTION_THREAD // force action queue to stop thread ActionQueue::getInstance().stop(); ActionQueue::getInstance().clearTempQueue(); #endif ActionQueue::getInstance().clearQueue(); status = false; } if (status) { 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); } return status; } /** 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); const bool status = Parse(); if (status) 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; ActionQueue &AQ = ActionQueue::getInstance(); ActionQueue::ActionTokens_t tokens = AQ.getListOfActions(); for (ActionQueue::ActionTokens_t::const_iterator iter = tokens.begin(); iter != tokens.end(); ++iter) { const ActionTrait &CurrentTrait = AQ.getActionsTrait(*iter); if (CurrentTrait.hasShortForm()) { ASSERT(result.find(CurrentTrait.getShortForm()) == result.end(), "Short form "+toString(CurrentTrait.getShortForm())+ " for action "+toString(*iter)+" already present from "+ std::string(result[CurrentTrait.getShortForm()])+"!"); result[CurrentTrait.getShortForm()] = *iter; } } return result; } CONSTRUCT_SINGLETON(CommandLineParser)