program_options.h
Go to the documentation of this file.
00001 //
00002 //  Copyright (c) Benjamin Kaufmann 2004
00003 //
00004 //  This is free software; you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation; either version 2 of the License, or
00007 //  (at your option) any later version. 
00008 // 
00009 //  This file is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this file; if not, write to the Free Software
00016 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017 //
00018 //
00019 // NOTE: ProgramOptions is inspired by Boost.Program_options
00020 //       see: www.boost.org/libs/program_options
00021 //
00022 #ifndef PROGRAM_OPTIONS_PROGRAM_OPTIONS_H_INCLUDED
00023 #define PROGRAM_OPTIONS_PROGRAM_OPTIONS_H_INCLUDED
00024 #include "value.h"
00025 #include "detail/refcountable.h"
00026 #include <iosfwd>
00027 #include <set>
00028 #include <map>
00029 #include <vector>
00030 #include <stdexcept>
00031 #include <memory>
00032 #include <cstdio>
00033 namespace ProgramOptions {
00034 
00036 
00045 class Option : public detail::RefCountable {
00046 public:
00055         Option( const std::string& longName, char shortName,
00056                 const char* description, Value* value);
00057 
00058         ~Option();
00059 
00060         const std::string& name()           const  { return name_; }
00061         char               alias()          const  { return value_->alias(); }
00062         Value*             value()          const  { return value_; }
00063         const char*        description()    const  { return description_; }
00064         const char*        argName()        const  { return value_->arg(); }
00065         bool               assignDefault()  const;
00066         std::size_t        maxColumn()      const;
00067         DescriptionLevel   descLevel()      const  { return value_->level(); }
00068 private:
00069         std::string name_;        // name (and unique key) of option
00070         const char* description_; // description of the option (used for --help)
00071         Value*      value_;       // the option's value manager
00072 };
00073 
00074 typedef detail::IntrusiveSharedPtr<Option> SharedOptPtr;
00075 
00076 class OptionInitHelper;
00077 class OptionContext;
00078 class OptionParser;
00079 class ParsedValues;
00080 class ParsedOptions;
00081 class OptionOutput;
00082 
00084 
00088 class OptionGroup {
00089 public:
00090         typedef std::vector<SharedOptPtr>  OptionList;
00091         typedef OptionList::const_iterator option_iterator;
00092 
00096         OptionGroup(const std::string& caption = "", DescriptionLevel descLevel = desc_level_default);
00097         ~OptionGroup();
00098 
00100         const std::string& caption() const { return caption_; }
00101 
00102         std::size_t      size()     const { return options_.size();  }
00103         bool             empty()    const { return options_.empty(); }
00104         option_iterator  begin()    const { return options_.begin(); }
00105         option_iterator  end()      const { return options_.end();   }
00106         DescriptionLevel descLevel()const { return level_; }
00107         
00109 
00121         OptionInitHelper addOptions();
00122 
00124         void addOption(std::auto_ptr<Option> option);
00125 
00126         void setDescriptionLevel(DescriptionLevel level) { level_ = level; }
00127 
00129         void format(OptionOutput& out, size_t maxW, DescriptionLevel level = desc_level_default) const;
00130 
00131         std::size_t maxColumn(DescriptionLevel level) const;
00132 private:
00133         friend class OptionContext;
00134         std::string      caption_;
00135         OptionList       options_;
00136         DescriptionLevel level_;
00137 };
00138 
00139 class OptionInitHelper {
00140 public:
00141         explicit OptionInitHelper(OptionGroup& owner);
00142         
00144 
00152         OptionInitHelper& operator()(const char* key,
00153                 Value* val, const char* desc);
00154 private:
00155         OptionGroup* owner_;
00156 };
00157 
00159 
00167 class OptionContext {
00168 private:
00169         typedef std::size_t                               key_type;
00170         typedef std::map<std::string, key_type>           Name2Key;
00171         typedef std::vector<OptionGroup>                  GroupList;
00172         typedef Name2Key::const_iterator                  index_iterator;
00173         typedef std::pair<index_iterator, index_iterator> PrefixRange;
00174         typedef OptionGroup::OptionList                   OptionList;
00175 public:
00177         typedef OptionList::const_iterator option_iterator;
00178         typedef PrefixRange                OptionRange;  
00179         
00180         OptionContext(const std::string& caption = "", DescriptionLevel desc_default = desc_level_default);
00181         ~OptionContext();
00182 
00183         const std::string& caption() const;
00184         
00186 
00194         OptionContext& add(const OptionGroup& group);
00195 
00197 
00200         OptionContext& addAlias(const std::string& aliasName, option_iterator option);
00201 
00203 
00210         OptionContext& add(const OptionContext& other);
00211         
00212         option_iterator begin() const { return options_.begin(); }
00213         option_iterator end()   const { return options_.end();   }
00214         
00216         std::size_t    size()   const { return options_.size(); }
00218         std::size_t    groups() const { return groups_.size(); }
00219 
00220         enum FindType { find_name = 1, find_prefix = 2, find_name_or_prefix = find_name|find_prefix, find_alias = 4 };
00221         
00223 
00236         option_iterator find(const char* key, FindType t = find_name) const;
00241         option_iterator tryFind(const char* key, FindType t = find_name) const;
00242 
00243         OptionRange findImpl(const char* key, FindType t, unsigned eMask = unsigned(-1)) const { return findImpl(key, t, eMask, caption()); }
00244         OptionRange findImpl(const char* key, FindType t, unsigned eMask, const std::string& eCtx) const;
00245 
00246         const OptionGroup& findGroup(const std::string& caption) const;
00247         const OptionGroup* tryFindGroup(const std::string& caption) const;
00248         
00250 
00254         void             setActiveDescLevel(DescriptionLevel level);
00255         DescriptionLevel getActiveDescLevel() const { return descLevel_; }
00256         
00258         OptionOutput& description(OptionOutput& out) const;
00259         
00261         std::string defaults(std::size_t prefixSize = 0) const;
00262         
00264         friend std::ostream& operator<<(std::ostream& os,  const OptionContext& ctx);
00265 
00267 
00270         bool assignDefaults(const ParsedOptions& exclude) const;
00271 private:
00272         void        insertOption(size_t groupId, const SharedOptPtr& o);
00273         size_t      findGroupKey(const std::string& name) const;
00274         
00275         Name2Key         index_;
00276         OptionList       options_;
00277         GroupList        groups_;
00278         std::string      caption_;
00279         DescriptionLevel descLevel_;
00280 };
00281 
00282 class OptionParser;
00283 class ParsedValues;
00284 
00286 class ParsedOptions {
00287 public:
00288         ParsedOptions();
00289         ~ParsedOptions();
00290         bool        empty()                        const  { return parsed_.empty(); }
00291         std::size_t size()                         const  { return parsed_.size(); }
00292         std::size_t count(const std::string& name) const  { return parsed_.count(name); }
00293         void        add(const std::string& name)          { parsed_.insert(name); }
00294         
00296 
00307         bool        assign(const ParsedValues& p, const ParsedOptions* exclude = 0);
00308 private:
00309         std::set<std::string> parsed_;
00310         int assign(const Option& o, const std::string& value);
00311 };
00312 
00316 class ParsedValues {
00317 public:
00318         typedef std::pair<SharedOptPtr, std::string> OptionAndValue;
00319         typedef std::vector<OptionAndValue> Values;
00320         typedef Values::const_iterator iterator;
00321 
00325         explicit ParsedValues(const OptionContext& a_ctx)
00326                 : ctx(&a_ctx)
00327         {}
00328         const OptionContext* ctx;
00329         
00331         void add(const std::string& opt, const std::string& value);
00332         void add(const SharedOptPtr& opt, const std::string& value) {
00333                 parsed_.push_back(OptionAndValue(opt, value));
00334         }
00335 
00336         iterator begin() const { return parsed_.begin(); }
00337         iterator end()   const { return parsed_.end(); }
00338 
00339         void clear() { parsed_.clear(); }
00340 private:
00341         Values parsed_;
00342 };
00343 
00344 class ParseContext {
00345 public:
00346         typedef OptionContext::FindType FindType;
00347         virtual ~ParseContext();
00348         virtual SharedOptPtr getOption(const char* name, FindType ft)                    = 0;
00349         virtual SharedOptPtr getOption(int posKey, const char* tok)                      = 0;
00350         virtual void         addValue(const SharedOptPtr& key, const std::string& value) = 0;
00351 };
00352 
00354 class OptionParser {
00355 public:
00356         typedef OptionContext::FindType FindType;
00357         explicit OptionParser(ParseContext& ctx);
00358         virtual ~OptionParser();
00359         ParseContext& parse();
00360 protected:
00361         ParseContext& ctx() const { return *ctx_; }
00362         SharedOptPtr  getOption(const char* name, FindType ft) const { return ctx_->getOption(name, ft); }
00363         SharedOptPtr  getOption(int posKey, const char* tok)   const { return ctx_->getOption(posKey, tok); }
00364         void          addOptionValue(const SharedOptPtr& key, const std::string& value) { ctx_->addValue(key, value); } 
00365 private:
00366         virtual void doParse() = 0;
00367         ParseContext* ctx_;
00368 };
00369 
00371 struct DefaultFormat {
00372         std::size_t format(std::vector<char>&, const OptionContext&) { return 0; }
00374         std::size_t format(std::vector<char>& buffer, const OptionGroup& g);
00376         std::size_t format(std::vector<char>& buffer, const Option& o, std::size_t maxW);
00378 
00382         std::size_t format(std::vector<char>& buffer, const char* desc, const Value&, std::size_t maxW);
00383 };
00384 
00386 class OptionOutput {
00387 public:
00388         OptionOutput() {}
00389         virtual ~OptionOutput() {}
00390         virtual bool printContext(const OptionContext& ctx)           = 0;
00391         virtual bool printGroup(const OptionGroup& group)             = 0;
00392         virtual bool printOption(const Option& opt, std::size_t maxW) = 0;
00393 };
00394 
00396 template <class Writer, class Formatter = DefaultFormat>
00397 class OptionOutputImpl : public OptionOutput {
00398 public:
00399         OptionOutputImpl(const Writer& w = Writer(), const Formatter& form = Formatter()) 
00400                 : writer_(w)
00401                 , formatter_(form) { }
00402         bool printContext(const OptionContext& ctx) {
00403                 writer_.write(buffer_, formatter_.format(buffer_, ctx));
00404                 return true;
00405         }
00406         bool printGroup(const OptionGroup& group) {
00407                 writer_.write(buffer_, formatter_.format(buffer_, group));
00408                 return true;
00409         }
00410         bool printOption(const Option& opt, std::size_t maxW) {
00411                 writer_.write(buffer_, formatter_.format(buffer_, opt, maxW));
00412                 writer_.write(buffer_, formatter_.format(buffer_, opt.description(), *opt.value(), maxW));
00413                 return true;
00414         }
00415 private:
00416         std::vector<char> buffer_;
00417         Writer            writer_;
00418         Formatter         formatter_;
00419 };
00421 struct OstreamWriter {
00422         OstreamWriter(std::ostream& os) : out(os) {}
00423         void write(const std::vector<char>& buf, std::size_t num);
00424         std::ostream& out;
00425 private: void operator=(const OstreamWriter&);
00426 };
00428 struct StringWriter {
00429         StringWriter(std::string& str) : out(str) {}
00430         void write(const std::vector<char>& buf, std::size_t num);
00431         std::string& out;
00432 private: void operator=(const StringWriter&);
00433 };
00435 struct FileWriter {
00436         FileWriter(FILE* f) : out(f) {}
00437         void write(const std::vector<char>& buf, std::size_t num);
00438         FILE* out;
00439 };
00440 typedef OptionOutputImpl<OstreamWriter> StreamOut;
00441 typedef OptionOutputImpl<StringWriter>  StringOut;
00442 typedef OptionOutputImpl<FileWriter>    FileOut;
00444 // parse functions
00446 
00452 typedef bool (*PosOption)(const std::string&, std::string&);
00453 
00454 enum CommandLineFlags {
00455         command_line_allow_flag_value = 1u,
00456 };
00457 
00473 ParsedValues parseCommandLine(int& argc, char** argv, const OptionContext& ctx,
00474         bool allowUnregistered = true,
00475         PosOption posParser = 0, unsigned flags = 0);
00476 
00477 ParseContext& parseCommandLine(int& argc, char** argv, ParseContext& ctx, unsigned flags = 0); 
00478 
00491 ParsedValues parseCommandString(const std::string& cmd, const OptionContext& ctx, bool allowUnreg = false, PosOption posParser = 0, unsigned flags = command_line_allow_flag_value);
00492 ParseContext& parseCommandString(const char* cmd, ParseContext& ctx, unsigned flags = command_line_allow_flag_value); 
00493 
00507 ParsedValues parseCfgFile(std::istream& is, const OptionContext& o, bool allowUnregistered);
00508 
00509 }
00510 
00511 #endif


clasp
Author(s): Benjamin Kaufmann
autogenerated on Thu Aug 27 2015 12:41:39