Option-- Documentation

2.2

logo.png

Introduction.

This library provides a number of classes to help applications with the tedious choir of parsing command line arguments. I made this library as this is a thing that keeps poping up, so I thought: `Why not put that stuff which I did a thousand times over into a library, and save me the grief of doing over and over again?' If you fell the same way, this library is for you.

Usage

The use of this library is really easy. First, include the header file optionmm/command_line.hh:
#ifndef OPTIONMM_command_line
#include <optionmm/command_line.hh>
#endif

Then, in the main program, construct an instance of the class optionmm::command_line:

int main(int argc, char** argv) 
{
  optionmm::basic_command_line<> cl("Demonstration of Option--", "1.0", 
                                    "Copyright (c) 2002 Christian Holm", 
                                    "", argc, argv);

The first argument of the constructor is a tenative title of the application at hand, and the second is the version number (as a string) of the application.

If the project is using Autoconf, the preprocessor macros PACKAGE_NAME and PACKAGE_VERSION for these two arguments, thereby automating the process.

The third argument is a short line giving the copyright information of the application. This is shown under the application title when the user requests help.

The fourth and fifth arguments are the command line length and array of arguments. These are usually called argc and argv.

One can pass an error handler class as a template parameter to the declaration of the optionmm::basic_command_line object. This class should define the appropriate member functions to deal with unknown arguments, and bad option values. See also optionmm::default_error_handler.

The next step is to define some options:

  
  optionmm::basic_option<int>  i_opt('i', "int", "Integer option", 0); 

The class optionmm::basic_option is a templated class. The requirements of the type parameter, is that it is assignable, and that it is possible to convert to from a string (const char* ) to that value type, using a regular cast a std::stringstream. For custom types, this is done by defining the extraction operator:

    class foo 
    {
      ...
    };
    
    std::istream& operator>>(std::istream& i, foo& f) 
    { 
      ...
    }

The template class optionmm::basic_option takes two more optional parameters, both of which should be booleans.

The optional second template parameter specifies whether or not the option needs an argument. An error will be issued if the application user didn't specify an argument for an option that has this template parameter set to true. The default value is true. If this parameter is set to false, then specifying this option to the application makes an instance of operator!(Type) which you better define unless Type is convertable to some simple type.

The optional third template parameter specifies whether or not the option can take multiple values (arguments or set count). If this parameter is true, (the default) then specifying the same option to the application more than once causes the optionmm::basic_option object to store all those values, which can later be retrived via calls to optionmm::basic_option::value(int). If false, giving the same option several times, overwrites the previous value.

The first argument to the constructor is the letter of the short command line option the object corresponds to. If '\0' is specified, the option has no short command line option.

The second argument to the constructor, is the long command line option corresponding to the argument. If this is left blank (the empty string) the object has no corresponding long option.

The third argument, is the help string corresponding to the object. This is shown, along with the applicaion synopsis and option list, when the user requests help from the application.

The final fourth argument to the constructor, is the default value for the option object. Note that this must be of the value type of the option object.

The library provides typedef of the most common option types: optionmm::int_option, optionmm::float_option, optionmm::string_option, and optionmm::bool_option. The latter is defined as a single-value, no-argument kind of option.

  optionmm::int_option         I_opt('I', "Int", "Integer option", 42);

After defining an option, the optionmm::basic_command_line object needs to know about it:

  
  cl.add(i_opt);
  cl.add(I_opt);

After registering all the options the application may need, the application must call optionmm::basic_command_line::process to process the actual command line.

  if (!cl.process()) return 1;

The member function optionmm::basic_command_line::process returns false if an error occured during parsing, so testing the return value of that member function is recommended.

Note, that optionmm::basic_command_line::process changes the arguments of main (argc, and argv in the example above), by removing all components that was used in the parsing. Hence, after optionmm::basic_command_line::process the two variables only contain what was on the command line, which wasn't options. This is useful if the application wants to process files or similar.

The optionmm::basic_command_line has two automatic options build in: One for showing the help, and one for showing the version number of the application. These are invoked from the command line by -h or --help for the help, and --version for the version information. To facilitate that output in the application, it must invoke the member functions optionmm::basic_command_line::help and optionmm::basic_command_line::version.

  if (cl.help()) return 0;
  cl.version();

Both of these member functions return true if the corresponding option was given on the application command line. Hence, one can for example stop the application if help was requested by the application user (as shown above). Note, that the help always implies the version information too.

After having processed the command line, and testing for errors or the like, the optionmm::basic_option objects now contain the values passed by the application user. The application can then retrive these values by (possibly repeated) calls to optionmm::basic_option::value. For example, one could print the values on standard out:

  
  for (int i = 0; i < i_opt.size(); i++) 
    std::cout << i_opt.value(i) << std::endl;

Error handling

Error handling is taken care of the template argument to optionmm::basic_command_line. It's a policy argument. The type should define four public member function, all returning a bool:

    bool on_onknown(char c,std::string& progname) 
Member function invoked in case an unknown short option was passed to the application. First argument is the short option given, while the second is the program invocation name.

    bool on_onknown(const char* c,std::string& progname) 
Member function invoked in case an unknown long option was passed to the application. First argument is the long option given, while the second is the program invocation name.

    template <typename O>
    bool on_missing_argument(O&, bool is_short,std::string& progname) 
Member function invoked in case no argument was given to an option that needs an argument. The first argument is the option that needs the argument, the second is whether it was invoked as in it's short form or not, and the third is the program invocation name.

    template <typename O>
    bool on_bad_argument(O&, bool is_short,std::string& progname) 
Member function invoked in case a bad argument was given to an option e.g., a string was passed to an option taking an integer argument. The long story of this is covered elsewhere (Converting the command line arguments to option). The first argument is the option that needs the argument, the second is whether it was invoked as in it's short form or not, and the third is the program invocation name.

All these methods should return true if the basic_command_line should stop processing the command line and return immediately, or false if it should continue.

Client code can freely define new error handlers to suite the needs of the application. For example:

    struct my_error_handler 
    {
      bool on_unknown(char c, const std::string& progname) 
      {
        throw std::runtime_error("unknown option");
        return true;
      }
      bool on_unknown(const std::string& str, const std::string& progname)
      {
        throw std::runtime_error("unknown option");
        return true;
      }
      template <typename Option>
      bool on_missing_argument(Option& o, 
                               bool is_short, 
                               const std::string& progname) 
      {
        throw std::runtime_error("missing argument to an option");
        return true;
      }
      template <typename Option>
      bool on_bad_argument(Option& o, 
                           bool is_short, 
                           const std::string& progname) 
      {
        throw std::runtime_error("bad argument to an option");
        return true;
      }
    };

    ...

    int main(int argc, char** argv) 
    { 
      optionmm::basic_command_line<my_error_handler> cl(...);

      ...

      try {
        cl.process();

        ...

      } catch (std::exception& e)  {
        std::cerr << e.what() << std::endl;
        return 1;
      }
      return 0;
    }

See also:
optionmm::default_error_handler

Converting the command line arguments to option

values.

When the command line arguments enters the application function (main) it is as an array of C string values. However, a command line option may conceptually be something completely different from a string. It could be a number or a flag.

Hence we need to convert the C strings to what ever type a given option wants and stores. This is done via a trait argument to the optionmm::basic_option structure. This trait type should define two member functions:

    bool  convert (const char *arg, value_type &val)
Convert the first argument (C string) to a value of type value_type and store it in the second output argument. It should return true on success, and false otherwise.

    bool  convert (reference val)
Toggle the value in the argument. Usually this is just assigning !val to val (possibly via a temporary).

The default trait is optionmm::option_trait. The first member function is implemented using std::stringstream. To extract a value, of a given type from a string, one can do

      std::stringstream s(str);
      Type t;
      s >> t;
were str is some std::string object, and Type is some type for which the extraction operator
      std::istream operator>>(std::istream& i, Type& t);
is defined.

Hence, defining the above extraction operator for a user type, allows it to be used seemlessly with the Option-- classes, as well as providing a useful tool in I/O operations, all in one go - pretty neat, eh! For example, one could do

    struct foo 
    {
      foo(int f) : _foo(0) {}
      int _foo;
    };
    std::istream& operator(std::istream& i, foo& f) 
    {
      return i >> f._foo;
    }
    int main(int argc, char** argv) 
    {
      optionmm::command_line cl("Trying foo", "1.0", 
                                "Copyright (c) 2003 Christian Holm", "",
                                argc, argv);
      optionmm::basic_option<foo> foo_option('f',"foo", "foo option",foo());
      cl.add(foo_option);
      return cl.process();
    }
The I/O sub-library of the Standard C++ Library is quite a powerful entity.

Application Usage

Running an application with lines like the above (demo.cc ) with various command lines will give:
 
    prompt> ./demo -h
    Demonstration of Option-- version 1.0
    Copyright (c) 2002 Christian Holm

    Usage: demo [OPTIONS]

        -h, --help         	Show this help
            --version      	Show version information
        -i, --int=VALUE    	Integer option (*)
        -I, --Int=VALUE    	Integer option (*)

    prompt> ./demo --version
    Demonstration of Option-- version 1.0
    Copyright (c) 2002 Christian Holm
    0
    prompt> ./demo -i 10 -i 42 
    10
    42
    prompt> ./demo --int=42 -i50 -I10 -I 19
    42
    50
    prompt> ./demo -f
    Option `-f' unknown, try `demo --help'
    

Support Features

The library comes with two extra files: an Autoconf macro file optionmm.m4 that defines AM_PATH_OPTIONMM, and a SH script optionmm-config that developers can use to get the relevant information into thier build system.

The syntax of the Autoconf macro is

 
    AM_PATH_OPTIONMM([MINIMUM-VERSION[,ACTION-IF_FOUND[,ACTION-IF-NOT-FOUND]])
    
If the macro finds Option-- on the system, then it defines OPTIONMM_CPPFLAGS to the relevant preprocessor flags for including <optionmm/command_line.hh>, and OPTIONMM_CONFIG to point to the optionmm-config shell script.

The shell script optionmm-config has the following synopsis:

    Usage: optionmm-config [options]
    
      --prefix          Gives the installation prefix
      --includedir      Gives path to headers 
      --cppflags        Gives preprocessor information
      --version         Gives version information
      --help            Gives this help
    
where the options gives the various installation details.

Finally, there's a man(1) page for optionmm-config too.

Copyright

Copyright (C) 2002 Christian Holm Christensen <cholm@nbi.dk>

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This library 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 Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

See also Licence of the source code.

Top of page Last update Tue Jan 13 19:10:34 2004
Christian Holm
Created by DoxyGen 1.3.4