/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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 "OptionParser.h" #include #include #include #include #include #include class Option { public: Option(const std::string& name, const std::string& description); virtual ~Option() {} virtual void setValue(const std::string&) = 0; virtual bool isValueExpected() = 0; bool match(const std::string&); std::ostream& print(std::ostream& out); private: std::string longName; std::string shortName; std::string description; std::ostream& printNames(std::ostream& out); friend class OptionParser; }; class StringOption : public Option { public: StringOption(const std::string& name, const std::string& description, std::string& v) : Option(name, description), value(v) {} void setValue(const std::string& v) { value = v; } bool isValueExpected() { return true; } private: std::string& value; }; class IntegerOption : public Option { public: IntegerOption(const std::string& name, const std::string& description, int& v) : Option(name, description), value(v) {} void setValue(const std::string& v) { value = atoi(v.c_str()); } bool isValueExpected() { return true; } private: int& value; }; class BooleanOption : public Option { public: BooleanOption(const std::string& name, const std::string& description, bool& v) : Option(name, description), value(v) {} void setValue(const std::string&) { value = true; } bool isValueExpected() { return false; } private: bool& value; }; class MultiStringOption : public Option { public: MultiStringOption(const std::string& name, const std::string& description, std::vector& v) : Option(name, description), value(v) {} void setValue(const std::string& v) { value.push_back(v); } bool isValueExpected() { return true; } private: std::vector& value; }; class OptionMatch { public: OptionMatch(const std::string& argument); bool operator()(Option* option); bool isOption(); private: std::string name; }; class OptionsError : public qpid::types::Exception { public: OptionsError(const std::string& message) : qpid::types::Exception(message) {} }; Option::Option(const std::string& name, const std::string& desc) : description(desc) { std::string::size_type i = name.find(","); if (i != std::string::npos) { longName = name.substr(0, i); if (i + 1 < name.size()) shortName = name.substr(i+1); } else { longName = name; } } bool Option::match(const std::string& name) { return name == longName || name == shortName; } std::ostream& Option::printNames(std::ostream& out) { if (shortName.size()) { out << "-" << shortName; if (isValueExpected()) out << " VALUE"; out << ", --" << longName; if (isValueExpected()) out << " VALUE"; } else { out << "--" << longName; if (isValueExpected()) out << " VALUE"; } return out; } std::ostream& Option::print(std::ostream& out) { std::stringstream names; printNames(names); out << std::setw(30) << std::left << names.str() << description << std::endl; return out; } std::vector& OptionParser::getArguments() { return arguments; } void OptionParser::add(Option* option) { options.push_back(option); } void OptionParser::add(const std::string& name, std::string& value, const std::string& description) { add(new StringOption(name, description, value)); } void OptionParser::add(const std::string& name, int& value, const std::string& description) { add(new IntegerOption(name, description, value)); } void OptionParser::add(const std::string& name, bool& value, const std::string& description) { add(new BooleanOption(name, description, value)); } void OptionParser::add(const std::string& name, std::vector& value, const std::string& description) { add(new MultiStringOption(name, description, value)); } OptionMatch::OptionMatch(const std::string& argument) { if (argument.find("--") == 0) { name = argument.substr(2); } else if (argument.find("-") == 0) { name = argument.substr(1); } } bool OptionMatch::operator()(Option* option) { return option->match(name); } bool OptionMatch::isOption() { return name.size() > 0; } OptionParser::OptionParser(const std::string& s, const std::string& d) : summary(s), description(d), help(false) { add("help,h", help, "show this message"); } Option* OptionParser::getOption(const std::string& argument) { OptionMatch match(argument); if (match.isOption()) { Options::iterator i = std::find_if(options.begin(), options.end(), match); if (i == options.end()) { std::stringstream error; error << "Unrecognised option: " << argument; throw OptionsError(error.str()); } else { return *i; } } else { return 0; } } void OptionParser::error(const std::string& message) { std::cout << summary << std::endl << std::endl; std::cerr << "Error: " << message << "; try --help for more information" << std::endl; } bool OptionParser::parse(int argc, char** argv) { try { for (int i = 1; i < argc; ++i) { std::string argument = argv[i]; Option* o = getOption(argument); if (o) { if (o->isValueExpected()) { if (i + 1 < argc) { o->setValue(argv[++i]); } else { std::stringstream error; error << "Value expected for option " << o->longName; throw OptionsError(error.str()); } } else { o->setValue(""); } } else { arguments.push_back(argument); } } if (help) { std::cout << summary << std::endl << std::endl; std::cout << description << std::endl << std::endl; std::cout << "Options: " << std::endl; for (Options::iterator i = options.begin(); i != options.end(); ++i) { (*i)->print(std::cout); } return false; } else { return true; } } catch (const std::exception& e) { error(e.what()); return false; } } OptionParser::~OptionParser() { for (Options::iterator i = options.begin(); i != options.end(); ++i) { delete *i; } }