Open Lighting Architecture  0.9.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
FlagsPrivate.h
Go to the documentation of this file.
1 /*
2  * This library is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU Lesser General Public
4  * License as published by the Free Software Foundation; either
5  * version 2.1 of the License, or (at your option) any later version.
6  *
7  * This library is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10  * Lesser General Public License for more details.
11  *
12  * You should have received a copy of the GNU Lesser General Public
13  * License along with this library; if not, write to the Free Software
14  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
15  *
16  * FlagsPrivate.h
17  * Command line flag (option) handling.
18  * Copyright (C) 2013 Simon Newton
19  */
20 
29 #ifndef INCLUDE_OLA_BASE_FLAGSPRIVATE_H_
30 #define INCLUDE_OLA_BASE_FLAGSPRIVATE_H_
31 
32 #include <getopt.h>
33 #include <string.h>
34 #include <ola/StringUtils.h>
35 #include <ola/base/Macro.h>
36 #include <map>
37 #include <sstream>
38 #include <string>
39 #include <utility>
40 #include <vector>
41 
42 namespace ola {
43 
53  public:
54  virtual ~FlagInterface() {}
55 
59  virtual const char* name() const = 0;
60 
64  virtual char short_opt() const = 0;
65 
69  virtual bool has_arg() const = 0;
70 
74  virtual const char* arg_type() const = 0;
75 
79  virtual std::string help() const = 0;
80 
86  virtual bool present() const = 0;
87 
93  virtual bool SetValue(const std::string &input) = 0;
94 };
95 
99 class BaseFlag : public FlagInterface {
100  public:
107  BaseFlag(const char *arg_type, const char *short_opt, const char *help)
108  : m_arg_type(arg_type),
109  m_short_opt(short_opt[0]),
110  m_help(help),
111  m_present(false) {
112  }
113 
114  char short_opt() const { return m_short_opt; }
115  const char* arg_type() const { return m_arg_type; }
116  std::string help() const { return m_help; }
117  bool present() const { return m_present; }
118 
122  void MarkAsPresent() { m_present = true; }
123 
124  protected:
125  void ReplaceUnderscoreWithHyphen(char *input);
126  const char* NewCanonicalName(const char *name);
127 
128  private:
129  const char *m_arg_type;
130  char m_short_opt;
131  const char *m_help;
132  bool m_present;
133 };
134 
139 template <typename T>
140 class Flag : public BaseFlag {
141  public:
152  Flag(const char *name, const char *arg_type, const char *short_opt,
153  T default_value, const char *help,
154  OLA_UNUSED const bool has_arg)
155  : BaseFlag(arg_type, short_opt, help),
156  m_name(name),
157  m_default(default_value),
158  m_value(default_value) {
159  m_name = NewCanonicalName(name);
160  }
161 
162  ~Flag() {
163  delete[] m_name;
164  }
165 
166  const char *name() const { return m_name; }
167  bool has_arg() const { return true; }
168  bool default_value() const { return m_default; }
169 
170  operator T() const { return m_value; }
171 
172  Flag &operator=(T v) {
173  m_value = v;
174  return *this;
175  }
176 
177  bool SetValue(const std::string &input);
178 
179  private:
180  const char *m_name;
181  T m_default;
182  T m_value;
183 
184  DISALLOW_COPY_AND_ASSIGN(Flag);
185 };
186 
190 template<>
191 class Flag<bool> : public BaseFlag {
192  public:
193  Flag(const char *name, const char *arg_type, const char *short_opt,
194  bool default_value, const char *help, const bool has_arg)
195  : BaseFlag(arg_type, short_opt, help),
196  m_name(name),
197  m_default(default_value),
198  m_value(default_value),
199  m_has_arg(has_arg) {
200  if (!has_arg && default_value) {
201  // prefix the long option with 'no'
202  size_t prefix_size = strlen(NO_PREFIX);
203  size_t name_size = strlen(name);
204  char* new_name = new char[prefix_size + name_size + 1];
205  memcpy(new_name, NO_PREFIX, prefix_size);
206  memcpy(new_name + prefix_size, name, name_size);
207  new_name[prefix_size + name_size] = 0;
208  ReplaceUnderscoreWithHyphen(new_name);
209  m_name = new_name;
210  } else {
211  m_name = NewCanonicalName(name);
212  }
213  }
214 
215  ~Flag() {
216  delete[] m_name;
217  }
218 
219  const char *name() const { return m_name; }
220  bool has_arg() const { return m_has_arg; }
221  bool default_value() const { return m_default; }
222 
223  operator bool() const { return m_value; }
224 
225  Flag &operator=(bool v) {
226  m_value = v;
227  return *this;
228  }
229 
230  bool SetValue(const std::string &input) {
231  MarkAsPresent();
232  if (m_has_arg) {
233  return ola::StringToBoolTolerant(input, &m_value);
234  } else {
235  m_value = !m_default;
236  return true;
237  }
238  }
239 
240  private:
241  const char *m_name;
242  bool m_default;
243  bool m_value;
244  bool m_has_arg;
245 
246  static const char NO_PREFIX[];
247 
248  DISALLOW_COPY_AND_ASSIGN(Flag);
249 };
250 
254 template<>
255 class Flag<std::string> : public BaseFlag {
256  public:
257  Flag(const char *name, const char *arg_type, const char *short_opt,
258  std::string default_value, const char *help,
259  OLA_UNUSED const bool has_arg)
260  : BaseFlag(arg_type, short_opt, help),
261  m_name(name),
262  m_default(default_value),
263  m_value(default_value) {
264  m_name = NewCanonicalName(name);
265  }
266 
267  ~Flag() {
268  delete[] m_name;
269  }
270 
271  const char *name() const { return m_name; }
272  bool has_arg() const { return true; }
273  std::string default_value() const { return m_default; }
274  const char* arg_type() const { return "string"; }
275 
276  operator const char*() const { return m_value.c_str(); }
277  operator std::string() const { return m_value; }
278  std::string str() const { return m_value; }
279 
280  Flag &operator=(const std::string &v) {
281  m_value = v;
282  return *this;
283  }
284 
285  bool SetValue(const std::string &input) {
286  MarkAsPresent();
287  m_value = input;
288  return true;
289  }
290 
291  private:
292  const char *m_name;
293  std::string m_default;
294  std::string m_value;
295 
296  DISALLOW_COPY_AND_ASSIGN(Flag);
297 };
298 
302 template <typename T>
303 bool Flag<T>::SetValue(const std::string &input) {
304  MarkAsPresent();
305  return ola::StringToInt(input, &m_value, true);
306 }
307 
308 
314  public:
315  FlagRegistry() {}
316 
317  void RegisterFlag(FlagInterface *flag);
318  void ParseFlags(int *argc, char **argv);
319 
320  void SetFirstLine(const std::string &help);
321  void SetDescription(const std::string &help);
322  void DisplayUsage();
323  void DisplayVersion();
324  void GenManPage();
325 
326  private:
327  typedef std::map<std::string, FlagInterface*> LongOpts;
328  typedef std::map<char, FlagInterface*> ShortOpts;
329  typedef std::map<int, FlagInterface*> FlagMap;
330  // <flag, description>
331  typedef std::pair<std::string, std::string> OptionPair;
332 
333  LongOpts m_long_opts;
334  ShortOpts m_short_opts;
335  std::string m_argv0;
336  std::string m_first_line;
337  std::string m_description;
338 
339  std::string GetShortOptsString() const;
340  struct option *GetLongOpts(FlagMap *flag_map);
341  void PrintFlags(std::vector<std::string> *lines);
342  void PrintManPageFlags(std::vector<OptionPair> *lines);
343 
345 };
346 
351 
356  public:
357  explicit FlagRegisterer(FlagInterface *flag) {
358  GetRegistry()->RegisterFlag(flag);
359  }
360 
361  FlagRegisterer(FlagInterface *flag, char *short_opt) {
362  *short_opt = flag->short_opt();
363  GetRegistry()->RegisterFlag(flag);
364  }
365 
366  private:
367  DISALLOW_COPY_AND_ASSIGN(FlagRegisterer);
368 };
369 
372 } // namespace ola
373 
381 #define DECLARE_flag(type, name) \
382  namespace ola_flags { extern ola::Flag<type> FLAGS_##name; } \
383  using ola_flags::FLAGS_##name;
384 
388 #define DEFINE_flag(type, name, short_opt, default_value, help_str, \
389  has_arg) \
390  namespace ola_flags { \
391  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
392  help_str, has_arg); \
393  ola::FlagRegisterer flag_registerer_##name(&FLAGS_##name); \
394  } \
395  using ola_flags::FLAGS_##name
396 
400 #define DEFINE_flag_with_short(type, name, short_opt, default_value, help_str, \
401  has_arg) \
402  namespace ola_flags { char flag_short_##short_opt = 0; } \
403  namespace ola_flags { \
404  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
405  help_str, has_arg); \
406  ola::FlagRegisterer flag_registerer_##name( \
407  &FLAGS_##name, &flag_short_##short_opt); \
408  } \
409  using ola_flags::FLAGS_##name
410 
416 #endif // INCLUDE_OLA_BASE_FLAGSPRIVATE_H_