CVC3

command_line_flags.h

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file command_line_flags.h
00004  *
00005  * Author: Sergey Berezin
00006  *
00007  * Created: Mon Feb 10 16:22:00 2003
00008  *
00009  * <hr>
00010  *
00011  * License to use, copy, modify, sell and/or distribute this software
00012  * and its documentation for any purpose is hereby granted without
00013  * royalty, subject to the terms and conditions defined in the \ref
00014  * LICENSE file provided with this distribution.
00015  *
00016  * <hr>
00017  *
00018  */
00019 /*****************************************************************************/
00020 
00021 #ifndef _cvc3__command_line_flags_h_
00022 #define _cvc3__command_line_flags_h_
00023 
00024 #include <sstream>
00025 #include <cstring>
00026 #include <vector>
00027 #include <map>
00028 #include "command_line_exception.h"
00029 #include "debug.h"
00030 
00031 namespace CVC3 {
00032 
00033   //! Different types of command line flags
00034   typedef enum {
00035     CLFLAG_NULL,
00036     CLFLAG_BOOL,
00037     CLFLAG_INT,
00038     CLFLAG_STRING,
00039     CLFLAG_STRVEC //!< Vector of pair<string, bool>
00040   } CLFlagType;
00041 
00042   /*!
00043     Class CLFlag (for Command Line Flag)
00044 
00045     Author: Sergey Berezin
00046 
00047     Date: Fri May 30 14:10:48 2003
00048 
00049     This class implements a data structure to hold a value of a single
00050     command line flag.
00051   */
00052 
00053 class CLFlag {
00054  private:
00055   //! Type of the argument
00056   CLFlagType d_tp;
00057   //! The argument
00058   union {
00059     bool b;
00060     int i;
00061     std::string* s;
00062     std::vector<std::pair<std::string,bool> >* sv;
00063   } d_data;
00064   //! This tag is set to true when the flag is assigned a new value
00065   bool d_modified;
00066   //! Help string
00067   std::string d_help;
00068   //! Whether to display this flag when user invokes cvc3 -h
00069   bool d_display;
00070  public:
00071   //! Constructor for a boolean flag
00072   CLFlag(bool b, const std::string& help, bool display = true)
00073     : d_tp(CLFLAG_BOOL), d_modified(0), d_help(help), d_display(display)
00074     { d_data.b = b; }
00075   //! Constructor for an integer flag
00076   CLFlag(int i, const std::string& help, bool display = true)
00077     : d_tp(CLFLAG_INT), d_modified(0), d_help(help), d_display(display)
00078     { d_data.i = i; }
00079   //! Constructor for a string flag
00080   CLFlag(const std::string& s, const std::string& help, bool display = true)
00081     : d_tp(CLFLAG_STRING), d_modified(0), d_help(help), d_display(display) {
00082     d_data.s = new std::string(s);
00083   }
00084   //! Constructor for a string flag from char*
00085   CLFlag(const char* s, const std::string& help, bool display = true)
00086     : d_tp(CLFLAG_STRING), d_modified(0), d_help(help), d_display(display) {
00087     d_data.s = new std::string((char*)s);
00088   }
00089   //! Constructor for a vector flag
00090   CLFlag(const std::vector<std::pair<std::string,bool> >& sv,
00091    const std::string& help, bool display = true)
00092     : d_tp(CLFLAG_STRVEC), d_modified(0), d_help(help), d_display(display) {
00093     d_data.sv = new std::vector<std::pair<std::string,bool> >(sv);
00094   }
00095   //! Default constructor
00096   CLFlag(): d_tp(CLFLAG_NULL), d_modified(0), d_help("Undefined flag"), d_display(false) { }
00097   //! Copy constructor
00098   CLFlag(const CLFlag& f)
00099     : d_tp(f.d_tp), d_modified(f.d_modified), d_help(f.d_help), d_display(f.d_display) {
00100     switch(d_tp) {
00101     case CLFLAG_STRING:
00102       d_data.s = new std::string(*f.d_data.s); break;
00103     case CLFLAG_STRVEC:
00104       d_data.sv = new std::vector<std::pair<std::string,bool> >(*f.d_data.sv); break;
00105     default: d_data = f.d_data;
00106     }
00107   }
00108   //! Destructor
00109   ~CLFlag() {
00110     switch(d_tp) {
00111     case CLFLAG_STRING: delete d_data.s; break;
00112     case CLFLAG_STRVEC: delete d_data.sv; break;
00113     default: break;// Nothing to do
00114     }
00115   }
00116   //! Assignment from another flag
00117   CLFlag& operator=(const CLFlag& f) {
00118     if(this == &f) return *this; // Self-assignment
00119     // Try to preserve the existing heap objects if possible
00120     if(d_tp == f.d_tp) {
00121       switch(d_tp) {
00122       case CLFLAG_STRING: *d_data.s = *f.d_data.s; break;
00123       case CLFLAG_STRVEC: *d_data.sv = *f.d_data.sv; break;
00124       default: d_data = f.d_data;
00125       }
00126     } else {
00127       switch(d_tp) {
00128       case CLFLAG_STRING: delete d_data.s; break;
00129       case CLFLAG_STRVEC: delete d_data.sv; break;
00130       default: break;
00131       }
00132       switch(f.d_tp) {
00133       case CLFLAG_STRING: d_data.s = new std::string(*f.d_data.s); break;
00134       case CLFLAG_STRVEC:
00135   d_data.sv=new std::vector<std::pair<std::string,bool> >(*f.d_data.sv);
00136   break;
00137       default: d_data = f.d_data;
00138       }
00139     }
00140     d_tp = f.d_tp;
00141     d_modified = f.d_modified;
00142     d_help = f.d_help;
00143     d_display = f.d_display;
00144     return *this;
00145   }
00146   //! Assignment of a boolean value
00147   /*! The flag must already have the right type */
00148   CLFlag& operator=(bool b) {
00149     DebugAssert(d_tp == CLFLAG_BOOL, "");
00150     d_data.b = b;
00151     d_modified = true;
00152     return *this;
00153   }
00154   //! Assignment of an integer value
00155   /*! The flag must already have the right type */
00156   CLFlag& operator=(int i) {
00157     DebugAssert(d_tp == CLFLAG_INT, "");
00158     d_data.i = i;
00159     d_modified = true;
00160     return *this;
00161   }
00162   //! Assignment of a string value
00163   /*! The flag must already have a string type. */
00164   CLFlag& operator=(const std::string& s) {
00165     DebugAssert(d_tp == CLFLAG_STRING, "");
00166     *d_data.s = s;
00167     d_modified = true;
00168     return *this;
00169   }
00170   //! Assignment of an string value from char*
00171   /*! The flag must already have a string type. */
00172   CLFlag& operator=(const char* s) {
00173     DebugAssert(d_tp == CLFLAG_STRING, "");
00174     *d_data.s = s;
00175     d_modified = true;
00176     return *this;
00177   }
00178   //! Assignment of a string value with a boolean tag to a vector flag
00179   /*! The flag must already have a vector type.  The pair of
00180     <string,bool> will be appended to the vector. */
00181   CLFlag& operator=(const std::pair<std::string,bool>& p) {
00182     DebugAssert(d_tp == CLFLAG_STRVEC, "");
00183     d_data.sv->push_back(p);
00184     d_modified = true;
00185     return *this;
00186   }
00187   //! Assignment of a vector value
00188   /*! The flag must already have a vector type. */
00189   CLFlag& operator=(const std::vector<std::pair<std::string,bool> >& sv) {
00190     DebugAssert(d_tp == CLFLAG_STRVEC, "");
00191     *d_data.sv = sv;
00192     d_modified = true;
00193     return *this;
00194   }
00195   // Accessor methods
00196   //! Return the type of the flag
00197   CLFlagType getType() const { return d_tp; }
00198   /*! @brief Return true if the flag was modified from the default
00199     value (e.g. set on the command line) */
00200   bool modified() const { return d_modified; }
00201   //! Return true if flag should be displayed in regular help
00202   bool display() const { return d_display; }
00203 
00204   // The value accessors return a reference.  For the system-wide
00205   // flags, this reference will remain valid throughout the run of the
00206   // program, even if the flag's value changes.  So, the reference can
00207   // be cached, and the value can be checked directly (which is more
00208   // efficient).
00209   const bool& getBool() const {
00210     DebugAssert(d_tp == CLFLAG_BOOL, "CLFlag::getBool: not a boolean flag");
00211     return d_data.b;
00212   }
00213 
00214   const int& getInt() const {
00215     DebugAssert(d_tp == CLFLAG_INT, "CLFlag::getInt: not an integer flag");
00216     return d_data.i;
00217   }
00218 
00219   const std::string& getString() const {
00220     DebugAssert(d_tp == CLFLAG_STRING,
00221     "CLFlag::getString: not a string flag");
00222     return *d_data.s;
00223   }
00224 
00225   const std::vector<std::pair<std::string,bool> >& getStrVec() const {
00226     DebugAssert(d_tp == CLFLAG_STRVEC,
00227     "CLFlag::getStrVec: not a string vector flag");
00228     return *d_data.sv;
00229   }
00230 
00231   const std::string& getHelp() const {
00232     return d_help;
00233   }
00234 
00235 }; // end of class CLFlag
00236 
00237 ///////////////////////////////////////////////////////////////////////
00238 // Class CLFlag (for Command Line Flag)
00239 //
00240 // Author: Sergey Berezin
00241 // Date: Fri May 30 14:10:48 2003
00242 //
00243 // Database of command line flags.
00244 ///////////////////////////////////////////////////////////////////////
00245 
00246 class CLFlags {
00247  private:
00248   typedef std::map<std::string, CLFlag> CharMap;
00249   CharMap d_map;
00250 
00251   // Private methods
00252 
00253   // Retrieve an existing flag for modification.  The 'name' must be a
00254   // full name of an existing flag.
00255   CLFlag& getFlag0(const std::string& name) {
00256     DebugAssert(d_map.count(name) > 0,
00257     "getFlag0("+name+"): there are no flags with this name");
00258     return (*d_map.find(name)).second;
00259   }
00260  public:
00261   // Public methods
00262   // Add a new flag.  The name must be a complete flag name.
00263   void addFlag(const std::string& name, const CLFlag& f) {
00264     d_map[name] = f;
00265   }
00266   // Count how many flags match the name prefix
00267   size_t countFlags(const std::string& name) const {
00268     size_t res(0), len(name.size());
00269     for(CharMap::const_iterator i=d_map.begin(), iend=d_map.end();
00270   i!=iend; ++i) {
00271       if(std::strncmp(name.c_str(), (*i).first.c_str(), len) == 0) res++;
00272     }
00273     return res;
00274   }
00275   // Match the name prefix and add all the matching names to the vector
00276   size_t countFlags(const std::string& name,
00277         std::vector<std::string>& names) const {
00278     size_t res(0), len(name.size());
00279     for(CharMap::const_iterator i=d_map.begin(), iend=d_map.end();
00280   i!=iend; ++i) {
00281       if(std::strncmp(name.c_str(), (*i).first.c_str(), len) == 0) {
00282   names.push_back((*i).first);
00283   res++;
00284       }
00285     }
00286     return res;
00287   }
00288   // Retrieve an existing flag.  The 'name' must be a full name of an
00289   // existing flag.
00290   const CLFlag& getFlag(const std::string& name) const {
00291     DebugAssert(d_map.count(name) > 0,
00292     "getFlag("+name+"): there are no flags with this name");
00293     return (*d_map.find(name)).second;
00294   }
00295 
00296   const CLFlag& operator[](const std::string& name) const {
00297     return getFlag(name);
00298   }
00299 
00300   // Setting the flag to a new value, but preserving the help string.
00301   // The 'name' prefix must uniquely resolve to an existing flag.
00302   void setFlag(const std::string& name, const CLFlag& f) {
00303     CLFlag& oldF(getFlag0(name));
00304     DebugAssert(oldF.getType() == f.getType(),
00305     "setFlag("+name+"): flag type doesn't match");
00306     oldF = f;
00307   }
00308 
00309   // Variants of setFlag for all the types
00310   void setFlag(const std::string& name, bool b) { getFlag0(name) = b; }
00311   void setFlag(const std::string& name, int i) { getFlag0(name) = i; }
00312   void setFlag(const std::string& name, const std::string& s)
00313     { getFlag0(name) = s; }
00314   void setFlag(const std::string& name, const char* s)
00315     { getFlag0(name) = s; }
00316   void setFlag(const std::string& name, const std::pair<std::string,bool>& p)
00317     { getFlag0(name) = p; }
00318   void setFlag(const std::string& name,
00319          const std::vector<std::pair<std::string,bool> >& sv)
00320     { getFlag0(name) = sv; }
00321 
00322 }; // end of class CLFlags
00323 
00324 } // end of namespace CVC3
00325 
00326 #endif