Commandline.h

Go to the documentation of this file.
00001 #ifndef TAGCOLL_COMMANDLINE_H
00002 #define TAGCOLL_COMMANDLINE_H
00003 
00004 #include <tagcoll/Exception.h>
00005 #include <string>
00006 #include <vector>
00007 #include <list>
00008 #include <map>
00009 #include <ostream>
00010 
00011 namespace Tagcoll {
00012 namespace commandline {
00013 
00014 typedef std::list<const char*> arglist;
00015 typedef arglist::iterator iter;
00016 
00017 class BadOption : public ConsistencyCheckException
00018 {
00019 public:
00020     BadOption(const std::string& context) throw ()
00021         : ConsistencyCheckException(context) {}
00022     virtual ~BadOption() throw () {}
00023 
00024     virtual const char* type() const throw () { return "BadOption"; }
00025 };
00026 
00028 class Parser
00029 {
00030     std::string m_name;
00031 
00032 public:
00033     Parser(const std::string& name) : m_name(name) {}
00034     virtual ~Parser() {}
00035     
00036     const std::string& name() const { return m_name; }
00037 
00045     virtual iter parseList(arglist& list) { return parse(list, list.begin()); }
00046 
00056     virtual iter parse(arglist& list, iter begin) = 0;
00057 };
00058 
00060 class Option
00061 {
00062     std::string m_name;
00063     mutable std::string m_fullUsage;
00064 
00065 public:
00066     Option(const std::string& name) : m_name(name) {}
00067     Option(const std::string& name, char shortName, const std::string& longName) : m_name(name)
00068     {
00069         if (shortName != 0)
00070             shortNames.push_back(shortName);
00071         if (!longName.empty())
00072             longNames.push_back(longName);
00073     }
00074     virtual ~Option() {}
00075 
00076     const std::string& name() const { return m_name; }
00077 
00078     void addAlias(char c) { shortNames.push_back(c); }
00079     void addAlias(const std::string& str) { longNames.push_back(str); }
00080 
00081     virtual bool boolValue() const = 0;
00082     virtual std::string stringValue() const = 0;
00083     virtual int intValue() const;
00084 
00092     virtual bool parse(const char* str = 0) = 0;
00093 
00095     const std::string& fullUsage() const;
00096     std::string fullUsageForMan() const;
00097 
00098     std::vector<char> shortNames;
00099     std::vector<std::string> longNames;
00100 
00101     std::string usage;
00102     std::string description;
00103 };
00104 
00106 class BoolOption : public Option
00107 {
00108     bool m_value;
00109 public:
00110     BoolOption(const std::string& name)
00111         : Option(name), m_value(false) {}
00112     BoolOption(const std::string& name, char shortName, const std::string& longName)
00113         : Option(name, shortName, longName), m_value(false) {}
00114 
00115     bool boolValue() const { return m_value; }
00116     std::string stringValue() const { return m_value ? "true" : "false"; }
00117 
00118     bool parse(const char* str) { m_value = true; return false; }
00119 };
00120 
00121 // Option needing a compulsory string value
00122 class StringOption : public Option
00123 {
00124     std::string m_value;
00125 public:
00126     StringOption(const std::string& name)
00127         : Option(name)
00128     {
00129         usage = "<val>";
00130     }
00131     StringOption(const std::string& name, char shortName, const std::string& longName)
00132         : Option(name, shortName, longName)
00133     {
00134         usage = "<val>";
00135     }
00136 
00137     bool boolValue() const { return !m_value.empty(); }
00138     std::string stringValue() const { return m_value; }
00139 
00140     bool parse(const char* str);
00141 };
00142 
00143 // Option needing a compulsory int value
00144 class IntOption : public Option
00145 {
00146     bool m_has_value;
00147     int m_value;
00148 
00149 public:
00150     IntOption(const std::string& name)
00151         : Option(name), m_has_value(false), m_value(0)
00152     {
00153         usage = "<num>";
00154     }
00155     IntOption(const std::string& name, char shortName, const std::string& longName)
00156         : Option(name, shortName, longName), m_has_value(false), m_value(0)
00157     {
00158         usage = "<num>";
00159     }
00160 
00161     bool boolValue() const { return m_has_value; }
00162     int intValue() const { return m_value; }
00163     std::string stringValue() const;
00164 
00165     bool parse(const char* str);
00166 };
00167 
00168 class ExistingFileOption : public Option
00169 {
00170     std::string m_value;
00171 public:
00172     ExistingFileOption(const std::string& name)
00173         : Option(name)
00174     {
00175         usage = "<file>";
00176     }
00177     ExistingFileOption(const std::string& name, char shortName, const std::string& longName)
00178         : Option(name, shortName, longName)
00179     {
00180         usage = "<file>";
00181     }
00182 
00183     bool boolValue() const { return !m_value.empty(); }
00184     std::string stringValue() const { return m_value; }
00185 
00186     bool parse(const char* str);
00187 };
00188 
00189 class OptionGroup
00190 {
00191 
00192 public:
00193     void add(Option* o) { options.push_back(o); }
00194 
00195     std::vector<Option*> options;
00196 
00197     std::string description;
00198 };
00199 
00201 class OptionParser : public Parser
00202 {
00203     std::map<char, Option*> m_short;
00204     std::map<std::string, Option*> m_long;
00205     std::vector<OptionGroup*> m_groups;
00206     std::vector<Option*> m_options;
00207 
00209     iter parseConsecutiveSwitches(arglist& list, iter begin);
00210 
00211     void addWithoutAna(Option* o);
00212 
00213 public:
00214     OptionParser(const std::string& name)
00215         : Parser(name), primaryAlias(name) {}
00216 
00217     void add(Option* o);
00218     void add(OptionGroup* group);
00219 
00220     const std::vector<OptionGroup*>& groups() const { return m_groups; }
00221     const std::vector<Option*>& options() const { return m_options; }
00222 
00227     virtual iter parse(arglist& list, iter begin);
00228 
00229     std::string primaryAlias;
00230     std::vector<std::string> aliases;
00231     std::string usage;
00232     std::string description;
00233     std::string longDescription;
00234     std::string examples;
00235 };
00236 
00237 class CommandParser : public Parser
00238 {
00239     OptionParser* m_last_command;
00240     std::map<std::string, OptionParser*> m_aliases;
00241 
00242     void add(const std::string& alias, OptionParser* o);
00243 
00244 public:
00245     CommandParser(const std::string& name)
00246         : Parser(name), m_last_command(0) {}
00247 
00248     OptionParser* lastCommand() const { return m_last_command; }
00249     OptionParser* command(const std::string& name) const;
00250 
00251     void add(OptionParser& o);
00252 
00261     virtual iter parse(arglist& list, iter begin);
00262 
00263     std::map<std::string, OptionParser*> getCommandInfo() const;
00264 
00265     std::string usage;
00266     std::string description;
00267     std::string longDescription;
00268 };
00269 
00276 template<class Base>
00277 class MainParser : public Base
00278 {
00279     arglist args;
00280 
00281 public:
00282     MainParser(const std::string& name) : Base(name) {}
00283 
00284     arglist parse(int argc, const char* argv[])
00285     {
00286         for (int i = 1; i < argc; i++)
00287             args.push_back(argv[i]);
00288         this->parseList(args);
00289         return args;
00290     }
00291 
00292     bool hasNext() const { return !args.empty(); }
00293 
00294     std::string next()
00295     {
00296         if (args.empty())
00297             return std::string();
00298         std::string res(*args.begin());
00299         args.erase(args.begin());
00300         return res;
00301     }
00302 };
00303 
00304 class DocMaker
00305 {
00306 protected:
00307     std::string m_app;
00308     std::string m_ver;
00309 
00310 public:
00311     DocMaker(const std::string& app, const std::string& ver)
00312         : m_app(app), m_ver(ver) {}
00313 };
00314 
00315 class Help : public DocMaker
00316 {
00317 public:
00318     Help(const std::string& app, const std::string& ver)
00319         : DocMaker(app, ver) {}
00320     
00321     void outputVersion(std::ostream& out);
00322     void outputHelp(std::ostream& out, const CommandParser& cp);
00323     void outputHelp(std::ostream& out, const OptionParser& cp);
00324 };
00325 
00326 class Manpage : public DocMaker
00327 {
00328 public:
00329     enum where { BEFORE, BEGINNING, END };
00330 
00331 private:
00332     struct Hook
00333     {
00334         std::string section;
00335         where placement;
00336         std::string text;
00337 
00338         Hook(const std::string& section, where placement, const std::string& text)
00339             : section(section), placement(placement), text(text) {}
00340     };
00341 
00342     std::vector<Hook> hooks;
00343     std::string lastSection;
00344     
00345     void outputParagraph(std::ostream& out, const std::string& str);
00346     void outputOption(std::ostream& out, const Option* o);
00347     void runHooks(std::ostream& out, const std::string& section, where where);
00348     void startSection(std::ostream& out, const std::string& name);
00349     void endSection(std::ostream& out);
00350 
00351 
00352 public:
00353     Manpage(const std::string& app, const std::string& ver)
00354         : DocMaker(app, ver) {}
00355 
00356     void addHook(const std::string& section, where placement, const std::string& text)
00357     {
00358         hooks.push_back(Hook(section, placement, text));
00359     }
00360     void readHooks(const std::string& file);
00361 
00362     void output(std::ostream& out, const CommandParser& cp, int section);
00363     void output(std::ostream& out, const OptionParser& cp, int section);
00364 };
00365 
00366 }
00367 }
00368 
00369 // vim:set ts=4 sw=4:
00370 #endif

Generated on Sat Jan 17 03:10:50 2009 for libtagcoll by  doxygen 1.5.1