/* * 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 "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"), 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["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 < 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::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() * * @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)