Logo Search packages:      
Sourcecode: gaffitter version File versions  Download package

CmdLineParser.hh

Go to the documentation of this file.
// ---------------------------------------------------------------------
// $Id: CmdLineParser.hh,v 1.14 2006/08/26 09:43:05 daaugusto Exp $
//
//   CmdLineParser.hh (created on Tue Aug  8 11:01:58 BRT 2006)
// 
//   Genetic Algorithm File Fitter (gaffitter)
//
//   Copyright (C) 2005-2006 Douglas A. Augusto
// 
// This file is part of gaffitter.
// 
// gaffitter is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the
// Free Software Foundation; either version 2 of the License, or (at
// your option) any later version.
// 
// gaffitter 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
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public License
// along with gaffitter; if not, write to the Free Software Foundation,
// Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// ---------------------------------------------------------------------

#ifndef cmd_line_parser_hh
#define cmd_line_parser_hh

#include <string>
#include <sstream>
#include <list>
#include <limits>
#include <map>

#include "Exception.hh"

/** @file CmdLineParser.hh
 *
 * Read and extract options/args from command-line (via argv/argc).
 *
 * Example:
 * \code
 *   int main(int argc, char** argv)
 *   {
 *     // will contain the unrecognized options/arguments
 *     list<const char*> remains;
 *
 *     CmdLineParser Opts(argc,argv,remains);
 *
 *     // declaring a boolean option with an alias (optional)
 *     Opts.Bool.Add("-h","--help");
 *
 *     // a integer option (without alias) with default, min and max values
 *     Opts.Int.Add("-n","",5,0,10);
 *
 *     // float (float/double/long double) option
 *     Opts.Float.Add("--float","--float-option",1.0,-10.0,10.0);
 *
 *     // string option
 *     Opts.String.Add("-s","--string-option","default string");
 *
 *     // ...
 *
 *     // processing the command-line
 *     Opts.Process();
 *
 *     // getting the results!
 *     if (Opts.Bool.Get("-h")) cout << "-h is set" << endl;
 *
 *     if (!Opts.Int.Found("-n")) 
 *        cout << "-n not declared, using default." << endl;
 *
 *     int integer = Opts.Int.Get("-n");
 *     cout << "Value for '-n': " << integer << " As short int: "
 *          << Opts.Int.Get<short int>("-n") << endl;
 *
 *     cout << "Value for '-s': " << Opts.String.Get("-s") << endl;
 *
 *     // ...
 *
 *     cout << "\nUnrecognized arguments:" << endl;
 *
 *     list<const char*>::const_iterator ci = remains.begin();
 *     while (ci != remains.end()) cout << *ci++ << endl;
 *   }
 * \endcode
 *
 * For the code above, for example:
 * \verbatim
   $ ./a.out -h --string-option "abc" item1 item2
   -h is set
   -n not declared, using default.
   Value for '-n': 5
   Value for '-s': abc
  
   Unrecognized arguments:
   item1
   item2
   \endverbatim
  
   Other features:
  
   \li A command-line with '--' makes the remaining parameters "unrecognized" 
       a priori, i.e., stops the processing for options.

   \li Using an option with a minus sign after the name cancels the previous
       declaration (if any). For instance, '-x-' (or '--blahblah-') turns off
       the previous declaration of '-x' (or '--blahblah').

   \li If an option is declared two or more times, the last is used.

   \li 'Char' options allows special characters such as '\0', '\n', etc.
*/

using namespace std;

/** Default type for the <b>float</b> options */
00120 typedef long double FLOAT;

/** Default type for the <b>integer</b> options */
00123 typedef long INT;

// ---------------------------------------------------------------------
/** 
 * Holds the current value, min and max values for an option.
 */
00129 template<class T> class Option {
public:
   Option(T def, T min, T max) 
      : m_value(def), m_min(min), m_max(max), m_found(false), 
        m_has_alias(false) {}

public:
00136    T m_value, /**< Current value (the last encountered) for the option. */
     m_min, /**< Minimum allowed value (only for numerical types).*/
     m_max; /**< Maximum allowed value (only for numerical types).*/

00140    bool m_found; /**< <b>true</b> if the option was declared; 
                      <b>false</b> otherwise. */

public:
   /**
    * Indicate if this option has an alias. Used to avoid double free
    * corruption during memory deallocation (see ~OptionsType()).
    */
00148    bool m_has_alias;
};

// ---------------------------------------------------------------------
/**
 * Base class for the five types of options: Bool, Integer, Float, Char
 * and String.
 */
00156 template <class T> class OptionsType {
public:
   /**
    * Just for maintaining the code clean.
    */
00161    typedef typename map<string, void*>::const_iterator CI;

   /**
    * Add an option into \ref m_opts, checking for errors. Actually
    * m_opts holds just the name/alias (sorted), which then link to an
    * Option<T> object:
    *
    * \verbatim
    ...
    [name_option_1]  ------> | Option<T> |
    ...                   /  |   object  | 
    [alias_option_1] ----/    (values of 
    ...                        option_1)
    \endverbatim
    */
00176    void Add(const string& name, const string& alias="", T def=T(),
                                             T min=T(), T max=T())
   {
      CheckOption(name, alias);

      void* tmp = new Option<T>(def,min,max);
      m_opts[name] = tmp;

      if (alias.size() > 0) 
      {
         m_opts[alias] = tmp;
         static_cast<Option<T>*>(tmp)->m_has_alias = true;
      }
   }
   /**
    * Return true if the option specified as 's' was found in
    * command-line parameters. Return false otherwise.
    */
00194    bool Found(const string& s) const
   {
      const Option<T>* p = Find(s); if (p) return p->m_found;

      throw E_Exception("","Option "+s+" does not exist");
   }
   /** 
    * Return the value of option 's'. If 's' was not found in
    * command-line (or not in [min:max]) then the returned value =
    * 'default'.
    */
00205    T Get(const string& s) const
   {
      const Option<T>* p = Find(s); if (p) return p->m_value;

      throw E_Exception("","Option "+s+" does not exist");
   }
   /**
    * Simplified interface to perform casting. At times it is necessary
    * to convert a INT (possibly "long int") into 'short int', for
    * instance.
    */
00216    template<class C> C Get(const string& s) const
   {
      return static_cast<C>(Get(s));
   }

protected:
   /**
    * Memory deallocation for Option<T> objects. First check if the
    * object has two shared references (when an alias is used), making
    * sure that only one reference (pointer) will be deleted.
    */
00227    virtual ~OptionsType()
   {
      for (CI p = m_opts.begin(); p != m_opts.end(); ++p)
      {
         if (Cast(p)->m_has_alias) { Cast(p)->m_has_alias = false; continue; }

         delete Cast(p);
      }
   }

   /**
    * Make sure that an option name/alias begins with minus sign.
    */
00240    void CheckOption(const string& name, const string& alias) const
   {
      if (name[0] != '-')
         throw E_Exception("","Invalid option name: '"+name+"'");

      if (alias.size()>0 && alias[0] != '-')
         throw E_Exception("","Invalid option alias: '"+alias+"'");
   }

   /**
    * Performs a static_cast from a void pointer, returning the
    * correct type of option.
    */
00253    Option<T>* Cast(CI p) const { return static_cast<Option<T>*>(p->second); }

   /**
    * Try to find an option 's' and returns its pointer.
    */
00258    Option<T>* Find(const string& s) const
   { 
      CI p = m_opts.find(s); return p != m_opts.end() ? Cast(p) : 0;
   }

private:
   /**
    * Database of options of type T (Bool, Int, Float, Char or String).
    * STL 'map' object provides fast search via 'binary search'.
    */
00268    map<string,void*> m_opts;
};


// ---------------------------------------------------------------------
/**
 * Integer options.
 */
00276 class OptionsINT: public OptionsType<INT> {
public:
   
   void Add(const string& name, const string& alias="", INT def=0,
                               INT min=numeric_limits<INT>::min(), 
                               INT max=numeric_limits<INT>::max())
   {
      if (max<min) throw E_MaxMin<INT>(min, max, "Option "+name+": ");

      // calls the base Add function
      OptionsType<INT>::Add(name,alias,def,min,max);
   }
   /**
    * Try to identify an integer option in command-line and then add it
    * (together its int argument) into \ref m_opts.
    */
   bool Match(int&, char**, int);
};

// ---------------------------------------------------------------------
/**
 * Float options.
 */
00299 class OptionsFLOAT: public OptionsType<FLOAT> {
public:
   void Add(const string& name, const string& alias="", FLOAT def=0.0,
                               FLOAT min=numeric_limits<FLOAT>::min(), 
                               FLOAT max=numeric_limits<FLOAT>::max())
   {
      if (max<min) throw E_MaxMin<FLOAT>(min, max, "Option "+name+": ");

      // calls the base Add function
      OptionsType<FLOAT>::Add(name,alias,def,min,max);
   }
   /**
    * Try to identify a float option in command-line and then add it
    * (together its float argument) into \ref m_opts.
    */
   bool Match(int&, char**, int);
};

// ---------------------------------------------------------------------
/**
 * Boolean options.
 */
00321 class OptionsBOOL: public OptionsType<bool> {
public:
   /**
    * Try to identify a bool option in command-line and then add it
    * into \ref m_opts.
    */
   bool Match(int&, char**, int);
};

// ---------------------------------------------------------------------
/**
 * Char options.
 */
00334 class OptionsCHAR: public OptionsType<char> {
public:
   /**
    Try to identify a char option in command-line and then add it
    (together its char argument) into \ref m_opts.
    
    Some input combinations are interpreted as special characters:
    
    \verbatim
    \0 = null byte
    \a = bell character
    \b = backspace
    \f = formfeed
    \n = newline
    \r = carriage return
    \t = horizontal tab
    \v = vertical tab
    \\ = backslash
    \endverbatim
   */
   bool Match(int&, char**, int);
};
// ---------------------------------------------------------------------
/**
 * String options.
 */
00360 class OptionsSTRING: public OptionsType<string> {
public:
   /**
    * Try to identify a string option in command-line and then add it
    * (together its string argument) into \ref m_opts.
    */
   bool Match(int&, char**, int);
};

// ---------------------------------------------------------------------
/**
 * The user interface for the command-line parser.
 */
00373 class CmdLineParser {
public:
   /**
    * Starts the command-line parser.
    */
00378    CmdLineParser(int argc, char** argv, list<const char*>& remains): 
                 m_argc(argc), m_argv(argv), m_remains(remains) {}
   /**
    * After added all options then this function process the command-line
    * parameters searching for options and their arguments.
    */
   void Process();

public:
00387    class OptionsINT Int; /**< A database of integer options. */
00388    class OptionsFLOAT Float; /**< A database of float options. */
00389    class OptionsBOOL Bool; /**< A database of boolean options. */
00390    class OptionsCHAR Char; /**< A database of char options. */
00391    class OptionsSTRING String; /**< A database of string options. */

   /**
    * m_remains holds the unrecognized options. In other words, anyone
    * not int \ref Int, \ref Float, \ref Bool, \ref Char or \ref String.
    */
00397    list<const char*>& m_remains;

private:
00400    int m_argc; /**< Number of command-line "tokens". */
00401    char** m_argv; /**< The "command-line" (pointer to) itself. */
};

// ---------------------------------------------------------------------

#endif

Generated by  Doxygen 1.6.0   Back to index