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 & 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 << """;
87*9356374aSAndroid Build Coastguard Worker break;
88*9356374aSAndroid Build Coastguard Worker case '\'':
89*9356374aSAndroid Build Coastguard Worker out << "'";
90*9356374aSAndroid Build Coastguard Worker break;
91*9356374aSAndroid Build Coastguard Worker case '&':
92*9356374aSAndroid Build Coastguard Worker out << "&";
93*9356374aSAndroid Build Coastguard Worker break;
94*9356374aSAndroid Build Coastguard Worker case '<':
95*9356374aSAndroid Build Coastguard Worker out << "<";
96*9356374aSAndroid Build Coastguard Worker break;
97*9356374aSAndroid Build Coastguard Worker case '>':
98*9356374aSAndroid Build Coastguard Worker out << ">";
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