00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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_;
00070 const char* description_;
00071 Value* value_;
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
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