00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "absl/flags/internal/usage.h"
00017
00018 #include <map>
00019 #include <string>
00020
00021 #include "absl/flags/flag.h"
00022 #include "absl/flags/internal/path_util.h"
00023 #include "absl/flags/internal/program_name.h"
00024 #include "absl/flags/usage_config.h"
00025 #include "absl/strings/ascii.h"
00026 #include "absl/strings/str_cat.h"
00027 #include "absl/strings/str_split.h"
00028 #include "absl/synchronization/mutex.h"
00029
00030 ABSL_FLAG(bool, help, false,
00031 "show help on important flags for this binary [tip: all flags can "
00032 "have two dashes]");
00033 ABSL_FLAG(bool, helpfull, false, "show help on all flags");
00034 ABSL_FLAG(bool, helpshort, false,
00035 "show help on only the main module for this program");
00036 ABSL_FLAG(bool, helppackage, false,
00037 "show help on all modules in the main package");
00038 ABSL_FLAG(bool, version, false, "show version and build info and exit");
00039 ABSL_FLAG(bool, only_check_args, false, "exit after checking all flags");
00040 ABSL_FLAG(std::string, helpon, "",
00041 "show help on the modules named by this flag value");
00042 ABSL_FLAG(std::string, helpmatch, "",
00043 "show help on modules whose name contains the specified substr");
00044
00045 namespace absl {
00046 namespace flags_internal {
00047 namespace {
00048
00049
00050
00051
00052
00053
00054 class XMLElement {
00055 public:
00056 XMLElement(absl::string_view tag, absl::string_view txt)
00057 : tag_(tag), txt_(txt) {}
00058
00059 friend std::ostream& operator<<(std::ostream& out,
00060 const XMLElement& xml_elem) {
00061 out << "<" << xml_elem.tag_ << ">";
00062
00063 for (auto c : xml_elem.txt_) {
00064 switch (c) {
00065 case '"':
00066 out << """;
00067 break;
00068 case '\'':
00069 out << "'";
00070 break;
00071 case '&':
00072 out << "&";
00073 break;
00074 case '<':
00075 out << "<";
00076 break;
00077 case '>':
00078 out << ">";
00079 break;
00080 default:
00081 out << c;
00082 break;
00083 }
00084 }
00085
00086 return out << "</" << xml_elem.tag_ << ">";
00087 }
00088
00089 private:
00090 absl::string_view tag_;
00091 absl::string_view txt_;
00092 };
00093
00094
00095
00096
00097 class FlagHelpPrettyPrinter {
00098 public:
00099
00100
00101 FlagHelpPrettyPrinter(int max_line_len, std::ostream* out)
00102 : out_(*out),
00103 max_line_len_(max_line_len),
00104 line_len_(0),
00105 first_line_(true) {}
00106
00107 void Write(absl::string_view str, bool wrap_line = false) {
00108
00109 if (str.empty()) return;
00110
00111 std::vector<absl::string_view> tokens;
00112 if (wrap_line) {
00113 tokens = absl::StrSplit(str, absl::ByAnyChar(" \f\n\r\t\v"),
00114 absl::SkipEmpty());
00115 } else {
00116 tokens.push_back(str);
00117 }
00118
00119 for (auto token : tokens) {
00120 bool new_line = (line_len_ == 0);
00121
00122
00123 if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
00124 EndLine();
00125 new_line = true;
00126 }
00127
00128 if (new_line) {
00129 StartLine();
00130 } else {
00131 out_ << ' ';
00132 ++line_len_;
00133 }
00134
00135 out_ << token;
00136 line_len_ += token.size();
00137 }
00138 }
00139
00140 void StartLine() {
00141 if (first_line_) {
00142 out_ << " ";
00143 line_len_ = 4;
00144 first_line_ = false;
00145 } else {
00146 out_ << " ";
00147 line_len_ = 6;
00148 }
00149 }
00150 void EndLine() {
00151 out_ << '\n';
00152 line_len_ = 0;
00153 }
00154
00155 private:
00156 std::ostream& out_;
00157 const int max_line_len_;
00158 int line_len_;
00159 bool first_line_;
00160 };
00161
00162 void FlagHelpHumanReadable(const flags_internal::CommandLineFlag& flag,
00163 std::ostream* out) {
00164 FlagHelpPrettyPrinter printer(80, out);
00165
00166
00167 printer.Write(absl::StrCat("-", flag.Name()));
00168
00169
00170 printer.Write(absl::StrCat("(", flag.Help(), ");"), true);
00171
00172
00173 if (!flag.IsAbseilFlag() && !flag.IsRetired()) {
00174 printer.Write(absl::StrCat("type: ", flag.Typename(), ";"));
00175 }
00176
00177
00178
00179
00180
00181 std::string dflt_val = flag.DefaultValue();
00182 if (flag.IsOfType<std::string>()) {
00183 dflt_val = absl::StrCat("\"", dflt_val, "\"");
00184 }
00185 printer.Write(absl::StrCat("default: ", dflt_val, ";"));
00186
00187 if (flag.modified) {
00188 std::string curr_val = flag.CurrentValue();
00189 if (flag.IsOfType<std::string>()) {
00190 curr_val = absl::StrCat("\"", curr_val, "\"");
00191 }
00192 printer.Write(absl::StrCat("currently: ", curr_val, ";"));
00193 }
00194
00195 printer.EndLine();
00196 }
00197
00198
00199
00200
00201
00202
00203 void FlagsHelpImpl(std::ostream& out, flags_internal::FlagKindFilter filter_cb,
00204 HelpFormat format = HelpFormat::kHumanReadable) {
00205 if (format == HelpFormat::kHumanReadable) {
00206 out << flags_internal::ShortProgramInvocationName() << ": "
00207 << flags_internal::ProgramUsageMessage() << "\n\n";
00208 } else {
00209
00210 out << "<?xml version=\"1.0\"?>\n"
00211
00212 << "<AllFlags>\n"
00213
00214 << XMLElement("program", flags_internal::ShortProgramInvocationName())
00215 << '\n'
00216 << XMLElement("usage", flags_internal::ProgramUsageMessage()) << '\n';
00217 }
00218
00219
00220
00221
00222
00223
00224 std::map<std::string,
00225 std::map<std::string,
00226 std::vector<const flags_internal::CommandLineFlag*>>>
00227 matching_flags;
00228
00229 flags_internal::ForEachFlag([&](flags_internal::CommandLineFlag* flag) {
00230 absl::MutexLock l(InitFlagIfNecessary(flag));
00231
00232 std::string flag_filename = flag->Filename();
00233
00234
00235 if (flag->IsRetired()) return;
00236
00237
00238 if (flag->Help() == flags_internal::kStrippedFlagHelp) return;
00239
00240
00241 if (!filter_cb || !filter_cb(flag_filename)) return;
00242
00243 matching_flags[std::string(flags_internal::Package(flag_filename))]
00244 [flag_filename]
00245 .push_back(flag);
00246 });
00247
00248 absl::string_view
00249 package_separator;
00250 absl::string_view file_separator;
00251 for (const auto& package : matching_flags) {
00252 if (format == HelpFormat::kHumanReadable) {
00253 out << package_separator;
00254 package_separator = "\n\n";
00255 }
00256
00257 file_separator = "";
00258 for (const auto& flags_in_file : package.second) {
00259 if (format == HelpFormat::kHumanReadable) {
00260 out << file_separator << " Flags from " << flags_in_file.first
00261 << ":\n";
00262 file_separator = "\n";
00263 }
00264
00265 for (const auto* flag : flags_in_file.second) {
00266 flags_internal::FlagHelp(out, *flag, format);
00267 }
00268 }
00269 }
00270
00271 if (format == HelpFormat::kHumanReadable) {
00272 if (filter_cb && matching_flags.empty()) {
00273 out << " No modules matched: use -helpfull\n";
00274 }
00275 } else {
00276
00277 out << "</AllFlags>\n";
00278 }
00279 }
00280
00281 ABSL_CONST_INIT absl::Mutex usage_message_guard(absl::kConstInit);
00282 ABSL_CONST_INIT std::string* program_usage_message
00283 GUARDED_BY(usage_message_guard) = nullptr;
00284
00285 }
00286
00287
00288
00289
00290 void SetProgramUsageMessage(absl::string_view new_usage_message) {
00291 absl::MutexLock l(&usage_message_guard);
00292
00293 if (flags_internal::program_usage_message != nullptr) {
00294 ABSL_INTERNAL_LOG(FATAL, "SetProgramUsageMessage() called twice.");
00295 std::exit(1);
00296 }
00297
00298 program_usage_message = new std::string(new_usage_message);
00299 }
00300
00301
00302
00303
00304
00305 absl::string_view ProgramUsageMessage() {
00306 absl::MutexLock l(&usage_message_guard);
00307
00308 return program_usage_message != nullptr
00309 ? absl::string_view(*program_usage_message)
00310 : "Warning: SetProgramUsageMessage() never called";
00311 }
00312
00313
00314
00315 void FlagHelp(std::ostream& out, const flags_internal::CommandLineFlag& flag,
00316 HelpFormat format) {
00317 if (format == HelpFormat::kHumanReadable)
00318 flags_internal::FlagHelpHumanReadable(flag, &out);
00319 }
00320
00321
00322
00323
00324 void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format) {
00325 flags_internal::FlagKindFilter filter_cb = [&](absl::string_view filename) {
00326 return filter.empty() || filename.find(filter) != absl::string_view::npos;
00327 };
00328 flags_internal::FlagsHelpImpl(out, filter_cb, format);
00329 }
00330
00331
00332
00333
00334 int HandleUsageFlags(std::ostream& out) {
00335 if (absl::GetFlag(FLAGS_helpshort)) {
00336 flags_internal::FlagsHelpImpl(
00337 out, flags_internal::GetUsageConfig().contains_helpshort_flags,
00338 HelpFormat::kHumanReadable);
00339 return 1;
00340 }
00341
00342 if (absl::GetFlag(FLAGS_helpfull)) {
00343
00344 flags_internal::FlagsHelp(out);
00345 return 1;
00346 }
00347
00348 if (!absl::GetFlag(FLAGS_helpon).empty()) {
00349 flags_internal::FlagsHelp(
00350 out, absl::StrCat("/", absl::GetFlag(FLAGS_helpon), "."));
00351 return 1;
00352 }
00353
00354 if (!absl::GetFlag(FLAGS_helpmatch).empty()) {
00355 flags_internal::FlagsHelp(out, absl::GetFlag(FLAGS_helpmatch));
00356 return 1;
00357 }
00358
00359 if (absl::GetFlag(FLAGS_help)) {
00360 flags_internal::FlagsHelpImpl(
00361 out, flags_internal::GetUsageConfig().contains_help_flags);
00362
00363 out << "\nTry --helpfull to get a list of all flags.\n";
00364
00365 return 1;
00366 }
00367
00368 if (absl::GetFlag(FLAGS_helppackage)) {
00369 flags_internal::FlagsHelpImpl(
00370 out, flags_internal::GetUsageConfig().contains_helppackage_flags);
00371
00372 out << "\nTry --helpfull to get a list of all flags.\n";
00373
00374 return 1;
00375 }
00376
00377 if (absl::GetFlag(FLAGS_version)) {
00378 if (flags_internal::GetUsageConfig().version_string)
00379 out << flags_internal::GetUsageConfig().version_string();
00380
00381 return 0;
00382 }
00383
00384 if (absl::GetFlag(FLAGS_only_check_args)) {
00385 return 0;
00386 }
00387
00388 return -1;
00389 }
00390
00391 }
00392 }