Open Lighting Architecture  0.9.3
 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  const char *name() const { return m_name; }
163  bool has_arg() const { return true; }
164  bool default_value() const { return m_default; }
165 
166  operator T() const { return m_value; }
167 
168  Flag &operator=(T v) {
169  m_value = v;
170  return *this;
171  }
172 
173  bool SetValue(const std::string &input);
174 
175  private:
176  const char *m_name;
177  T m_default;
178  T m_value;
179 };
180 
184 template<>
185 class Flag<bool> : public BaseFlag {
186  public:
187  Flag(const char *name, const char *arg_type, const char *short_opt,
188  bool default_value, const char *help, const bool has_arg)
189  : BaseFlag(arg_type, short_opt, help),
190  m_name(name),
191  m_default(default_value),
192  m_value(default_value),
193  m_has_arg(has_arg) {
194  if (!has_arg && default_value) {
195  // prefix the long option with 'no'
196  size_t total_size = strlen(NO_PREFIX) + strlen(name) + 1;
197  char* new_name = new char[total_size];
198  strncpy(new_name, NO_PREFIX, strlen(NO_PREFIX) + 1);
199  strncat(new_name, name, total_size);
200  ReplaceUnderscoreWithHyphen(new_name);
201  m_name = new_name;
202  } else {
203  m_name = NewCanonicalName(name);
204  }
205  }
206 
207  const char *name() const { return m_name; }
208  bool has_arg() const { return m_has_arg; }
209  bool default_value() const { return m_default; }
210 
211  operator bool() const { return m_value; }
212 
213  Flag &operator=(bool v) {
214  m_value = v;
215  return *this;
216  }
217 
218  bool SetValue(const std::string &input) {
219  MarkAsPresent();
220  if (m_has_arg) {
221  return ola::StringToBoolTolerant(input, &m_value);
222  } else {
223  m_value = !m_default;
224  return true;
225  }
226  }
227 
228  private:
229  const char *m_name;
230  bool m_default;
231  bool m_value;
232  bool m_has_arg;
233 
234  static const char NO_PREFIX[];
235 };
236 
240 template<>
241 class Flag<std::string> : public BaseFlag {
242  public:
243  Flag(const char *name, const char *arg_type, const char *short_opt,
244  std::string default_value, const char *help,
245  OLA_UNUSED const bool has_arg)
246  : BaseFlag(arg_type, short_opt, help),
247  m_name(name),
248  m_default(default_value),
249  m_value(default_value) {
250  m_name = NewCanonicalName(name);
251  }
252 
253  const char *name() const { return m_name; }
254  bool has_arg() const { return true; }
255  std::string default_value() const { return m_default; }
256  const char* arg_type() const { return "string"; }
257 
258  operator const char*() const { return m_value.c_str(); }
259  operator std::string() const { return m_value; }
260  std::string str() const { return m_value; }
261 
262  Flag &operator=(const std::string &v) {
263  m_value = v;
264  return *this;
265  }
266 
267  bool SetValue(const std::string &input) {
268  MarkAsPresent();
269  m_value = input;
270  return true;
271  }
272 
273  private:
274  const char *m_name;
275  std::string m_default;
276  std::string m_value;
277 };
278 
282 template <typename T>
283 bool Flag<T>::SetValue(const std::string &input) {
284  MarkAsPresent();
285  return ola::StringToInt(input, &m_value, true);
286 }
287 
288 
294  public:
295  FlagRegistry() {}
296 
297  void RegisterFlag(FlagInterface *flag);
298  void ParseFlags(int *argc, char **argv);
299 
300  void SetFirstLine(const std::string &help);
301  void SetDescription(const std::string &help);
302  void DisplayUsage();
303  void DisplayVersion();
304  void GenManPage();
305 
306  private:
307  typedef std::map<std::string, FlagInterface*> LongOpts;
308  typedef std::map<char, FlagInterface*> ShortOpts;
309  typedef std::map<int, FlagInterface*> FlagMap;
310  // <flag, description>
311  typedef std::pair<std::string, std::string> OptionPair;
312 
313  LongOpts m_long_opts;
314  ShortOpts m_short_opts;
315  std::string m_argv0;
316  std::string m_first_line;
317  std::string m_description;
318 
319  std::string GetShortOptsString() const;
320  struct option *GetLongOpts(FlagMap *flag_map);
321  void PrintFlags(std::vector<std::string> *lines);
322  void PrintManPageFlags(std::vector<OptionPair> *lines);
323 };
324 
329 
334  public:
335  explicit FlagRegisterer(FlagInterface *flag) {
336  GetRegistry()->RegisterFlag(flag);
337  }
338 
339  FlagRegisterer(FlagInterface *flag, char *short_opt) {
340  *short_opt = flag->short_opt();
341  GetRegistry()->RegisterFlag(flag);
342  }
343 };
344 
347 } // namespace ola
348 
356 #define DECLARE_flag(type, name) \
357  namespace ola_flags { extern ola::Flag<type> FLAGS_##name; } \
358  using ola_flags::FLAGS_##name;
359 
363 #define DEFINE_flag(type, name, short_opt, default_value, help_str, \
364  has_arg) \
365  namespace ola_flags { \
366  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
367  help_str, has_arg); \
368  ola::FlagRegisterer flag_registerer_##name(&FLAGS_##name); \
369  } \
370  using ola_flags::FLAGS_##name
371 
375 #define DEFINE_flag_with_short(type, name, short_opt, default_value, help_str, \
376  has_arg) \
377  namespace ola_flags { char flag_short_##short_opt = 0; } \
378  namespace ola_flags { \
379  ola::Flag<type> FLAGS_##name(#name, #type, #short_opt, default_value, \
380  help_str, has_arg); \
381  ola::FlagRegisterer flag_registerer_##name( \
382  &FLAGS_##name, &flag_short_##short_opt); \
383  } \
384  using ola_flags::FLAGS_##name
385 
391 #endif // INCLUDE_OLA_BASE_FLAGSPRIVATE_H_