blob: 1210434409900942ceb4677cc40c9605933c9507 [file] [log] [blame]
Craig Silversteinb9f23482007-03-22 00:15:41 +00001// Copyright (c) 2006, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30// ---
31// Author: Ray Sidney
32// Revamped and reorganized by Craig Silverstein
33//
34// This file contains the implementation of all our command line flags
35// stuff.
36
37#include "config.h"
Craig Silverstein690172b2007-04-20 21:16:33 +000038#include <stdio.h> // for snprintf
Craig Silversteinb9f23482007-03-22 00:15:41 +000039#include <ctype.h>
40#include <errno.h>
41#include <string.h>
42#include <assert.h>
43#include <pthread.h>
44#include <fnmatch.h>
45#include <pthread.h>
46#include <string>
47#include <map>
48#include <vector>
49#include <utility> // for pair<>
50#include <algorithm>
51#include "google/gflags.h"
52
53#ifndef PATH_SEPARATOR
54#define PATH_SEPARATOR '/'
55#endif
56
Craig Silverstein690172b2007-04-20 21:16:33 +000057// Work properly if either strtoll or strtoq is on this system
58#ifdef HAVE_STRTOLL
59# define strtoint64 strtoll
60# define strtouint64 strtoull
61#elif HAVE_STRTOQ
62# define strtoint64 strtoq
63# define strtouint64 strtouq
64#else
65// Neither strtoll nor strtoq are defined. I hope strtol works!
66# define strtoint64 strtol
67# define strtouint64 strtoul
68#endif
69
Craig Silversteinb9f23482007-03-22 00:15:41 +000070using std::string;
71using std::map;
72using std::vector;
73using std::pair;
74
75// Special flags, type 1: the 'recursive' flags. They set another flag's val.
76DEFINE_string(flagfile, "",
77 "load flags from file");
78DEFINE_string(fromenv, "",
79 "set flags from the environment [use 'export FLAGS_flag1=value']");
80DEFINE_string(tryfromenv, "",
81 "set flags from the environment if present");
82
83// Special flags, type 2: the 'parsing' flags. They modify how we parse.
84DEFINE_string(undefok, "",
85 "comma-separated list of flag names that it is okay to specify "
86 "on the command line even if the program does not define a flag "
87 "with that name. IMPORTANT: flags in this list that have "
88 "arguments MUST use the flag=value format");
89
90_START_GOOGLE_NAMESPACE_
91
92// There are also 'reporting' flags, in commandlineflags_reporting.cc.
93
94static const char kError[] = "ERROR: ";
95
96
97// Indicates that undefined options are to be ignored.
98// Enables deferred processing of flags in dynamically loaded libraries.
99static bool allow_command_line_reparsing = false;
100
101static bool logging_is_probably_set_up = false; // google3-specific
102
103// This is used by the unittest to test error-exit code
104void (*commandlineflags_exitfunc)(int) = &exit; // from stdlib.h
105
106// --------------------------------------------------------------------
107// FlagValue
108// This represent the value a single flag might have. The major
109// functionality is to convert from a string to an object of a
110// given type, and back.
111// --------------------------------------------------------------------
112
113class FlagValue {
114 public:
115 FlagValue(void* valbuf, const char* type);
116 ~FlagValue();
117
118 bool ParseFrom(const char* spec);
119 string ToString() const;
120
121 private:
122 friend class CommandLineFlag;
123 friend class FlagSaverImpl; // calls New()
124 template <typename T> friend T GetFromEnv(const char*, const char*, T);
125
126 enum ValueType {FV_BOOL, FV_INT32, FV_INT64, FV_UINT64, FV_DOUBLE, FV_STRING};
127
128 const char* TypeName() const;
129 bool Equal(const FlagValue& x) const;
130 FlagValue* New() const; // creates a new one with default value
131 void CopyFrom(const FlagValue& x);
132
133 void* value_buffer_; // points to the buffer holding our data
134 bool we_own_buffer_; // true iff we new-ed the buffer
135 ValueType type_; // how to interpret value_
136
137 FlagValue(const FlagValue&); // no copying!
138 void operator=(const FlagValue&);
139};
140
141
142// This could be a templated method of FlagValue, but doing so adds to the
143// size of the .o. Since there's no type-safety here anyway, macro is ok.
144#define VALUE_AS(type) *reinterpret_cast<type*>(value_buffer_)
145#define OTHER_VALUE_AS(fv, type) *reinterpret_cast<type*>(fv.value_buffer_)
146#define SET_VALUE_AS(type, value) VALUE_AS(type) = (value)
147
148FlagValue::FlagValue(void* valbuf, const char* type) : value_buffer_(valbuf) {
149 if (strcmp(type, "bool") == 0) type_ = FV_BOOL;
150 else if (strcmp(type, "int32") == 0) type_ = FV_INT32;
151 else if (strcmp(type, "int64") == 0) type_ = FV_INT64;
152 else if (strcmp(type, "uint64") == 0) type_ = FV_UINT64;
153 else if (strcmp(type, "double") == 0) type_ = FV_DOUBLE;
154 else if (strcmp(type, "string") == 0) type_ = FV_STRING;
Craig Silverstein690172b2007-04-20 21:16:33 +0000155 else assert(false); // Unknown typename
Craig Silversteinb9f23482007-03-22 00:15:41 +0000156}
157
158FlagValue::~FlagValue() {
159 switch (type_) {
160 case FV_BOOL: delete reinterpret_cast<bool*>(value_buffer_); break;
161 case FV_INT32: delete reinterpret_cast<int32*>(value_buffer_); break;
162 case FV_INT64: delete reinterpret_cast<int64*>(value_buffer_); break;
163 case FV_UINT64: delete reinterpret_cast<uint64*>(value_buffer_); break;
164 case FV_DOUBLE: delete reinterpret_cast<double*>(value_buffer_); break;
165 case FV_STRING: delete reinterpret_cast<string*>(value_buffer_); break;
166 }
167}
168
169bool FlagValue::ParseFrom(const char* value) {
170 if (type_ == FV_BOOL) {
171 const char* kTrue[] = { "1", "t", "true", "y", "yes" };
172 const char* kFalse[] = { "0", "f", "false", "n", "no" };
173 for (int i = 0; i < sizeof(kTrue)/sizeof(*kTrue); ++i) {
174 if (strcasecmp(value, kTrue[i]) == 0) {
175 SET_VALUE_AS(bool, true);
176 return true;
177 } else if (strcasecmp(value, kFalse[i]) == 0) {
178 SET_VALUE_AS(bool, false);
179 return true;
180 }
181 }
182 return false; // didn't match a legal input
183
184 } else if (type_ == FV_STRING) {
185 SET_VALUE_AS(string, value);
186 return true;
187 }
188
189 // OK, it's likely to be numeric, and we'll be using a strtoXXX method.
190 if (value[0] == '\0') // empty-string is only allowed for string type.
191 return false;
192 char* end;
193 // Leading 0x puts us in base 16. But leading 0 does not put us in base 8!
194 // It caused too many bugs when we had that behavior.
195 int base = 10; // by default
196 if (value[0] == '0' && (value[1] == 'x' || value[1] == 'X'))
197 base = 16;
198 errno = 0;
199
200 switch (type_) {
201 case FV_INT32: {
Craig Silverstein690172b2007-04-20 21:16:33 +0000202 const int64 r = strtoint64(value, &end, base);
Craig Silversteinb9f23482007-03-22 00:15:41 +0000203 if (errno || end != value + strlen(value)) return false; // bad parse
204 if (static_cast<int32>(r) != r) // worked, but number out of range
205 return false;
206 SET_VALUE_AS(int32, r);
207 return true;
208 }
209 case FV_INT64: {
Craig Silverstein690172b2007-04-20 21:16:33 +0000210 const int64 r = strtoint64(value, &end, base);
Craig Silversteinb9f23482007-03-22 00:15:41 +0000211 if (errno || end != value + strlen(value)) return false; // bad parse
212 SET_VALUE_AS(int64, r);
213 return true;
214 }
215 case FV_UINT64: {
216 while (*value == ' ') value++;
217 if (*value == '-') return false; // negative number
Craig Silverstein690172b2007-04-20 21:16:33 +0000218 const uint64 r = strtouint64(value, &end, base);
Craig Silversteinb9f23482007-03-22 00:15:41 +0000219 if (errno || end != value + strlen(value)) return false; // bad parse
220 SET_VALUE_AS(uint64, r);
221 return true;
222 }
223 case FV_DOUBLE: {
224 const double r = strtod(value, &end);
225 if (errno || end != value + strlen(value)) return false; // bad parse
226 SET_VALUE_AS(double, r);
227 return true;
228 }
229 default: {
Craig Silverstein690172b2007-04-20 21:16:33 +0000230 assert(false); // unknown type
Craig Silversteinb9f23482007-03-22 00:15:41 +0000231 return false;
232 }
233 }
234}
235
236string FlagValue::ToString() const {
237 char intbuf[64]; // enough to hold even the biggest number
238 switch (type_) {
239 case FV_BOOL:
240 return VALUE_AS(bool) ? "true" : "false";
241 case FV_INT32:
242 snprintf(intbuf, sizeof(intbuf), "%d", VALUE_AS(int32));
243 return intbuf;
244 case FV_INT64:
245 snprintf(intbuf, sizeof(intbuf), "%lld", VALUE_AS(int64));
246 return intbuf;
247 case FV_UINT64:
248 snprintf(intbuf, sizeof(intbuf), "%llu", VALUE_AS(uint64));
249 return intbuf;
250 case FV_DOUBLE:
251 snprintf(intbuf, sizeof(intbuf), "%.17g", VALUE_AS(double));
252 return intbuf;
253 case FV_STRING:
254 return VALUE_AS(string);
255 default:
Craig Silverstein690172b2007-04-20 21:16:33 +0000256 assert(false); return ""; // unknown type
Craig Silversteinb9f23482007-03-22 00:15:41 +0000257 }
258}
259
260const char* FlagValue::TypeName() const {
261 switch (type_) {
262 case FV_BOOL: return "bool";
263 case FV_INT32: return "int32";
264 case FV_INT64: return "int64";
265 case FV_UINT64: return "uint64";
266 case FV_DOUBLE: return "double";
267 case FV_STRING: return "string";
Craig Silverstein690172b2007-04-20 21:16:33 +0000268 default: assert(false); return ""; // unknown type
Craig Silversteinb9f23482007-03-22 00:15:41 +0000269 }
270}
271
272bool FlagValue::Equal(const FlagValue& x) const {
273 if (type_ != x.type_)
274 return false;
275 switch (type_) {
276 case FV_BOOL: return VALUE_AS(bool) == OTHER_VALUE_AS(x, bool);
277 case FV_INT32: return VALUE_AS(int32) == OTHER_VALUE_AS(x, int32);
278 case FV_INT64: return VALUE_AS(int64) == OTHER_VALUE_AS(x, int64);
279 case FV_UINT64: return VALUE_AS(uint64) == OTHER_VALUE_AS(x, uint64);
280 case FV_DOUBLE: return VALUE_AS(double) == OTHER_VALUE_AS(x, double);
281 case FV_STRING: return VALUE_AS(string) == OTHER_VALUE_AS(x, string);
Craig Silverstein690172b2007-04-20 21:16:33 +0000282 default: assert(false); return false; // unknown type
Craig Silversteinb9f23482007-03-22 00:15:41 +0000283 }
284}
285
286FlagValue* FlagValue::New() const {
287 switch (type_) {
288 case FV_BOOL: return new FlagValue(new bool, "bool");
289 case FV_INT32: return new FlagValue(new int32, "int32");
290 case FV_INT64: return new FlagValue(new int64, "int64");
291 case FV_UINT64: return new FlagValue(new uint64, "uint64");
292 case FV_DOUBLE: return new FlagValue(new double, "double");
293 case FV_STRING: return new FlagValue(new string, "string");
Craig Silverstein690172b2007-04-20 21:16:33 +0000294 default: assert(false); return NULL; // assert false
Craig Silversteinb9f23482007-03-22 00:15:41 +0000295 }
296}
297
298void FlagValue::CopyFrom(const FlagValue& x) {
299 assert(type_ == x.type_);
300 switch (type_) {
301 case FV_BOOL: SET_VALUE_AS(bool, OTHER_VALUE_AS(x, bool)); break;
302 case FV_INT32: SET_VALUE_AS(int32, OTHER_VALUE_AS(x, int32)); break;
303 case FV_INT64: SET_VALUE_AS(int64, OTHER_VALUE_AS(x, int64)); break;
304 case FV_UINT64: SET_VALUE_AS(uint64, OTHER_VALUE_AS(x, uint64)); break;
305 case FV_DOUBLE: SET_VALUE_AS(double, OTHER_VALUE_AS(x, double)); break;
306 case FV_STRING: SET_VALUE_AS(string, OTHER_VALUE_AS(x, string)); break;
Craig Silverstein690172b2007-04-20 21:16:33 +0000307 default: assert(false); // unknown type
Craig Silversteinb9f23482007-03-22 00:15:41 +0000308 }
309}
310
311// --------------------------------------------------------------------
312// CommandLineFlag
313// This represents a single flag, including its name, description,
314// default value, and current value. Mostly this serves as a
315// struct, though it also knows how to register itself.
316// --------------------------------------------------------------------
317
318class CommandLineFlag {
319 public:
320 // Note: we take over memory-ownership of current_val and default_val.
321 CommandLineFlag(const char* name, const char* help, const char* filename,
322 FlagValue* current_val, FlagValue* default_val);
323 ~CommandLineFlag();
324
325 const char* name() const { return name_; }
326 const char* help() const { return help_; }
327 const char* filename() const { return file_; }
328 const char* CleanFileName() const; // nixes irrelevant prefix such as homedir
329 string current_value() const { return current_->ToString(); }
330 string default_value() const { return defvalue_->ToString(); }
331 const char* type_name() const { return defvalue_->TypeName(); }
332
Craig Silverstein290da382007-03-28 21:54:07 +0000333 void FillCommandLineFlagInfo(struct CommandLineFlagInfo* result);
Craig Silversteinb9f23482007-03-22 00:15:41 +0000334
335 private:
336 friend class FlagRegistry; // for SetFlagLocked()
337 friend class FlagSaverImpl; // for cloning the values
338 friend bool GetCommandLineOption(const char*, string*, bool*);
339
340 // This copies all the non-const members: modified, processed, defvalue, etc.
341 void CopyFrom(const CommandLineFlag& src);
342
343 void UpdateModifiedBit();
344
345 const char* const name_; // Flag name
346 const char* const help_; // Help message
347 const char* const file_; // Which file did this come from?
348 bool modified_; // Set after default assignment?
349 FlagValue* defvalue_; // Default value for flag
350 FlagValue* current_; // Current value for flag
351
352 CommandLineFlag(const CommandLineFlag&); // no copying!
353 void operator=(const CommandLineFlag&);
354};
355
356CommandLineFlag::CommandLineFlag(const char* name, const char* help,
357 const char* filename,
358 FlagValue* current_val, FlagValue* default_val)
359 : name_(name), help_(help), file_(filename), modified_(false),
360 defvalue_(default_val), current_(current_val) {
361}
362
363CommandLineFlag::~CommandLineFlag() {
364 delete current_;
365 delete defvalue_;
366}
367
368const char* CommandLineFlag::CleanFileName() const {
369 // Compute top-level directory & file that this appears in
Craig Silversteineb208392007-08-15 19:44:54 +0000370 // search full path backwards.
371 // Stop going backwards at kGoogle; and skip by the first slash.
Craig Silversteinb9f23482007-03-22 00:15:41 +0000372 // E.g.
373 // filename_where_defined = "froogle/wrapping/autowrap/clustering/**.cc"
374 // filename_where_defined = "file/util/fileutil.cc"
Craig Silversteinb9f23482007-03-22 00:15:41 +0000375 static const char kGoogle[] = ""; // can set this to whatever
376
377 if (sizeof(kGoogle)-1 == 0) // no prefix to strip
378 return filename();
379
380 const char* clean_name = filename() + strlen(filename()) - 1;
Craig Silversteinb9f23482007-03-22 00:15:41 +0000381 while ( clean_name > filename() ) {
382 if (*clean_name == PATH_SEPARATOR) {
Craig Silversteineb208392007-08-15 19:44:54 +0000383 if (strncmp(clean_name, kGoogle, sizeof(kGoogle)-1) == 0) {
Craig Silversteinb9f23482007-03-22 00:15:41 +0000384 // ".../google/base/logging.cc" ==> "base/logging.cc"
385 clean_name += sizeof(kGoogle)-1; // past "/google/"
386 break;
387 }
388 }
389 --clean_name;
390 }
391 while ( *clean_name == PATH_SEPARATOR ) ++clean_name; // Skip any slashes
392 return clean_name;
393}
394
395void CommandLineFlag::FillCommandLineFlagInfo(
Craig Silverstein290da382007-03-28 21:54:07 +0000396 CommandLineFlagInfo* result) {
Craig Silversteinb9f23482007-03-22 00:15:41 +0000397 result->name = name();
398 result->type = type_name();
399 result->description = help();
400 result->current_value = current_value();
401 result->default_value = default_value();
402 result->filename = CleanFileName();
Craig Silverstein290da382007-03-28 21:54:07 +0000403 UpdateModifiedBit();
404 result->is_default = !modified_;
Craig Silversteinb9f23482007-03-22 00:15:41 +0000405}
406
407void CommandLineFlag::UpdateModifiedBit() {
408 // Update the "modified" bit in case somebody bypassed the
409 // Flags API and wrote directly through the FLAGS_name variable.
410 if (!modified_ && !current_->Equal(*defvalue_)) {
411 modified_ = true;
412 }
413}
414
415void CommandLineFlag::CopyFrom(const CommandLineFlag& src) {
416 // Note we only copy the non-const members; others are fixed at construct time
417 modified_ = src.modified_;
418 current_->CopyFrom(*src.current_);
419 defvalue_->CopyFrom(*src.defvalue_);
420}
421
422
423// --------------------------------------------------------------------
424// FlagRegistry
425// A FlagRegistry singleton object holds all flag objects indexed
426// by their names so that if you know a flag's name (as a C
427// string), you can access or set it. If the function is named
428// FooLocked(), you must own the registry lock before calling
429// the function; otherwise, you should *not* hold the lock, and
430// the function will acquire it itself if needed.
431// --------------------------------------------------------------------
432
433struct StringCmp { // Used by the FlagRegistry map class to compare char*'s
434 bool operator() (const char* s1, const char* s2) const {
435 return (strcmp(s1, s2) < 0);
436 }
437};
438
439#define SAFE_PTHREAD(fncall) do { if ((fncall) != 0) abort(); } while (0)
440
441class FlagRegistry {
442 public:
443 FlagRegistry() { SAFE_PTHREAD(pthread_mutex_init(&lock_, NULL)); }
444 ~FlagRegistry() { SAFE_PTHREAD(pthread_mutex_destroy(&lock_)); }
445
446 // Store a flag in this registry. Takes ownership of the given pointer.
447 void RegisterFlag(CommandLineFlag* flag);
448
449 void Lock() { SAFE_PTHREAD(pthread_mutex_lock(&lock_)); }
450 void Unlock() { SAFE_PTHREAD(pthread_mutex_unlock(&lock_)); }
451
452 // Returns the flag object for the specified name, or NULL if not found.
453 CommandLineFlag* FindFlagLocked(const char* name);
454
455 // A fancier form of FindFlag that works correctly if name is of the
456 // form flag=value. In that case, we set key to point to flag, and
457 // modify v to point to the value, and return the flag with the
458 // given name (or NULL if not found).
459 CommandLineFlag* SplitArgumentLocked(const char* argument,
460 string* key, const char** v);
461
462 // Set the value of a flag. If the flag was successfully set to
463 // value, set msg to indicate the new flag-value, and return true.
464 // Otherwise, set msg to indicate the error, leave flag unchanged,
465 // and return false. msg can be NULL.
466 bool SetFlagLocked(CommandLineFlag* flag, const char* value,
467 FlagSettingMode set_mode, string* msg);
468
469 static FlagRegistry* GlobalRegistry(); // returns a singleton registry
470
471 private:
472 friend class FlagSaverImpl; // reads all the flags in order to copy them
473 friend void GetAllFlags(vector<CommandLineFlagInfo>*);
474
475 typedef map<const char*, CommandLineFlag*, StringCmp> FlagMap;
476 typedef FlagMap::iterator FlagIterator;
477 typedef FlagMap::const_iterator FlagConstIterator;
478 FlagMap flags_;
479 pthread_mutex_t lock_;
480 static FlagRegistry* global_registry_; // a singleton registry
481 static pthread_once_t global_registry_once_;
Craig Silversteineb208392007-08-15 19:44:54 +0000482 static int global_registry_once_nothreads_; // when we don't link pthreads
Craig Silversteinb9f23482007-03-22 00:15:41 +0000483
484 static void InitGlobalRegistry();
485
486 // Disallow
487 FlagRegistry(const FlagRegistry&);
488 FlagRegistry& operator=(const FlagRegistry&);
489};
490
491void FlagRegistry::RegisterFlag(CommandLineFlag* flag) {
492 Lock();
493 pair<FlagIterator, bool> ins =
494 flags_.insert(pair<const char*, CommandLineFlag*>(flag->name(), flag));
495 if (ins.second == false) { // means the name was already in the map
496 if (strcmp(ins.first->second->filename(), flag->filename()) != 0) {
497 fprintf(stderr,
498 "ERROR: flag '%s' was defined more than once "
499 "(in files '%s' and '%s').\n",
500 flag->name(),
501 ins.first->second->filename(),
502 flag->filename());
503 } else {
504 fprintf(stderr,
505 "ERROR: something wrong with flag '%s' in file '%s'. "
506 "One possibility: file '%s' is being linked both statically "
507 "and dynamically into this executable.\n",
508 flag->name(),
509 flag->filename(), flag->filename());
510 }
511 commandlineflags_exitfunc(1); // almost certainly exit()
512 }
513 Unlock();
514}
515
516CommandLineFlag* FlagRegistry::FindFlagLocked(const char* name) {
517 FlagConstIterator i = flags_.find(name);
518 if (i == flags_.end()) {
519 return NULL;
520 } else {
521 return i->second;
522 }
523}
524
525CommandLineFlag* FlagRegistry::SplitArgumentLocked(const char* arg,
526 string* key,
527 const char** v) {
528 // Find the flag object for this option
529 const char* flag_name;
530 const char* value = strchr(arg, '=');
531 if (value == NULL) {
532 key->assign(arg);
533 *v = NULL;
534 } else {
535 // Strip out the "=value" portion from arg
536 key->assign(arg, value-arg);
537 *v = ++value; // advance past the '='
538 }
539 flag_name = key->c_str();
540
541 CommandLineFlag* flag = FindFlagLocked(flag_name);
542 if (flag == NULL && (flag_name[0] == 'n') && (flag_name[1] == 'o')) {
543 // See if we can find a boolean flag named "x" for an option
544 // named "nox".
545 flag = FindFlagLocked(flag_name+2);
546 if (flag != NULL) {
547 if (strcmp(flag->type_name(), "bool") != 0) {
548 // This is not a boolean flag, so we should not strip the "no" prefix
549 flag = NULL;
550 } else {
551 // Make up a fake value to replace the "no" we stripped out
552 key->assign(flag_name+2); // the name without the "no"
553 *v = "0";
554 }
555 }
556 }
557
558 if (flag == NULL) {
559 return NULL;
560 }
561
562 // Assign a value if this is a boolean flag
563 if (*v == NULL && strcmp(flag->type_name(), "bool") == 0) {
564 *v = "1"; // the --nox case was already handled, so this is the --x case
565 }
566
567 return flag;
568}
569
570// Can't make this static because of friendship.
571inline bool TryParse(const CommandLineFlag* flag, FlagValue* flag_value,
572 const char* value, string* msg) {
573 if (flag_value->ParseFrom(value)) {
574 if (msg)
575 *msg += (string(flag->name()) + " set to " + flag_value->ToString()
576 + "\n");
577 return true;
578 } else {
579 if (msg)
580 *msg += (string(kError) + "illegal value '" + value +
581 + "' specified for " + flag->type_name() + " flag '"
582 + flag->name() + "'\n");
583 return false;
584 }
585}
586
587bool FlagRegistry::SetFlagLocked(CommandLineFlag* flag,
588 const char* value,
589 FlagSettingMode set_mode,
590 string* msg) {
591 flag->UpdateModifiedBit();
592 switch (set_mode) {
593 case SET_FLAGS_VALUE: {
594 // set or modify the flag's value
595 if (!TryParse(flag, flag->current_, value, msg))
596 return false;
597 flag->modified_ = true;
598 break;
599 }
600 case SET_FLAG_IF_DEFAULT: {
601 // set the flag's value, but only if it hasn't been set by someone else
602 if (!flag->modified_) {
603 if (!TryParse(flag, flag->current_, value, msg))
604 return false;
605 flag->modified_ = true;
606 } else {
607 *msg = string(flag->name()) + " set to " + flag->current_value();
608 }
609 break;
610 }
611 case SET_FLAGS_DEFAULT: {
612 // modify the flag's default-value
613 if (!TryParse(flag, flag->defvalue_, value, msg))
614 return false;
615 if (!flag->modified_) {
616 // Need to set both defvalue *and* current, in this case
617 TryParse(flag, flag->current_, value, NULL);
618 }
619 break;
620 }
621 default: {
Craig Silverstein690172b2007-04-20 21:16:33 +0000622 // unknown set_mode
623 assert(false); return false;
Craig Silversteinb9f23482007-03-22 00:15:41 +0000624 }
625 }
626
627 return true;
628}
629
630// Get the singleton FlagRegistry object
631FlagRegistry* FlagRegistry::global_registry_ = NULL;
632pthread_once_t FlagRegistry::global_registry_once_ = PTHREAD_ONCE_INIT;
Craig Silversteineb208392007-08-15 19:44:54 +0000633int FlagRegistry::global_registry_once_nothreads_ = 0;
Craig Silversteinb9f23482007-03-22 00:15:41 +0000634
635void FlagRegistry::InitGlobalRegistry() {
636 global_registry_ = new FlagRegistry;
637}
638
Craig Silversteineb208392007-08-15 19:44:54 +0000639// We want to use pthread_once here, for safety, but have to worry about
640// whether libpthread is linked in or not.
Craig Silversteinb9f23482007-03-22 00:15:41 +0000641FlagRegistry* FlagRegistry::GlobalRegistry() {
Craig Silversteineb208392007-08-15 19:44:54 +0000642 if (pthread_once) { // means we're running with pthreads
643 pthread_once(&global_registry_once_, &FlagRegistry::InitGlobalRegistry);
644 } else { // not running with pthreads: we're the only thread
645 if (global_registry_once_nothreads_++ == 0)
646 InitGlobalRegistry();
647 }
Craig Silversteinb9f23482007-03-22 00:15:41 +0000648 return global_registry_;
649}
650
651// --------------------------------------------------------------------
652// FlagRegisterer
653// This class exists merely to have a global constructor (the
654// kind that runs before main(), that goes an initializes each
655// flag that's been declared. Note that it's very important we
656// don't have a destructor that deletes flag_, because that would
657// cause us to delete current_storage/defvalue_storage as well,
658// which can cause a crash if anything tries to access the flag
659// values in a global destructor.
660// --------------------------------------------------------------------
661
662FlagRegisterer::FlagRegisterer(const char* name, const char* type,
663 const char* help, const char* filename,
664 void* current_storage, void* defvalue_storage) {
665 FlagValue* current = new FlagValue(current_storage, type);
666 FlagValue* defvalue = new FlagValue(defvalue_storage, type);
667 // Importantly, flag_ will never be deleted, so storage is always good.
668 flag_ = new CommandLineFlag(name, help, filename, current, defvalue);
669 FlagRegistry::GlobalRegistry()->RegisterFlag(flag_); // default registry
670}
671
672
673// --------------------------------------------------------------------
674// GetAllFlags()
675// The main way the FlagRegistry class exposes its data. This
676// returns, as strings, all the info about all the flags in
677// the main registry, sorted first by filename they are defined
678// in, and then by flagname.
679// --------------------------------------------------------------------
680
681struct FilenameFlagnameCmp {
682 bool operator()(const CommandLineFlagInfo& a,
683 const CommandLineFlagInfo& b) const {
684 int cmp = strcmp(a.filename.c_str(), b.filename.c_str());
685 if (cmp == 0)
686 cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key
687 return cmp < 0;
688 }
689};
690
691void GetAllFlags(vector<CommandLineFlagInfo>* OUTPUT) {
692 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
693 registry->Lock();
694 for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
695 i != registry->flags_.end(); ++i) {
696 CommandLineFlagInfo fi;
697 i->second->FillCommandLineFlagInfo(&fi);
698 OUTPUT->push_back(fi);
699 }
700 registry->Unlock();
701 // Now sort the flags, first by filename they occur in, then alphabetically
702 sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp());
703}
704
705// --------------------------------------------------------------------
706// SetArgv()
707// GetArgvs()
708// GetArgv()
709// GetArgv0()
710// ProgramInvocationName()
711// ProgramInvocationShortName()
712// SetUsageMessage()
713// ProgramUsage()
714// Functions to set and get argv. Typically the setter is called
715// by ParseCommandLineFlags. Also can get the ProgramUsage string,
716// set by SetUsageMessage.
717// --------------------------------------------------------------------
718
719// These values are not protected by a Mutex because they are normally
720// set only once during program startup.
721static const char* argv0 = "UNKNOWN"; // just the program name
722static const char* cmdline = ""; // the entire command-line
723static vector<string> argvs;
724static uint32 argv_sum = 0;
725static const char* program_usage = "Warning: SetUsageMessage() never called";
726static bool program_usage_set = false;
727
728void SetArgv(int argc, const char** argv) {
729 static bool called_set_argv = false;
730 if (called_set_argv) // we already have an argv for you
731 return;
732
733 called_set_argv = true;
734
735 assert(argc > 0); // every program has at least a progname
736 argv0 = strdup(argv[0]); // small memory leak, but fn only called once
737 assert(argv0);
738
739 string cmdline_string = string(""); // easier than doing strcats
740 argvs.clear();
741 for (int i = 0; i < argc; i++) {
742 if (i != 0)
743 cmdline_string += " ";
744 cmdline_string += argv[i];
745 argvs.push_back(argv[i]);
746 }
747 cmdline = strdup(cmdline_string.c_str()); // another small memory leak
748 assert(cmdline);
749
750 // Compute a simple sum of all the chars in argv
751 argv_sum = 0;
752 for (const char* c = cmdline; *c; c++)
753 argv_sum += *c;
754}
755
756const vector<string>& GetArgvs() { return argvs; }
757const char* GetArgv() { return cmdline; }
758const char* GetArgv0() { return argv0; }
759uint32 GetArgvSum() { return argv_sum; }
760const char* ProgramInvocationName() { // like the GNU libc fn
761 return GetArgv0();
762}
763const char* ProgramInvocationShortName() { // like the GNU libc fn
764 const char* slash = strrchr(argv0, '/');
765#ifdef OS_WINDOWS
766 if (!slash) slash = strrchr(argv0, '\\');
767#endif
768 return slash ? slash + 1 : argv0;
769}
770
771void SetUsageMessage(const string& usage) {
772 if (program_usage_set) {
773 fprintf(stderr, "ERROR: SetUsageMessage() called more than once\n");
774 commandlineflags_exitfunc(1); // almost certainly exit()
775 }
776
777 program_usage = strdup(usage.c_str()); // small memory leak
778 program_usage_set = true;
779}
780
781const char* ProgramUsage() {
782 return program_usage;
783}
784
785// --------------------------------------------------------------------
786// CommandLineFlagParser
787// Parsing is done in two stages. In the first, we go through
788// argv. For every flag-like arg we can make sense of, we parse
789// it and set the appropriate FLAGS_* variable. For every flag-
790// like arg we can't make sense of, we store it in a vector,
791// along with an explanation of the trouble. In stage 2, we
792// handle the 'reporting' flags like --help and --mpm_version.
793// (This is via a call to HandleCommandLineHelpFlags(), in
794// commandlineflags_reporting.cc.)
795// An optional stage 3 prints out the error messages.
796// This is a bit of a simplification. For instance, --flagfile
797// is handled as soon as it's seen in stage 1, not in stage 2.
798// --------------------------------------------------------------------
799
800class CommandLineFlagParser {
801 public:
802 // The argument is the flag-registry to register the parsed flags in
803 explicit CommandLineFlagParser(FlagRegistry* reg) : registry_(reg) {}
804 ~CommandLineFlagParser() {}
805
806 // Stage 1: Every time this is called, it reads all flags in argv.
807 // However, it ignores all flags that have been successfully set
808 // before. Typically this is only called once, so this 'reparsing'
809 // behavior isn't important. It can be useful when trying to
810 // reparse after loading a dll, though.
811 uint32 ParseNewCommandLineFlags(int* argc, char*** argv, bool remove_flags);
812
813 // Stage 2: print reporting info and exit, if requested.
814 // In commandlineflags_reporting.cc:HandleCommandLineHelpFlags().
815
816 // Stage 3: report any errors and return true if any were found.
817 bool ReportErrors();
818
819 // Set a particular command line option. "newval" is a string
820 // describing the new value that the option has been set to. If
821 // option_name does not specify a valid option name, or value is not
822 // a valid value for option_name, newval is empty. Does recursive
823 // processing for --flagfile and --fromenv. Returns the new value
824 // if everything went ok, or empty-string if not. (Actually, the
825 // return-string could hold many flag/value pairs due to --flagfile.)
826 // NB: Must have called registry_->Lock() before calling this function.
827 string ProcessSingleOptionLocked(CommandLineFlag* flag,
828 const char* value,
829 FlagSettingMode set_mode);
830
831 // Set a whole batch of command line options as specified by contentdata,
832 // which is in flagfile format (and probably has been read from a flagfile).
833 // Returns the new value if everything went ok, or empty-string if
834 // not. (Actually, the return-string could hold many flag/value
835 // pairs due to --flagfile.)
836 // NB: Must have called registry_->Lock() before calling this function.
837 string ProcessOptionsFromStringLocked(const string& contentdata,
838 FlagSettingMode set_mode);
839
840 // These are the 'recursive' flags, defined at the top of this file.
841 // Whenever we see these flags on the commandline, we must take action.
842 // These are called by ProcessSingleOptionLocked and, similarly, return
843 // new values if everything went ok, or the empty-string if not.
844 string ProcessFlagfileLocked(const string& flagval, FlagSettingMode set_mode);
845 string ProcessFromenvLocked(const string& flagval, FlagSettingMode set_mode,
846 bool errors_are_fatal); // diff fromenv/tryfromenv
847
848 private:
849 FlagRegistry* const registry_;
850 map<string, string> error_flags_; // map from name to error message
851 // This could be a set<string>, but we reuse the map to minimize the .o size
852 map<string, string> undefined_names_; // --name for name that's not registered
853};
854
855
856// Parse a list of (comma-separated) flags.
857static void ParseFlagList(const char* value, vector<string>* flags) {
858 for (const char *p = value; p && *p; value = p) {
859 p = strchr(value, ',');
860 int len;
861 if (p) {
862 len = p - value;
863 p++;
864 } else {
865 len = strlen(value);
866 }
867
868 if (len == 0) {
869 fprintf(stderr, "ERROR: empty flaglist entry\n");
870 commandlineflags_exitfunc(1); // almost certainly exit()
871 }
872 if (value[0] == '-') {
873 fprintf(stderr, "ERROR: flag \"%*s\" begins with '-'\n", len, value);
874 commandlineflags_exitfunc(1);
875 }
876
877 flags->push_back(string(value, len));
878 }
879}
880
881// Snarf an entire file into a C++ string. This is just so that we
882// can do all the I/O in one place and not worry about it everywhere.
883// Plus, it's convenient to have the whole file contents at hand.
884// Adds a newline at the end of the file.
885#define PFATAL(s) do { perror(s); commandlineflags_exitfunc(1); } while (0)
886
887static string ReadFileIntoString(const char* filename) {
888 const int bufsize = 8092;
889 char buffer[bufsize];
890 string s;
891 FILE* fp = fopen(filename, "r");
892 if (!fp) PFATAL(filename);
893 int n;
894 while ( (n=fread(buffer, 1, bufsize, fp)) > 0 ) {
895 if (ferror(fp)) PFATAL(filename);
896 s.append(buffer, n);
897 }
898 fclose(fp);
899 return s;
900}
901
902uint32 CommandLineFlagParser::ParseNewCommandLineFlags(int* argc, char*** argv,
903 bool remove_flags) {
904 const char *program_name = strrchr((*argv)[0], PATH_SEPARATOR); // nix path
905 program_name = (program_name == NULL ? (*argv)[0] : program_name+1);
906
907 int first_nonopt = *argc; // for non-options moved to the end
908
909 registry_->Lock();
910 for (int i = 1; i < first_nonopt; i++) {
911 char* arg = (*argv)[i];
912
913 // Like getopt(), we permute non-option flags to be at the end.
914 if (arg[0] != '-') { // must be a program argument
915 memmove((*argv) + i, (*argv) + i+1, (*argc - (i+1)) * sizeof((*argv)[i]));
916 (*argv)[*argc-1] = arg; // we go last
917 first_nonopt--; // we've been pushed onto the stack
918 i--; // to undo the i++ in the loop
919 continue;
920 }
921
922 if (arg[0] == '-') arg++; // allow leading '-'
923 if (arg[0] == '-') arg++; // or leading '--'
924
925 // - and -- alone mean what they do for GNU: stop options parsing
926 if (*arg == '\0') {
927 first_nonopt = i+1;
928 break;
929 }
930
931 // Find the flag object for this option
932 string key;
933 const char* value;
934 CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value);
935 if (flag == NULL) {
936 undefined_names_[key] = ""; // value isn't actually used
937 error_flags_[key] = (string(kError) +
938 "unknown command line flag '" + key + "'\n");
939 continue;
940 }
941
942 if (value == NULL) {
943 // Boolean options are always assigned a value by SplitArgumentLocked()
944 assert(strcmp(flag->type_name(), "bool") != 0);
945 if (i+1 >= first_nonopt) {
946 // This flag needs a value, but there is nothing available
947 error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'" +
948 + " is missing its argument\n");
949 break; // we treat this as an unrecoverable error
950 } else {
951 value = (*argv)[++i]; // read next arg for value
952 }
953 }
954
955 // TODO(csilvers): only set a flag if we hadn't set it before here
956 ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE);
957 }
958 registry_->Unlock();
959
960 if (remove_flags) { // Fix up argc and argv by removing command line flags
961 (*argv)[first_nonopt-1] = (*argv)[0];
962 (*argv) += (first_nonopt-1);
963 (*argc) -= (first_nonopt-1);
964 first_nonopt = 1; // because we still don't count argv[0]
965 }
966
967 logging_is_probably_set_up = true; // because we've parsed --logdir, etc.
968
969 return first_nonopt;
970}
971
972string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval,
973 FlagSettingMode set_mode) {
974 if (flagval.empty())
975 return "";
976
977 string msg;
978 vector<string> filename_list;
979 ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames
980 for (int i = 0; i < filename_list.size(); ++i) {
981 const char* file = filename_list[i].c_str();
982 msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode);
983 }
984 return msg;
985}
986
987string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
988 FlagSettingMode set_mode,
989 bool errors_are_fatal) {
990 if (flagval.empty())
991 return "";
992
993 string msg;
994 vector<string> flaglist;
995 ParseFlagList(flagval.c_str(), &flaglist);
996
997 for (int i = 0; i < flaglist.size(); ++i) {
998 const char* flagname = flaglist[i].c_str();
999 CommandLineFlag* flag = registry_->FindFlagLocked(flagname);
1000 if (flag == NULL) {
1001 error_flags_[flagname] = (string(kError) + "unknown command line flag"
1002 + " '" + flagname + "'"
1003 + " (via --fromenv or --tryfromenv)\n");
1004 undefined_names_[flagname] = "";
1005 continue;
1006 }
1007
1008 const string envname = string("FLAGS_") + string(flagname);
1009 const char* envval = getenv(envname.c_str());
1010 if (!envval) {
1011 if (errors_are_fatal) {
1012 error_flags_[flagname] = (string(kError) + envname +
1013 " not found in environment\n");
1014 }
1015 continue;
1016 }
1017
1018 // Avoid infinite recursion.
1019 if ((strcmp(envval, "fromenv") == 0) ||
1020 (strcmp(envval, "tryfromenv") == 0)) {
1021 error_flags_[flagname] = (string(kError) + "infinite recursion on " +
1022 "environment flag '" + envval + "'\n");
1023 continue;
1024 }
1025
1026 msg += ProcessSingleOptionLocked(flag, envval, set_mode);
1027 }
1028 return msg;
1029}
1030
1031string CommandLineFlagParser::ProcessSingleOptionLocked(
1032 CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) {
1033 string msg;
1034 if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) {
1035 error_flags_[flag->name()] = msg;
1036 return "";
1037 }
1038
1039 // The recursive flags, --flagfile and --fromenv and --tryfromenv,
1040 // must be dealt with as soon as they're seen. They will emit
1041 // messages of their own.
1042 if (strcmp(flag->name(), "flagfile") == 0) {
1043 msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode);
1044
1045 } else if (strcmp(flag->name(), "fromenv") == 0) {
1046 // last arg indicates envval-not-found is fatal (unlike in --tryfromenv)
1047 msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true);
1048
1049 } else if (strcmp(flag->name(), "tryfromenv") == 0) {
1050 msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false);
1051
1052 }
1053
1054 return msg;
1055}
1056
1057bool CommandLineFlagParser::ReportErrors() {
1058 // error_flags_ indicates errors we saw while parsing.
1059 // But we ignore undefined-names if ok'ed by --undef_ok
1060 if (!FLAGS_undefok.empty()) {
1061 vector<string> flaglist;
1062 ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
1063 for (int i = 0; i < flaglist.size(); ++i)
1064 if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) {
1065 error_flags_[flaglist[i]] = ""; // clear the error message
1066 }
1067 }
1068 // Likewise, if they decided to allow reparsing, all undefined-names
1069 // are ok; we just silently ignore them now, and hope that a future
1070 // parse will pick them up somehow.
1071 if (allow_command_line_reparsing) {
1072 for (map<string,string>::const_iterator it = undefined_names_.begin();
1073 it != undefined_names_.end(); ++it)
1074 error_flags_[it->first] = ""; // clear the error message
1075 }
1076
1077 bool found_error = false;
1078 for (map<string,string>::const_iterator it = error_flags_.begin();
1079 it != error_flags_.end(); ++it) {
1080 if (!it->second.empty()) {
1081 fprintf(stderr, "%s", it->second.c_str());
1082 found_error = true;
1083 }
1084 }
1085 return found_error;
1086}
1087
1088string CommandLineFlagParser::ProcessOptionsFromStringLocked(
1089 const string& contentdata, FlagSettingMode set_mode) {
1090 string retval;
1091 const char* flagfile_contents = contentdata.c_str();
1092 bool flags_are_relevant = true; // set to false when filenames don't match
1093 bool in_filename_section = false;
1094
1095 const char* line_end = flagfile_contents;
1096 // We read this file a line at a time.
1097 for (; line_end; flagfile_contents = line_end + 1) {
1098 while (*flagfile_contents && isspace(*flagfile_contents))
1099 ++flagfile_contents;
1100 line_end = strchr(flagfile_contents, '\n');
1101 int len = line_end ? line_end-flagfile_contents : strlen(flagfile_contents);
1102 string line(flagfile_contents, len);
1103
1104 // Each line can be one of four things:
1105 // 1) A comment line -- we skip it
1106 // 2) An empty line -- we skip it
1107 // 3) A list of filenames -- starts a new filenames+flags section
1108 // 4) A --flag=value line -- apply if previous filenames match
1109 if (line.empty() || line[0] == '#') {
1110 // comment or empty line; just ignore
1111
1112 } else if (line[0] == '-') { // flag
1113 in_filename_section = false; // instead, it was a flag-line
1114 if (!flags_are_relevant) // skip this flag; applies to someone else
1115 continue;
1116
1117 const char* name_and_val = line.c_str() + 1; // skip the leading -
1118 if (*name_and_val == '-')
1119 name_and_val++; // skip second - too
1120 string key;
1121 const char* value;
1122 CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val,
1123 &key, &value);
1124 // By API, errors parsing flagfile lines are silently ignored.
1125 if (flag == NULL) {
1126 // "WARNING: flagname '" + key + "' not found\n"
1127 } else if (value == NULL) {
1128 // "WARNING: flagname '" + key + "' missing a value\n"
1129 } else {
1130 retval += ProcessSingleOptionLocked(flag, value, set_mode);
1131 }
1132
1133 } else { // a filename!
1134 if (!in_filename_section) { // start over: assume filenames don't match
1135 in_filename_section = true;
1136 flags_are_relevant = false;
1137 }
1138
1139 // Split the line up at spaces into glob-patterns
1140 const char* space = line.c_str(); // just has to be non-NULL
1141 for (const char* word = line.c_str(); *space; word = space+1) {
1142 if (flags_are_relevant) // we can stop as soon as we match
1143 break;
1144 space = strchr(word, ' ');
1145 if (space == NULL)
1146 space = word + strlen(word);
1147 const string glob(word, space - word);
1148 // We try matching both against the full argv0 and basename(argv0)
1149 if (fnmatch(glob.c_str(), ProgramInvocationName(), FNM_PATHNAME) == 0 ||
1150 fnmatch(glob.c_str(), ProgramInvocationShortName(), FNM_PATHNAME) == 0) {
1151 flags_are_relevant = true;
1152 }
1153 }
1154 }
1155 }
1156 return retval;
1157}
1158
1159
1160// --------------------------------------------------------------------
1161// GetCommandLineOption()
1162// GetCommandLineFlagInfo()
Craig Silverstein290da382007-03-28 21:54:07 +00001163// GetCommandLineFlagInfoOrDie()
Craig Silversteinb9f23482007-03-22 00:15:41 +00001164// SetCommandLineOption()
1165// SetCommandLineOptionWithMode()
1166// The programmatic way to set a flag's value, using a string
1167// for its name rather than the variable itself (that is,
1168// SetCommandLineOption("foo", x) rather than FLAGS_foo = x).
1169// There's also a bit more flexibility here due to the various
1170// set-modes, but typically these are used when you only have
1171// that flag's name as a string, perhaps at runtime.
1172// All of these work on the default, global registry.
1173// For GetCommandLineOption, return false if no such flag
1174// is known, true otherwise. We clear "value" if a suitable
Craig Silverstein690172b2007-04-20 21:16:33 +00001175// flag is found.
Craig Silversteinb9f23482007-03-22 00:15:41 +00001176// --------------------------------------------------------------------
1177
1178
Craig Silverstein690172b2007-04-20 21:16:33 +00001179bool GetCommandLineOption(const char* name, string* value) {
Craig Silversteinb9f23482007-03-22 00:15:41 +00001180 if (NULL == name)
1181 return false;
1182 assert(value);
1183
1184 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
1185 registry->Lock();
1186 CommandLineFlag* flag = registry->FindFlagLocked(name);
1187 if (flag == NULL) {
1188 registry->Unlock();
1189 return false;
1190 } else {
1191 *value = flag->current_value();
Craig Silversteinb9f23482007-03-22 00:15:41 +00001192 registry->Unlock();
1193 return true;
1194 }
1195}
1196
1197bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
1198 if (NULL == name) return false;
1199 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
1200 registry->Lock();
1201 CommandLineFlag* flag = registry->FindFlagLocked(name);
1202 if (flag == NULL) {
1203 registry->Unlock();
1204 return false;
1205 } else {
1206 assert(OUTPUT);
1207 flag->FillCommandLineFlagInfo(OUTPUT);
1208 registry->Unlock();
1209 return true;
1210 }
1211}
1212
Craig Silverstein290da382007-03-28 21:54:07 +00001213CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
1214 CommandLineFlagInfo info;
1215 if (!GetCommandLineFlagInfo(name, &info)) {
1216 fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exit", name);
1217 commandlineflags_exitfunc(1); // almost certainly exit()
1218 }
1219 return info;
1220}
1221
Craig Silversteinb9f23482007-03-22 00:15:41 +00001222string SetCommandLineOptionWithMode(const char* name, const char* value,
1223 FlagSettingMode set_mode) {
1224 string result;
1225 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
1226 registry->Lock();
1227 CommandLineFlag* flag = registry->FindFlagLocked(name);
1228 if (flag) {
1229 CommandLineFlagParser parser(registry);
1230 result = parser.ProcessSingleOptionLocked(flag, value, set_mode);
1231 if (!result.empty()) { // in the error case, we've already logged
1232 // You could consider logging this change, if you wanted to know it:
Craig Silverstein2b66a842007-06-12 23:59:42 +00001233 //fprintf(stderr, "%sFLAGS_%s\n",
Craig Silversteinb9f23482007-03-22 00:15:41 +00001234 // (set_mode == SET_FLAGS_DEFAULT ? "default value of " : ""),
Craig Silverstein2b66a842007-06-12 23:59:42 +00001235 // result);
Craig Silversteinb9f23482007-03-22 00:15:41 +00001236 }
1237 }
1238 registry->Unlock();
1239 // The API of this function is that we return empty string on error
1240 return result;
1241}
1242
1243string SetCommandLineOption(const char* name, const char* value) {
1244 return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE);
1245}
1246
1247
1248// --------------------------------------------------------------------
1249// FlagSaver
1250// FlagSaverImpl
1251// This class stores the states of all flags at construct time,
1252// and restores all flags to that state at destruct time.
1253// Its major implementation challenge is that it never modifies
1254// pointers in the 'main' registry, so global FLAG_* vars always
1255// point to the right place.
1256// --------------------------------------------------------------------
1257
1258class FlagSaverImpl {
1259 public:
1260 // Constructs an empty FlagSaverImpl object.
1261 explicit FlagSaverImpl(FlagRegistry* main_registry)
1262 : main_registry_(main_registry) { }
1263 ~FlagSaverImpl() {
1264 // reclaim memory from each of our CommandLineFlags
1265 vector<CommandLineFlag*>::const_iterator it;
1266 for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it)
1267 delete *it;
1268 }
1269
1270 // Saves the flag states from the flag registry into this object.
1271 // It's an error to call this more than once.
1272 // Must be called when the registry mutex is not held.
1273 void SaveFromRegistry() {
1274 main_registry_->Lock();
1275 assert(backup_registry_.empty()); // call only once!
1276 for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin();
1277 it != main_registry_->flags_.end();
1278 ++it) {
1279 const CommandLineFlag* main = it->second;
1280 // Sets up all the const variables in backup correctly
1281 CommandLineFlag* backup = new CommandLineFlag(
1282 main->name(), main->help(), main->filename(),
1283 main->current_->New(), main->defvalue_->New());
1284 // Sets up all the non-const variables in backup correctly
1285 backup->CopyFrom(*main);
1286 backup_registry_.push_back(backup); // add it to a convenient list
1287 }
1288 main_registry_->Unlock();
1289 }
1290
1291 // Restores the saved flag states into the flag registry. We
1292 // assume no flags were added or deleted from the registry since
1293 // the SaveFromRegistry; if they were, that's trouble! Must be
1294 // called when the registry mutex is not held.
1295 void RestoreToRegistry() {
1296 main_registry_->Lock();
1297 vector<CommandLineFlag*>::const_iterator it;
1298 for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) {
1299 CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name());
1300 if (main != NULL) { // if NULL, flag got deleted from registry(!)
1301 main->CopyFrom(**it);
1302 }
1303 }
1304 main_registry_->Unlock();
1305 }
1306
1307 private:
1308 FlagRegistry* const main_registry_;
1309 vector<CommandLineFlag*> backup_registry_;
1310
1311 FlagSaverImpl(const FlagSaverImpl&); // no copying!
1312 void operator=(const FlagSaverImpl&);
1313};
1314
1315FlagSaver::FlagSaver() : impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) {
1316 impl_->SaveFromRegistry();
1317}
1318
1319FlagSaver::~FlagSaver() {
1320 impl_->RestoreToRegistry();
1321 delete impl_;
1322}
1323
1324
1325// --------------------------------------------------------------------
1326// CommandlineFlagsIntoString()
1327// ReadFlagsFromString()
1328// AppendFlagsIntoFile()
1329// ReadFromFlagsFile()
1330// These are mostly-deprecated routines that stick the
1331// commandline flags into a file/string and read them back
1332// out again. I can see a use for CommandlineFlagsIntoString,
1333// for creating a flagfile, but the rest don't seem that useful
1334// -- some, I think, are a poor-man's attempt at FlagSaver --
1335// and are included only until we can delete them from callers.
1336// Note they don't save --flagfile flags (though they do save
1337// the result of having called the flagfile, of course).
1338// --------------------------------------------------------------------
1339
1340static string TheseCommandlineFlagsIntoString(
1341 const vector<CommandLineFlagInfo>& flags) {
1342 vector<CommandLineFlagInfo>::const_iterator i;
1343
1344 int retval_space = 0;
1345 for (i = flags.begin(); i != flags.end(); ++i) {
1346 // An (over)estimate of how much space it will take to print this flag
1347 retval_space += i->name.length() + i->current_value.length() + 5;
1348 }
1349
1350 string retval;
1351 retval.reserve(retval_space);
1352 for (i = flags.begin(); i != flags.end(); ++i) {
1353 retval += "--";
1354 retval += i->name;
1355 retval += "=";
1356 retval += i->current_value;
1357 retval += "\n";
1358 }
1359 return retval;
1360}
1361
1362string CommandlineFlagsIntoString() {
1363 vector<CommandLineFlagInfo> sorted_flags;
1364 GetAllFlags(&sorted_flags);
1365 return TheseCommandlineFlagsIntoString(sorted_flags);
1366}
1367
1368bool ReadFlagsFromString(const string& flagfilecontents,
1369 const char* prog_name, // TODO(csilvers): nix this
1370 bool errors_are_fatal) {
1371 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
1372 FlagSaverImpl saved_states(registry);
1373 saved_states.SaveFromRegistry();
1374
1375 CommandLineFlagParser parser(registry);
1376 registry->Lock();
1377 parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE);
1378 registry->Unlock();
1379 // Should we handle --help and such when reading flags from a string? Sure.
1380 HandleCommandLineHelpFlags();
1381 if (parser.ReportErrors()) {
1382 // Error. Restore all global flags to their previous values.
1383 if (errors_are_fatal)
1384 commandlineflags_exitfunc(1); // almost certainly exit()
1385 saved_states.RestoreToRegistry();
1386 return false;
1387 }
1388 return true;
1389}
1390
1391// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
1392bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
1393 FILE *fp = fopen(filename.c_str(), "a");
1394 if (!fp) {
1395 return false;
1396 }
1397
1398 if (prog_name)
1399 fprintf(fp, "%s\n", prog_name);
1400
1401 vector<CommandLineFlagInfo> flags;
1402 GetAllFlags(&flags);
1403 // But we don't want --flagfile, which leads to weird recursion issues
1404 vector<CommandLineFlagInfo>::iterator i;
1405 for (i = flags.begin(); i != flags.end(); ++i) {
1406 if (strcmp(i->name.c_str(), "flagfile") == 0) {
1407 flags.erase(i);
1408 break;
1409 }
1410 }
1411 fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str());
1412
1413 fclose(fp);
1414 return true;
1415}
1416
1417bool ReadFromFlagsFile(const string& filename, const char* prog_name,
1418 bool errors_are_fatal) {
1419 return ReadFlagsFromString(ReadFileIntoString(filename.c_str()),
1420 prog_name, errors_are_fatal);
1421}
1422
1423
1424// --------------------------------------------------------------------
1425// BoolFromEnv()
1426// Int32FromEnv()
1427// Int64FromEnv()
1428// Uint64FromEnv()
1429// DoubleFromEnv()
1430// StringFromEnv()
1431// Reads the value from the environment and returns it.
1432// We use an FlagValue to make the parsing easy.
1433// Example usage:
Craig Silverstein2b66a842007-06-12 23:59:42 +00001434// DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever");
Craig Silversteinb9f23482007-03-22 00:15:41 +00001435// --------------------------------------------------------------------
1436
1437template<typename T>
1438T GetFromEnv(const char *varname, const char* type, T dflt) {
1439 const char* const valstr = getenv(varname);
1440 if (!valstr)
1441 return dflt;
1442 FlagValue ifv(new T, type);
1443 if (!ifv.ParseFrom(valstr)) {
1444 fprintf(stderr, "ERROR: error parsing env variable '%s' with value '%s'\n",
1445 varname, valstr);
1446 commandlineflags_exitfunc(1); // almost certainly exit()
1447 }
1448 return OTHER_VALUE_AS(ifv, T);
1449}
1450
1451bool BoolFromEnv(const char *v, bool dflt) {
1452 return GetFromEnv(v, "bool", dflt);
1453}
1454int32 Int32FromEnv(const char *v, int32 dflt) {
1455 return GetFromEnv(v, "int32", dflt);
1456}
1457int64 Int64FromEnv(const char *v, int64 dflt) {
1458 return GetFromEnv(v, "int64", dflt);
1459}
1460uint64 Uint64FromEnv(const char *v, uint64 dflt) {
1461 return GetFromEnv(v, "uint64", dflt);
1462}
1463double DoubleFromEnv(const char *v, double dflt) {
1464 return GetFromEnv(v, "double", dflt);
1465}
1466const char *StringFromEnv(const char *varname, const char *dflt) {
1467 const char* const val = getenv(varname);
1468 return val ? val : dflt;
1469}
1470
1471
1472// --------------------------------------------------------------------
1473// ParseCommandLineFlags()
1474// ParseCommandLineNonHelpFlags()
1475// HandleCommandLineHelpFlags()
1476// This is the main function called from main(), to actually
1477// parse the commandline. It modifies argc and argv as described
1478// at the top of commandlineflags.h. You can also divide this
1479// function into two parts, if you want to do work between
1480// the parsing of the flags and the printing of any help output.
1481// --------------------------------------------------------------------
1482
1483static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv,
1484 bool remove_flags, bool do_report) {
1485 SetArgv(*argc, const_cast<const char**>(*argv)); // save it for later
1486
1487 FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
1488 CommandLineFlagParser parser(registry);
1489
1490 // When we parse the commandline flags, we'll handle --flagfile,
1491 // --tryfromenv, etc. as we see them (since flag-evaluation order
1492 // may be important). But sometimes apps set FLAGS_tryfromenv/etc.
1493 // manually before calling ParseCommandLineFlags. We want to evaluate
1494 // those too, as if they were the first flags on the commandline.
1495 registry->Lock();
1496 parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE);
1497 // Last arg here indicates whether flag-not-found is a fatal error or not
1498 parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true);
1499 parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false);
1500 registry->Unlock();
1501
1502 // Now get the flags specified on the commandline
1503 const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags);
1504
1505 if (do_report)
1506 HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc.
1507 if (parser.ReportErrors()) // may cause us to exit on illegal flags
1508 commandlineflags_exitfunc(1); // almost certainly exit()
1509 return r;
1510}
1511
1512uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) {
1513 return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true);
1514}
1515
1516uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv,
1517 bool remove_flags) {
1518 return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false);
1519}
1520
1521// --------------------------------------------------------------------
1522// AllowCommandLineReparsing()
1523// ReparseCommandLineNonHelpFlags()
1524// This is most useful for shared libraries. The idea is if
1525// a flag is defined in a shared library that is dlopen'ed
1526// sometime after main(), you can ParseCommandLineFlags before
1527// the dlopen, then ReparseCommandLineNonHelpFlags() after the
1528// dlopen, to get the new flags. But you have to explicitly
1529// Allow() it; otherwise, you get the normal default behavior
1530// of unrecognized flags calling a fatal error.
1531// TODO(csilvers): this isn't used. Just delete it?
1532// --------------------------------------------------------------------
1533
1534void AllowCommandLineReparsing() {
1535 allow_command_line_reparsing = true;
1536}
1537
1538uint32 ReparseCommandLineNonHelpFlags() {
1539 // We make a copy of argc and argv to pass in
1540 const vector<string>& argvs = GetArgvs();
1541 int tmp_argc = argvs.size();
1542 char** tmp_argv = new char* [tmp_argc + 1];
1543 for (int i = 0; i < tmp_argc; ++i)
1544 tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup
1545
1546 const int retval = ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false);
1547
1548 for (int i = 0; i < tmp_argc; ++i)
1549 free(tmp_argv[i]);
1550 delete[] tmp_argv;
1551
1552 return retval;
1553}
1554
1555_END_GOOGLE_NAMESPACE_