/* GetOpt_pp: Yet another C++ version of getopt. Copyright (C) 2007, 2008 Daniel Gutson, FuDePAN This file is part of GetOpt_pp. GetOpt_pp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. board-games is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef CS_GETOPT_PP_H_ #define CS_GETOPT_PP_H_ #include #include #include #include #ifndef GETOPT_INLINE # define GETOPT_INLINE #endif namespace GetOpt { typedef std::vector OptionArgs; struct OptionData { enum _Flags { CmdLine_NotExtracted, CmdLine_Extracted, Envir }; _Flags flags; OptionArgs args; OptionData() : flags(CmdLine_NotExtracted) {} void clear() { flags = CmdLine_NotExtracted; args.clear(); } }; typedef std::map LongOptions; typedef std::map ShortOptions; struct _Option { enum Result { OK, ParsingError, OptionNotFound, BadType, NoArgs, TooManyArgs, OptionNotFound_NoEx }; virtual Result operator() (ShortOptions& short_ops, LongOptions& long_ops, std::ios::fmtflags flags) const = 0; virtual ~_Option() {} }; template inline _Option::Result convert(const std::string& s, T& result, std::ios::fmtflags flags) { std::stringstream ss; ss.clear(); ss.flags(flags); ss << s; ss >> result; if (ss.fail() || !ss.eof()) return _Option::BadType; else return _Option::OK; } template <> inline _Option::Result convert(const std::string& s, std::string& result, std::ios::fmtflags) { result = s; return _Option::OK; } template class _OptionTBase : public _Option { const char short_opt; const std::string long_opt; protected: T& target; virtual Result _assign(const OptionArgs& args, std::ios::fmtflags flags) const = 0; public: _OptionTBase(const _OptionTBase& other) : _Option(other), short_opt(other.short_opt), long_opt(other.long_opt), target(other.target) {} _OptionTBase(char short_opt, const std::string& long_opt, T& target) : short_opt(short_opt), long_opt(long_opt), target(target) {} virtual Result operator() (ShortOptions& short_ops, LongOptions& long_ops, std::ios::fmtflags flags) const { Result ret = OptionNotFound; ShortOptions::iterator it = short_ops.find(short_opt); if (it != short_ops.end()) { it->second.flags = OptionData::CmdLine_Extracted; ret = _assign(it->second.args, flags); } else if (!long_opt.empty()) { LongOptions::iterator iter = long_ops.find(long_opt); if (iter != long_ops.end()) { iter->second.flags = OptionData::CmdLine_Extracted; ret = _assign(iter->second.args, flags); } } return ret; } }; template class _OptionT : public _OptionTBase { protected: virtual _Option::Result _assign(const OptionArgs& args, std::ios::fmtflags flags) const { switch (args.size()) { case 0: return _Option::NoArgs; case 1: return convert(args[0], this->target, flags); default: return _Option::TooManyArgs; } } public: _OptionT(const _OptionT& other) : _OptionTBase(other) {} _OptionT(char short_opt, const std::string& long_opt, T& target) : _OptionTBase(short_opt, long_opt, target) {} }; template class _OptionT > : public _OptionTBase > { protected: virtual _Option::Result _assign(const OptionArgs& args, std::ios::fmtflags flags) const { if (!args.empty()) { _Option::Result result; OptionArgs::const_iterator it = args.begin(); T temp; do { result = convert(*it, temp, flags); if (result == _Option::OK) this->target.push_back(temp); ++it; } while(it != args.end() && result == _Option::OK); return result; } else { return _Option::NoArgs; } } public: _OptionT(const _OptionT >& other) : _OptionTBase >(other) {} _OptionT(char short_opt, const std::string& long_opt, std::vector& target) : _OptionTBase >(short_opt, long_opt, target) {} }; template class _DefValOption : public BaseOption { const T default_value; public: _DefValOption(const _DefValOption& other) : BaseOption(other), default_value(other.default_value) {} _DefValOption(char short_opt, const std::string& long_opt, T& target, const T& default_value) : BaseOption(short_opt, long_opt, target), default_value(default_value) {} virtual _Option::Result operator() (ShortOptions& short_ops, LongOptions& long_ops, std::ios::fmtflags flags) const { _Option::Result ret = BaseOption::operator()(short_ops, long_ops, flags); if (ret == _Option::OptionNotFound) { this->target = default_value; ret = _Option::OK; } return ret; } }; template inline _OptionT Option(char short_opt, const std::string& long_opt, T& target) { return _OptionT(short_opt, long_opt, target); } template inline _OptionT Option(char short_opt, T& target) { return _OptionT(short_opt, std::string(), target); } // Defaulted version template inline _DefValOption > Option(char short_opt, const std::string& long_opt, T& target, const T& def) { return _DefValOption >(short_opt, long_opt, target, def); } template inline _DefValOption > Option(char short_opt, T& target, const T& def) { return _DefValOption >(short_opt, std::string(), target, def); } // Defaults for strings: inline _DefValOption > Option(char short_opt, const std::string& long_opt, std::string& target, const char* def) { return _DefValOption >(short_opt, long_opt, target, def); } inline _OptionT Option(char short_opt, std::string& target, const char* def) { return _DefValOption >(short_opt, std::string(), target, def); } class OptionPresent : public _Option { const char short_opt; const std::string long_opt; bool* const present; public: // two combinations: with/without target, and with/without long opt. // WITH long_opt: OptionPresent(char short_opt, const std::string& long_opt, bool& present) : short_opt(short_opt), long_opt(long_opt), present(&present) {} OptionPresent(char short_opt, const std::string& long_opt) : short_opt(short_opt), long_opt(long_opt), present(NULL) {} // WITHOUT long_opt: OptionPresent(char short_opt, bool& present) : short_opt(short_opt), present(&present) {} OptionPresent(char short_opt) : short_opt(short_opt), present(NULL) {} protected: virtual Result operator() (ShortOptions& short_ops, LongOptions& long_ops, std::ios::fmtflags) const { bool found; ShortOptions::iterator it = short_ops.find(short_opt); found = (it != short_ops.end()); if (found) { it->second.flags = OptionData::CmdLine_Extracted; } else if (!long_opt.empty()) { LongOptions::iterator iter = long_ops.find(long_opt); found = (iter != long_ops.end()); if (found){ iter->second.flags = OptionData::CmdLine_Extracted; } } if (present != NULL) { *present = found; return OK; } else { return found ? OK : OptionNotFound_NoEx; } } }; class GetOptEx : public std::exception {}; struct ParsingErrorEx : public GetOptEx{}; struct InvalidFormatEx : public GetOptEx{}; struct ArgumentNotFoundEx : public GetOptEx{}; struct TooManyArgumentsEx : public GetOptEx{}; struct OptionNotFoundEx : public GetOptEx{}; struct TooManyOptionsEx : public GetOptEx{}; enum _EnvTag { Include_Environment }; class GetOpt_pp { ShortOptions _shortOps; LongOptions _longOps; std::ios_base::iostate _exc; _Option::Result _last; std::ios::fmtflags _flags; std::string _app_name; GETOPT_INLINE void _init_flags(); GETOPT_INLINE void _parse(int argc, char* argv[]); GETOPT_INLINE void _parse_env(); public: static const char EMPTY_OPTION; GETOPT_INLINE GetOpt_pp(int argc, char* argv[]); GETOPT_INLINE GetOpt_pp(int argc, char* argv[], _EnvTag); std::ios_base::iostate exceptions ( ) const { return _exc; } void exceptions ( std::ios_base::iostate except ) { _exc = except; } void exceptions_all() { _exc = std::ios_base::failbit | std::ios_base::eofbit; } operator bool() const { return _last == _Option::OK; } GETOPT_INLINE bool options_remain() const; void end_of_options() const throw(GetOptEx) { if (options_remain() && (_exc & std::ios_base::eofbit)) throw TooManyOptionsEx(); } std::ios::fmtflags flags() const { return _flags; } void flags(std::ios::fmtflags flags) { _flags = flags; } const std::string& app_name() const { return _app_name; } GETOPT_INLINE GetOpt_pp& operator >> (const _Option& opt) throw(GetOptEx); GETOPT_INLINE GetOpt_pp& operator >> (std::ios_base& (*iomanip)(std::ios_base&)); // Alternative to manipulators, for those who don't like them: the 'getopt' // method :) // Combination 1: with long option: template inline T getopt(char short_opt, const std::string& long_opt) throw(GetOptEx) { T result; operator >> (Option(short_opt, long_opt, result)); return result; } template inline T getopt(char short_opt, const std::string& long_opt, const T& def_value) { T result; operator >> (Option(short_opt, long_opt, result, def_value)); return result; } // Combination 2: without long option: template inline T getopt(char short_opt) throw(GetOptEx) { T result; operator >> (Option(short_opt, result)); return result; } template inline T getopt(char short_opt, const T& def_value) { T result; operator >> (Option(short_opt, result, def_value)); return result; } typedef std::pair ItPair; template class _iterator { typename Container::const_iterator _it; public: _iterator(ItPair p) { _it = Adapter::adapt(p); } _iterator() {} _iterator& operator = ( const _iterator& other) { _it = other._it; return *this; } bool operator != (const _iterator& other) const { return _it != other._it; } OptionType option() const { return _it->first; } const OptionArgs& args() const { return _it->second.args; } bool extracted() const { return _it->second.flags == OptionData::CmdLine_Extracted; } _iterator& operator ++() { ++_it; return *this; } }; ItPair begin() const { return ItPair(_shortOps.begin(), _longOps.begin() ); } ItPair end() const { return ItPair(_shortOps.end(), _longOps.end()); } struct ShortAdapter { static ShortOptions::const_iterator adapt(ItPair p) { return p.first; } }; struct LongAdapter { static LongOptions::const_iterator adapt(ItPair p) { return p.second; } }; typedef _iterator short_iterator; typedef _iterator long_iterator; }; class Environment { // Coming soon! }; } // namespace GetOpt #endif // CS_GETOPT_PP_H_