Arg.h
1 /*
2  Copyright (C) 2006,2010 by Tommi Maekitalo
3  Copyright (C) 2006-2016 by Marc Duerner
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Lesser General Public
7  License as published by the Free Software Foundation; either
8  version 2.1 of the License, or (at your option) any later version.
9 
10  As a special exception, you may use this file as part of a free
11  software library without restriction. Specifically, if other files
12  instantiate templates or use macros or inline functions from this
13  file, or you compile this file and link it with other files to
14  produce an executable, this file does not by itself cause the
15  resulting executable to be covered by the GNU General Public
16  License. This exception does not however invalidate any other
17  reasons why the executable file might be covered by the GNU Library
18  General Public License.
19 
20  This library is distributed in the hope that it will be useful,
21  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23  Lesser General Public License for more details.
24 
25  You should have received a copy of the GNU Lesser General Public
26  License along with this library; if not, write to the Free Software
27  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
28  MA 02110-1301 USA
29 */
30 
31 #ifndef Pt_Arg_h
32 #define Pt_Arg_h
33 
34 #include <Pt/Api.h>
35 #include <sstream>
36 #include <cstring>
37 
38 namespace Pt {
39 
41 class ArgBase
42 {
43  public:
44  ArgBase()
45  : m_isset(false)
46  { }
47 
49  bool isSet() const
50  { return m_isset; }
51 
52  protected:
53  bool m_isset;
54 
56  static void removeArg(int& argc, char* argv[], int pos, int n)
57  {
58  for ( ; pos < argc - n; ++pos)
59  argv[pos] = argv[pos + n];
60 
61  argc -= n;
62  argv[argc] = 0;
63  }
64 };
65 
67 template <typename T>
68 class ArgBaseT : public ArgBase
69 {
70  protected:
71  explicit ArgBaseT(const T& def)
72  : m_value(def)
73  { }
74 
76  bool extract(const char* str, int& argc, char* argv[], int i, int n)
77  {
78  std::istringstream s(str);
79  s >> m_value;
80  if( ! s.fail() )
81  {
82  m_isset = true;
83  removeArg(argc, argv, i, n);
84  return true;
85  }
86 
87  return false;
88  }
89 
90  public:
92  const T& get() const
93  { return m_value; }
94 
95  private:
96  T m_value;
97 };
98 
100 template <>
101 class ArgBaseT<const char*> : public ArgBase
102 {
103  protected:
104  explicit ArgBaseT(const char* def)
105  : m_value(def)
106  { }
107 
109  bool extract(const char* str, int& argc, char* argv[], int i, int n)
110  {
111  m_value = str;
112  m_isset = true;
113  removeArg(argc, argv, i, n);
114  return true;
115  }
116 
117  public:
119  const char* get() const
120  { return m_value; }
121 
122  private:
123  const char* m_value;
124 };
125 
127 template <>
128 class ArgBaseT<std::string> : public ArgBase
129 {
130  protected:
131  explicit ArgBaseT(const std::string& def)
132  : m_value(def)
133  { }
134 
136  bool extract(const char* str, int& argc, char* argv[], int i, int n)
137  {
138  m_value = str;
139  m_isset = true;
140  removeArg(argc, argv, i, n);
141  return true;
142  }
143 
144  public:
146  const std::string& get() const
147  { return m_value; }
148 
149  private:
150  std::string m_value;
151 };
152 
198 template <typename T>
199 class Arg : public ArgBaseT<T>
200 {
201  public:
204  Arg(const T& def = T())
205  : ArgBaseT<T>(def)
206  { }
207 
221  Arg(int& argc, char* argv[], char ch, const T& def = T())
222  : ArgBaseT<T>(def)
223  {
224  set(argc, argv, ch);
225  }
226 
238  Arg(int& argc, char* argv[], const char* str, const T& def = T())
239  : ArgBaseT<T>(def)
240  {
241  this->m_isset = set(argc, argv, str);
242  }
243 
246  Arg(int& argc, char* argv[])
247  : ArgBaseT<T>(T())
248  {
249  this->m_isset = set(argc, argv);
250  }
251 
265  bool set(int& argc, char* argv[], char ch)
266  {
267  // don't extract value, when already found
268  if(this->m_isset)
269  return false;
270 
271  for(int i = 1; i < argc; ++i)
272  {
273  if (argv[i] && argv[i][0] == '-' && argv[i][1] == ch)
274  {
275  if(argv[i][2] == '\0' && i < argc - 1)
276  {
277  // -O foo
278  if (this->extract(argv[i + 1], argc, argv, i, 2))
279  return true;
280  }
281 
282  // -Ofoo
283  if( this->extract(argv[i] + 2, argc, argv, i, 1) )
284  return true;
285  }
286  }
287 
288  return false;
289  }
290 
304  bool set(int& argc, char* argv[], const char* str)
305  {
306  // don't extract value, when already found
307  if (this->m_isset)
308  return false;
309 
310  unsigned n = std::strlen(str);
311  for (int i = 1; i < argc; ++i)
312  {
313  if(argv[i] && (std::strncmp(argv[i], str, n) == 0))
314  {
315  if (i < argc - 1 && argv[i][n] == '\0')
316  {
317  // --option value
318  if (this->extract(argv[i + 1], argc, argv, i, 2))
319  return true;
320  }
321 
322  if (argv[i][n] == '=')
323  {
324  // --option=value
325  if (this->extract(argv[i] + n + 1, argc, argv, i, 1))
326  return true;
327  }
328  }
329  }
330 
331  return false;
332  }
333 
335  bool set(int& argc, char* argv[])
336  {
337  // don't extract value, when already found
338  if (this->m_isset)
339  return false;
340 
341  if (argc > 1)
342  this->extract(argv[1], argc, argv, 1, 1);
343 
344  return this->m_isset;
345  }
346 };
347 
349 template <>
350 class Arg<bool> : public ArgBase
351 {
352  public:
353  Arg(bool def = false)
354  : m_value(def)
355  { }
356 
357  Arg(int& argc, char* argv[], char ch, bool def = false)
358  : m_value(def)
359  {
360  m_isset = set(argc, argv, ch);
361  }
362 
363  Arg(int& argc, char* argv[], const char* str, bool def = false)
364  : m_value(def)
365  {
366  m_isset = set(argc, argv, str);
367  }
368 
369  bool set(int& argc, char* argv[], char ch)
370  {
371  // don't extract value, when already found
372  if (m_isset)
373  return false;
374 
375  for (int i = 1; i < argc; ++i)
376  {
377  if (argv[i][0] == '-' && argv[i][1] != '-')
378  {
379  // starts with a '-', but not with "--"
380  if (argv[i][1] == ch && argv[i][2] == '\0')
381  {
382  // single option found
383  m_value = true;
384  m_isset = true;
385  removeArg(argc, argv, i, 1);
386  return true;
387  }
388  else if(argv[i][1] == ch &&
389  argv[i][2] == '-' &&
390  argv[i][3] == '\0')
391  {
392  // Option was explicitly disabled with -x-
393  m_value = false;
394  m_isset = true;
395  removeArg(argc, argv, i, 1);
396  return true;
397  }
398  else
399  {
400  // check for optiongroup
401  for (char* p = argv[i] + 1; *p != '\0'; ++p)
402  {
403  if (*p == ch)
404  {
405  // here it is - extract it
406  m_value = true;
407  m_isset = true;
408  do
409  {
410  *p = *(p + 1);
411  }
412  while (*p++ != '\0');
413 
414  return true;
415  }
416  }
417  }
418  }
419  }
420 
421  return false;
422  }
423 
424  bool set(int& argc, char* argv[], const char* str)
425  {
426  // don't extract value, when already found
427  if(m_isset)
428  return false;
429 
430  for (int i = 1; i < argc; ++i)
431  {
432  if (std::strcmp(argv[i], str) == 0)
433  {
434  m_value = true;
435  m_isset = true;
436  removeArg(argc, argv, i, 1);
437  return true;
438  }
439  }
440 
441  return false;
442  }
443 
444  bool get() const
445  { return m_value; }
446 
447  operator bool() const
448  { return m_value; }
449 
450  private:
451  bool m_value;
452 };
453 
458 template <typename T>
459 inline std::ostream& operator<<(std::ostream& out, const Arg<T>& arg)
460 {
461  return out << arg.get();
462 }
463 
464 } // namespace Pt
465 
466 #endif
Arg(int &argc, char *argv[], const char *str, const T &def=T())
Extract long option.
Definition: Arg.h:238
Arg(int &argc, char *argv[], char ch, const T &def=T())
Extract short option.
Definition: Arg.h:221
Arg(int &argc, char *argv[])
Extracts the next parameter.
Definition: Arg.h:246
Arg(const T &def=T())
Constructor with initial value.
Definition: Arg.h:204
bool set(int &argc, char *argv[])
Reads next parameter and removes it.
Definition: Arg.h:335
Read and extract command-line options.
Definition: Arg.h:199
bool set(int &argc, char *argv[], char ch)
Extract short option.
Definition: Arg.h:265
bool set(int &argc, char *argv[], const char *str)
Extract long option.
Definition: Arg.h:304