Open Lighting Architecture  0.9.4
 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 
188 template<>
189 class Flag<bool> : public BaseFlag {
190  public:
191  Flag(const char *name, const char *arg_type, const char *short_opt,
192  bool default_value, const char *help, const bool has_arg)
193  : BaseFlag(arg_type, short_opt, help),
194  m_name(name),
195  m_default(default_value),
196  m_value(default_value),
197  m_has_arg(has_arg) {
198  if (!has_arg && default_value) {
199  // prefix the long option with 'no'
200  size_t prefix_size = strlen(NO_PREFIX);
201  size_t name_size = strlen(name);
202  char* new_name = new char[prefix_size + name_size + 1];
203  memcpy(new_name, NO_PREFIX, prefix_size);
204  memcpy(new_name + prefix_size, name, name_size);
205  new_name[prefix_size + name_size] = 0;
206  ReplaceUnderscoreWithHyphen(new_name);
207  m_name = new_name;
208  } else {
209  m_name = NewCanonicalName(name);
210  }
211  }
212 
213  ~Flag() {
214  delete[] m_name;
215  }
216 
217  const char *name() const { return m_name; }
218  bool has_arg() const { return m_has_arg; }
219  bool default_value() const { return m_default; }
220 
221  operator bool() const { return m_value; }
222 
223  Flag &operator=(bool v) {
224  m_value = v;
225  return *this;
226  }
227 
228  bool SetValue(const std::string &input) {
229  MarkAsPresent();
230  if (m_has_arg) {
231  return ola::StringToBoolTolerant(input, &m_value);
232  } else {
233  m_value = !m_default;
234  return true;
235  }
236  }
237 
238  private:
239  const char *m_name;
240  bool m_default;
241  bool m_value;
242  bool m_has_arg;
243 
244  static const char NO_PREFIX[];
245 };
246 
250 template<>
251 class Flag<std::string> : public BaseFlag {
252  public:
253  Flag(const char *name, const char *arg_type, const char *short_opt,
254  std::string default_value, const char *help,
255  OLA_UNUSED const bool has_arg)
256  : BaseFlag(arg_type, short_opt, help),
257  m_name(name),
258  m_default(default_value),
259  m_value(default_value) {
260  m_name = NewCanonicalName(name);
261  }
262 
263  ~Flag() {
264  delete[] m_name;
265  }
266 
267  const char *name() const { return m_name; }
268  bool has_arg() const { return true; }
269  std::string default_value() const { return m_default; }
270  const char* arg_type() const { return "string"; }
271 
272  operator const char*() const { return m_value.c_str(); }
273  operator std::string() const { return m_value; }
274  std::string str() const { return m_value; }
275 
276  Flag &operator=(const std::string &v) {
277  m_value = v;
278  return *this;
279  }
280 
281  bool SetValue(const std::string &input) {
282  MarkAsPresent();
283  m_value = input;
284  return true;
285  }
286 
287  private:
288  const char *m_name;
289  std::string m_default;
290  std::string m_value;
291 };
292 
296 template <typename T>
297 bool Flag<T>::SetValue(const std::string &input) {
298  MarkAsPresent();
299  return ola::StringToInt(input, &m_value, true);
300 }
301 
302 
308  public:
309  FlagRegistry() {}
310 
311  void RegisterFlag(FlagInterface *flag);
312  void ParseFlags(int *argc, char **argv);
313 
314  void SetFirstLine(const std::string &help);
315  void SetDescription(const std::string &help);
316  void DisplayUsage();
317  void DisplayVersion();
318  void GenManPage();
319 
320  private:
321  typedef std::map<std::string, FlagInterface*> LongOpts;
322  typedef std::map<char, FlagInterface*> ShortOpts;
323  typedef std::map<int, FlagInterface*> FlagMap;
324  // <flag, description>
325  typedef std::pair<std::string, std::string> OptionPair;
326 
327  LongOpts m_long_opts;
328  ShortOpts m_short_opts;
329  std::string m_argv0;
330  std::string m_first_line;
331  std::string m_description;
332 
333  std::string GetShortOptsString() const;
334  struct option *GetLongOpts(FlagMap *flag_map);
335  void PrintFlags(std::vector<std::string> *lines);
336  void PrintManPageFlags(std::vector<OptionPair> *lines);
337 };
338 
343 
348  public:
349  explicit FlagRegisterer(FlagInterface *flag) {
350  GetRegistry()->RegisterFlag(flag);
351  }
352 
353  FlagRegisterer(FlagInterface *flag, char *short_opt) {
354  *short_opt = flag->short_opt();
355  GetRegistry()->RegisterFlag(flag);
356  }
357 };
358 
361 } // namespace ola
362 
370 #define DECLARE_flag(type, name) \
371  namespace ola_flags { extern ola::Flag<type> FLAGS_##name; } \
372  using ola_flags::FLAGS_##name;
373 
377 #define DEFINE_flag(type, name, short_opt, default_value, help_str, \
378  has_arg) \
379  namespace ola_flags { \
380  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
381  help_str, has_arg); \
382  ola::FlagRegisterer flag_registerer_##name(&FLAGS_##name); \
383  } \
384  using ola_flags::FLAGS_##name
385 
389 #define DEFINE_flag_with_short(type, name, short_opt, default_value, help_str, \
390  has_arg) \
391  namespace ola_flags { char flag_short_##short_opt = 0; } \
392  namespace ola_flags { \
393  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
394  help_str, has_arg); \
395  ola::FlagRegisterer flag_registerer_##name( \
396  &FLAGS_##name, &flag_short_##short_opt); \
397  } \
398  using ola_flags::FLAGS_##name
399 
405 #endif // INCLUDE_OLA_BASE_FLAGSPRIVATE_H_