/******************************************************************************** * 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.cxx * Author: winckler * * Created on March 11, 2015, 5:38 PM */ #include "FairProgOptions.h" /// ////////////////////////////////////////////////////////////////////////////////////////////////////// /// Constructor / destructor FairProgOptions::FairProgOptions() : fGenericDesc("Generic options description"), fConfigDesc("Configuration options description"), fHiddenDesc("Hidden options description"), fEnvironmentDesc("Environment Variables"), fCmdline_options("Command line options"), fConfig_file_options("Configuration file options"), fVisible_options("Visible options"), fVerboseLvl("INFO"), fUseConfigFile(false), fConfigFile() { // ////////////////////////////////// // define generic options fGenericDesc.add_options() ("help,h", "produce help") ("version,v", "print version") ("verbose", po::value(&fVerboseLvl)->default_value("INFO"), "Verbosity level : \n" " TRACE \n" " DEBUG \n" " RESULTS \n" " INFO \n" " WARN \n" " ERROR \n" " STATE \n" " NOLOG" ) ; fSeverity_map["TRACE"] = fairmq::severity_level::TRACE; fSeverity_map["DEBUG"] = fairmq::severity_level::DEBUG; fSeverity_map["RESULTS"] = fairmq::severity_level::RESULTS; fSeverity_map["INFO"] = fairmq::severity_level::INFO; fSeverity_map["WARN"] = fairmq::severity_level::WARN; fSeverity_map["ERROR"] = fairmq::severity_level::ERROR; fSeverity_map["STATE"] = fairmq::severity_level::STATE; fSeverity_map["NOLOG"] = fairmq::severity_level::NOLOG; } FairProgOptions::~FairProgOptions() { } /// ////////////////////////////////////////////////////////////////////////////////////////////////////// /// Add option descriptions int FairProgOptions::AddToCmdLineOptions(const po::options_description& optdesc, bool visible) { fCmdline_options.add(optdesc); if(visible) fVisible_options.add(optdesc); return 0; } int FairProgOptions::AddToCfgFileOptions(const po::options_description& optdesc, bool visible) { //if UseConfigFile() not yet called, then enable it with required file name to be provided by command line if(!fUseConfigFile) UseConfigFile(); fConfig_file_options.add(optdesc); if(visible) fVisible_options.add(optdesc); return 0; } int FairProgOptions::AddToEnvironmentOptions(const po::options_description& optdesc) { fEnvironmentDesc.add(optdesc); return 0; } void FairProgOptions::UseConfigFile(const std::string& filename) { fUseConfigFile = true; if (filename.empty()) { fConfigDesc.add_options() ("config,c", po::value(&fConfigFile)->required(), "Path to configuration file (required argument)"); AddToCmdLineOptions(fConfigDesc); } else { fConfigFile = filename; } } /// ////////////////////////////////////////////////////////////////////////////////////////////////////// /// Parser int FairProgOptions::ParseCmdLine(const int argc, char** argv, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) { // ////////////////////////////////// // get options from cmd line and store in variable map // here we use command_line_parser instead of parse_command_line, to allow unregistered and positional options if(AllowUnregistered) { po::command_line_parser parser{argc, argv}; parser.options(desc).allow_unregistered(); po::parsed_options parsedOptions = parser.run(); po::store(parsedOptions,varmap); } else po::store(po::parse_command_line(argc, argv, desc), varmap); // ////////////////////////////////// // call the virtual NotifySwitchOption method to handle switch options like e.g. "--help" or "--version" // return 1 if switch options found in varmap if(NotifySwitchOption()) return 1; po::notify(varmap); return 0; } int FairProgOptions::ParseCmdLine(const int argc, char** argv, const po::options_description& desc, bool AllowUnregistered) { return ParseCmdLine(argc,argv,desc,fvarmap,AllowUnregistered); } int FairProgOptions::ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) { if (!ifs) { std::cout << "can not open configuration file \n"; return -1; } else { po:store(parse_config_file(ifs, desc, AllowUnregistered), varmap); po::notify(varmap); } return 0; } int FairProgOptions::ParseCfgFile(const std::string& filename, const po::options_description& desc, po::variables_map& varmap, bool AllowUnregistered) { std::ifstream ifs(filename.c_str()); if (!ifs) { std::cout << "can not open configuration file: " << filename << "\n"; return -1; } else { po:store(parse_config_file(ifs, desc, AllowUnregistered), varmap); po::notify(varmap); } return 0; } int FairProgOptions::ParseCfgFile(const std::string& filename, const po::options_description& desc, bool AllowUnregistered) { return ParseCfgFile(filename,desc,fvarmap,AllowUnregistered); } int FairProgOptions::ParseCfgFile(std::ifstream& ifs, const po::options_description& desc, bool AllowUnregistered) { return ParseCfgFile(ifs,desc,fvarmap,AllowUnregistered); } int FairProgOptions::ParseEnvironment(const std::function & environment_mapper) { po::store(po::parse_environment(fEnvironmentDesc, environment_mapper), fvarmap); po::notify(fvarmap); return 0; } // Given a key, convert the variable value to string std::string FairProgOptions::GetStringValue(const std::string& key) { std::string val_str; try { if ( fvarmap.count(key) ) { auto& value = fvarmap[key].value(); // string albeit useless here if(auto q = boost::any_cast< std::string >(&value )) { val_str = variable_value_to_string< std::string >(fvarmap[key]); return val_str; } // vector if(auto q = boost::any_cast< std::vector >(&value )) { val_str = variable_value_to_string< std::vector >(fvarmap[key]); return val_str; } // int if(auto q = boost::any_cast< int >(&value )) { val_str = variable_value_to_string< int >(fvarmap[key]); return val_str; } // vector if(auto q = boost::any_cast< std::vector >(&value )) { val_str = variable_value_to_string< std::vector >(fvarmap[key]); return val_str; } // float if(auto q = boost::any_cast< float >(&value )) { val_str = variable_value_to_string< float >(fvarmap[key]); return val_str; } // vector float if(auto q = boost::any_cast< std::vector >(&value )) { val_str = variable_value_to_string< std::vector >(fvarmap[key]); return val_str; } // double if(auto q = boost::any_cast< double >(&value )) { val_str = variable_value_to_string< double >(fvarmap[key]); return val_str; } // vector double if(auto q = boost::any_cast< std::vector >(&value )) { val_str = variable_value_to_string< std::vector >(fvarmap[key]); return val_str; } } } catch(std::exception& e) { LOG(ERROR) << "Exception thrown for the key '" << key << "'"; LOG(ERROR) << e.what(); } return val_str; } /// ////////////////////////////////////////////////////////////////////////////////////////////////////// /// Print/notify options int FairProgOptions::PrintHelp() const { std::cout << fVisible_options << "\n"; return 0; } int FairProgOptions::PrintOptions() { // ////////////////////////////////// // Method to overload. // -> loop over variable map and print its content // -> In this example the following types are supported: // std::string, int, float, double, boost::filesystem::path // std::vector, std::vector, std::vector, std::vector MapVarValInfo_t mapinfo; // get string length for formatting and convert varmap values into string int maxlen_1st = 0; int maxlen_2nd = 0; int maxlen_TypeInfo = 0; int maxlen_default =0; int maxlen_empty = 0; int total_len=0; for (const auto& m : fvarmap) { Max(maxlen_1st, m.first.length()); VarValInfo_t valinfo=Get_variable_value_info(m.second); mapinfo[m.first]=valinfo; std::string val_str; std::string typeInfo_str; std::string default_str; std::string empty_str; std::tie(val_str,typeInfo_str,default_str,empty_str)=valinfo; Max(maxlen_2nd, val_str.length()); Max(maxlen_TypeInfo, typeInfo_str.length()); Max(maxlen_default, default_str.length()); Max(maxlen_empty, empty_str.length()); } // TODO : limit the value length field in a better way if(maxlen_2nd>100) maxlen_2nd=100; total_len=maxlen_1st+maxlen_2nd+maxlen_TypeInfo+maxlen_default+maxlen_empty; //maxlen_2nd=200; // formatting and printing LOG(INFO)< auto& value = var_val.value(); std::string defaulted_val; std::string empty_val; if(var_val.empty()) empty_val=" [empty]"; else if(var_val.defaulted()) defaulted_val=" [default value]"; else defaulted_val=" [provided value]"; empty_val+=" *"; // string if(auto q = boost::any_cast< std::string >(&value)) { std::string val_str = *q; return std::make_tuple(val_str,std::string(" [Type=string]"),defaulted_val,empty_val); } // vector if(auto q = boost::any_cast< std::vector >(&value)) { std::string val_str = variable_value_to_string< std::vector >(var_val); return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); } // int if(auto q = boost::any_cast< int >(&value)) { std::string val_str = variable_value_to_string< int >(var_val); return std::make_tuple(val_str,std::string(" [Type=int]"),defaulted_val,empty_val); } // vector if(auto q = boost::any_cast< std::vector >(&value)) { std::string val_str = variable_value_to_string< std::vector >(var_val); return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); } // float if(auto q = boost::any_cast< float >(&value)) { std::string val_str = variable_value_to_string< float >(var_val); return std::make_tuple(val_str,std::string(" [Type=float]"),defaulted_val,empty_val); } // vector if(auto q = boost::any_cast< std::vector >(&value)) { std::string val_str = variable_value_to_string< std::vector >(var_val); return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); } // double if(auto q = boost::any_cast< double >(&value)) { std::string val_str = variable_value_to_string< double >(var_val); return std::make_tuple(val_str,std::string(" [Type=double]"),defaulted_val,empty_val); } // vector if(auto q = boost::any_cast< std::vector >(&value)) { std::string val_str = variable_value_to_string< std::vector >(var_val); return std::make_tuple(val_str,std::string(" [Type=vector]"),defaulted_val,empty_val); } // boost::filesystem::path if(auto q = boost::any_cast(&value)) { std::string val_str = (*q).string(); //std::string val_str = (*q).filename().generic_string(); return std::make_tuple(val_str,std::string(" [Type=boost::filesystem::path]"),defaulted_val,empty_val); } // if we get here, the type is not supported return unknown info return std::make_tuple(std::string("Unknown value"), std::string(" [Type=Unknown]"),defaulted_val,empty_val); }