OpenADFortTk (including Open64 and OpenAnalysis references)
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
CmdLineParser.h
Go to the documentation of this file.
1 // ##########################################################
2 // # This file is part of OpenADFortTk. #
3 // # The full COPYRIGHT notice can be found in the top #
4 // # level directory of the OpenADFortTk source tree. #
5 // # For more information visit #
6 // # http://www.mcs.anl.gov/openad #
7 // ##########################################################
8 
9 #ifndef CmdLineParser_H
10 #define CmdLineParser_H
11 
12 #include <iostream>
13 #include <map>
14 #include <vector>
15 #include <string>
16 
17 //*************************** User Include Files ****************************
18 
19 #include <inttypes.h> /* commonly available, unlike <stdint.h> */
20 
21 //*************************** Forward Declarations ***************************
22 
23 //****************************************************************************
24 
25 //****************************************************************************
26 // CmdLineParser
27 //****************************************************************************
28 
29 // CmdLineParser: Parses arguments on the command line, argc and argv.
30 // Provides easy access to both optional arguments (with short or long
31 // specifiers) and regular arguments. Provides functionality similar
32 // to getopt() and GNU's getopt_long(), but in an easier to use -- and
33 // in the case of getopt_long(), more portable -- package. In
34 // addition, the package provides configurable handling of duplicate
35 // options/arguments and routines to convert string arguments into
36 // numerical types.
37 //
38 // A user creates a NULL-terminated array of option descriptors
39 // (OptArgDesc) indicating switch names and arguments, if any. He
40 // then instantiates a CmdLineParser and parses argc/argv. Errors are
41 // delivered with the exception Exception. The parser object provides
42 // access to all optional and regular arguments using the interface
43 // routines belows.
44 //
45 // More details:
46 // The command line generally has the form (but note qualifications below):
47 // <command> [arguments]
48 //
49 // [arguments] ::= [optional_arg] | [regular_arg]
50 //
51 // [optional_arg] ::= -f [arg] | -f[arg]
52 // | --foo [arg] | --foo=arg
53 //
54 // An element of argv that starts with '-' or '--' (and is not exactly
55 // '--') signifies an option. The option switch is the text without
56 // the initial dashes. As the above shows, we support a variety of
57 // option styles.
58 //
59 // Features:
60 // - The '--' token forces the end of optional argument scanning and
61 // iterprets everything following as a list of regular arguments.
62 // This is useful for non-option arguments that begin with dashes.
63 // - Unlike getopt() we do not support the deprecated use of the single
64 // '-'; this is an error.
65 // - Long argument switches may be abbreviated if the abbreviation
66 // is unique.
67 // - Configurable handling of duplicate options and arguments.
68 //
69 // Limitations:
70 // - Unlike getopt(), we do not currently support short switch grouping,
71 // e.g. using -abc instead of -a -b -c. [FIXME: we can assume that
72 // only options without arguments are allowed to be grouped.]
73 //
74 // Warnings:
75 // - Switches that take optional arguments can be confusing. For
76 // example, assume a command 'foo' takes a filename and on option,
77 // --debug, which itself takes an optional debug level. The
78 // following commands pose no difficulties:
79 // foo myfile
80 // foo --debug=3 myfile
81 // foo --debug 3 myfile
82 // foo myfile --debug
83 // However, in the following
84 // foo --debug myfile
85 // 'myfile' is erroneously assumed to be the optional argument to
86 // --debug. While the '--' token solves this, it remains awkward.
87 //
89 public:
90 
91  // ---------------------------------------------------------
92  // Structure used to describe command line options
93  // ---------------------------------------------------------
94 
95  // Describes if an option switch takes an argument
96  enum OptKind {
97  ARG_NULL = 0,
98  ARG_NONE, // switch does not take argument
99  ARG_REQ, // switch must take an argument
100  ARG_OPT // switch takes an (optional!) argument
101  };
102 
103  // Describes how to handle duplicate options and option arguments
104  enum DupOptKind {
106  DUPOPT_ERR, // throw an exception for duplicate option or argument
107  DUPOPT_CLOB, // clobber any previous argument
108  DUPOPT_CAT // concat all available arguments using 'dupArgSep'
109  };
110 
111  struct OptArgDesc {
112 
113  bool operator==(const OptArgDesc& x) const {
114  return (swShort == x.swShort && swLong == x.swLong
115  && kind == x.kind && dupKind == x.dupKind
116  && dupArgSep == x.dupArgSep);
117  }
118  bool operator!=(const OptArgDesc& x) const { return !(*this == x); }
119 
120  // Data
121  char swShort; // 0 if n/a
122  const char* swLong; // NULL if n/a
125  const char* dupArgSep; // separator for 'DUPARG_CONCAT'
126  };
127 
128  // The NULL terminator (two versions). The use of the first version
129  // is preferable, but some older compilers won't support it.
131 # define CmdLineParser_OptArgDesc_NULL_MACRO \
132  { 0, NULL, CmdLineParser::ARG_NULL, CmdLineParser::DUPOPT_NULL, NULL }
133 
134 
135  // ---------------------------------------------------------
136  // Exception thrown when errors are encountered
137  // ---------------------------------------------------------
138 
139  class Exception {
140  public:
141  Exception(const char* m) : msg(m) { }
143  virtual ~Exception () { }
144 
145  virtual const std::string& GetMessage() const { return msg; }
146  virtual void Report(std::ostream& os) const {
147  os << "CmdLineParser::Exception: " << msg << std::endl;
148  }
149  virtual void Report() const { Report(std::cerr); }
150 
151  protected:
153  };
154 
155  class ParseError : public Exception {
156  public:
157  ParseError(const char* m) : Exception(m) { }
159  virtual ~ParseError () { }
160  };
161 
162  class InternalError : public Exception {
163  public:
164  InternalError(const char* m) : Exception(m) { }
166  virtual ~InternalError () { }
167  private:
168  void Ctor() {
169  msg = "CmdLineParser internal error (Don't abuse me!): " + msg;
170  }
171  };
172 
173  // ---------------------------------------------------------
174 
175 public:
176  // ---------------------------------------------------------
177  // Constructor/Destructor
178  // ---------------------------------------------------------
179  CmdLineParser();
180  CmdLineParser(const OptArgDesc* optArgDescs,
181  int argc, const char* const argv[]);
182  ~CmdLineParser();
183 
184  // -------------------------------------------------------
185  // Parsing
186  // -------------------------------------------------------
187 
188  // Parse: Given a NULL terminated array of OptArgDesc describing
189  // command line arguments, parses the argv/argc into switches,
190  // optional and required arguments.
191  void
192  Parse(const OptArgDesc* optArgDescs,
193  int argc, const char* const argv[]);
194 
195  // -------------------------------------------------------
196  // Parsed Data: Command
197  // -------------------------------------------------------
198 
199  // GetCmd: The command (will be valid even after a parse error)
200  const std::string& GetCmd() const;
201 
202  // -------------------------------------------------------
203  // Parsed Data: Optional arguments
204  // -------------------------------------------------------
205 
206  // IsOpt: (IsOption) Given a short or long switch, returns whether
207  // the switch has been seen.
208  bool IsOpt(const char swShort) const;
209  bool IsOpt(const char* swLong) const;
210  bool IsOpt(const std::string& sw) const;
211 
212  // IsOptArg: (IsOptionArgument) Given a short or long switch,
213  // returns whether an argument is associated with it. Designed for
214  // switches that optionally take arguments.
215  bool IsOptArg(const char swShort) const;
216  bool IsOptArg(const char* swLong) const;
217  bool IsOptArg(const std::string& sw) const;
218 
219  // GetOptArg: (GetOptionArgument) Given a short or long switch, get
220  // the argument associated with it. Assumes user has verified that
221  // an argument *exists*.
222  const std::string& GetOptArg(const char swShort) const;
223  const std::string& GetOptArg(const char* swLong) const;
224  const std::string& GetOptArg(const std::string& sw) const;
225 
226  // -------------------------------------------------------
227  // Parsed Data: Arguments
228  // -------------------------------------------------------
229  unsigned int GetNumArgs() const;
230  const std::string& GetArg(unsigned int i) const;
231 
232  // -------------------------------------------------------
233  // Convert strings into other formats
234  // -------------------------------------------------------
235  // The input should be non-empty
236  static long ToLong(const std::string& str);
237  static uint64_t ToUInt64(const std::string& str);
238  static double ToDbl(const std::string& str);
239 
240  // -------------------------------------------------------
241  // Misc
242  // -------------------------------------------------------
243  void Dump(std::ostream& os = std::cerr) const;
244  void DDump() const;
245 
246 private:
247  // Should not be used
249  CmdLineParser& operator=(const CmdLineParser& x) { return *this; }
250 
251  typedef std::map<std::string, std::string*> SwitchToArgMap;
252  typedef std::vector<std::string> ArgVec;
253 
254  // Switch descriptor (Because of limited use, we allow this to be
255  // returned as an object)
256  class SwDesc {
257  public:
258  SwDesc() : isLong(false) { }
259  SwDesc(const char* sw_, bool isLong_, const char* arg_)
260  : sw(sw_), isLong(isLong_), arg(arg_) { }
261  SwDesc(const std::string& sw_, bool isLong_, const std::string& arg_)
262  : sw(sw_), isLong(isLong_), arg(arg_) { }
263  ~SwDesc() { }
264  // use default copy constructor if necessary
265 
266  std::string sw; // switch text without dashes
267  bool isLong; // long style
268  std::string arg; // any argument
269  };
270 
271 private:
272  void Ctor();
273  void Reset();
274  void CheckForErrors(const OptArgDesc* optArgDescs);
275 
276  const OptArgDesc*
277  CreateSortedCopy(const OptArgDesc* optArgDescs);
278 
279  // Parsing helpers
280  SwDesc
281  MakeSwitchDesc(const char* str);
282 
283  const OptArgDesc*
284  FindOptDesc(const OptArgDesc* optArgDescs, const SwDesc& swdesc,
285  bool errOnMultipleMatches = true);
286 
287  void
288  AddOption(const OptArgDesc& odesc, const SwDesc& swdesc);
289 
290  void
291  AddOption(const OptArgDesc& odesc,
292  const std::string& sw, const std::string& arg);
293 
294 private:
295 
296  std::string command; // comand name
297  SwitchToArgMap switchToArgMap; // optional arguments
298  ArgVec arguments; // regular arguments
299 };
300 
301 
302 #endif
303