CMS 3D CMS Logo

CmdLine.h
Go to the documentation of this file.
1 #ifndef CONDTOOLS_HCAL_CMDLINE_H_
2 #define CONDTOOLS_HCAL_CMDLINE_H_
3 
4 //=========================================================================
5 // CmdLine.h
6 //
7 // Simple command line parser for the C++ "main" program. It provides
8 // functionality of "getopt" and "getopt_long" with a convenient interface.
9 // Typical usage is as follows:
10 //
11 // #include <necessary standard headers>
12 //
13 // #include "CmdLine.h"
14 //
15 // using namespace cmdline;
16 //
17 // int main(int argc, char *argv[])
18 // {
19 // CmdLine cmdline(argc, argv);
20 //
21 // int i = 0;
22 // double d = 0;
23 // bool b = false;
24 // std::string requiredOption;
25 // std::vector<std::string> positionalArgs;
26 //
27 // try {
28 // /* Arguments are short and long versions of the option name. */
29 // /* Long version can be omitted. If you want to use the long */
30 // /* version only, call the two-argument method with the short */
31 // /* version set to 0. */
32 // cmdline.option("-i", "--integer") >> i;
33 // cmdline.option("-d") >> d;
34 //
35 // /* Options that must be present on the command line */
36 // cmdline.require("-r", "--required") >> requiredOption;
37 //
38 // /* Switches that do not require subsequent arguments */
39 // b = cmdline.has("-b");
40 //
41 // /* Declare the end of option processing. Unconsumed options */
42 // /* will cause an exception to be thrown. */
43 // cmdline.optend();
44 //
45 // /* Process all remaining arguments */
46 // while (cmdline)
47 // {
48 // std::string s;
49 // cmdline >> s;
50 // positionalArgs.push_back(s);
51 // }
52 // }
53 // catch (const CmdLineError& e) {
54 // std::cerr << "Error in " << cmdline.progname() << ": "
55 // << e.str() << std::endl;
56 // return 1;
57 // }
58 //
59 // /* ..... Do main processing here ..... */
60 //
61 // return 0;
62 // }
63 //
64 // Short version options must use a single character. It is possible
65 // to combine several short options together on the command line,
66 // for example, "-xzvf" is equivalent to "-x -z -v -f".
67 //
68 // Use standalone "-" to indicate that the next argument is either
69 // an option value or the program argument (but not a switch), even
70 // if it starts with "-". This is useful if the option value has to
71 // be set to a negative number.
72 //
73 // Use standalone "--" (not preceded by standalone "-") to indicate
74 // the end of options. All remaining arguments will be treated as
75 // program arguments, even if they start with "-".
76 //
77 // Note that each of the parsing methods of the CmdLine class ("option",
78 // "has", and "require") is greedy. These methods will consume all
79 // corresponding options or switches and will set the result to the last
80 // option value seen. It is therefore impossible to provide a collection
81 // of values by using an option more than once. This is done in order to
82 // avoid difficulties with deciding what to do when multiple option values
83 // were consumed by the user code only partially.
84 //
85 // After the "optend()" call, the "argc()" method of the CmdLine
86 // class can be used to determine the number of remaining program
87 // arguments. If the expected number of arguments is known in advance,
88 // the simplest way to get the arguments out is like this (should be
89 // inside the "try" block):
90 //
91 // if (cmdline.argc() != n_expected)
92 // throw CmdLineError("wrong number of command line arguments");
93 // cmdline >> arg0 >> arg1 >> ...;
94 //
95 // I. Volobouev
96 // January 2016
97 //=========================================================================
98 
99 #include <list>
100 #include <sstream>
101 #include <cstring>
102 #include <utility>
103 #include <cstdio>
104 
105 #ifdef __GNUC__
106 #include <cstdlib>
107 #include <typeinfo>
108 #include <cxxabi.h>
109 #endif
110 
111 #ifdef __GXX_EXPERIMENTAL_CXX0X__
112 #include <memory>
113 #define CmdLine_shared_ptr std::shared_ptr
114 #else
115 #include <tr1/memory>
116 #define CmdLine_shared_ptr std::tr1::shared_ptr
117 #endif
118 
119 namespace cmdline {
120 
121 // Subsequent classes will throw exceptions of the following class
123 {
124 public:
125  inline CmdLineError(const char* msg = 0)
126  : os_(new std::ostringstream()) {if (msg) *os_ << msg;}
127 
128  template<typename T>
129  inline CmdLineError& operator<<(const T& obj)
130  {
131  *os_ << obj;
132  return *this;
133  }
134 
135  inline std::string str() const {return os_->str();}
136 
137 private:
138  CmdLine_shared_ptr<std::ostringstream> os_;
139 };
140 
141 template<typename T>
142 inline void OneShotExtract(std::istringstream& is, T& obj)
143 {is >> obj;}
144 
145 template<>
146 inline void OneShotExtract<std::string>(std::istringstream& is,
147  std::string& obj)
148 {obj = is.str(); is.seekg(0, std::ios_base::end);}
149 
151 {
152 public:
153  inline OneShotIStream() : valid_(false), readout_(false) {}
154 
155  inline OneShotIStream(const std::string& s)
156  : str_(s), valid_(true), readout_(false) {}
157 
158  inline operator void*() const
159  {
160  return valid_ && !readout_ ? (void*)this : (void*)0;
161  }
162 
163  template<typename T>
164  inline bool operator>>(T& obj)
165  {
166  if (readout_)
167  throw CmdLineError()
168  << "can't reuse command line argument \"" << str_ << '"';
169  readout_ = true;
170  if (valid_)
171  {
172  std::istringstream is(str_);
173  OneShotExtract(is, obj);
174  if (is.bad() || is.fail())
175  throw CmdLineError()
176  << "failed to parse command line argument \""
177  << str_ << '"'
178 #ifdef __GNUC__
179  << ", " << demangle(obj) << " expected"
180 #endif
181  ;
182  if (is.peek() != EOF)
183  throw CmdLineError()
184  << "extra characters in command line argument \""
185  << str_ << '"'
186 #ifdef __GNUC__
187  << ", " << demangle(obj) << " expected"
188 #endif
189  ;
190  }
191  return valid_;
192  }
193 
194  inline bool isValid() const {return valid_;}
195 
196 private:
198  bool valid_;
199  bool readout_;
200 
201 #ifdef __GNUC__
202  template <typename T>
203  inline std::string demangle(T& obj) const
204  {
205  int status;
206  const std::type_info &ti = typeid(obj);
207  char *realname = abi::__cxa_demangle(ti.name(), 0, 0, &status);
208  std::string s(realname);
209  free(realname);
210  return s;
211  }
212 #endif
213 };
214 
215 class CmdLine
216 {
217  // Argument codes (second member of the pair):
218  // 0 -- possible option value (or program argument, not yet known which)
219  // 1 -- short option switch
220  // 2 -- long option switch
221  // 3 -- program argument
222  typedef std::pair<std::string,int> Pair;
223  typedef std::list<Pair> Optlist;
224 
225  inline Optlist::iterator find(const char* shortOpt, const char* longOpt)
226  {
227  Optlist::iterator iend = args_.end();
228  for (Optlist::iterator it = args_.begin(); it != iend; ++it)
229  {
230  if (shortOpt && it->second == 1 && it->first == shortOpt)
231  return it;
232  if (longOpt && it->second == 2 && it->first == longOpt)
233  return it;
234  }
235  return iend;
236  }
237 
238 public:
239  inline CmdLine(const unsigned argc, const char* const argv[])
240  : nprogargs_(0)
241  {
242  // Parse the program name
243  const char *progname = std::strrchr(argv[0], '/');
244  if (progname)
245  ++progname;
246  else
247  progname = argv[0];
248 
249  // Take into account program name mangling by GNU autotools
250  if (strncmp(progname, "lt-", 3) == 0)
251  progname += 3;
252  progname_ = progname;
253 
254  // Make a list of arguments noting on the way if this is
255  // a short option, long option, or possible option argument
256  bool previousIsOpt = false;
257  bool nextIsArg = false;
258  for (unsigned i=1; i<argc; ++i)
259  {
260  if (nextIsArg)
261  {
262  args_.push_back(Pair(argv[i], previousIsOpt ? 0 : 3));
263  previousIsOpt = false;
264  ++nprogargs_;
265  nextIsArg = false;
266  }
267  else if (strcmp(argv[i], "-") == 0)
268  nextIsArg = true;
269  else if (strcmp(argv[i], "--") == 0)
270  {
271  // End of options
272  for (unsigned k=i+1; k<argc; ++k)
273  {
274  args_.push_back(Pair(argv[k], 3));
275  ++nprogargs_;
276  }
277  return;
278  }
279  else if (strncmp(argv[i], "--", 2) == 0)
280  {
281  args_.push_back(Pair(argv[i], 2));
282  previousIsOpt = true;
283  }
284  else if (argv[i][0] == '-')
285  {
286  const unsigned len = strlen(argv[i]);
287  for (unsigned k=1; k<len; ++k)
288  {
289  std::string dummy("-");
290  dummy += argv[i][k];
291  args_.push_back(Pair(dummy, 1));
292  previousIsOpt = true;
293  }
294  }
295  else
296  {
297  args_.push_back(Pair(argv[i], previousIsOpt ? 0 : 3));
298  previousIsOpt = false;
299  ++nprogargs_;
300  }
301  }
302  }
303 
304  inline const char* progname() const {return progname_.c_str();}
305 
306  inline bool has(const char* shortOpt, const char* longOpt=0)
307  {
308  bool found = false;
309  for (Optlist::iterator it = find(shortOpt, longOpt);
310  it != args_.end(); it = find(shortOpt, longOpt))
311  {
312  found = true;
313  Optlist::iterator it0(it);
314  if (++it != args_.end())
315  if (it->second == 0)
316  it->second = 3;
317  args_.erase(it0);
318  }
319  return found;
320  }
321 
322  inline OneShotIStream option(const char* shortOpt, const char* longOpt=0)
323  {
325  for (Optlist::iterator it = find(shortOpt, longOpt);
326  it != args_.end(); it = find(shortOpt, longOpt))
327  {
328  Optlist::iterator it0(it);
329  if (++it != args_.end())
330  if (it->second == 0)
331  {
332  result = OneShotIStream(it->first);
333  args_.erase(it0, ++it);
334  --nprogargs_;
335  continue;
336  }
337  throw CmdLineError()
338  << "missing command line argument for option \""
339  << it0->first << '"';
340  }
341  return result;
342  }
343 
344  inline OneShotIStream require(const char* shortOpt, const char* longOpt=0)
345  {
346  const OneShotIStream& is(option(shortOpt, longOpt));
347  if (!is.isValid())
348  {
349  const char empty[] = "";
350  const char* s = shortOpt ? shortOpt : (longOpt ? longOpt : empty);
351  throw CmdLineError()
352  << "required command line option \"" << s << "\" is missing";
353  }
354  return is;
355  }
356 
357  inline void optend() const
358  {
359  for (Optlist::const_iterator it = args_.begin();
360  it != args_.end(); ++it)
361  if (it->second == 1 || it->second == 2)
362  throw CmdLineError("invalid command line option \"")
363  << it->first << '"';
364  }
365 
366  inline operator void*() const
367  {
368  return (void*)(static_cast<unsigned long>(nprogargs_));
369  }
370 
371  inline unsigned argc() const
372  {
373  return nprogargs_;
374  }
375 
376  template<typename T>
378  {
379  if (!nprogargs_)
380  throw CmdLineError("no more input available on the command line");
381  Optlist::iterator it = args_.begin();
382  for (; it != args_.end(); ++it)
383  if (it->second == 0 || it->second == 3)
384  break;
385  OneShotIStream is(it->first);
386  args_.erase(it);
387  --nprogargs_;
388  is >> obj;
389  return *this;
390  }
391 
392 private:
393  CmdLine();
394 
396  Optlist args_;
397  unsigned nprogargs_;
398 };
399 
400 } // namespace cmdline
401 
402 #endif // CONDTOOLS_HCAL_CMDLINE_H_
bool has(const char *shortOpt, const char *longOpt=0)
Definition: CmdLine.h:306
std::list< Pair > Optlist
Definition: CmdLine.h:223
CmdLineError(const char *msg=0)
Definition: CmdLine.h:125
static const uint16_t valid_
Definition: Constants.h:17
std::pair< std::string, int > Pair
Definition: CmdLine.h:222
void find(edm::Handle< EcalRecHitCollection > &hits, DetId thisDet, std::vector< EcalRecHitCollection::const_iterator > &hit, bool debug=false)
Definition: FindCaloHit.cc:20
bool isValid() const
Definition: CmdLine.h:194
OneShotIStream(const std::string &s)
Definition: CmdLine.h:155
std::tr1::shared_ptr< std::ostringstream > os_
Definition: CmdLine.h:138
std::string str() const
Definition: CmdLine.h:135
std::string str_
Definition: CmdLine.h:197
void OneShotExtract(std::istringstream &is, T &obj)
Definition: CmdLine.h:142
CmdLine & operator>>(T &obj)
Definition: CmdLine.h:377
unsigned nprogargs_
Definition: CmdLine.h:397
#define end
Definition: vmac.h:37
OneShotIStream require(const char *shortOpt, const char *longOpt=0)
Definition: CmdLine.h:344
const char * progname() const
Definition: CmdLine.h:304
CmdLineError & operator<<(const T &obj)
Definition: CmdLine.h:129
int k[5][pyjets_maxn]
void optend() const
Definition: CmdLine.h:357
CmdLine(const unsigned argc, const char *const argv[])
Definition: CmdLine.h:239
unsigned argc() const
Definition: CmdLine.h:371
OneShotIStream option(const char *shortOpt, const char *longOpt=0)
Definition: CmdLine.h:322
std::string progname_
Definition: CmdLine.h:395
long double T
bool operator>>(T &obj)
Definition: CmdLine.h:164
Optlist::iterator find(const char *shortOpt, const char *longOpt)
Definition: CmdLine.h:225
Optlist args_
Definition: CmdLine.h:396