1/*
2 * libjingle
3 * Copyright 2006, Google Inc.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 *  1. Redistributions of source code must retain the above copyright notice,
9 *     this list of conditions and the following disclaimer.
10 *  2. Redistributions in binary form must reproduce the above copyright notice,
11 *     this list of conditions and the following disclaimer in the documentation
12 *     and/or other materials provided with the distribution.
13 *  3. The name of the author may not be used to endorse or promote products
14 *     derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28// Flags are defined and declared using DEFINE_xxx and DECLARE_xxx macros,
29// where xxx is the flag type. Flags are referred to via FLAG_yyy,
30// where yyy is the flag name. For intialization and iteration of flags,
31// see the FlagList class. For full programmatic access to any
32// flag, see the Flag class.
33//
34// The implementation only relies and basic C++ functionality
35// and needs no special library or STL support.
36
37#ifndef TALK_BASE_FLAGS_H__
38#define TALK_BASE_FLAGS_H__
39
40#include <assert.h>
41
42#include "talk/base/checks.h"
43#include "talk/base/common.h"
44
45// Internal use only.
46union FlagValue {
47  // Note: Because in C++ non-bool values are silently converted into
48  // bool values ('bool b = "false";' results in b == true!), we pass
49  // and int argument to New_BOOL as this appears to be safer - sigh.
50  // In particular, it prevents the (not uncommon!) bug where a bool
51  // flag is defined via: DEFINE_bool(flag, "false", "some comment");.
52  static FlagValue New_BOOL(int b) {
53    FlagValue v;
54    v.b = (b != 0);
55    return v;
56  }
57
58  static FlagValue New_INT(int i) {
59    FlagValue v;
60    v.i = i;
61    return v;
62  }
63
64  static FlagValue New_FLOAT(float f) {
65    FlagValue v;
66    v.f = f;
67    return v;
68  }
69
70  static FlagValue New_STRING(const char* s) {
71    FlagValue v;
72    v.s = s;
73    return v;
74  }
75
76  bool b;
77  int i;
78  double f;
79  const char* s;
80};
81
82
83// Each flag can be accessed programmatically via a Flag object.
84class Flag {
85 public:
86  enum Type { BOOL, INT, FLOAT, STRING };
87
88  // Internal use only.
89  Flag(const char* file, const char* name, const char* comment,
90       Type type, void* variable, FlagValue default_);
91
92  // General flag information
93  const char* file() const  { return file_; }
94  const char* name() const  { return name_; }
95  const char* comment() const  { return comment_; }
96
97  // Flag type
98  Type type() const  { return type_; }
99
100  // Flag variables
101  bool* bool_variable() const {
102    assert(type_ == BOOL);
103    return &variable_->b;
104  }
105
106  int* int_variable() const {
107    assert(type_ == INT);
108    return &variable_->i;
109  }
110
111  double* float_variable() const {
112    assert(type_ == FLOAT);
113    return &variable_->f;
114  }
115
116  const char** string_variable() const {
117    assert(type_ == STRING);
118    return &variable_->s;
119  }
120
121  // Default values
122  bool bool_default() const {
123    assert(type_ == BOOL);
124    return default_.b;
125  }
126
127  int int_default() const {
128    assert(type_ == INT);
129    return default_.i;
130  }
131
132  double float_default() const {
133    assert(type_ == FLOAT);
134    return default_.f;
135  }
136
137  const char* string_default() const {
138    assert(type_ == STRING);
139    return default_.s;
140  }
141
142  // Resets a flag to its default value
143  void SetToDefault();
144
145  // Iteration support
146  Flag* next() const  { return next_; }
147
148  // Prints flag information. The current flag value is only printed
149  // if print_current_value is set.
150  void Print(bool print_current_value);
151
152 private:
153  const char* file_;
154  const char* name_;
155  const char* comment_;
156
157  Type type_;
158  FlagValue* variable_;
159  FlagValue default_;
160
161  Flag* next_;
162
163  friend class FlagList;  // accesses next_
164};
165
166
167// Internal use only.
168#define DEFINE_FLAG(type, c_type, name, default, comment) \
169  /* define and initialize the flag */                    \
170  c_type FLAG_##name = (default);                         \
171  /* register the flag */                                 \
172  static Flag Flag_##name(__FILE__, #name, (comment),   \
173                          Flag::type, &FLAG_##name,       \
174                          FlagValue::New_##type(default))
175
176
177// Internal use only.
178#define DECLARE_FLAG(c_type, name)              \
179  /* declare the external flag */               \
180  extern c_type FLAG_##name
181
182
183// Use the following macros to define a new flag:
184#define DEFINE_bool(name, default, comment) \
185  DEFINE_FLAG(BOOL, bool, name, default, comment)
186#define DEFINE_int(name, default, comment) \
187  DEFINE_FLAG(INT, int, name, default, comment)
188#define DEFINE_float(name, default, comment) \
189  DEFINE_FLAG(FLOAT, double, name, default, comment)
190#define DEFINE_string(name, default, comment) \
191  DEFINE_FLAG(STRING, const char*, name, default, comment)
192
193
194// Use the following macros to declare a flag defined elsewhere:
195#define DECLARE_bool(name)  DECLARE_FLAG(bool, name)
196#define DECLARE_int(name)  DECLARE_FLAG(int, name)
197#define DECLARE_float(name)  DECLARE_FLAG(double, name)
198#define DECLARE_string(name)  DECLARE_FLAG(const char*, name)
199
200
201// The global list of all flags.
202class FlagList {
203 public:
204  FlagList();
205
206  // The NULL-terminated list of all flags. Traverse with Flag::next().
207  static Flag* list()  { return list_; }
208
209  // If file != NULL, prints information for all flags defined in file;
210  // otherwise prints information for all flags in all files. The current
211  // flag value is only printed if print_current_value is set.
212  static void Print(const char* file, bool print_current_value);
213
214  // Lookup a flag by name. Returns the matching flag or NULL.
215  static Flag* Lookup(const char* name);
216
217  // Helper function to parse flags: Takes an argument arg and splits it into
218  // a flag name and flag value (or NULL if they are missing). is_bool is set
219  // if the arg started with "-no" or "--no". The buffer may be used to NUL-
220  // terminate the name, it must be large enough to hold any possible name.
221  static void SplitArgument(const char* arg,
222                            char* buffer, int buffer_size,
223                            const char** name, const char** value,
224                            bool* is_bool);
225
226  // Set the flag values by parsing the command line. If remove_flags
227  // is set, the flags and associated values are removed from (argc,
228  // argv). Returns 0 if no error occurred. Otherwise, returns the
229  // argv index > 0 for the argument where an error occurred. In that
230  // case, (argc, argv) will remain unchanged indepdendent of the
231  // remove_flags value, and no assumptions about flag settings should
232  // be made.
233  //
234  // The following syntax for flags is accepted (both '-' and '--' are ok):
235  //
236  //   --flag        (bool flags only)
237  //   --noflag      (bool flags only)
238  //   --flag=value  (non-bool flags only, no spaces around '=')
239  //   --flag value  (non-bool flags only)
240  static int SetFlagsFromCommandLine(int* argc,
241                                     const char** argv,
242                                     bool remove_flags);
243  static inline int SetFlagsFromCommandLine(int* argc,
244                                            char** argv,
245                                            bool remove_flags) {
246    return SetFlagsFromCommandLine(argc, const_cast<const char**>(argv),
247                                   remove_flags);
248  }
249
250  // Registers a new flag. Called during program initialization. Not
251  // thread-safe.
252  static void Register(Flag* flag);
253
254 private:
255  static Flag* list_;
256};
257
258#ifdef WIN32
259// A helper class to translate Windows command line arguments into UTF8,
260// which then allows us to just pass them to the flags system.
261// This encapsulates all the work of getting the command line and translating
262// it to an array of 8-bit strings; all you have to do is create one of these,
263// and then call argc() and argv().
264class WindowsCommandLineArguments {
265 public:
266  WindowsCommandLineArguments();
267  ~WindowsCommandLineArguments();
268
269  int argc() { return argc_; }
270  char **argv() { return argv_; }
271 private:
272  int argc_;
273  char **argv_;
274
275 private:
276  DISALLOW_EVIL_CONSTRUCTORS(WindowsCommandLineArguments);
277};
278#endif  // WIN32
279
280
281#endif  // SHARED_COMMANDLINEFLAGS_FLAGS_H__
282