diff options
Diffstat (limited to 'qpid/cpp/src/qpid/Options.cpp')
-rw-r--r-- | qpid/cpp/src/qpid/Options.cpp | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/qpid/cpp/src/qpid/Options.cpp b/qpid/cpp/src/qpid/Options.cpp new file mode 100644 index 0000000000..4b13e349f5 --- /dev/null +++ b/qpid/cpp/src/qpid/Options.cpp @@ -0,0 +1,200 @@ +/* + * + * Copyright (c) 2006 The Apache Software Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +#include "qpid/Options.h" +#include "qpid/Exception.h" + +#include <boost/bind.hpp> + +#include <fstream> +#include <algorithm> +#include <iostream> + +namespace qpid { + +using namespace std; + + +namespace { + +struct EnvOptMapper { + static bool matchChar(char env, char opt) { + return (env==toupper(opt)) || (strchr("-.", opt) && env=='_'); + } + + static bool matchStr(const string& env, boost::shared_ptr<po::option_description> desc) { + return desc->long_name().size() == env.size() && + std::equal(env.begin(), env.end(), desc->long_name().begin(), &matchChar); + } + + static bool matchCase(const string& env, boost::shared_ptr<po::option_description> desc) { + return env == desc->long_name(); + } + + EnvOptMapper(const Options& o) : opts(o) {} + + string operator()(const string& envVar) { + static const std::string prefix("QPID_"); + if (envVar.substr(0, prefix.size()) == prefix) { + string env = envVar.substr(prefix.size()); + typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs; + OptDescs::const_iterator i = + find_if(opts.options().begin(), opts.options().end(), boost::bind(matchStr, env, _1)); + if (i != opts.options().end()) + return (*i)->long_name(); + } + return string(); + } + + + bool + isComment ( string const & str ) + { + size_t i = str.find_first_not_of ( " \t" ); + + if ( i == string::npos ) + return true; + + return str[i] == '#'; + } + + + string configFileLine (string& line) { + + if ( isComment ( line ) ) + return string(); + + size_t pos = line.find ('='); + if (pos == string::npos) + return string(); + string key = line.substr (0, pos); +#if (BOOST_VERSION >= 103300) + typedef const std::vector< boost::shared_ptr<po::option_description> > OptDescs; + OptDescs::const_iterator i = + find_if(opts.options().begin(), opts.options().end(), boost::bind(matchCase, key, _1)); + if (i != opts.options().end()) + return string (line) + "\n"; + else + return string(); +#else + // Use 'count' to see if this option exists. Using 'find' will SEGV or hang + // if the option has not been defined yet. + if ( opts.count(key.c_str()) > 0 ) + return string ( line ) + "\n"; + else + return string ( ); +#endif + } + + const Options& opts; +}; + +} +std::string prettyArg(const std::string& name, const std::string& value) { + return value.empty() ? name+" " : name+" ("+value+") "; +} + +Options::Options(const string& name) : + po::options_description(name) +{ +} + + + + + +void Options::parse(int argc, char const* const* argv, const std::string& configFile, bool allowUnknown) +{ + string defaultConfigFile = configFile; // May be changed by env/cmdline + string parsing; + try { + po::variables_map vm; + parsing="command line options"; + if (argc > 0 && argv != 0) { + if (allowUnknown) { + // This hideous workaround is required because boost 1.33 has a bug + // that causes 'allow_unregistered' to not work. + po::command_line_parser clp = po::command_line_parser(argc, const_cast<char**>(argv)). + options(*this).allow_unregistered(); + po::parsed_options opts = clp.run(); + po::parsed_options filtopts = clp.run(); + filtopts.options.clear (); + for (std::vector< po::basic_option<char> >::iterator i = opts.options.begin(); + i != opts.options.end(); i++) + if (!i->unregistered) + filtopts.options.push_back (*i); + po::store(filtopts, vm); + + } + else + po::store(po::parse_command_line(argc, const_cast<char**>(argv), *this), vm); + } + parsing="environment variables"; + po::store(po::parse_environment(*this, EnvOptMapper(*this)), vm); + po::notify(vm); // configFile may be updated from arg/env options. + if (!configFile.empty()) { + parsing="configuration file "+configFile; + ifstream conf(configFile.c_str()); + if (conf.good()) { + // Remove this hack when we get a stable version of boost that + // can allow unregistered options in config files. + EnvOptMapper mapper(*this); + stringstream filtered; + + while (!conf.eof()) { + string line; + getline (conf, line); + filtered << mapper.configFileLine (line); + } + + po::store(po::parse_config_file(filtered, *this), vm); + // End of hack + } + else { + // No error if default configfile is missing/unreadable + // but complain for non-default config file. + if (configFile != defaultConfigFile) + throw Exception("cannot read configuration file " + +configFile); + } + } + po::notify(vm); + } + catch (const std::exception& e) { + ostringstream msg; + msg << "Error in " << parsing << ": " << e.what() << endl; +#if (BOOST_VERSION >= 103300) + if (find_nothrow("help", false)) + msg << "Use --help to see valid options" << endl; +#endif + throw Exception(msg.str()); + } +} + +CommonOptions::CommonOptions(const string& name, const string& configfile) + : Options(name), config(configfile) +{ + addOptions() + ("help,h", optValue(help), "Displays the help message") + ("version,v", optValue(version), "Displays version information") + ("config", optValue(config, "FILE"), "Reads configuration from FILE"); +} + + +} // namespace qpid + |