Newer
Older
continue;
}
if (arg[0] == '-') arg++; // allow leading '-'
if (arg[0] == '-') arg++; // or leading '--'
// -- alone means what it does for GNU: stop options parsing
if (*arg == '\0') {
first_nonopt = i+1;
break;
}
// Find the flag object for this option
string key;
const char* value;
string error_message;
CommandLineFlag* flag = registry_->SplitArgumentLocked(arg, &key, &value,
&error_message);
if (flag == NULL) {
undefined_names_[key] = ""; // value isn't actually used
error_flags_[key] = error_message;
continue;
}
if (value == NULL) {
// Boolean options are always assigned a value by SplitArgumentLocked()
assert(strcmp(flag->type_name(), "bool") != 0);
if (i+1 >= first_nonopt) {
// This flag needs a value, but there is nothing available
error_flags_[key] = (string(kError) + "flag '" + (*argv)[i] + "'"
+ " is missing its argument");
if (flag->help() && flag->help()[0] > '\001') {
// Be useful in case we have a non-stripped description.
error_flags_[key] += string("; flag description: ") + flag->help();
}
error_flags_[key] += "\n";
break; // we treat this as an unrecoverable error
} else {
value = (*argv)[++i]; // read next arg for value
// Heuristic to detect the case where someone treats a string arg
// like a bool:
// --my_string_var --foo=bar
// We look for a flag of string type, whose value begins with a
// dash, and where the flag-name and value are separated by a
// space rather than an '='.
// To avoid false positives, we also require the word "true"
// or "false" in the help string. Without this, a valid usage
// "-lat -30.5" would trigger the warning. The common cases we
// want to solve talk about true and false as values.
if (value[0] == '-'
&& strcmp(flag->type_name(), "string") == 0
&& (strstr(flag->help(), "true")
|| strstr(flag->help(), "false"))) {
fprintf(stderr, "Did you really mean to set flag '%s'"
" to the value '%s'?\n",
flag->name(), value);
}
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
}
}
// TODO(csilvers): only set a flag if we hadn't set it before here
ProcessSingleOptionLocked(flag, value, SET_FLAGS_VALUE);
}
registry_->Unlock();
if (remove_flags) { // Fix up argc and argv by removing command line flags
(*argv)[first_nonopt-1] = (*argv)[0];
(*argv) += (first_nonopt-1);
(*argc) -= (first_nonopt-1);
first_nonopt = 1; // because we still don't count argv[0]
}
logging_is_probably_set_up = true; // because we've parsed --logdir, etc.
return first_nonopt;
}
string CommandLineFlagParser::ProcessFlagfileLocked(const string& flagval,
FlagSettingMode set_mode) {
if (flagval.empty())
return "";
string msg;
vector<string> filename_list;
ParseFlagList(flagval.c_str(), &filename_list); // take a list of filenames
for (size_t i = 0; i < filename_list.size(); ++i) {
const char* file = filename_list[i].c_str();
msg += ProcessOptionsFromStringLocked(ReadFileIntoString(file), set_mode);
}
return msg;
}
string CommandLineFlagParser::ProcessFromenvLocked(const string& flagval,
FlagSettingMode set_mode,
bool errors_are_fatal) {
if (flagval.empty())
return "";
string msg;
vector<string> flaglist;
ParseFlagList(flagval.c_str(), &flaglist);
for (size_t i = 0; i < flaglist.size(); ++i) {
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
const char* flagname = flaglist[i].c_str();
CommandLineFlag* flag = registry_->FindFlagLocked(flagname);
if (flag == NULL) {
error_flags_[flagname] = (string(kError) + "unknown command line flag"
+ " '" + flagname + "'"
+ " (via --fromenv or --tryfromenv)\n");
undefined_names_[flagname] = "";
continue;
}
const string envname = string("FLAGS_") + string(flagname);
const char* envval = getenv(envname.c_str());
if (!envval) {
if (errors_are_fatal) {
error_flags_[flagname] = (string(kError) + envname +
" not found in environment\n");
}
continue;
}
// Avoid infinite recursion.
if ((strcmp(envval, "fromenv") == 0) ||
(strcmp(envval, "tryfromenv") == 0)) {
error_flags_[flagname] = (string(kError) + "infinite recursion on " +
"environment flag '" + envval + "'\n");
continue;
}
msg += ProcessSingleOptionLocked(flag, envval, set_mode);
}
return msg;
}
string CommandLineFlagParser::ProcessSingleOptionLocked(
CommandLineFlag* flag, const char* value, FlagSettingMode set_mode) {
string msg;
if (value && !registry_->SetFlagLocked(flag, value, set_mode, &msg)) {
error_flags_[flag->name()] = msg;
return "";
}
// The recursive flags, --flagfile and --fromenv and --tryfromenv,
// must be dealt with as soon as they're seen. They will emit
// messages of their own.
if (strcmp(flag->name(), "flagfile") == 0) {
msg += ProcessFlagfileLocked(FLAGS_flagfile, set_mode);
} else if (strcmp(flag->name(), "fromenv") == 0) {
// last arg indicates envval-not-found is fatal (unlike in --tryfromenv)
msg += ProcessFromenvLocked(FLAGS_fromenv, set_mode, true);
} else if (strcmp(flag->name(), "tryfromenv") == 0) {
msg += ProcessFromenvLocked(FLAGS_tryfromenv, set_mode, false);
}
return msg;
}
void CommandLineFlagParser::ValidateAllFlags() {
FlagRegistryLock frl(registry_);
for (FlagRegistry::FlagConstIterator i = registry_->flags_.begin();
i != registry_->flags_.end(); ++i) {
if (!i->second->ValidateCurrent()) {
// only set a message if one isn't already there. (If there's
// an error message, our job is done, even if it's not exactly
// the same error.)
if (error_flags_[i->second->name()].empty())
error_flags_[i->second->name()] =
string(kError) + "--" + i->second->name() +
" must be set on the commandline"
" (default value fails validation)\n";
}
}
}
bool CommandLineFlagParser::ReportErrors() {
// error_flags_ indicates errors we saw while parsing.
// But we ignore undefined-names if ok'ed by --undef_ok
if (!FLAGS_undefok.empty()) {
vector<string> flaglist;
ParseFlagList(FLAGS_undefok.c_str(), &flaglist);
for (size_t i = 0; i < flaglist.size(); ++i) {
// We also deal with --no<flag>, in case the flagname was boolean
const string no_version = string("no") + flaglist[i];
if (undefined_names_.find(flaglist[i]) != undefined_names_.end()) {
error_flags_[flaglist[i]] = ""; // clear the error message
} else if (undefined_names_.find(no_version) != undefined_names_.end()) {
error_flags_[no_version] = "";
}
// Likewise, if they decided to allow reparsing, all undefined-names
// are ok; we just silently ignore them now, and hope that a future
// parse will pick them up somehow.
if (allow_command_line_reparsing) {
for (map<string, string>::const_iterator it = undefined_names_.begin();
it != undefined_names_.end(); ++it)
error_flags_[it->first] = ""; // clear the error message
}
bool found_error = false;
string error_message;
for (map<string, string>::const_iterator it = error_flags_.begin();
it != error_flags_.end(); ++it) {
if (!it->second.empty()) {
error_message.append(it->second.data(), it->second.size());
if (found_error)
ReportError(DO_NOT_DIE, "%s", error_message.c_str());
return found_error;
}
string CommandLineFlagParser::ProcessOptionsFromStringLocked(
const string& contentdata, FlagSettingMode set_mode) {
string retval;
const char* flagfile_contents = contentdata.c_str();
bool flags_are_relevant = true; // set to false when filenames don't match
bool in_filename_section = false;
const char* line_end = flagfile_contents;
// We read this file a line at a time.
for (; line_end; flagfile_contents = line_end + 1) {
while (*flagfile_contents && isspace(*flagfile_contents))
++flagfile_contents;
line_end = strchr(flagfile_contents, '\n');
size_t len = line_end ? static_cast<size_t>(line_end - flagfile_contents)
: strlen(flagfile_contents);
string line(flagfile_contents, len);
// Each line can be one of four things:
// 1) A comment line -- we skip it
// 2) An empty line -- we skip it
// 3) A list of filenames -- starts a new filenames+flags section
// 4) A --flag=value line -- apply if previous filenames match
if (line.empty() || line[0] == '#') {
// comment or empty line; just ignore
} else if (line[0] == '-') { // flag
in_filename_section = false; // instead, it was a flag-line
if (!flags_are_relevant) // skip this flag; applies to someone else
continue;
const char* name_and_val = line.c_str() + 1; // skip the leading -
if (*name_and_val == '-')
name_and_val++; // skip second - too
string key;
const char* value;
string error_message;
CommandLineFlag* flag = registry_->SplitArgumentLocked(name_and_val,
&key, &value,
&error_message);
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
// By API, errors parsing flagfile lines are silently ignored.
if (flag == NULL) {
// "WARNING: flagname '" + key + "' not found\n"
} else if (value == NULL) {
// "WARNING: flagname '" + key + "' missing a value\n"
} else {
retval += ProcessSingleOptionLocked(flag, value, set_mode);
}
} else { // a filename!
if (!in_filename_section) { // start over: assume filenames don't match
in_filename_section = true;
flags_are_relevant = false;
}
// Split the line up at spaces into glob-patterns
const char* space = line.c_str(); // just has to be non-NULL
for (const char* word = line.c_str(); *space; word = space+1) {
if (flags_are_relevant) // we can stop as soon as we match
break;
space = strchr(word, ' ');
if (space == NULL)
space = word + strlen(word);
const string glob(word, space - word);
// We try matching both against the full argv0 and basename(argv0)
#ifdef HAVE_FNMATCH_H
if (fnmatch(glob.c_str(),
ProgramInvocationName(),
FNM_PATHNAME) == 0 ||
fnmatch(glob.c_str(),
ProgramInvocationShortName(),
FNM_PATHNAME) == 0) {
#else // !HAVE_FNMATCH_H
if ((glob == ProgramInvocationName()) ||
(glob == ProgramInvocationShortName())) {
#endif // HAVE_FNMATCH_H
flags_are_relevant = true;
}
}
}
}
return retval;
}
// --------------------------------------------------------------------
// GetFromEnv()
// AddFlagValidator()
// These are helper functions for routines like BoolFromEnv() and
// RegisterFlagValidator, defined below. They're defined here so
// they can live in the unnamed namespace (which makes friendship
// declarations for these classes possible).
// --------------------------------------------------------------------
template<typename T>
T GetFromEnv(const char *varname, const char* type, T dflt) {
const char* const valstr = getenv(varname);
if (!valstr)
return dflt;
FlagValue ifv(new T, type);
if (!ifv.ParseFrom(valstr))
ReportError(DIE, "ERROR: error parsing env variable '%s' with value '%s'\n",
varname, valstr);
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
return OTHER_VALUE_AS(ifv, T);
}
bool AddFlagValidator(const void* flag_ptr, ValidateFnProto validate_fn_proto) {
// We want a lock around this routine, in case two threads try to
// add a validator (hopefully the same one!) at once. We could use
// our own thread, but we need to loook at the registry anyway, so
// we just steal that one.
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
// First, find the flag whose current-flag storage is 'flag'.
// This is the CommandLineFlag whose current_->value_buffer_ == flag
CommandLineFlag* flag = registry->FindFlagViaPtrLocked(flag_ptr);
if (!flag) {
// WARNING << "Ignoring RegisterValidateFunction() for flag pointer "
// << flag_ptr << ": no flag found at that address";
return false;
} else if (validate_fn_proto == flag->validate_function()) {
return true; // ok to register the same function over and over again
} else if (validate_fn_proto != NULL && flag->validate_function() != NULL) {
// WARNING << "Ignoring RegisterValidateFunction() for flag '"
// << flag->name() << "': validate-fn already registered";
return false;
} else {
flag->validate_fn_proto_ = validate_fn_proto;
return true;
}
}
} // end unnamed namespaces
// Now define the functions that are exported via the .h file
// --------------------------------------------------------------------
// FlagRegisterer
// This class exists merely to have a global constructor (the
// kind that runs before main(), that goes an initializes each
// flag that's been declared. Note that it's very important we
// don't have a destructor that deletes flag_, because that would
// cause us to delete current_storage/defvalue_storage as well,
// which can cause a crash if anything tries to access the flag
// values in a global destructor.
// --------------------------------------------------------------------
FlagRegisterer::FlagRegisterer(const char* name, const char* type,
const char* help, const char* filename,
void* current_storage, void* defvalue_storage) {
if (help == NULL)
help = "";
// FlagValue expects the type-name to not include any namespace
// components, so we get rid of those, if any.
if (strchr(type, ':'))
type = strrchr(type, ':') + 1;
FlagValue* current = new FlagValue(current_storage, type);
FlagValue* defvalue = new FlagValue(defvalue_storage, type);
// Importantly, flag_ will never be deleted, so storage is always good.
CommandLineFlag* flag = new CommandLineFlag(name, help, filename,
current, defvalue);
FlagRegistry::GlobalRegistry()->RegisterFlag(flag); // default registry
}
// --------------------------------------------------------------------
// GetAllFlags()
// The main way the FlagRegistry class exposes its data. This
// returns, as strings, all the info about all the flags in
// the main registry, sorted first by filename they are defined
// in, and then by flagname.
// --------------------------------------------------------------------
struct FilenameFlagnameCmp {
bool operator()(const CommandLineFlagInfo& a,
const CommandLineFlagInfo& b) const {
int cmp = strcmp(a.filename.c_str(), b.filename.c_str());
if (cmp == 0)
cmp = strcmp(a.name.c_str(), b.name.c_str()); // secondary sort key
return cmp < 0;
}
};
void GetAllFlags(vector<CommandLineFlagInfo>* OUTPUT) {
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
registry->Lock();
for (FlagRegistry::FlagConstIterator i = registry->flags_.begin();
i != registry->flags_.end(); ++i) {
CommandLineFlagInfo fi;
i->second->FillCommandLineFlagInfo(&fi);
OUTPUT->push_back(fi);
}
registry->Unlock();
// Now sort the flags, first by filename they occur in, then alphabetically
sort(OUTPUT->begin(), OUTPUT->end(), FilenameFlagnameCmp());
}
// --------------------------------------------------------------------
// SetArgv()
// GetArgvs()
// GetArgv()
// GetArgv0()
// ProgramInvocationName()
// ProgramInvocationShortName()
// SetUsageMessage()
// ProgramUsage()
// Functions to set and get argv. Typically the setter is called
// by ParseCommandLineFlags. Also can get the ProgramUsage string,
// set by SetUsageMessage.
// --------------------------------------------------------------------
// These values are not protected by a Mutex because they are normally
// set only once during program startup.
static const char* argv0 = "UNKNOWN"; // just the program name
static const char* cmdline = ""; // the entire command-line
static vector<string> argvs;
static uint32 argv_sum = 0;
static const char* program_usage = NULL;
void SetArgv(int argc, const char** argv) {
static bool called_set_argv = false;
if (called_set_argv) // we already have an argv for you
return;
called_set_argv = true;
assert(argc > 0); // every program has at least a progname
argv0 = strdup(argv[0]); // small memory leak, but fn only called once
assert(argv0);
string cmdline_string; // easier than doing strcats
for (int i = 0; i < argc; i++) {
if (i != 0) {
cmdline_string += " ";
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
cmdline_string += argv[i];
argvs.push_back(argv[i]);
}
cmdline = strdup(cmdline_string.c_str()); // another small memory leak
assert(cmdline);
// Compute a simple sum of all the chars in argv
for (const char* c = cmdline; *c; c++)
argv_sum += *c;
}
const vector<string>& GetArgvs() { return argvs; }
const char* GetArgv() { return cmdline; }
const char* GetArgv0() { return argv0; }
uint32 GetArgvSum() { return argv_sum; }
const char* ProgramInvocationName() { // like the GNU libc fn
return GetArgv0();
}
const char* ProgramInvocationShortName() { // like the GNU libc fn
const char* slash = strrchr(argv0, '/');
#ifdef OS_WINDOWS
if (!slash) slash = strrchr(argv0, '\\');
#endif
return slash ? slash + 1 : argv0;
}
void SetUsageMessage(const string& usage) {
if (program_usage != NULL)
ReportError(DIE, "ERROR: SetUsageMessage() called twice\n");
program_usage = strdup(usage.c_str()); // small memory leak
}
const char* ProgramUsage() {
if (program_usage) {
return program_usage;
}
return "Warning: SetUsageMessage() never called";
// --------------------------------------------------------------------
// GetCommandLineOption()
// GetCommandLineFlagInfo()
// GetCommandLineFlagInfoOrDie()
// SetCommandLineOption()
// SetCommandLineOptionWithMode()
// The programmatic way to set a flag's value, using a string
// for its name rather than the variable itself (that is,
// SetCommandLineOption("foo", x) rather than FLAGS_foo = x).
// There's also a bit more flexibility here due to the various
// set-modes, but typically these are used when you only have
// that flag's name as a string, perhaps at runtime.
// All of these work on the default, global registry.
// For GetCommandLineOption, return false if no such flag
// is known, true otherwise. We clear "value" if a suitable
// flag is found.
// --------------------------------------------------------------------
bool GetCommandLineOption(const char* name, string* value) {
if (NULL == name)
return false;
assert(value);
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
CommandLineFlag* flag = registry->FindFlagLocked(name);
if (flag == NULL) {
return false;
} else {
*value = flag->current_value();
return true;
}
}
bool GetCommandLineFlagInfo(const char* name, CommandLineFlagInfo* OUTPUT) {
if (NULL == name) return false;
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
CommandLineFlag* flag = registry->FindFlagLocked(name);
if (flag == NULL) {
return false;
} else {
assert(OUTPUT);
flag->FillCommandLineFlagInfo(OUTPUT);
return true;
}
}
CommandLineFlagInfo GetCommandLineFlagInfoOrDie(const char* name) {
CommandLineFlagInfo info;
if (!GetCommandLineFlagInfo(name, &info)) {
fprintf(stderr, "FATAL ERROR: flag name '%s' doesn't exist\n", name);
commandlineflags_exitfunc(1); // almost certainly exit()
}
return info;
}
string SetCommandLineOptionWithMode(const char* name, const char* value,
FlagSettingMode set_mode) {
string result;
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
FlagRegistryLock frl(registry);
CommandLineFlag* flag = registry->FindFlagLocked(name);
if (flag) {
CommandLineFlagParser parser(registry);
result = parser.ProcessSingleOptionLocked(flag, value, set_mode);
if (!result.empty()) { // in the error case, we've already logged
// You could consider logging this change, if you wanted to know it:
//fprintf(stderr, "%sFLAGS_%s\n",
// (set_mode == SET_FLAGS_DEFAULT ? "default value of " : ""),
// result);
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
}
}
// The API of this function is that we return empty string on error
return result;
}
string SetCommandLineOption(const char* name, const char* value) {
return SetCommandLineOptionWithMode(name, value, SET_FLAGS_VALUE);
}
// --------------------------------------------------------------------
// FlagSaver
// FlagSaverImpl
// This class stores the states of all flags at construct time,
// and restores all flags to that state at destruct time.
// Its major implementation challenge is that it never modifies
// pointers in the 'main' registry, so global FLAG_* vars always
// point to the right place.
// --------------------------------------------------------------------
class FlagSaverImpl {
public:
// Constructs an empty FlagSaverImpl object.
explicit FlagSaverImpl(FlagRegistry* main_registry)
: main_registry_(main_registry) { }
~FlagSaverImpl() {
// reclaim memory from each of our CommandLineFlags
vector<CommandLineFlag*>::const_iterator it;
for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it)
delete *it;
}
// Saves the flag states from the flag registry into this object.
// It's an error to call this more than once.
// Must be called when the registry mutex is not held.
void SaveFromRegistry() {
FlagRegistryLock frl(main_registry_);
assert(backup_registry_.empty()); // call only once!
for (FlagRegistry::FlagConstIterator it = main_registry_->flags_.begin();
it != main_registry_->flags_.end();
++it) {
const CommandLineFlag* main = it->second;
// Sets up all the const variables in backup correctly
CommandLineFlag* backup = new CommandLineFlag(
main->name(), main->help(), main->filename(),
main->current_->New(), main->defvalue_->New());
// Sets up all the non-const variables in backup correctly
backup->CopyFrom(*main);
backup_registry_.push_back(backup); // add it to a convenient list
}
}
// Restores the saved flag states into the flag registry. We
// assume no flags were added or deleted from the registry since
// the SaveFromRegistry; if they were, that's trouble! Must be
// called when the registry mutex is not held.
void RestoreToRegistry() {
FlagRegistryLock frl(main_registry_);
vector<CommandLineFlag*>::const_iterator it;
for (it = backup_registry_.begin(); it != backup_registry_.end(); ++it) {
CommandLineFlag* main = main_registry_->FindFlagLocked((*it)->name());
if (main != NULL) { // if NULL, flag got deleted from registry(!)
main->CopyFrom(**it);
}
}
}
private:
FlagRegistry* const main_registry_;
vector<CommandLineFlag*> backup_registry_;
FlagSaverImpl(const FlagSaverImpl&); // no copying!
void operator=(const FlagSaverImpl&);
};
FlagSaver::FlagSaver()
: impl_(new FlagSaverImpl(FlagRegistry::GlobalRegistry())) {
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
impl_->SaveFromRegistry();
}
FlagSaver::~FlagSaver() {
impl_->RestoreToRegistry();
delete impl_;
}
// --------------------------------------------------------------------
// CommandlineFlagsIntoString()
// ReadFlagsFromString()
// AppendFlagsIntoFile()
// ReadFromFlagsFile()
// These are mostly-deprecated routines that stick the
// commandline flags into a file/string and read them back
// out again. I can see a use for CommandlineFlagsIntoString,
// for creating a flagfile, but the rest don't seem that useful
// -- some, I think, are a poor-man's attempt at FlagSaver --
// and are included only until we can delete them from callers.
// Note they don't save --flagfile flags (though they do save
// the result of having called the flagfile, of course).
// --------------------------------------------------------------------
static string TheseCommandlineFlagsIntoString(
const vector<CommandLineFlagInfo>& flags) {
vector<CommandLineFlagInfo>::const_iterator i;
size_t retval_space = 0;
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
for (i = flags.begin(); i != flags.end(); ++i) {
// An (over)estimate of how much space it will take to print this flag
retval_space += i->name.length() + i->current_value.length() + 5;
}
string retval;
retval.reserve(retval_space);
for (i = flags.begin(); i != flags.end(); ++i) {
retval += "--";
retval += i->name;
retval += "=";
retval += i->current_value;
retval += "\n";
}
return retval;
}
string CommandlineFlagsIntoString() {
vector<CommandLineFlagInfo> sorted_flags;
GetAllFlags(&sorted_flags);
return TheseCommandlineFlagsIntoString(sorted_flags);
}
bool ReadFlagsFromString(const string& flagfilecontents,
const char* /*prog_name*/, // TODO(csilvers): nix this
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
bool errors_are_fatal) {
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
FlagSaverImpl saved_states(registry);
saved_states.SaveFromRegistry();
CommandLineFlagParser parser(registry);
registry->Lock();
parser.ProcessOptionsFromStringLocked(flagfilecontents, SET_FLAGS_VALUE);
registry->Unlock();
// Should we handle --help and such when reading flags from a string? Sure.
HandleCommandLineHelpFlags();
if (parser.ReportErrors()) {
// Error. Restore all global flags to their previous values.
if (errors_are_fatal)
commandlineflags_exitfunc(1); // almost certainly exit()
saved_states.RestoreToRegistry();
return false;
}
return true;
}
// TODO(csilvers): nix prog_name in favor of ProgramInvocationShortName()
bool AppendFlagsIntoFile(const string& filename, const char *prog_name) {
FILE *fp = fopen(filename.c_str(), "a");
if (!fp) {
return false;
}
if (prog_name)
fprintf(fp, "%s\n", prog_name);
vector<CommandLineFlagInfo> flags;
GetAllFlags(&flags);
// But we don't want --flagfile, which leads to weird recursion issues
vector<CommandLineFlagInfo>::iterator i;
for (i = flags.begin(); i != flags.end(); ++i) {
if (strcmp(i->name.c_str(), "flagfile") == 0) {
flags.erase(i);
break;
}
}
fprintf(fp, "%s", TheseCommandlineFlagsIntoString(flags).c_str());
fclose(fp);
return true;
}
bool ReadFromFlagsFile(const string& filename, const char* prog_name,
bool errors_are_fatal) {
return ReadFlagsFromString(ReadFileIntoString(filename.c_str()),
prog_name, errors_are_fatal);
}
// --------------------------------------------------------------------
// BoolFromEnv()
// Int32FromEnv()
// Int64FromEnv()
// Uint64FromEnv()
// DoubleFromEnv()
// StringFromEnv()
// Reads the value from the environment and returns it.
// We use an FlagValue to make the parsing easy.
// Example usage:
// DEFINE_bool(myflag, BoolFromEnv("MYFLAG_DEFAULT", false), "whatever");
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
// --------------------------------------------------------------------
bool BoolFromEnv(const char *v, bool dflt) {
return GetFromEnv(v, "bool", dflt);
}
int32 Int32FromEnv(const char *v, int32 dflt) {
return GetFromEnv(v, "int32", dflt);
}
int64 Int64FromEnv(const char *v, int64 dflt) {
return GetFromEnv(v, "int64", dflt);
}
uint64 Uint64FromEnv(const char *v, uint64 dflt) {
return GetFromEnv(v, "uint64", dflt);
}
double DoubleFromEnv(const char *v, double dflt) {
return GetFromEnv(v, "double", dflt);
}
const char *StringFromEnv(const char *varname, const char *dflt) {
const char* const val = getenv(varname);
return val ? val : dflt;
}
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
// --------------------------------------------------------------------
// RegisterFlagValidator()
// RegisterFlagValidator() is the function that clients use to
// 'decorate' a flag with a validation function. Once this is
// done, every time the flag is set (including when the flag
// is parsed from argv), the validator-function is called.
// These functions return true if the validator was added
// successfully, or false if not: the flag already has a validator,
// (only one allowed per flag), the 1st arg isn't a flag, etc.
// This function is not thread-safe.
// --------------------------------------------------------------------
bool RegisterFlagValidator(const bool* flag,
bool (*validate_fn)(const char*, bool)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const int32* flag,
bool (*validate_fn)(const char*, int32)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const int64* flag,
bool (*validate_fn)(const char*, int64)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const uint64* flag,
bool (*validate_fn)(const char*, uint64)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const double* flag,
bool (*validate_fn)(const char*, double)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
bool RegisterFlagValidator(const string* flag,
bool (*validate_fn)(const char*, const string&)) {
return AddFlagValidator(flag, reinterpret_cast<ValidateFnProto>(validate_fn));
}
// --------------------------------------------------------------------
// ParseCommandLineFlags()
// ParseCommandLineNonHelpFlags()
// HandleCommandLineHelpFlags()
// This is the main function called from main(), to actually
// parse the commandline. It modifies argc and argv as described
// at the top of gflags.h. You can also divide this
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
// function into two parts, if you want to do work between
// the parsing of the flags and the printing of any help output.
// --------------------------------------------------------------------
static uint32 ParseCommandLineFlagsInternal(int* argc, char*** argv,
bool remove_flags, bool do_report) {
SetArgv(*argc, const_cast<const char**>(*argv)); // save it for later
FlagRegistry* const registry = FlagRegistry::GlobalRegistry();
CommandLineFlagParser parser(registry);
// When we parse the commandline flags, we'll handle --flagfile,
// --tryfromenv, etc. as we see them (since flag-evaluation order
// may be important). But sometimes apps set FLAGS_tryfromenv/etc.
// manually before calling ParseCommandLineFlags. We want to evaluate
// those too, as if they were the first flags on the commandline.
registry->Lock();
parser.ProcessFlagfileLocked(FLAGS_flagfile, SET_FLAGS_VALUE);
// Last arg here indicates whether flag-not-found is a fatal error or not
parser.ProcessFromenvLocked(FLAGS_fromenv, SET_FLAGS_VALUE, true);
parser.ProcessFromenvLocked(FLAGS_tryfromenv, SET_FLAGS_VALUE, false);
registry->Unlock();
// Now get the flags specified on the commandline
const int r = parser.ParseNewCommandLineFlags(argc, argv, remove_flags);
if (do_report)
HandleCommandLineHelpFlags(); // may cause us to exit on --help, etc.
// See if any of the unset flags fail their validation checks
parser.ValidateAllFlags();
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
if (parser.ReportErrors()) // may cause us to exit on illegal flags
commandlineflags_exitfunc(1); // almost certainly exit()
return r;
}
uint32 ParseCommandLineFlags(int* argc, char*** argv, bool remove_flags) {
return ParseCommandLineFlagsInternal(argc, argv, remove_flags, true);
}
uint32 ParseCommandLineNonHelpFlags(int* argc, char*** argv,
bool remove_flags) {
return ParseCommandLineFlagsInternal(argc, argv, remove_flags, false);
}
// --------------------------------------------------------------------
// AllowCommandLineReparsing()
// ReparseCommandLineNonHelpFlags()
// This is most useful for shared libraries. The idea is if
// a flag is defined in a shared library that is dlopen'ed
// sometime after main(), you can ParseCommandLineFlags before
// the dlopen, then ReparseCommandLineNonHelpFlags() after the
// dlopen, to get the new flags. But you have to explicitly
// Allow() it; otherwise, you get the normal default behavior
// of unrecognized flags calling a fatal error.
// TODO(csilvers): this isn't used. Just delete it?
// --------------------------------------------------------------------
void AllowCommandLineReparsing() {
allow_command_line_reparsing = true;
}
uint32 ReparseCommandLineNonHelpFlags() {
// We make a copy of argc and argv to pass in
const vector<string>& argvs = GetArgvs();
int tmp_argc = static_cast<int>(argvs.size());
char** tmp_argv = new char* [tmp_argc + 1];
for (int i = 0; i < tmp_argc; ++i)
tmp_argv[i] = strdup(argvs[i].c_str()); // TODO(csilvers): don't dup
const int retval = ParseCommandLineNonHelpFlags(&tmp_argc, &tmp_argv, false);
for (int i = 0; i < tmp_argc; ++i)
free(tmp_argv[i]);
delete[] tmp_argv;
return retval;
}
_END_GOOGLE_NAMESPACE_