]> git.tdb.fi Git - libs/core.git/blobdiff - source/core/getopt.h
Add support for positional arguments in GetOpt
[libs/core.git] / source / core / getopt.h
index 70841cbf6b8dc50da4800bfae42ebc78e6d7e122..f4e318e55d3eec1e8b14a160101e75c7be9e9cbb 100644 (file)
@@ -44,9 +44,19 @@ A single option may have both alternative forms, but must always have at least
 a long form.  This is to encourage self-documenting options; it's much easier
 to remember words than letters.
 
-A built-in --help option is provided and will output a list of options and
-their associated help texts.  An application may override this by providing
-its own option with the same name.
+Positional arguments are also supported.  They are identified by an arbitrary
+string, but the identifier is only used in help text and error messages.  Any
+number of the final arguments may be optional.
+
+To support applications that take an arbitrary amount of arguments, a single
+positional argument list can be specified.  Fixed positional arguments are
+allowed together with a list, but they can't be optional.  An application that
+wants to do complex processing on the argument list can declare a list of
+string arguments.
+
+A built-in --help option is provided and will output a list of options,
+arguments and their associated help texts.  An application may override this by
+providing its own option with the same name.
 */
 class GetOpt
 {
@@ -78,6 +88,16 @@ public:
                virtual unsigned get_seen_count() const = 0;
        };
 
+       class Argument
+       {
+       protected:
+               Argument() { }
+       public:
+               virtual ~Argument() { }
+
+               virtual Argument &set_help(const std::string &) = 0;
+       };
+
 private:
        class Store
        {
@@ -122,6 +142,26 @@ private:
                void process(const std::string &);
        };
 
+       class ArgumentImpl: public Argument
+       {
+       private:
+               std::string name;
+               ArgType type;
+               std::string help;
+               Store *store;
+
+       public:
+               ArgumentImpl(const std::string &, const Store &, ArgType);
+               virtual ~ArgumentImpl();
+
+               virtual ArgumentImpl &set_help(const std::string &);
+               const std::string &get_name() const { return name; }
+               ArgType get_type() const { return type; }
+               const std::string &get_help() const { return help; }
+               bool is_list_store() const { return store->is_list(); }
+               void process(const std::string &);
+       };
+
        template<typename T>
        class SimpleStore: public Store
        {
@@ -163,17 +203,20 @@ private:
        };
 
        typedef std::list<OptionImpl *> OptionList;
+       typedef std::list<ArgumentImpl *> ArgumentList;
 
        bool help;
        OptionList opts;
-       std::vector<std::string> args;
+       ArgumentList args;
+       std::vector<std::string> args_raw;
 
 public:
        GetOpt();
        ~GetOpt();
 
-       /// Returns any non-option arguments encountered during processing.
-       const std::vector<std::string> &get_args() const { return args; }
+       /** Returns any non-option arguments encountered during processing.
+       Deprecated. */
+       const std::vector<std::string> &get_args() const { return args_raw; }
 
        /** Adds an option with both short and long forms.  Processing depends on
        the type of the destination variable and whether an argument is taken or
@@ -196,8 +239,22 @@ public:
        Option &add_option(const std::string &l, T &d, ArgType a)
        { return add_option(0, l, d, a); }
 
+       /** Adds a positional argument.  The value will be lexical_cast to the
+       appropriate type and stored in the destination. */
+       template<typename T>
+       Argument &add_argument(const std::string &n, T &d, ArgType a = REQUIRED_ARG)
+       { return add_argument(n, SimpleStore<T>(d), a); }
+
+       /** Adds a positional argument list.  If the list is declared as required,
+       at least one element must be given; an optional list may be empty.  Only one
+       list may be added, and optional fixed arguments can't be used with it. */
+       template<typename T>
+       Argument &add_argument(const std::string &n, std::list<T> &d, ArgType a = REQUIRED_ARG)
+       { return add_argument(n, ListStore<std::list<T> >(d), a); }
+
 private:
        OptionImpl &add_option(char, const std::string &, const Store &, ArgType);
+       ArgumentImpl &add_argument(const std::string &, const Store &, ArgType);
 
        OptionImpl &get_option(char);
        OptionImpl &get_option(const std::string &);
@@ -215,11 +272,11 @@ private:
        unsigned process_short(const char *const *);
 
 public:
-       /** Generates a single line that describes known options. */
+       /** Generates a single line that describes known options and arguments. */
        std::string generate_usage(const std::string &) const;
 
-       /** Generates help for known options in tabular format, one option per
-       line.  The returned string will have a linefeed at the end. */
+       /** Generates help for known options and arguments in tabular format, one
+       item per line.  The returned string will have a linefeed at the end. */
        std::string generate_help() const;
 };