xref: /aosp_15_r20/external/abseil-cpp/absl/flags/internal/usage.cc (revision 9356374a3709195abf420251b3e825997ff56c0f)
1*9356374aSAndroid Build Coastguard Worker //
2*9356374aSAndroid Build Coastguard Worker // Copyright 2019 The Abseil Authors.
3*9356374aSAndroid Build Coastguard Worker //
4*9356374aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
5*9356374aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
6*9356374aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
7*9356374aSAndroid Build Coastguard Worker //
8*9356374aSAndroid Build Coastguard Worker //      https://www.apache.org/licenses/LICENSE-2.0
9*9356374aSAndroid Build Coastguard Worker //
10*9356374aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
11*9356374aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
12*9356374aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*9356374aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
14*9356374aSAndroid Build Coastguard Worker // limitations under the License.
15*9356374aSAndroid Build Coastguard Worker 
16*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/usage.h"
17*9356374aSAndroid Build Coastguard Worker 
18*9356374aSAndroid Build Coastguard Worker #include <stdint.h>
19*9356374aSAndroid Build Coastguard Worker 
20*9356374aSAndroid Build Coastguard Worker #include <algorithm>
21*9356374aSAndroid Build Coastguard Worker #include <cstdlib>
22*9356374aSAndroid Build Coastguard Worker #include <functional>
23*9356374aSAndroid Build Coastguard Worker #include <iterator>
24*9356374aSAndroid Build Coastguard Worker #include <map>
25*9356374aSAndroid Build Coastguard Worker #include <ostream>
26*9356374aSAndroid Build Coastguard Worker #include <string>
27*9356374aSAndroid Build Coastguard Worker #include <utility>
28*9356374aSAndroid Build Coastguard Worker #include <vector>
29*9356374aSAndroid Build Coastguard Worker 
30*9356374aSAndroid Build Coastguard Worker #include "absl/base/attributes.h"
31*9356374aSAndroid Build Coastguard Worker #include "absl/base/config.h"
32*9356374aSAndroid Build Coastguard Worker #include "absl/base/const_init.h"
33*9356374aSAndroid Build Coastguard Worker #include "absl/base/thread_annotations.h"
34*9356374aSAndroid Build Coastguard Worker #include "absl/flags/commandlineflag.h"
35*9356374aSAndroid Build Coastguard Worker #include "absl/flags/flag.h"
36*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/flag.h"
37*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/path_util.h"
38*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/private_handle_accessor.h"
39*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/program_name.h"
40*9356374aSAndroid Build Coastguard Worker #include "absl/flags/internal/registry.h"
41*9356374aSAndroid Build Coastguard Worker #include "absl/flags/usage_config.h"
42*9356374aSAndroid Build Coastguard Worker #include "absl/strings/match.h"
43*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_cat.h"
44*9356374aSAndroid Build Coastguard Worker #include "absl/strings/str_split.h"
45*9356374aSAndroid Build Coastguard Worker #include "absl/strings/string_view.h"
46*9356374aSAndroid Build Coastguard Worker #include "absl/strings/strip.h"
47*9356374aSAndroid Build Coastguard Worker #include "absl/synchronization/mutex.h"
48*9356374aSAndroid Build Coastguard Worker 
49*9356374aSAndroid Build Coastguard Worker // Dummy global variables to prevent anyone else defining these.
50*9356374aSAndroid Build Coastguard Worker bool FLAGS_help = false;
51*9356374aSAndroid Build Coastguard Worker bool FLAGS_helpfull = false;
52*9356374aSAndroid Build Coastguard Worker bool FLAGS_helpshort = false;
53*9356374aSAndroid Build Coastguard Worker bool FLAGS_helppackage = false;
54*9356374aSAndroid Build Coastguard Worker bool FLAGS_version = false;
55*9356374aSAndroid Build Coastguard Worker bool FLAGS_only_check_args = false;
56*9356374aSAndroid Build Coastguard Worker bool FLAGS_helpon = false;
57*9356374aSAndroid Build Coastguard Worker bool FLAGS_helpmatch = false;
58*9356374aSAndroid Build Coastguard Worker 
59*9356374aSAndroid Build Coastguard Worker namespace absl {
60*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_BEGIN
61*9356374aSAndroid Build Coastguard Worker namespace flags_internal {
62*9356374aSAndroid Build Coastguard Worker namespace {
63*9356374aSAndroid Build Coastguard Worker 
64*9356374aSAndroid Build Coastguard Worker using PerFlagFilter = std::function<bool(const absl::CommandLineFlag&)>;
65*9356374aSAndroid Build Coastguard Worker 
66*9356374aSAndroid Build Coastguard Worker // Maximum length size in a human readable format.
67*9356374aSAndroid Build Coastguard Worker constexpr size_t kHrfMaxLineLength = 80;
68*9356374aSAndroid Build Coastguard Worker 
69*9356374aSAndroid Build Coastguard Worker // This class is used to emit an XML element with `tag` and `text`.
70*9356374aSAndroid Build Coastguard Worker // It adds opening and closing tags and escapes special characters in the text.
71*9356374aSAndroid Build Coastguard Worker // For example:
72*9356374aSAndroid Build Coastguard Worker // std::cout << XMLElement("title", "Milk & Cookies");
73*9356374aSAndroid Build Coastguard Worker // prints "<title>Milk &amp; Cookies</title>"
74*9356374aSAndroid Build Coastguard Worker class XMLElement {
75*9356374aSAndroid Build Coastguard Worker  public:
XMLElement(absl::string_view tag,absl::string_view txt)76*9356374aSAndroid Build Coastguard Worker   XMLElement(absl::string_view tag, absl::string_view txt)
77*9356374aSAndroid Build Coastguard Worker       : tag_(tag), txt_(txt) {}
78*9356374aSAndroid Build Coastguard Worker 
operator <<(std::ostream & out,const XMLElement & xml_elem)79*9356374aSAndroid Build Coastguard Worker   friend std::ostream& operator<<(std::ostream& out,
80*9356374aSAndroid Build Coastguard Worker                                   const XMLElement& xml_elem) {
81*9356374aSAndroid Build Coastguard Worker     out << "<" << xml_elem.tag_ << ">";
82*9356374aSAndroid Build Coastguard Worker 
83*9356374aSAndroid Build Coastguard Worker     for (auto c : xml_elem.txt_) {
84*9356374aSAndroid Build Coastguard Worker       switch (c) {
85*9356374aSAndroid Build Coastguard Worker         case '"':
86*9356374aSAndroid Build Coastguard Worker           out << "&quot;";
87*9356374aSAndroid Build Coastguard Worker           break;
88*9356374aSAndroid Build Coastguard Worker         case '\'':
89*9356374aSAndroid Build Coastguard Worker           out << "&apos;";
90*9356374aSAndroid Build Coastguard Worker           break;
91*9356374aSAndroid Build Coastguard Worker         case '&':
92*9356374aSAndroid Build Coastguard Worker           out << "&amp;";
93*9356374aSAndroid Build Coastguard Worker           break;
94*9356374aSAndroid Build Coastguard Worker         case '<':
95*9356374aSAndroid Build Coastguard Worker           out << "&lt;";
96*9356374aSAndroid Build Coastguard Worker           break;
97*9356374aSAndroid Build Coastguard Worker         case '>':
98*9356374aSAndroid Build Coastguard Worker           out << "&gt;";
99*9356374aSAndroid Build Coastguard Worker           break;
100*9356374aSAndroid Build Coastguard Worker         case '\n':
101*9356374aSAndroid Build Coastguard Worker         case '\v':
102*9356374aSAndroid Build Coastguard Worker         case '\f':
103*9356374aSAndroid Build Coastguard Worker         case '\t':
104*9356374aSAndroid Build Coastguard Worker           out << " ";
105*9356374aSAndroid Build Coastguard Worker           break;
106*9356374aSAndroid Build Coastguard Worker         default:
107*9356374aSAndroid Build Coastguard Worker           if (IsValidXmlCharacter(static_cast<unsigned char>(c))) {
108*9356374aSAndroid Build Coastguard Worker             out << c;
109*9356374aSAndroid Build Coastguard Worker           }
110*9356374aSAndroid Build Coastguard Worker           break;
111*9356374aSAndroid Build Coastguard Worker       }
112*9356374aSAndroid Build Coastguard Worker     }
113*9356374aSAndroid Build Coastguard Worker 
114*9356374aSAndroid Build Coastguard Worker     return out << "</" << xml_elem.tag_ << ">";
115*9356374aSAndroid Build Coastguard Worker   }
116*9356374aSAndroid Build Coastguard Worker 
117*9356374aSAndroid Build Coastguard Worker  private:
IsValidXmlCharacter(unsigned char c)118*9356374aSAndroid Build Coastguard Worker   static bool IsValidXmlCharacter(unsigned char c) { return c >= 0x20; }
119*9356374aSAndroid Build Coastguard Worker   absl::string_view tag_;
120*9356374aSAndroid Build Coastguard Worker   absl::string_view txt_;
121*9356374aSAndroid Build Coastguard Worker };
122*9356374aSAndroid Build Coastguard Worker 
123*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
124*9356374aSAndroid Build Coastguard Worker // Helper class to pretty-print info about a flag.
125*9356374aSAndroid Build Coastguard Worker 
126*9356374aSAndroid Build Coastguard Worker class FlagHelpPrettyPrinter {
127*9356374aSAndroid Build Coastguard Worker  public:
128*9356374aSAndroid Build Coastguard Worker   // Pretty printer holds on to the std::ostream& reference to direct an output
129*9356374aSAndroid Build Coastguard Worker   // to that stream.
FlagHelpPrettyPrinter(size_t max_line_len,size_t min_line_len,size_t wrapped_line_indent,std::ostream & out)130*9356374aSAndroid Build Coastguard Worker   FlagHelpPrettyPrinter(size_t max_line_len, size_t min_line_len,
131*9356374aSAndroid Build Coastguard Worker                         size_t wrapped_line_indent, std::ostream& out)
132*9356374aSAndroid Build Coastguard Worker       : out_(out),
133*9356374aSAndroid Build Coastguard Worker         max_line_len_(max_line_len),
134*9356374aSAndroid Build Coastguard Worker         min_line_len_(min_line_len),
135*9356374aSAndroid Build Coastguard Worker         wrapped_line_indent_(wrapped_line_indent),
136*9356374aSAndroid Build Coastguard Worker         line_len_(0),
137*9356374aSAndroid Build Coastguard Worker         first_line_(true) {}
138*9356374aSAndroid Build Coastguard Worker 
Write(absl::string_view str,bool wrap_line=false)139*9356374aSAndroid Build Coastguard Worker   void Write(absl::string_view str, bool wrap_line = false) {
140*9356374aSAndroid Build Coastguard Worker     // Empty string - do nothing.
141*9356374aSAndroid Build Coastguard Worker     if (str.empty()) return;
142*9356374aSAndroid Build Coastguard Worker 
143*9356374aSAndroid Build Coastguard Worker     std::vector<absl::string_view> tokens;
144*9356374aSAndroid Build Coastguard Worker     if (wrap_line) {
145*9356374aSAndroid Build Coastguard Worker       for (auto line : absl::StrSplit(str, absl::ByAnyChar("\n\r"))) {
146*9356374aSAndroid Build Coastguard Worker         if (!tokens.empty()) {
147*9356374aSAndroid Build Coastguard Worker           // Keep line separators in the input string.
148*9356374aSAndroid Build Coastguard Worker           tokens.emplace_back("\n");
149*9356374aSAndroid Build Coastguard Worker         }
150*9356374aSAndroid Build Coastguard Worker         for (auto token :
151*9356374aSAndroid Build Coastguard Worker              absl::StrSplit(line, absl::ByAnyChar(" \t"), absl::SkipEmpty())) {
152*9356374aSAndroid Build Coastguard Worker           tokens.push_back(token);
153*9356374aSAndroid Build Coastguard Worker         }
154*9356374aSAndroid Build Coastguard Worker       }
155*9356374aSAndroid Build Coastguard Worker     } else {
156*9356374aSAndroid Build Coastguard Worker       tokens.push_back(str);
157*9356374aSAndroid Build Coastguard Worker     }
158*9356374aSAndroid Build Coastguard Worker 
159*9356374aSAndroid Build Coastguard Worker     for (auto token : tokens) {
160*9356374aSAndroid Build Coastguard Worker       bool new_line = (line_len_ == 0);
161*9356374aSAndroid Build Coastguard Worker 
162*9356374aSAndroid Build Coastguard Worker       // Respect line separators in the input string.
163*9356374aSAndroid Build Coastguard Worker       if (token == "\n") {
164*9356374aSAndroid Build Coastguard Worker         EndLine();
165*9356374aSAndroid Build Coastguard Worker         continue;
166*9356374aSAndroid Build Coastguard Worker       }
167*9356374aSAndroid Build Coastguard Worker 
168*9356374aSAndroid Build Coastguard Worker       // Write the token, ending the string first if necessary/possible.
169*9356374aSAndroid Build Coastguard Worker       if (!new_line && (line_len_ + token.size() >= max_line_len_)) {
170*9356374aSAndroid Build Coastguard Worker         EndLine();
171*9356374aSAndroid Build Coastguard Worker         new_line = true;
172*9356374aSAndroid Build Coastguard Worker       }
173*9356374aSAndroid Build Coastguard Worker 
174*9356374aSAndroid Build Coastguard Worker       if (new_line) {
175*9356374aSAndroid Build Coastguard Worker         StartLine();
176*9356374aSAndroid Build Coastguard Worker       } else {
177*9356374aSAndroid Build Coastguard Worker         out_ << ' ';
178*9356374aSAndroid Build Coastguard Worker         ++line_len_;
179*9356374aSAndroid Build Coastguard Worker       }
180*9356374aSAndroid Build Coastguard Worker 
181*9356374aSAndroid Build Coastguard Worker       out_ << token;
182*9356374aSAndroid Build Coastguard Worker       line_len_ += token.size();
183*9356374aSAndroid Build Coastguard Worker     }
184*9356374aSAndroid Build Coastguard Worker   }
185*9356374aSAndroid Build Coastguard Worker 
StartLine()186*9356374aSAndroid Build Coastguard Worker   void StartLine() {
187*9356374aSAndroid Build Coastguard Worker     if (first_line_) {
188*9356374aSAndroid Build Coastguard Worker       line_len_ = min_line_len_;
189*9356374aSAndroid Build Coastguard Worker       first_line_ = false;
190*9356374aSAndroid Build Coastguard Worker     } else {
191*9356374aSAndroid Build Coastguard Worker       line_len_ = min_line_len_ + wrapped_line_indent_;
192*9356374aSAndroid Build Coastguard Worker     }
193*9356374aSAndroid Build Coastguard Worker     out_ << std::string(line_len_, ' ');
194*9356374aSAndroid Build Coastguard Worker   }
EndLine()195*9356374aSAndroid Build Coastguard Worker   void EndLine() {
196*9356374aSAndroid Build Coastguard Worker     out_ << '\n';
197*9356374aSAndroid Build Coastguard Worker     line_len_ = 0;
198*9356374aSAndroid Build Coastguard Worker   }
199*9356374aSAndroid Build Coastguard Worker 
200*9356374aSAndroid Build Coastguard Worker  private:
201*9356374aSAndroid Build Coastguard Worker   std::ostream& out_;
202*9356374aSAndroid Build Coastguard Worker   const size_t max_line_len_;
203*9356374aSAndroid Build Coastguard Worker   const size_t min_line_len_;
204*9356374aSAndroid Build Coastguard Worker   const size_t wrapped_line_indent_;
205*9356374aSAndroid Build Coastguard Worker   size_t line_len_;
206*9356374aSAndroid Build Coastguard Worker   bool first_line_;
207*9356374aSAndroid Build Coastguard Worker };
208*9356374aSAndroid Build Coastguard Worker 
FlagHelpHumanReadable(const CommandLineFlag & flag,std::ostream & out)209*9356374aSAndroid Build Coastguard Worker void FlagHelpHumanReadable(const CommandLineFlag& flag, std::ostream& out) {
210*9356374aSAndroid Build Coastguard Worker   FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 4, 2, out);
211*9356374aSAndroid Build Coastguard Worker 
212*9356374aSAndroid Build Coastguard Worker   // Flag name.
213*9356374aSAndroid Build Coastguard Worker   printer.Write(absl::StrCat("--", flag.Name()));
214*9356374aSAndroid Build Coastguard Worker 
215*9356374aSAndroid Build Coastguard Worker   // Flag help.
216*9356374aSAndroid Build Coastguard Worker   printer.Write(absl::StrCat("(", flag.Help(), ");"), /*wrap_line=*/true);
217*9356374aSAndroid Build Coastguard Worker 
218*9356374aSAndroid Build Coastguard Worker   // The listed default value will be the actual default from the flag
219*9356374aSAndroid Build Coastguard Worker   // definition in the originating source file, unless the value has
220*9356374aSAndroid Build Coastguard Worker   // subsequently been modified using SetCommandLineOption() with mode
221*9356374aSAndroid Build Coastguard Worker   // SET_FLAGS_DEFAULT.
222*9356374aSAndroid Build Coastguard Worker   std::string dflt_val = flag.DefaultValue();
223*9356374aSAndroid Build Coastguard Worker   std::string curr_val = flag.CurrentValue();
224*9356374aSAndroid Build Coastguard Worker   bool is_modified = curr_val != dflt_val;
225*9356374aSAndroid Build Coastguard Worker 
226*9356374aSAndroid Build Coastguard Worker   if (flag.IsOfType<std::string>()) {
227*9356374aSAndroid Build Coastguard Worker     dflt_val = absl::StrCat("\"", dflt_val, "\"");
228*9356374aSAndroid Build Coastguard Worker   }
229*9356374aSAndroid Build Coastguard Worker   printer.Write(absl::StrCat("default: ", dflt_val, ";"));
230*9356374aSAndroid Build Coastguard Worker 
231*9356374aSAndroid Build Coastguard Worker   if (is_modified) {
232*9356374aSAndroid Build Coastguard Worker     if (flag.IsOfType<std::string>()) {
233*9356374aSAndroid Build Coastguard Worker       curr_val = absl::StrCat("\"", curr_val, "\"");
234*9356374aSAndroid Build Coastguard Worker     }
235*9356374aSAndroid Build Coastguard Worker     printer.Write(absl::StrCat("currently: ", curr_val, ";"));
236*9356374aSAndroid Build Coastguard Worker   }
237*9356374aSAndroid Build Coastguard Worker 
238*9356374aSAndroid Build Coastguard Worker   printer.EndLine();
239*9356374aSAndroid Build Coastguard Worker }
240*9356374aSAndroid Build Coastguard Worker 
241*9356374aSAndroid Build Coastguard Worker // Shows help for every filename which matches any of the filters
242*9356374aSAndroid Build Coastguard Worker // If filters are empty, shows help for every file.
243*9356374aSAndroid Build Coastguard Worker // If a flag's help message has been stripped (e.g. by adding '#define
244*9356374aSAndroid Build Coastguard Worker // STRIP_FLAG_HELP 1' then this flag will not be displayed by '--help'
245*9356374aSAndroid Build Coastguard Worker // and its variants.
FlagsHelpImpl(std::ostream & out,PerFlagFilter filter_cb,HelpFormat format,absl::string_view program_usage_message)246*9356374aSAndroid Build Coastguard Worker void FlagsHelpImpl(std::ostream& out, PerFlagFilter filter_cb,
247*9356374aSAndroid Build Coastguard Worker                    HelpFormat format, absl::string_view program_usage_message) {
248*9356374aSAndroid Build Coastguard Worker   if (format == HelpFormat::kHumanReadable) {
249*9356374aSAndroid Build Coastguard Worker     out << flags_internal::ShortProgramInvocationName() << ": "
250*9356374aSAndroid Build Coastguard Worker         << program_usage_message << "\n\n";
251*9356374aSAndroid Build Coastguard Worker   } else {
252*9356374aSAndroid Build Coastguard Worker     // XML schema is not a part of our public API for now.
253*9356374aSAndroid Build Coastguard Worker     out << "<?xml version=\"1.0\"?>\n"
254*9356374aSAndroid Build Coastguard Worker         << "<!-- This output should be used with care. We do not report type "
255*9356374aSAndroid Build Coastguard Worker            "names for flags with user defined types -->\n"
256*9356374aSAndroid Build Coastguard Worker         << "<!-- Prefer flag only_check_args for validating flag inputs -->\n"
257*9356374aSAndroid Build Coastguard Worker         // The document.
258*9356374aSAndroid Build Coastguard Worker         << "<AllFlags>\n"
259*9356374aSAndroid Build Coastguard Worker         // The program name and usage.
260*9356374aSAndroid Build Coastguard Worker         << XMLElement("program", flags_internal::ShortProgramInvocationName())
261*9356374aSAndroid Build Coastguard Worker         << '\n'
262*9356374aSAndroid Build Coastguard Worker         << XMLElement("usage", program_usage_message) << '\n';
263*9356374aSAndroid Build Coastguard Worker   }
264*9356374aSAndroid Build Coastguard Worker 
265*9356374aSAndroid Build Coastguard Worker   // Ordered map of package name to
266*9356374aSAndroid Build Coastguard Worker   //   map of file name to
267*9356374aSAndroid Build Coastguard Worker   //     vector of flags in the file.
268*9356374aSAndroid Build Coastguard Worker   // This map is used to output matching flags grouped by package and file
269*9356374aSAndroid Build Coastguard Worker   // name.
270*9356374aSAndroid Build Coastguard Worker   std::map<std::string,
271*9356374aSAndroid Build Coastguard Worker            std::map<std::string, std::vector<const absl::CommandLineFlag*>>>
272*9356374aSAndroid Build Coastguard Worker       matching_flags;
273*9356374aSAndroid Build Coastguard Worker 
274*9356374aSAndroid Build Coastguard Worker   flags_internal::ForEachFlag([&](absl::CommandLineFlag& flag) {
275*9356374aSAndroid Build Coastguard Worker     // Ignore retired flags.
276*9356374aSAndroid Build Coastguard Worker     if (flag.IsRetired()) return;
277*9356374aSAndroid Build Coastguard Worker 
278*9356374aSAndroid Build Coastguard Worker     // If the flag has been stripped, pretend that it doesn't exist.
279*9356374aSAndroid Build Coastguard Worker     if (flag.Help() == flags_internal::kStrippedFlagHelp) return;
280*9356374aSAndroid Build Coastguard Worker 
281*9356374aSAndroid Build Coastguard Worker     // Make sure flag satisfies the filter
282*9356374aSAndroid Build Coastguard Worker     if (!filter_cb(flag)) return;
283*9356374aSAndroid Build Coastguard Worker 
284*9356374aSAndroid Build Coastguard Worker     std::string flag_filename = flag.Filename();
285*9356374aSAndroid Build Coastguard Worker 
286*9356374aSAndroid Build Coastguard Worker     matching_flags[std::string(flags_internal::Package(flag_filename))]
287*9356374aSAndroid Build Coastguard Worker                   [flag_filename]
288*9356374aSAndroid Build Coastguard Worker                       .push_back(&flag);
289*9356374aSAndroid Build Coastguard Worker   });
290*9356374aSAndroid Build Coastguard Worker 
291*9356374aSAndroid Build Coastguard Worker   absl::string_view package_separator;  // controls blank lines between packages
292*9356374aSAndroid Build Coastguard Worker   absl::string_view file_separator;     // controls blank lines between files
293*9356374aSAndroid Build Coastguard Worker   for (auto& package : matching_flags) {
294*9356374aSAndroid Build Coastguard Worker     if (format == HelpFormat::kHumanReadable) {
295*9356374aSAndroid Build Coastguard Worker       out << package_separator;
296*9356374aSAndroid Build Coastguard Worker       package_separator = "\n\n";
297*9356374aSAndroid Build Coastguard Worker     }
298*9356374aSAndroid Build Coastguard Worker 
299*9356374aSAndroid Build Coastguard Worker     file_separator = "";
300*9356374aSAndroid Build Coastguard Worker     for (auto& flags_in_file : package.second) {
301*9356374aSAndroid Build Coastguard Worker       if (format == HelpFormat::kHumanReadable) {
302*9356374aSAndroid Build Coastguard Worker         out << file_separator << "  Flags from " << flags_in_file.first
303*9356374aSAndroid Build Coastguard Worker             << ":\n";
304*9356374aSAndroid Build Coastguard Worker         file_separator = "\n";
305*9356374aSAndroid Build Coastguard Worker       }
306*9356374aSAndroid Build Coastguard Worker 
307*9356374aSAndroid Build Coastguard Worker       std::sort(std::begin(flags_in_file.second),
308*9356374aSAndroid Build Coastguard Worker                 std::end(flags_in_file.second),
309*9356374aSAndroid Build Coastguard Worker                 [](const CommandLineFlag* lhs, const CommandLineFlag* rhs) {
310*9356374aSAndroid Build Coastguard Worker                   return lhs->Name() < rhs->Name();
311*9356374aSAndroid Build Coastguard Worker                 });
312*9356374aSAndroid Build Coastguard Worker 
313*9356374aSAndroid Build Coastguard Worker       for (const auto* flag : flags_in_file.second) {
314*9356374aSAndroid Build Coastguard Worker         flags_internal::FlagHelp(out, *flag, format);
315*9356374aSAndroid Build Coastguard Worker       }
316*9356374aSAndroid Build Coastguard Worker     }
317*9356374aSAndroid Build Coastguard Worker   }
318*9356374aSAndroid Build Coastguard Worker 
319*9356374aSAndroid Build Coastguard Worker   if (format == HelpFormat::kHumanReadable) {
320*9356374aSAndroid Build Coastguard Worker     FlagHelpPrettyPrinter printer(kHrfMaxLineLength, 0, 0, out);
321*9356374aSAndroid Build Coastguard Worker 
322*9356374aSAndroid Build Coastguard Worker     if (filter_cb && matching_flags.empty()) {
323*9356374aSAndroid Build Coastguard Worker       printer.Write("No flags matched.\n", true);
324*9356374aSAndroid Build Coastguard Worker     }
325*9356374aSAndroid Build Coastguard Worker     printer.EndLine();
326*9356374aSAndroid Build Coastguard Worker     printer.Write(
327*9356374aSAndroid Build Coastguard Worker         "Try --helpfull to get a list of all flags or --help=substring "
328*9356374aSAndroid Build Coastguard Worker         "shows help for flags which include specified substring in either "
329*9356374aSAndroid Build Coastguard Worker         "in the name, or description or path.\n",
330*9356374aSAndroid Build Coastguard Worker         true);
331*9356374aSAndroid Build Coastguard Worker   } else {
332*9356374aSAndroid Build Coastguard Worker     // The end of the document.
333*9356374aSAndroid Build Coastguard Worker     out << "</AllFlags>\n";
334*9356374aSAndroid Build Coastguard Worker   }
335*9356374aSAndroid Build Coastguard Worker }
336*9356374aSAndroid Build Coastguard Worker 
FlagsHelpImpl(std::ostream & out,flags_internal::FlagKindFilter filename_filter_cb,HelpFormat format,absl::string_view program_usage_message)337*9356374aSAndroid Build Coastguard Worker void FlagsHelpImpl(std::ostream& out,
338*9356374aSAndroid Build Coastguard Worker                    flags_internal::FlagKindFilter filename_filter_cb,
339*9356374aSAndroid Build Coastguard Worker                    HelpFormat format, absl::string_view program_usage_message) {
340*9356374aSAndroid Build Coastguard Worker   FlagsHelpImpl(
341*9356374aSAndroid Build Coastguard Worker       out,
342*9356374aSAndroid Build Coastguard Worker       [&](const absl::CommandLineFlag& flag) {
343*9356374aSAndroid Build Coastguard Worker         return filename_filter_cb && filename_filter_cb(flag.Filename());
344*9356374aSAndroid Build Coastguard Worker       },
345*9356374aSAndroid Build Coastguard Worker       format, program_usage_message);
346*9356374aSAndroid Build Coastguard Worker }
347*9356374aSAndroid Build Coastguard Worker 
348*9356374aSAndroid Build Coastguard Worker }  // namespace
349*9356374aSAndroid Build Coastguard Worker 
350*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
351*9356374aSAndroid Build Coastguard Worker // Produces the help message describing specific flag.
FlagHelp(std::ostream & out,const CommandLineFlag & flag,HelpFormat format)352*9356374aSAndroid Build Coastguard Worker void FlagHelp(std::ostream& out, const CommandLineFlag& flag,
353*9356374aSAndroid Build Coastguard Worker               HelpFormat format) {
354*9356374aSAndroid Build Coastguard Worker   if (format == HelpFormat::kHumanReadable)
355*9356374aSAndroid Build Coastguard Worker     flags_internal::FlagHelpHumanReadable(flag, out);
356*9356374aSAndroid Build Coastguard Worker }
357*9356374aSAndroid Build Coastguard Worker 
358*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
359*9356374aSAndroid Build Coastguard Worker // Produces the help messages for all flags matching the filename filter.
360*9356374aSAndroid Build Coastguard Worker // If filter is empty produces help messages for all flags.
FlagsHelp(std::ostream & out,absl::string_view filter,HelpFormat format,absl::string_view program_usage_message)361*9356374aSAndroid Build Coastguard Worker void FlagsHelp(std::ostream& out, absl::string_view filter, HelpFormat format,
362*9356374aSAndroid Build Coastguard Worker                absl::string_view program_usage_message) {
363*9356374aSAndroid Build Coastguard Worker   flags_internal::FlagKindFilter filter_cb = [&](absl::string_view filename) {
364*9356374aSAndroid Build Coastguard Worker     return filter.empty() || absl::StrContains(filename, filter);
365*9356374aSAndroid Build Coastguard Worker   };
366*9356374aSAndroid Build Coastguard Worker   flags_internal::FlagsHelpImpl(out, filter_cb, format, program_usage_message);
367*9356374aSAndroid Build Coastguard Worker }
368*9356374aSAndroid Build Coastguard Worker 
369*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
370*9356374aSAndroid Build Coastguard Worker // Checks all the 'usage' command line flags to see if any have been set.
371*9356374aSAndroid Build Coastguard Worker // If so, handles them appropriately.
HandleUsageFlags(std::ostream & out,absl::string_view program_usage_message)372*9356374aSAndroid Build Coastguard Worker HelpMode HandleUsageFlags(std::ostream& out,
373*9356374aSAndroid Build Coastguard Worker                           absl::string_view program_usage_message) {
374*9356374aSAndroid Build Coastguard Worker   switch (GetFlagsHelpMode()) {
375*9356374aSAndroid Build Coastguard Worker     case HelpMode::kNone:
376*9356374aSAndroid Build Coastguard Worker       break;
377*9356374aSAndroid Build Coastguard Worker     case HelpMode::kImportant:
378*9356374aSAndroid Build Coastguard Worker       flags_internal::FlagsHelpImpl(
379*9356374aSAndroid Build Coastguard Worker           out, flags_internal::GetUsageConfig().contains_help_flags,
380*9356374aSAndroid Build Coastguard Worker           GetFlagsHelpFormat(), program_usage_message);
381*9356374aSAndroid Build Coastguard Worker       break;
382*9356374aSAndroid Build Coastguard Worker 
383*9356374aSAndroid Build Coastguard Worker     case HelpMode::kShort:
384*9356374aSAndroid Build Coastguard Worker       flags_internal::FlagsHelpImpl(
385*9356374aSAndroid Build Coastguard Worker           out, flags_internal::GetUsageConfig().contains_helpshort_flags,
386*9356374aSAndroid Build Coastguard Worker           GetFlagsHelpFormat(), program_usage_message);
387*9356374aSAndroid Build Coastguard Worker       break;
388*9356374aSAndroid Build Coastguard Worker 
389*9356374aSAndroid Build Coastguard Worker     case HelpMode::kFull:
390*9356374aSAndroid Build Coastguard Worker       flags_internal::FlagsHelp(out, "", GetFlagsHelpFormat(),
391*9356374aSAndroid Build Coastguard Worker                                 program_usage_message);
392*9356374aSAndroid Build Coastguard Worker       break;
393*9356374aSAndroid Build Coastguard Worker 
394*9356374aSAndroid Build Coastguard Worker     case HelpMode::kPackage:
395*9356374aSAndroid Build Coastguard Worker       flags_internal::FlagsHelpImpl(
396*9356374aSAndroid Build Coastguard Worker           out, flags_internal::GetUsageConfig().contains_helppackage_flags,
397*9356374aSAndroid Build Coastguard Worker           GetFlagsHelpFormat(), program_usage_message);
398*9356374aSAndroid Build Coastguard Worker       break;
399*9356374aSAndroid Build Coastguard Worker 
400*9356374aSAndroid Build Coastguard Worker     case HelpMode::kMatch: {
401*9356374aSAndroid Build Coastguard Worker       std::string substr = GetFlagsHelpMatchSubstr();
402*9356374aSAndroid Build Coastguard Worker       if (substr.empty()) {
403*9356374aSAndroid Build Coastguard Worker         // show all options
404*9356374aSAndroid Build Coastguard Worker         flags_internal::FlagsHelp(out, substr, GetFlagsHelpFormat(),
405*9356374aSAndroid Build Coastguard Worker                                   program_usage_message);
406*9356374aSAndroid Build Coastguard Worker       } else {
407*9356374aSAndroid Build Coastguard Worker         auto filter_cb = [&substr](const absl::CommandLineFlag& flag) {
408*9356374aSAndroid Build Coastguard Worker           if (absl::StrContains(flag.Name(), substr)) return true;
409*9356374aSAndroid Build Coastguard Worker           if (absl::StrContains(flag.Filename(), substr)) return true;
410*9356374aSAndroid Build Coastguard Worker           if (absl::StrContains(flag.Help(), substr)) return true;
411*9356374aSAndroid Build Coastguard Worker 
412*9356374aSAndroid Build Coastguard Worker           return false;
413*9356374aSAndroid Build Coastguard Worker         };
414*9356374aSAndroid Build Coastguard Worker         flags_internal::FlagsHelpImpl(
415*9356374aSAndroid Build Coastguard Worker             out, filter_cb, HelpFormat::kHumanReadable, program_usage_message);
416*9356374aSAndroid Build Coastguard Worker       }
417*9356374aSAndroid Build Coastguard Worker       break;
418*9356374aSAndroid Build Coastguard Worker     }
419*9356374aSAndroid Build Coastguard Worker     case HelpMode::kVersion:
420*9356374aSAndroid Build Coastguard Worker       if (flags_internal::GetUsageConfig().version_string)
421*9356374aSAndroid Build Coastguard Worker         out << flags_internal::GetUsageConfig().version_string();
422*9356374aSAndroid Build Coastguard Worker       // Unlike help, we may be asking for version in a script, so return 0
423*9356374aSAndroid Build Coastguard Worker       break;
424*9356374aSAndroid Build Coastguard Worker 
425*9356374aSAndroid Build Coastguard Worker     case HelpMode::kOnlyCheckArgs:
426*9356374aSAndroid Build Coastguard Worker       break;
427*9356374aSAndroid Build Coastguard Worker   }
428*9356374aSAndroid Build Coastguard Worker 
429*9356374aSAndroid Build Coastguard Worker   return GetFlagsHelpMode();
430*9356374aSAndroid Build Coastguard Worker }
431*9356374aSAndroid Build Coastguard Worker 
432*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
433*9356374aSAndroid Build Coastguard Worker // Globals representing usage reporting flags
434*9356374aSAndroid Build Coastguard Worker 
435*9356374aSAndroid Build Coastguard Worker namespace {
436*9356374aSAndroid Build Coastguard Worker 
437*9356374aSAndroid Build Coastguard Worker ABSL_CONST_INIT absl::Mutex help_attributes_guard(absl::kConstInit);
438*9356374aSAndroid Build Coastguard Worker ABSL_CONST_INIT std::string* match_substr
439*9356374aSAndroid Build Coastguard Worker     ABSL_GUARDED_BY(help_attributes_guard) = nullptr;
440*9356374aSAndroid Build Coastguard Worker ABSL_CONST_INIT HelpMode help_mode ABSL_GUARDED_BY(help_attributes_guard) =
441*9356374aSAndroid Build Coastguard Worker     HelpMode::kNone;
442*9356374aSAndroid Build Coastguard Worker ABSL_CONST_INIT HelpFormat help_format ABSL_GUARDED_BY(help_attributes_guard) =
443*9356374aSAndroid Build Coastguard Worker     HelpFormat::kHumanReadable;
444*9356374aSAndroid Build Coastguard Worker 
445*9356374aSAndroid Build Coastguard Worker }  // namespace
446*9356374aSAndroid Build Coastguard Worker 
GetFlagsHelpMatchSubstr()447*9356374aSAndroid Build Coastguard Worker std::string GetFlagsHelpMatchSubstr() {
448*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
449*9356374aSAndroid Build Coastguard Worker   if (match_substr == nullptr) return "";
450*9356374aSAndroid Build Coastguard Worker   return *match_substr;
451*9356374aSAndroid Build Coastguard Worker }
452*9356374aSAndroid Build Coastguard Worker 
SetFlagsHelpMatchSubstr(absl::string_view substr)453*9356374aSAndroid Build Coastguard Worker void SetFlagsHelpMatchSubstr(absl::string_view substr) {
454*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
455*9356374aSAndroid Build Coastguard Worker   if (match_substr == nullptr) match_substr = new std::string;
456*9356374aSAndroid Build Coastguard Worker   match_substr->assign(substr.data(), substr.size());
457*9356374aSAndroid Build Coastguard Worker }
458*9356374aSAndroid Build Coastguard Worker 
GetFlagsHelpMode()459*9356374aSAndroid Build Coastguard Worker HelpMode GetFlagsHelpMode() {
460*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
461*9356374aSAndroid Build Coastguard Worker   return help_mode;
462*9356374aSAndroid Build Coastguard Worker }
463*9356374aSAndroid Build Coastguard Worker 
SetFlagsHelpMode(HelpMode mode)464*9356374aSAndroid Build Coastguard Worker void SetFlagsHelpMode(HelpMode mode) {
465*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
466*9356374aSAndroid Build Coastguard Worker   help_mode = mode;
467*9356374aSAndroid Build Coastguard Worker }
468*9356374aSAndroid Build Coastguard Worker 
GetFlagsHelpFormat()469*9356374aSAndroid Build Coastguard Worker HelpFormat GetFlagsHelpFormat() {
470*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
471*9356374aSAndroid Build Coastguard Worker   return help_format;
472*9356374aSAndroid Build Coastguard Worker }
473*9356374aSAndroid Build Coastguard Worker 
SetFlagsHelpFormat(HelpFormat format)474*9356374aSAndroid Build Coastguard Worker void SetFlagsHelpFormat(HelpFormat format) {
475*9356374aSAndroid Build Coastguard Worker   absl::MutexLock l(&help_attributes_guard);
476*9356374aSAndroid Build Coastguard Worker   help_format = format;
477*9356374aSAndroid Build Coastguard Worker }
478*9356374aSAndroid Build Coastguard Worker 
479*9356374aSAndroid Build Coastguard Worker // Deduces usage flags from the input argument in a form --name=value or
480*9356374aSAndroid Build Coastguard Worker // --name. argument is already split into name and value before we call this
481*9356374aSAndroid Build Coastguard Worker // function.
DeduceUsageFlags(absl::string_view name,absl::string_view value)482*9356374aSAndroid Build Coastguard Worker bool DeduceUsageFlags(absl::string_view name, absl::string_view value) {
483*9356374aSAndroid Build Coastguard Worker   if (absl::ConsumePrefix(&name, "help")) {
484*9356374aSAndroid Build Coastguard Worker     if (name.empty()) {
485*9356374aSAndroid Build Coastguard Worker       if (value.empty()) {
486*9356374aSAndroid Build Coastguard Worker         SetFlagsHelpMode(HelpMode::kImportant);
487*9356374aSAndroid Build Coastguard Worker       } else {
488*9356374aSAndroid Build Coastguard Worker         SetFlagsHelpMode(HelpMode::kMatch);
489*9356374aSAndroid Build Coastguard Worker         SetFlagsHelpMatchSubstr(value);
490*9356374aSAndroid Build Coastguard Worker       }
491*9356374aSAndroid Build Coastguard Worker       return true;
492*9356374aSAndroid Build Coastguard Worker     }
493*9356374aSAndroid Build Coastguard Worker 
494*9356374aSAndroid Build Coastguard Worker     if (name == "match") {
495*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMode(HelpMode::kMatch);
496*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMatchSubstr(value);
497*9356374aSAndroid Build Coastguard Worker       return true;
498*9356374aSAndroid Build Coastguard Worker     }
499*9356374aSAndroid Build Coastguard Worker 
500*9356374aSAndroid Build Coastguard Worker     if (name == "on") {
501*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMode(HelpMode::kMatch);
502*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMatchSubstr(absl::StrCat("/", value, "."));
503*9356374aSAndroid Build Coastguard Worker       return true;
504*9356374aSAndroid Build Coastguard Worker     }
505*9356374aSAndroid Build Coastguard Worker 
506*9356374aSAndroid Build Coastguard Worker     if (name == "full") {
507*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMode(HelpMode::kFull);
508*9356374aSAndroid Build Coastguard Worker       return true;
509*9356374aSAndroid Build Coastguard Worker     }
510*9356374aSAndroid Build Coastguard Worker 
511*9356374aSAndroid Build Coastguard Worker     if (name == "short") {
512*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMode(HelpMode::kShort);
513*9356374aSAndroid Build Coastguard Worker       return true;
514*9356374aSAndroid Build Coastguard Worker     }
515*9356374aSAndroid Build Coastguard Worker 
516*9356374aSAndroid Build Coastguard Worker     if (name == "package") {
517*9356374aSAndroid Build Coastguard Worker       SetFlagsHelpMode(HelpMode::kPackage);
518*9356374aSAndroid Build Coastguard Worker       return true;
519*9356374aSAndroid Build Coastguard Worker     }
520*9356374aSAndroid Build Coastguard Worker 
521*9356374aSAndroid Build Coastguard Worker     return false;
522*9356374aSAndroid Build Coastguard Worker   }
523*9356374aSAndroid Build Coastguard Worker 
524*9356374aSAndroid Build Coastguard Worker   if (name == "version") {
525*9356374aSAndroid Build Coastguard Worker     SetFlagsHelpMode(HelpMode::kVersion);
526*9356374aSAndroid Build Coastguard Worker     return true;
527*9356374aSAndroid Build Coastguard Worker   }
528*9356374aSAndroid Build Coastguard Worker 
529*9356374aSAndroid Build Coastguard Worker   if (name == "only_check_args") {
530*9356374aSAndroid Build Coastguard Worker     SetFlagsHelpMode(HelpMode::kOnlyCheckArgs);
531*9356374aSAndroid Build Coastguard Worker     return true;
532*9356374aSAndroid Build Coastguard Worker   }
533*9356374aSAndroid Build Coastguard Worker 
534*9356374aSAndroid Build Coastguard Worker   return false;
535*9356374aSAndroid Build Coastguard Worker }
536*9356374aSAndroid Build Coastguard Worker 
537*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
538*9356374aSAndroid Build Coastguard Worker 
MaybeExit(HelpMode mode)539*9356374aSAndroid Build Coastguard Worker void MaybeExit(HelpMode mode) {
540*9356374aSAndroid Build Coastguard Worker   switch (mode) {
541*9356374aSAndroid Build Coastguard Worker     case flags_internal::HelpMode::kNone:
542*9356374aSAndroid Build Coastguard Worker       return;
543*9356374aSAndroid Build Coastguard Worker     case flags_internal::HelpMode::kOnlyCheckArgs:
544*9356374aSAndroid Build Coastguard Worker     case flags_internal::HelpMode::kVersion:
545*9356374aSAndroid Build Coastguard Worker       std::exit(0);
546*9356374aSAndroid Build Coastguard Worker     default:  // For all the other modes we exit with 1
547*9356374aSAndroid Build Coastguard Worker       std::exit(1);
548*9356374aSAndroid Build Coastguard Worker   }
549*9356374aSAndroid Build Coastguard Worker }
550*9356374aSAndroid Build Coastguard Worker 
551*9356374aSAndroid Build Coastguard Worker // --------------------------------------------------------------------
552*9356374aSAndroid Build Coastguard Worker 
553*9356374aSAndroid Build Coastguard Worker }  // namespace flags_internal
554*9356374aSAndroid Build Coastguard Worker ABSL_NAMESPACE_END
555*9356374aSAndroid Build Coastguard Worker }  // namespace absl
556