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