/******************************************************************************** * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * * * This software is distributed under the terms of the * * GNU Lesser General Public Licence version 3 (LGPL) version 3, * * copied verbatim in the file "LICENSE" * ********************************************************************************/ /* * File: FairProgOptions.h * Author: winckler * * Created on March 11, 2015, 5:38 PM */ #ifndef FAIRPROGOPTIONS_H #define FAIRPROGOPTIONS_H #include "FairMQLogger.h" #include #include #include "FairProgOptionsHelper.h" #include #include #include #include #include #include #include /* * FairProgOptions abstract base class * parse command line, configuration file options as well as environment variables. * * The user defines in the derived class the option descriptions and * the pure virtual ParseAll() method * * class MyOptions : public FairProgOptions * { * public : * MyOptions() : FairProgOptions() * { * fCmdlineOptions.add(fGenericDesc); * fVisibleOptions.add(fCmdlineOptions); * } * virtual ~MyOptions() {} * virtual void ParseAll(const int argc, char** argv, bool allowUnregistered = false) * { * if (ParseCmdLine(argc, argv, fCmdlineOptions, fVarMap, allowUnregistered)) * { * exit(EXIT_FAILURE); * } * * PrintOptions(); * } * } */ namespace po = boost::program_options; namespace fs = boost::filesystem; class FairProgOptions { public: FairProgOptions(); virtual ~FairProgOptions(); // add options_description int AddToCmdLineOptions(const po::options_description& optDesc, bool visible = true); int AddToCfgFileOptions(const po::options_description& optDesc, bool visible = true); int AddToEnvironmentOptions(const po::options_description& optDesc); po::options_description& GetCmdLineOptions(); po::options_description& GetCfgFileOptions(); po::options_description& GetEnvironmentOptions(); void UseConfigFile(const std::string& filename = ""); // get value corresponding to the key template T GetValue(const std::string& key) const { std::unique_lock lock(fConfigMutex); T val = T(); try { if (fVarMap.count(key)) { val = fVarMap[key].as(); } else { LOG(ERROR) << "Config has no key: " << key; } } catch (std::exception& e) { LOG(ERROR) << "Exception thrown for the key '" << key << "'"; LOG(ERROR) << e.what(); this->PrintHelp(); } return val; } // Given a key, convert the variable value to string std::string GetStringValue(const std::string& key) { std::unique_lock lock(fConfigMutex); std::string valueStr; try { if (fVarMap.count(key)) { valueStr = FairMQ::ConvertVariableValue().Run(fVarMap.at(key)); } } catch (std::exception& e) { LOG(ERROR) << "Exception thrown for the key '" << key << "'"; LOG(ERROR) << e.what(); } return valueStr; } int Count(const std::string& key) const { std::unique_lock lock(fConfigMutex); return fVarMap.count(key); } //restrict conversion to fundamental types template T ConvertTo(const std::string& strValue) { if (std::is_arithmetic::value) { std::istringstream iss(strValue); T val; iss >> val; return val; } else { LOG(ERROR) << "the provided string " << strValue << " cannot be converted in the requested type. The target types must be arithmetic types"; } } const po::variables_map& GetVarMap() const { return fVarMap; } // boost prog options parsers int ParseCmdLine(const int argc, char** argv, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false); int ParseCmdLine(const int argc, char** argv, const po::options_description& desc, bool allowUnregistered = false); int ParseCfgFile(const std::string& filename, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false); int ParseCfgFile(const std::string& filename, const po::options_description& desc, bool allowUnregistered = false); int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool allowUnregistered = false); int ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, bool allowUnregistered = false); int ParseEnvironment(const std::function&); virtual void ParseAll(const int argc, char** argv, bool allowUnregistered = false) = 0;// TODO change return type to bool and propagate to executable virtual int PrintOptions(); virtual int PrintOptionsRaw(); int PrintHelp() const; protected: // options container po::variables_map fVarMap; // basic description categories po::options_description fGenericDesc; po::options_description fConfigDesc; po::options_description fEnvironmentDesc; po::options_description fHiddenDesc; // Description of cmd line and simple configuration file (configuration file like txt, but not like xml json ini) po::options_description fCmdLineOptions; po::options_description fConfigFileOptions; // Description which is printed in help command line // to handle logger severity std::map fSeverityMap; po::options_description fVisibleOptions; mutable std::mutex fConfigMutex; std::string fVerbosityLevel; bool fUseConfigFile; boost::filesystem::path fConfigFile; virtual int NotifySwitchOption(); // UpdateVarMap() and replace() --> helper functions to modify the value of variable map after calling po::store template void UpdateVarMap(const std::string& key, const T& val) { replace(fVarMap, key, val); } template void replace(std::map& vm, const std::string& opt, const T& val) { vm[opt].value() = boost::any(val); } private: // Methods below are helper functions used in the PrintOptions method typedef std::tuple VarValInfo_t; typedef std::map MapVarValInfo_t; VarValInfo_t GetVariableValueInfo(const po::variable_value& varValue); static void Max(int &val, const int &comp) { if (comp > val) { val = comp; } } }; #endif /* FAIRPROGOPTIONS_H */