CmdLineParser.h

Go to the documentation of this file.
00001 // -*-Mode: C++;-*-
00002 // $Header: /Volumes/cvsrep/developer/OpenADFortTk/src/CmdLineParser.h,v 1.5 2004/04/28 17:46:19 eraxxon Exp $
00003 
00004 // * BeginCopyright *********************************************************
00005 // *********************************************************** EndCopyright *
00006 
00007 //***************************************************************************
00008 //
00009 // File:
00010 //   $Source: /Volumes/cvsrep/developer/OpenADFortTk/src/CmdLineParser.h,v $
00011 //
00012 //   Nathan Tallent
00013 //
00014 // Purpose:
00015 //    [The purpose of this file]
00016 //
00017 // Description:
00018 //    [The set of functions, macros, etc. defined in the file]
00019 //
00020 //***************************************************************************
00021 
00022 #ifndef CmdLineParser_H 
00023 #define CmdLineParser_H
00024 
00025 //************************* System Include Files ****************************
00026 
00027 #include <iostream>
00028 #include <map>
00029 #include <vector>
00030 #include <string>
00031 
00032 //*************************** User Include Files ****************************
00033 
00034 #include <inttypes.h> /* commonly available, unlike <stdint.h> */
00035 
00036 //*************************** Forward Declarations ***************************
00037 
00038 //****************************************************************************
00039 
00040 //****************************************************************************
00041 // CmdLineParser
00042 //****************************************************************************
00043 
00044 // CmdLineParser: Parses arguments on the command line, argc and argv.
00045 // Provides easy access to both optional arguments (with short or long
00046 // specifiers) and regular arguments.  Provides functionality similar
00047 // to getopt() and GNU's getopt_long(), but in an easier to use -- and
00048 // in the case of getopt_long(), more portable -- package.  In
00049 // addition, the package provides configurable handling of duplicate
00050 // options/arguments and routines to convert string arguments into
00051 // numerical types.
00052 //
00053 // A user creates a NULL-terminated array of option descriptors
00054 // (OptArgDesc) indicating switch names and arguments, if any.  He
00055 // then instantiates a CmdLineParser and parses argc/argv.  Errors are
00056 // delivered with the exception Exception.  The parser object provides
00057 // access to all optional and regular arguments using the interface
00058 // routines belows.
00059 // 
00060 // More details:
00061 // The command line generally has the form (but note qualifications below):
00062 //   <command> [arguments]
00063 //   
00064 //   [arguments] ::= [optional_arg] | [regular_arg]
00065 //   
00066 //   [optional_arg] ::= -f [arg] | -f[arg]
00067 //                    | --foo [arg] | --foo=arg
00068 //
00069 // An element of argv that starts with '-' or '--' (and is not exactly
00070 // '--') signifies an option.  The option switch is the text without
00071 // the initial dashes.  As the above shows, we support a variety of
00072 // option styles.
00073 //
00074 // Features: 
00075 //   - The '--' token forces the end of optional argument scanning and
00076 //     iterprets everything following as a list of regular arguments.
00077 //     This is useful for non-option arguments that begin with dashes.
00078 //   - Unlike getopt() we do not support the deprecated use of the single
00079 //     '-'; this is an error.  
00080 //   - Long argument switches may be abbreviated if the abbreviation 
00081 //     is unique. 
00082 //   - Configurable handling of duplicate options and arguments.
00083 //
00084 // Limitations:
00085 //   - Unlike getopt(), we do not currently support short switch grouping,
00086 //     e.g. using -abc instead of -a -b -c.  [FIXME: we can assume that 
00087 //     only options without arguments are allowed to be grouped.]
00088 //
00089 // Warnings:
00090 //   - Switches that take optional arguments can be confusing.  For
00091 //     example, assume a command 'foo' takes a filename and on option,
00092 //     --debug, which itself takes an optional debug level.  The
00093 //     following commands pose no difficulties:
00094 //       foo myfile
00095 //       foo --debug=3 myfile
00096 //       foo --debug 3 myfile
00097 //       foo myfile --debug
00098 //     However, in the following
00099 //       foo --debug myfile
00100 //     'myfile' is erroneously assumed to be the optional argument to
00101 //     --debug.  While the '--' token solves this, it remains awkward.
00102 //
00103 class CmdLineParser {
00104 public:
00105 
00106   // ---------------------------------------------------------
00107   // Structure used to describe command line options
00108   // ---------------------------------------------------------
00109   
00110   // Describes if an option switch takes an argument
00111   enum OptKind { 
00112     ARG_NULL = 0,
00113     ARG_NONE, // switch does not take argument
00114     ARG_REQ,  // switch must take an argument
00115     ARG_OPT   // switch takes an (optional!) argument
00116   };
00117   
00118   // Describes how to handle duplicate options and option arguments
00119   enum DupOptKind {
00120     DUPOPT_NULL = 0,
00121     DUPOPT_ERR,  // throw an exception for duplicate option or argument
00122     DUPOPT_CLOB, // clobber any previous argument
00123     DUPOPT_CAT   // concat all available arguments using 'dupArgSep'
00124   };
00125   
00126   struct OptArgDesc {
00127     
00128     bool operator==(const OptArgDesc& x) const { 
00129       return (swShort == x.swShort && swLong == x.swLong 
00130               && kind == x.kind && dupKind == x.dupKind
00131               && dupArgSep == x.dupArgSep);
00132     }
00133     bool operator!=(const OptArgDesc& x) const { return !(*this == x); }
00134     
00135     // Data
00136     char swShort;       // 0 if n/a
00137     const char* swLong; // NULL if n/a
00138     OptKind kind;
00139     DupOptKind dupKind;
00140     const char* dupArgSep; // separator for 'DUPARG_CONCAT'
00141   };
00142 
00143   // The NULL terminator (two versions).  The use of the first version
00144   // is preferable, but some older compilers won't support it.
00145   static OptArgDesc OptArgDesc_NULL;
00146 # define CmdLineParser_OptArgDesc_NULL_MACRO \
00147     { 0, NULL, CmdLineParser::ARG_NULL, CmdLineParser::DUPOPT_NULL, NULL }
00148   
00149   
00150   // ---------------------------------------------------------
00151   // Exception thrown when errors are encountered
00152   // ---------------------------------------------------------
00153   
00154   class Exception {
00155   public:
00156     Exception(const char* m) : msg(m) { }
00157     Exception(std::string m) : msg(m) { }
00158     virtual ~Exception () { }
00159 
00160     virtual const std::string& GetMessage() const { return msg; }
00161     virtual void Report(std::ostream& os) const { 
00162       os << "CmdLineParser::Exception: " << msg << std::endl; 
00163     }    
00164     virtual void Report() const { Report(std::cerr); }
00165 
00166   protected: 
00167     std::string msg;
00168   };
00169 
00170   class ParseError : public Exception {
00171   public:
00172     ParseError(const char* m) : Exception(m) { }
00173     ParseError(std::string m) : Exception(m) { }
00174     virtual ~ParseError () { }
00175   };
00176 
00177   class InternalError : public Exception {
00178   public:
00179     InternalError(const char* m) : Exception(m) { }
00180     InternalError(std::string m) : Exception(m) { }
00181     virtual ~InternalError () { }
00182   private:
00183     void Ctor() {
00184       msg = "CmdLineParser internal error (Don't abuse me!): " + msg;
00185     }
00186   };
00187   
00188   // ---------------------------------------------------------
00189 
00190 public:
00191   // ---------------------------------------------------------
00192   // Constructor/Destructor
00193   // ---------------------------------------------------------
00194   CmdLineParser(); 
00195   CmdLineParser(const OptArgDesc* optArgDescs, 
00196                 int argc, const char* const argv[]); 
00197   ~CmdLineParser();
00198 
00199   // -------------------------------------------------------
00200   // Parsing
00201   // -------------------------------------------------------
00202   
00203   // Parse: Given a NULL terminated array of OptArgDesc describing
00204   // command line arguments, parses the argv/argc into switches,
00205   // optional and required arguments.
00206   void
00207   Parse(const OptArgDesc* optArgDescs, 
00208         int argc, const char* const argv[]);
00209   
00210   // -------------------------------------------------------
00211   // Parsed Data: Command
00212   // -------------------------------------------------------
00213 
00214   // GetCmd: The command (will be valid even after a parse error)
00215   const std::string& GetCmd() const;
00216   
00217   // -------------------------------------------------------
00218   // Parsed Data: Optional arguments
00219   // -------------------------------------------------------
00220   
00221   // IsOpt: (IsOption) Given a short or long switch, returns whether
00222   // the switch has been seen.
00223   bool IsOpt(const char swShort) const;
00224   bool IsOpt(const char* swLong) const;
00225   bool IsOpt(const std::string& sw) const;
00226 
00227   // IsOptArg: (IsOptionArgument) Given a short or long switch,
00228   // returns whether an argument is associated with it.  Designed for
00229   // switches that optionally take arguments.
00230   bool IsOptArg(const char swShort) const;
00231   bool IsOptArg(const char* swLong) const;
00232   bool IsOptArg(const std::string& sw) const;  
00233   
00234   // GetOptArg: (GetOptionArgument) Given a short or long switch, get
00235   // the argument associated with it.  Assumes user has verified that
00236   // an argument *exists*.
00237   const std::string& GetOptArg(const char swShort) const;
00238   const std::string& GetOptArg(const char* swLong) const;
00239   const std::string& GetOptArg(const std::string& sw) const;
00240 
00241   // -------------------------------------------------------
00242   // Parsed Data: Arguments
00243   // -------------------------------------------------------
00244   unsigned int GetNumArgs() const;
00245   const std::string& GetArg(unsigned int i) const;
00246 
00247   // -------------------------------------------------------
00248   // Convert strings into other formats
00249   // -------------------------------------------------------
00250   // The input should be non-empty
00251   static long     ToLong(const std::string& str);
00252   static uint64_t ToUInt64(const std::string& str);
00253   static double   ToDbl(const std::string& str);
00254   
00255   // -------------------------------------------------------
00256   // Misc
00257   // -------------------------------------------------------
00258   void Dump(std::ostream& os = std::cerr) const;
00259   void DDump() const;
00260   
00261 private:
00262   // Should not be used 
00263   CmdLineParser(const CmdLineParser& p) { }
00264   CmdLineParser& operator=(const CmdLineParser& x) { return *this; }
00265   
00266   typedef std::map<std::string, std::string*> SwitchToArgMap;
00267   typedef std::vector<std::string> ArgVec;
00268 
00269   // Switch descriptor (Because of limited use, we allow this to be
00270   // returned as an object)
00271   class SwDesc {
00272   public:
00273     SwDesc() : isLong(false) { }
00274     SwDesc(const char* sw_, bool isLong_, const char* arg_) 
00275       : sw(sw_), isLong(isLong_), arg(arg_) { }
00276     SwDesc(const std::string& sw_, bool isLong_, const std::string& arg_) 
00277       : sw(sw_), isLong(isLong_), arg(arg_) { }
00278     ~SwDesc() { }
00279     // use default copy constructor if necessary
00280     
00281     std::string sw;  // switch text without dashes
00282     bool isLong;     // long style
00283     std::string arg; // any argument
00284   };
00285 
00286 private:
00287   void Ctor();
00288   void Reset();
00289   void CheckForErrors(const OptArgDesc* optArgDescs);
00290 
00291   const OptArgDesc* 
00292   CreateSortedCopy(const OptArgDesc* optArgDescs);
00293 
00294   // Parsing helpers
00295   SwDesc
00296   MakeSwitchDesc(const char* str);
00297   
00298   const OptArgDesc*
00299   FindOptDesc(const OptArgDesc* optArgDescs, const SwDesc& swdesc,
00300               bool errOnMultipleMatches = true);
00301   
00302   void
00303   AddOption(const OptArgDesc& odesc, const SwDesc& swdesc);
00304   
00305   void
00306   AddOption(const OptArgDesc& odesc, 
00307             const std::string& sw, const std::string& arg);
00308   
00309 private:
00310   
00311   std::string command;           // comand name
00312   SwitchToArgMap switchToArgMap; // optional arguments
00313   ArgVec arguments;              // regular arguments
00314 };
00315 
00316 //****************************************************************************
00317 
00318 #endif
00319 

Generated on Fri Jul 24 04:29:02 2009 for OpenADFortTk (extended to Open64) by  doxygen 1.5.7.1