arg.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2003,2004,2010 Tommi Maekitalo
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * As a special exception, you may use this file as part of a free
10  * software library without restriction. Specifically, if other files
11  * instantiate templates or use macros or inline functions from this
12  * file, or you compile this file and link it with other files to
13  * produce an executable, this file does not by itself cause the
14  * resulting executable to be covered by the GNU General Public
15  * License. This exception does not however invalidate any other
16  * reasons why the executable file might be covered by the GNU Library
17  * General Public License.
18  *
19  * This library is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22  * Lesser General Public License for more details.
23  *
24  * You should have received a copy of the GNU Lesser General Public
25  * License along with this library; if not, write to the Free Software
26  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27  */
28 
29 #ifndef CXXTOOLS_ARG_H
30 #define CXXTOOLS_ARG_H
31 
32 #include <sstream>
33 #include <string.h>
34 
35 namespace cxxtools
36 {
37 
39 class ArgBase
40 {
41  protected:
42  bool m_isset;
43 
44  static void removeArg(int& argc, char* argv[], int pos, int n)
45  {
46  for ( ; pos < argc - n; ++pos)
47  argv[pos] = argv[pos + n];
48  argc -= n;
49  argv[argc] = 0;
50  }
51 
52  public:
53  ArgBase()
54  : m_isset(false)
55  { }
56 
60  bool isSet() const { return m_isset; }
61 };
62 
63 template <typename T>
64 class ArgBaseT : public ArgBase
65 {
66  T m_value;
67 
68  protected:
69  explicit ArgBaseT(const T& def)
70  : m_value(def)
71  { }
72 
73  bool extract(const char* str, int& argc, char* argv[], int i, int n)
74  {
75  std::istringstream s(str);
76  s >> m_value;
77  if (!s.fail())
78  {
79  m_isset = true;
80  removeArg(argc, argv, i, n);
81  return true;
82  }
83  return false;
84  }
85 
86  public:
90  const T& getValue() const { return m_value; }
91 
114  operator T() const { return m_value; }
115 
116  ArgBaseT<T>& operator= (const T& value)
117  {
118  m_value = value;
119  return *this;
120  }
121 };
122 
123 template <>
124 class ArgBaseT<const char*> : public ArgBase
125 {
126  const char* m_value;
127 
128  protected:
129  explicit ArgBaseT(const char* def)
130  : m_value(def)
131  { }
132 
133  bool extract(const char* str, int& argc, char* argv[], int i, int n)
134  {
135  m_value = str;
136  m_isset = true;
137  removeArg(argc, argv, i, n);
138  return true;
139  }
140 
141  public:
143  const char* getValue() const { return m_value; }
144 
146  operator const char*() const { return m_value; }
147 
148  ArgBaseT<const char*>& operator= (const char* value)
149  {
150  m_value = value;
151  return *this;
152  }
153 };
154 
155 template <>
156 class ArgBaseT<std::string> : public ArgBase
157 {
158  std::string m_value;
159 
160  protected:
161  explicit ArgBaseT(const std::string& def)
162  : m_value(def)
163  { }
164 
165  bool extract(const char* str, int& argc, char* argv[], int i, int n)
166  {
167  m_value = str;
168  m_isset = true;
169  removeArg(argc, argv, i, n);
170  return true;
171  }
172 
173  public:
175  const std::string& getValue() const { return m_value; }
176 
178  operator const std::string&() const { return m_value; }
179 
180  ArgBaseT<std::string>& operator= (const std::string& value)
181  {
182  m_value = value;
183  return *this;
184  }
185 };
187 
210 template <typename T>
211 class Arg : public ArgBaseT<T>
212 {
213  public:
219  explicit Arg(const T& def = T())
220  : ArgBaseT<T>(def)
221  { }
222 
237  Arg(int& argc, char* argv[], char ch, const T& def = T())
238  : ArgBaseT<T>(def)
239  {
240  set(argc, argv, ch);
241  }
242 
254  Arg(int& argc, char* argv[], const char* str, const T& def = T())
255  : ArgBaseT<T>(def)
256  {
257  this->m_isset = set(argc, argv, str);
258  }
259 
260  Arg(int& argc, char* argv[])
261  : ArgBaseT<T>(T())
262  {
263  this->m_isset = set(argc, argv);
264  }
265 
280  bool set(int& argc, char* argv[], char ch)
281  {
282  // don't extract value, when already found
283  if (this->m_isset)
284  return false;
285 
286  for (int i = 1; i < argc; ++i)
287  {
288  if (argv[i][0] == '-' && argv[i][1] == ch)
289  {
290  if (argv[i][2] == '\0' && i < argc - 1)
291  {
292  // -O foo
293  if (this->extract(argv[i + 1], argc, argv, i, 2))
294  return true;
295  }
296 
297  // -Ofoo
298  if (this->extract(argv[i] + 2, argc, argv, i, 1))
299  return true;
300  }
301  }
302 
303  return false;
304  }
305 
318  bool set(int& argc, char* argv[], const char* str)
319  {
320  // don't extract value, when already found
321  if (this->m_isset)
322  return false;
323 
324  unsigned n = strlen(str);
325  for (int i = 1; i < argc; ++i)
326  {
327  if (strncmp(argv[i], str, n) == 0)
328  {
329  if (i < argc - 1 && argv[i][n] == '\0')
330  {
331  // --option value
332  if (this->extract(argv[i + 1], argc, argv, i, 2))
333  return true;
334  }
335 
336  if (argv[i][n] == '=')
337  {
338  // --option=vlaue
339  if (this->extract(argv[i] + n + 1, argc, argv, i, 1))
340  return true;
341  }
342  }
343  }
344 
345  return false;
346  }
347 
351  bool set(int& argc, char* argv[])
352  {
353  // don't extract value, when already found
354  if (this->m_isset)
355  return false;
356 
357  if (argc > 1)
358  this->extract(argv[1], argc, argv, 1, 1);
359 
360  return this->m_isset;
361  }
362 };
363 
365 
378 template <>
379 class Arg<bool> : public ArgBase
380 {
381  public:
387  Arg(bool def = false)
388  : m_value(def)
389  { }
390 
434  Arg(int& argc, char* argv[], char ch, bool def = false)
435  : m_value(def)
436  {
437  m_isset = set(argc, argv, ch);
438  }
439 
440  Arg(int& argc, char* argv[], const char* str, bool def = false)
441  : m_value(def)
442  {
443  m_isset = set(argc, argv, str);
444  }
445 
446  bool set(int& argc, char* argv[], char ch)
447  {
448  // don't extract value, when already found
449  if (m_isset)
450  return false;
451 
452  for (int i = 1; i < argc; ++i)
453  {
454  if (argv[i][0] == '-' && argv[i][1] != '-')
455  {
456  // starts with a '-', but not with "--"
457  if (argv[i][1] == ch && argv[i][2] == '\0')
458  {
459  // single option found
460  m_value = true;
461  m_isset = true;
462  removeArg(argc, argv, i, 1);
463  return true;
464  }
465  else if (argv[i][1] == ch && argv[i][2] == '-' && argv[i][3] == '\0')
466  {
467  // Option was explicitly disabled with -x-
468  m_value = false;
469  m_isset = true;
470  removeArg(argc, argv, i, 1);
471  return true;
472  }
473  else
474  {
475  // look, if we find the option in an optiongroup
476  for (char* p = argv[i] + 1; *p != '\0'; ++p)
477  if (*p == ch)
478  {
479  // here it is - extract it
480  m_value = true;
481  m_isset = true;
482  do
483  {
484  *p = *(p + 1);
485  } while (*p++ != '\0');
486 
487  return true;
488  }
489  }
490  }
491  }
492 
493  return false;
494  }
495 
511  bool set(int& argc, char* argv[], const char* str)
512  {
513  // don't extract value, when already found
514  if (m_isset)
515  return false;
516 
517  for (int i = 1; i < argc; ++i)
518  {
519  if (strcmp(argv[i], str) == 0)
520  {
521  m_value = true;
522  m_isset = true;
523  removeArg(argc, argv, i, 1);
524  return true;
525  }
526  }
527 
528  return false;
529  }
530 
534  bool isTrue() const { return m_value; }
535 
539  bool isFalse() const { return !m_value; }
540 
544  operator bool() const { return m_value; }
545 
546  private:
547  bool m_value;
548 };
549 
551 template <typename T>
552 std::ostream& operator<< (std::ostream& out, const ArgBaseT<T>& arg)
553 {
554  return out << arg.getValue();
555 }
556 
557 }
558 
559 #endif // CXXTOOLS_ARG_H