/* */ #include "OptionParser.h" #include #include #include #include #include #include "util.h" #include "OptionHandlerImpl.h" #include "Option.h" #include "A2STR.h" #include "a2functional.h" #include "array_fun.h" #include "OptionHandlerFactory.h" #include "DlAbortEx.h" #include "error_code.h" namespace aria2 { OptionParser::OptionParser(): idCounter_(0) {} OptionParser::~OptionParser() {} namespace { template size_t countPublicOption(InputIterator first, InputIterator last) { size_t count = 0; for(; first != last; ++first) { if(!(*first)->isHidden()) { ++count; } } return count; } } // namespace namespace { template void putOptions(struct option* longOpts, int* plopt, InputIterator first, InputIterator last) { for(; first != last; ++first) { if(!(*first)->isHidden()) { #ifdef HAVE_OPTION_CONST_NAME (*longOpts).name = (*first)->getName().c_str(); #else // !HAVE_OPTION_CONST_NAME (*longOpts).name = strdup((*first)->getName().c_str()); #endif // !HAVE_OPTION_CONST_NAME switch((*first)->getArgType()) { case OptionHandler::REQ_ARG: (*longOpts).has_arg = required_argument; break; case OptionHandler::OPT_ARG: (*longOpts).has_arg = optional_argument; break; case OptionHandler::NO_ARG: (*longOpts).has_arg = no_argument; break; default: abort(); } if((*first)->getShortName() == 0) { (*longOpts).flag = plopt; (*longOpts).val = (*first)->getOptionID(); } else { (*longOpts).flag = 0; (*longOpts).val = (*first)->getShortName(); } ++longOpts; } } (*longOpts).name = 0; (*longOpts).has_arg = 0; (*longOpts).flag = 0; (*longOpts).val = 0; } } // namespace namespace { template std::string createOptstring(InputIterator first, InputIterator last) { std::string str = ""; for(; first != last; ++first) { if(!(*first)->isHidden()) { if((*first)->getShortName() != 0) { str += (*first)->getShortName(); if((*first)->getArgType() == OptionHandler::REQ_ARG) { str += ":"; } else if((*first)->getArgType() == OptionHandler::OPT_ARG) { str += "::"; } } } } return str; } } // namespace void OptionParser::parseArg (std::ostream& out, std::vector& nonopts, int argc, char* argv[]) { size_t numPublicOption = countPublicOption(optionHandlers_.begin(), optionHandlers_.end()); int lopt; array_ptr longOpts(new struct option[numPublicOption+1]); putOptions(longOpts, &lopt,optionHandlers_.begin(),optionHandlers_.end()); std::string optstring = createOptstring(optionHandlers_.begin(), optionHandlers_.end()); while(1) { int c = getopt_long(argc, argv, optstring.c_str(), longOpts, 0); if(c == -1) { break; } SharedHandle op; if(c == 0) { op = findByID(lopt); } else { op = findByShortName(c); } if(!op) { throw DL_ABORT_EX2("Failed to parse command-line options.", error_code::OPTION_ERROR); } out << op->getName() << "="; if(optarg) { out << optarg; if(op->getEraseAfterParse()) { for(char* p = optarg; *p != '\0'; ++p) { *p = '*'; } } } out << "\n"; } std::copy(argv+optind, argv+argc, std::back_inserter(nonopts)); } void OptionParser::parse(Option& option, std::istream& is) { std::string line; int32_t linenum = 0; while(getline(is, line)) { ++linenum; if(util::startsWith(line, A2STR::SHARP_C)) { continue; } std::pair nv; util::divide(nv, line, '='); if(nv.first.empty()) { continue; } OptionHandlerHandle handler = getOptionHandlerByName(nv.first); handler->parse(option, nv.second); } } namespace { class DummyOptionHandler:public NameMatchOptionHandler { protected: virtual void parseArg(Option& option, const std::string& arg) {} public: DummyOptionHandler(const std::string& name):NameMatchOptionHandler(name) {} virtual std::string createPossibleValuesString() const { return A2STR::NIL; } }; } // namespace OptionHandlerHandle OptionParser::getOptionHandlerByName (const std::string& optName) { SharedHandle handler(new DummyOptionHandler(optName)); std::vector >::const_iterator i = std::lower_bound(optionHandlers_.begin(), optionHandlers_.end(), handler, OptionHandlerNameLesser()); if(i != optionHandlers_.end() && (*i)->canHandle(optName)) { handler = *i; } else { handler.reset(new NullOptionHandler()); } return handler; } void OptionParser::setOptionHandlers (const std::vector >& optionHandlers) { optionHandlers_ = optionHandlers; for(std::vector >::const_iterator i = optionHandlers_.begin(), eoi = optionHandlers_.end(); i != eoi; ++i) { (*i)->setOptionID(++idCounter_); } std::sort(optionHandlers_.begin(), optionHandlers_.end(), OptionHandlerNameLesser()); } void OptionParser::addOptionHandler (const SharedHandle& optionHandler) { optionHandler->setOptionID(++idCounter_); std::vector >::iterator i = std::lower_bound(optionHandlers_.begin(), optionHandlers_.end(), optionHandler, OptionHandlerNameLesser()); optionHandlers_.insert(i, optionHandler); } void OptionParser::parseDefaultValues(Option& option) const { for(std::vector >::const_iterator i = optionHandlers_.begin(), eoi = optionHandlers_.end(); i != eoi; ++i) { if(!(*i)->getDefaultValue().empty()) { (*i)->parse(option, (*i)->getDefaultValue()); } } } namespace { class FindOptionHandlerByTag : public std::unary_function, bool> { private: std::string tag_; public: FindOptionHandlerByTag(const std::string& tag):tag_(tag) {} bool operator()(const SharedHandle& optionHandler) const { return !optionHandler->isHidden() && optionHandler->hasTag(tag_); } }; } // namespace std::vector > OptionParser::findByTag(const std::string& tag) const { std::vector > result; std::remove_copy_if(optionHandlers_.begin(), optionHandlers_.end(), std::back_inserter(result), std::not1(FindOptionHandlerByTag(tag))); std::sort(result.begin(), result.end(), OptionHandlerIDLesser()); return result; } namespace { class FindOptionHandlerByNameSubstring : public std::unary_function , bool> { private: std::string substring_; public: FindOptionHandlerByNameSubstring (const std::string& substring):substring_(substring) {} bool operator()(const SharedHandle& optionHandler) const { return !optionHandler->isHidden() && optionHandler->getName().find(substring_) != std::string::npos; } }; } // namespace std::vector > OptionParser::findByNameSubstring(const std::string& substring) const { std::vector > result; std::remove_copy_if(optionHandlers_.begin(), optionHandlers_.end(), std::back_inserter(result), std::not1(FindOptionHandlerByNameSubstring(substring))); std::sort(result.begin(), result.end(), OptionHandlerIDLesser()); return result; } std::vector > OptionParser::findAll() const { std::vector > result; std::remove_copy_if(optionHandlers_.begin(), optionHandlers_.end(), std::back_inserter(result), mem_fun_sh(&OptionHandler::isHidden)); std::sort(result.begin(), result.end(), OptionHandlerIDLesser()); return result; } namespace { template SharedHandle findOptionHandler (InputIterator first, InputIterator last, Predicate pred) { SharedHandle handler; InputIterator i = std::find_if(first, last, pred); if(i != last) { handler = *i; } return handler; } } // namespace SharedHandle OptionParser::findByName(const std::string& name) const { SharedHandle handler(new DummyOptionHandler(name)); std::vector >::const_iterator i = std::lower_bound(optionHandlers_.begin(), optionHandlers_.end(), handler, OptionHandlerNameLesser()); if(i != optionHandlers_.end() && (*i)->getName() == name && !(*i)->isHidden()) { handler = *i; } else { handler.reset(); } return handler; } namespace { class FindOptionHandlerByID:public std::unary_function , bool> { private: int id_; public: FindOptionHandlerByID(int id):id_(id) {} bool operator()(const SharedHandle& optionHandler) const { return !optionHandler->isHidden() && optionHandler->getOptionID() == id_; } }; } // namespace SharedHandle OptionParser::findByID(int id) const { return findOptionHandler(optionHandlers_.begin(), optionHandlers_.end(), FindOptionHandlerByID(id)); } namespace { class FindOptionHandlerByShortName: public std::unary_function, bool> { private: char shortName_; public: FindOptionHandlerByShortName(char shortName):shortName_(shortName) {} bool operator()(const SharedHandle& optionHandler) const { return !optionHandler->isHidden() && optionHandler->getShortName() == shortName_; } }; } // namespace SharedHandle OptionParser::findByShortName(char shortName) const { return findOptionHandler(optionHandlers_.begin(), optionHandlers_.end(), FindOptionHandlerByShortName(shortName)); } SharedHandle OptionParser::optionParser_; const SharedHandle& OptionParser::getInstance() { if(!optionParser_) { optionParser_.reset(new OptionParser()); optionParser_->setOptionHandlers(OptionHandlerFactory::createOptionHandlers()); } return optionParser_; } } // namespace aria2