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 
38 class ArgBase
39 {
40  protected:
41  bool m_isset;
42 
43  static void removeArg(int& argc, char* argv[], int pos, int n)
44  {
45  for ( ; pos < argc - n; ++pos)
46  argv[pos] = argv[pos + n];
47  argc -= n;
48  argv[argc] = 0;
49  }
50 
51  public:
53  : m_isset(false)
54  { }
55 
59  bool isSet() const { return m_isset; }
60 };
61 
62 template <typename T>
63 class ArgBaseT : public ArgBase
64 {
65  T m_value;
66 
67  protected:
68  explicit ArgBaseT(const T& def)
69  : m_value(def)
70  { }
71 
72  bool extract(const char* str, int& argc, char* argv[], int i, int n)
73  {
74  std::istringstream s(str);
75  s >> m_value;
76  if (!s.fail())
77  {
78  m_isset = true;
79  removeArg(argc, argv, i, n);
80  return true;
81  }
82  return false;
83  }
84 
85  public:
89  const T& getValue() const { return m_value; }
90 
113  operator T() const { return m_value; }
114 
115  ArgBaseT<T>& operator= (const T& value)
116  {
117  m_value = value;
118  return *this;
119  }
120 };
121 
122 template <>
123 class ArgBaseT<const char*> : public ArgBase
124 {
125  const char* m_value;
126 
127  protected:
128  explicit ArgBaseT(const char* def)
129  : m_value(def)
130  { }
131 
132  bool extract(const char* str, int& argc, char* argv[], int i, int n)
133  {
134  m_value = str;
135  m_isset = true;
136  removeArg(argc, argv, i, n);
137  return true;
138  }
139 
140  public:
142  const char* getValue() const { return m_value; }
143 
145  operator const char*() const { return m_value; }
146 
147  ArgBaseT<const char*>& operator= (const char* value)
148  {
149  m_value = value;
150  return *this;
151  }
152 };
153 
154 template <>
155 class ArgBaseT<std::string> : public ArgBase
156 {
157  std::string m_value;
158 
159  protected:
160  explicit ArgBaseT(const std::string& def)
161  : m_value(def)
162  { }
163 
164  bool extract(const char* str, int& argc, char* argv[], int i, int n)
165  {
166  m_value = str;
167  m_isset = true;
168  removeArg(argc, argv, i, n);
169  return true;
170  }
171 
172  public:
174  const std::string& getValue() const { return m_value; }
175 
177  operator const std::string&() const { return m_value; }
178 
179  ArgBaseT<std::string>& operator= (const std::string& value)
180  {
181  m_value = value;
182  return *this;
183  }
184 };
185 
208 template <typename T>
209 class Arg : public ArgBaseT<T>
210 {
211  public:
217  explicit Arg(const T& def = T())
218  : ArgBaseT<T>(def)
219  { }
220 
235  Arg(int& argc, char* argv[], char ch, const T& def = T())
236  : ArgBaseT<T>(def)
237  {
238  set(argc, argv, ch);
239  }
240 
252  Arg(int& argc, char* argv[], const char* str, const T& def = T())
253  : ArgBaseT<T>(def)
254  {
255  this->m_isset = set(argc, argv, str);
256  }
257 
258  Arg(int& argc, char* argv[])
259  : ArgBaseT<T>(T())
260  {
261  this->m_isset = set(argc, argv);
262  }
263 
278  bool set(int& argc, char* argv[], char ch)
279  {
280  // don't extract value, when already found
281  if (this->m_isset)
282  return false;
283 
284  for (int i = 1; i < argc; ++i)
285  {
286  if (argv[i][0] == '-' && argv[i][1] == ch)
287  {
288  if (argv[i][2] == '\0' && i < argc - 1)
289  {
290  // -O foo
291  if (this->extract(argv[i + 1], argc, argv, i, 2))
292  return true;
293  }
294 
295  // -Ofoo
296  if (this->extract(argv[i] + 2, argc, argv, i, 1))
297  return true;
298  }
299  }
300 
301  return false;
302  }
303 
316  bool set(int& argc, char* argv[], const char* str)
317  {
318  // don't extract value, when already found
319  if (this->m_isset)
320  return false;
321 
322  unsigned n = strlen(str);
323  for (int i = 1; i < argc; ++i)
324  {
325  if (strncmp(argv[i], str, n) == 0)
326  {
327  if (i < argc - 1 && argv[i][n] == '\0')
328  {
329  // --option value
330  if (this->extract(argv[i + 1], argc, argv, i, 2))
331  return true;
332  }
333 
334  if (argv[i][n] == '=')
335  {
336  // --option=vlaue
337  if (this->extract(argv[i] + n + 1, argc, argv, i, 1))
338  return true;
339  }
340  }
341  }
342 
343  return false;
344  }
345 
349  bool set(int& argc, char* argv[])
350  {
351  // don't extract value, when already found
352  if (this->m_isset)
353  return false;
354 
355  if (argc > 1)
356  this->extract(argv[1], argc, argv, 1, 1);
357 
358  return this->m_isset;
359  }
360 };
361 
363 
376 template <>
377 class Arg<bool> : public ArgBase
378 {
379  public:
385  Arg(bool def = false)
386  : m_value(def)
387  { }
388 
432  Arg(int& argc, char* argv[], char ch, bool def = false)
433  : m_value(def)
434  {
435  m_isset = set(argc, argv, ch);
436  }
437 
438  Arg(int& argc, char* argv[], const char* str, bool def = false)
439  : m_value(def)
440  {
441  m_isset = set(argc, argv, str);
442  }
443 
444  bool set(int& argc, char* argv[], char ch)
445  {
446  // don't extract value, when already found
447  if (m_isset)
448  return false;
449 
450  for (int i = 1; i < argc; ++i)
451  {
452  if (argv[i][0] == '-' && argv[i][1] != '-')
453  {
454  // starts with a '-', but not with "--"
455  if (argv[i][1] == ch && argv[i][2] == '\0')
456  {
457  // single option found
458  m_value = true;
459  m_isset = true;
460  removeArg(argc, argv, i, 1);
461  return true;
462  }
463  else if (argv[i][1] == ch && argv[i][2] == '-' && argv[i][3] == '\0')
464  {
465  // Option was explicitly disabled with -x-
466  m_value = false;
467  m_isset = true;
468  removeArg(argc, argv, i, 1);
469  return true;
470  }
471  else
472  {
473  // look, if we find the option in an optiongroup
474  for (char* p = argv[i] + 1; *p != '\0'; ++p)
475  if (*p == ch)
476  {
477  // here it is - extract it
478  m_value = true;
479  m_isset = true;
480  do
481  {
482  *p = *(p + 1);
483  } while (*p++ != '\0');
484 
485  return true;
486  }
487  }
488  }
489  }
490 
491  return false;
492  }
493 
509  bool set(int& argc, char* argv[], const char* str)
510  {
511  // don't extract value, when already found
512  if (m_isset)
513  return false;
514 
515  for (int i = 1; i < argc; ++i)
516  {
517  if (strcmp(argv[i], str) == 0)
518  {
519  m_value = true;
520  m_isset = true;
521  removeArg(argc, argv, i, 1);
522  return true;
523  }
524  }
525 
526  return false;
527  }
528 
532  bool isTrue() const { return m_value; }
533 
537  bool isFalse() const { return !m_value; }
538 
542  operator bool() const { return m_value; }
543 
544  private:
545  bool m_value;
546 };
547 
548 template <typename T>
549 std::ostream& operator<< (std::ostream& out, const ArgBaseT<T> arg)
550 {
551  return out << arg.getValue();
552 }
553 
554 }
555 
556 #endif // CXXTOOLS_ARG_H