xref: /aosp_15_r20/art/cmdline/cmdline_parser.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_CMDLINE_CMDLINE_PARSER_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_CMDLINE_CMDLINE_PARSER_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #define CMDLINE_NDEBUG 1  // Do not output any debugging information for parsing.
21*795d594fSAndroid Build Coastguard Worker 
22*795d594fSAndroid Build Coastguard Worker #include <memory>
23*795d594fSAndroid Build Coastguard Worker #include <optional>
24*795d594fSAndroid Build Coastguard Worker #include <string>
25*795d594fSAndroid Build Coastguard Worker #include <string_view>
26*795d594fSAndroid Build Coastguard Worker #include <tuple>
27*795d594fSAndroid Build Coastguard Worker #include <unordered_map>
28*795d594fSAndroid Build Coastguard Worker #include <unordered_set>
29*795d594fSAndroid Build Coastguard Worker #include <vector>
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker #include "base/indenter.h"
32*795d594fSAndroid Build Coastguard Worker #include "base/variant_map.h"
33*795d594fSAndroid Build Coastguard Worker #include "cmdline_parse_result.h"
34*795d594fSAndroid Build Coastguard Worker #include "cmdline_result.h"
35*795d594fSAndroid Build Coastguard Worker #include "cmdline_type_parser.h"
36*795d594fSAndroid Build Coastguard Worker #include "cmdline_types.h"
37*795d594fSAndroid Build Coastguard Worker #include "detail/cmdline_debug_detail.h"
38*795d594fSAndroid Build Coastguard Worker #include "detail/cmdline_parse_argument_detail.h"
39*795d594fSAndroid Build Coastguard Worker #include "detail/cmdline_parser_detail.h"
40*795d594fSAndroid Build Coastguard Worker #include "token_range.h"
41*795d594fSAndroid Build Coastguard Worker 
42*795d594fSAndroid Build Coastguard Worker namespace art {
43*795d594fSAndroid Build Coastguard Worker // Build a parser for command line arguments with a small domain specific language.
44*795d594fSAndroid Build Coastguard Worker // Each parsed type must have a specialized CmdlineType<T> in order to do the string->T parsing.
45*795d594fSAndroid Build Coastguard Worker // Each argument must also have a VariantMap::Key<T> in order to do the T storage.
46*795d594fSAndroid Build Coastguard Worker template <typename TVariantMap,
47*795d594fSAndroid Build Coastguard Worker           template <typename TKeyValue> class TVariantMapKey>
48*795d594fSAndroid Build Coastguard Worker struct CmdlineParser {
49*795d594fSAndroid Build Coastguard Worker   template <typename TArg>
50*795d594fSAndroid Build Coastguard Worker   struct ArgumentBuilder;
51*795d594fSAndroid Build Coastguard Worker 
52*795d594fSAndroid Build Coastguard Worker   struct Builder;  // Build the parser.
53*795d594fSAndroid Build Coastguard Worker   struct UntypedArgumentBuilder;  // Build arguments which weren't yet given a type.
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker  private:
56*795d594fSAndroid Build Coastguard Worker   // Forward declare some functions that we need to use before fully-defining structs.
57*795d594fSAndroid Build Coastguard Worker   template <typename TArg>
58*795d594fSAndroid Build Coastguard Worker   static ArgumentBuilder<TArg> CreateArgumentBuilder(Builder& parent);
59*795d594fSAndroid Build Coastguard Worker   static void AppendCompletedArgument(Builder& builder, detail::CmdlineParseArgumentAny* arg);
60*795d594fSAndroid Build Coastguard Worker 
61*795d594fSAndroid Build Coastguard Worker   // Allow argument definitions to save their values when they are parsed,
62*795d594fSAndroid Build Coastguard Worker   // without having a dependency on CmdlineParser or any of the builders.
63*795d594fSAndroid Build Coastguard Worker   //
64*795d594fSAndroid Build Coastguard Worker   // A shared pointer to the save destination is saved into the load/save argument callbacks.
65*795d594fSAndroid Build Coastguard Worker   //
66*795d594fSAndroid Build Coastguard Worker   // This also allows the underlying storage (i.e. a variant map) to be released
67*795d594fSAndroid Build Coastguard Worker   // to the user, without having to recreate all of the callbacks.
68*795d594fSAndroid Build Coastguard Worker   struct SaveDestination {
SaveDestinationCmdlineParser::SaveDestination69*795d594fSAndroid Build Coastguard Worker     SaveDestination() : variant_map_(new TVariantMap()) {}
70*795d594fSAndroid Build Coastguard Worker 
71*795d594fSAndroid Build Coastguard Worker     // Save value to the variant map.
72*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
SaveToMapCmdlineParser::SaveDestination73*795d594fSAndroid Build Coastguard Worker     void SaveToMap(const TVariantMapKey<TArg>& key, TArg& value) {
74*795d594fSAndroid Build Coastguard Worker       variant_map_->Set(key, value);
75*795d594fSAndroid Build Coastguard Worker     }
76*795d594fSAndroid Build Coastguard Worker 
77*795d594fSAndroid Build Coastguard Worker     // Get the existing value from a map, creating the value if it did not already exist.
78*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
GetOrCreateFromMapCmdlineParser::SaveDestination79*795d594fSAndroid Build Coastguard Worker     TArg& GetOrCreateFromMap(const TVariantMapKey<TArg>& key) {
80*795d594fSAndroid Build Coastguard Worker       auto* ptr = variant_map_->Get(key);
81*795d594fSAndroid Build Coastguard Worker       if (ptr == nullptr) {
82*795d594fSAndroid Build Coastguard Worker         variant_map_->Set(key, TArg());
83*795d594fSAndroid Build Coastguard Worker         ptr = variant_map_->Get(key);
84*795d594fSAndroid Build Coastguard Worker         assert(ptr != nullptr);
85*795d594fSAndroid Build Coastguard Worker       }
86*795d594fSAndroid Build Coastguard Worker 
87*795d594fSAndroid Build Coastguard Worker       return *ptr;
88*795d594fSAndroid Build Coastguard Worker     }
89*795d594fSAndroid Build Coastguard Worker 
90*795d594fSAndroid Build Coastguard Worker    protected:
91*795d594fSAndroid Build Coastguard Worker     // Release the map, clearing it as a side-effect.
92*795d594fSAndroid Build Coastguard Worker     // Future saves will be distinct from previous saves.
ReleaseMapCmdlineParser::SaveDestination93*795d594fSAndroid Build Coastguard Worker     TVariantMap&& ReleaseMap() {
94*795d594fSAndroid Build Coastguard Worker       return std::move(*variant_map_);
95*795d594fSAndroid Build Coastguard Worker     }
96*795d594fSAndroid Build Coastguard Worker 
97*795d594fSAndroid Build Coastguard Worker     // Get a read-only reference to the variant map.
GetMapCmdlineParser::SaveDestination98*795d594fSAndroid Build Coastguard Worker     const TVariantMap& GetMap() {
99*795d594fSAndroid Build Coastguard Worker       return *variant_map_;
100*795d594fSAndroid Build Coastguard Worker     }
101*795d594fSAndroid Build Coastguard Worker 
102*795d594fSAndroid Build Coastguard Worker     // Clear all potential save targets.
ClearCmdlineParser::SaveDestination103*795d594fSAndroid Build Coastguard Worker     void Clear() {
104*795d594fSAndroid Build Coastguard Worker       variant_map_->Clear();
105*795d594fSAndroid Build Coastguard Worker     }
106*795d594fSAndroid Build Coastguard Worker 
107*795d594fSAndroid Build Coastguard Worker    private:
108*795d594fSAndroid Build Coastguard Worker     // Don't try to copy or move this. Just don't.
109*795d594fSAndroid Build Coastguard Worker     SaveDestination(const SaveDestination&) = delete;
110*795d594fSAndroid Build Coastguard Worker     SaveDestination(SaveDestination&&) = delete;
111*795d594fSAndroid Build Coastguard Worker     SaveDestination& operator=(const SaveDestination&) = delete;
112*795d594fSAndroid Build Coastguard Worker     SaveDestination& operator=(SaveDestination&&) = delete;
113*795d594fSAndroid Build Coastguard Worker 
114*795d594fSAndroid Build Coastguard Worker     std::shared_ptr<TVariantMap> variant_map_;
115*795d594fSAndroid Build Coastguard Worker 
116*795d594fSAndroid Build Coastguard Worker     // Allow the parser to change the underlying pointers when we release the underlying storage.
117*795d594fSAndroid Build Coastguard Worker     friend struct CmdlineParser;
118*795d594fSAndroid Build Coastguard Worker   };
119*795d594fSAndroid Build Coastguard Worker 
120*795d594fSAndroid Build Coastguard Worker  public:
121*795d594fSAndroid Build Coastguard Worker   // Builder for the argument definition of type TArg. Do not use this type directly,
122*795d594fSAndroid Build Coastguard Worker   // it is only a separate type to provide compile-time enforcement against doing
123*795d594fSAndroid Build Coastguard Worker   // illegal builds.
124*795d594fSAndroid Build Coastguard Worker   template <typename TArg>
125*795d594fSAndroid Build Coastguard Worker   struct ArgumentBuilder {
126*795d594fSAndroid Build Coastguard Worker     // Add a range check to this argument.
WithRangeCmdlineParser::ArgumentBuilder127*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& WithRange(const TArg& min, const TArg& max) {
128*795d594fSAndroid Build Coastguard Worker       argument_info_.has_range_ = true;
129*795d594fSAndroid Build Coastguard Worker       argument_info_.min_ = min;
130*795d594fSAndroid Build Coastguard Worker       argument_info_.max_ = max;
131*795d594fSAndroid Build Coastguard Worker 
132*795d594fSAndroid Build Coastguard Worker       return *this;
133*795d594fSAndroid Build Coastguard Worker     }
134*795d594fSAndroid Build Coastguard Worker 
135*795d594fSAndroid Build Coastguard Worker     // Map the list of names into the list of values. List of names must not have
136*795d594fSAndroid Build Coastguard Worker     // any wildcards '_' in it.
137*795d594fSAndroid Build Coastguard Worker     //
138*795d594fSAndroid Build Coastguard Worker     // Do not use if a value map has already been set.
WithValuesCmdlineParser::ArgumentBuilder139*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& WithValues(std::initializer_list<TArg> value_list) {
140*795d594fSAndroid Build Coastguard Worker       SetValuesInternal(value_list);
141*795d594fSAndroid Build Coastguard Worker       return *this;
142*795d594fSAndroid Build Coastguard Worker     }
143*795d594fSAndroid Build Coastguard Worker 
144*795d594fSAndroid Build Coastguard Worker     // When used with a single alias, map the alias into this value.
145*795d594fSAndroid Build Coastguard Worker     // Same as 'WithValues({value})' , but allows the omission of the curly braces {}.
WithValueCmdlineParser::ArgumentBuilder146*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg> WithValue(const TArg& value) {
147*795d594fSAndroid Build Coastguard Worker       return WithValues({ value });
148*795d594fSAndroid Build Coastguard Worker     }
149*795d594fSAndroid Build Coastguard Worker 
150*795d594fSAndroid Build Coastguard Worker     // Map the parsed string values (from _) onto a concrete value. If no wildcard
151*795d594fSAndroid Build Coastguard Worker     // has been specified, then map the value directly from the arg name (i.e.
152*795d594fSAndroid Build Coastguard Worker     // if there are multiple aliases, then use the alias to do the mapping).
153*795d594fSAndroid Build Coastguard Worker     //
154*795d594fSAndroid Build Coastguard Worker     // Do not use if a values list has already been set.
WithValueMapCmdlineParser::ArgumentBuilder155*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& WithValueMap(
156*795d594fSAndroid Build Coastguard Worker         std::initializer_list<std::pair<const char*, TArg>> key_value_list) {
157*795d594fSAndroid Build Coastguard Worker       assert(!argument_info_.has_value_list_);
158*795d594fSAndroid Build Coastguard Worker 
159*795d594fSAndroid Build Coastguard Worker       argument_info_.has_value_map_ = true;
160*795d594fSAndroid Build Coastguard Worker       argument_info_.value_map_ = key_value_list;
161*795d594fSAndroid Build Coastguard Worker 
162*795d594fSAndroid Build Coastguard Worker       return *this;
163*795d594fSAndroid Build Coastguard Worker     }
164*795d594fSAndroid Build Coastguard Worker 
165*795d594fSAndroid Build Coastguard Worker     // If this argument is seen multiple times, successive arguments mutate the same value
166*795d594fSAndroid Build Coastguard Worker     // instead of replacing it with a new value.
AppendValuesCmdlineParser::ArgumentBuilder167*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& AppendValues() {
168*795d594fSAndroid Build Coastguard Worker       argument_info_.appending_values_ = true;
169*795d594fSAndroid Build Coastguard Worker 
170*795d594fSAndroid Build Coastguard Worker       return *this;
171*795d594fSAndroid Build Coastguard Worker     }
172*795d594fSAndroid Build Coastguard Worker 
WithMetavarCmdlineParser::ArgumentBuilder173*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& WithMetavar(const char* sv) {
174*795d594fSAndroid Build Coastguard Worker       argument_info_.metavar_ = sv;
175*795d594fSAndroid Build Coastguard Worker       return *this;
176*795d594fSAndroid Build Coastguard Worker     }
177*795d594fSAndroid Build Coastguard Worker 
WithHelpCmdlineParser::ArgumentBuilder178*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg>& WithHelp(const char* sv) {
179*795d594fSAndroid Build Coastguard Worker       argument_info_.help_ = sv;
180*795d594fSAndroid Build Coastguard Worker       return *this;
181*795d594fSAndroid Build Coastguard Worker     }
182*795d594fSAndroid Build Coastguard Worker 
183*795d594fSAndroid Build Coastguard Worker     // Convenience type alias for the variant map key type definition.
184*795d594fSAndroid Build Coastguard Worker     using MapKey = TVariantMapKey<TArg>;
185*795d594fSAndroid Build Coastguard Worker 
186*795d594fSAndroid Build Coastguard Worker     // Write the results of this argument into the key.
187*795d594fSAndroid Build Coastguard Worker     // To look up the parsed arguments, get the map and then use this key with VariantMap::Get
IntoKeyCmdlineParser::ArgumentBuilder188*795d594fSAndroid Build Coastguard Worker     CmdlineParser::Builder& IntoKey(const MapKey& key) {
189*795d594fSAndroid Build Coastguard Worker       // Only capture save destination as a pointer.
190*795d594fSAndroid Build Coastguard Worker       // This allows the parser to later on change the specific save targets.
191*795d594fSAndroid Build Coastguard Worker       auto save_destination = save_destination_;
192*795d594fSAndroid Build Coastguard Worker       save_value_ = [save_destination, &key](TArg& value) {
193*795d594fSAndroid Build Coastguard Worker         save_destination->SaveToMap(key, value);
194*795d594fSAndroid Build Coastguard Worker         CMDLINE_DEBUG_LOG << "Saved value into map '"
195*795d594fSAndroid Build Coastguard Worker             << detail::ToStringAny(value) << "'" << std::endl;
196*795d594fSAndroid Build Coastguard Worker       };
197*795d594fSAndroid Build Coastguard Worker 
198*795d594fSAndroid Build Coastguard Worker       load_value_ = [save_destination, &key]() -> TArg& {
199*795d594fSAndroid Build Coastguard Worker         TArg& value = save_destination->GetOrCreateFromMap(key);
200*795d594fSAndroid Build Coastguard Worker         CMDLINE_DEBUG_LOG << "Loaded value from map '" << detail::ToStringAny(value) << "'"
201*795d594fSAndroid Build Coastguard Worker             << std::endl;
202*795d594fSAndroid Build Coastguard Worker 
203*795d594fSAndroid Build Coastguard Worker         return value;
204*795d594fSAndroid Build Coastguard Worker       };
205*795d594fSAndroid Build Coastguard Worker 
206*795d594fSAndroid Build Coastguard Worker       save_value_specified_ = true;
207*795d594fSAndroid Build Coastguard Worker       load_value_specified_ = true;
208*795d594fSAndroid Build Coastguard Worker 
209*795d594fSAndroid Build Coastguard Worker       CompleteArgument();
210*795d594fSAndroid Build Coastguard Worker       return parent_;
211*795d594fSAndroid Build Coastguard Worker     }
212*795d594fSAndroid Build Coastguard Worker 
213*795d594fSAndroid Build Coastguard Worker     // Write the results of this argument into a variable pointed to by destination.
214*795d594fSAndroid Build Coastguard Worker     // An optional is used to tell whether the command line argument was present.
IntoLocationCmdlineParser::ArgumentBuilder215*795d594fSAndroid Build Coastguard Worker     CmdlineParser::Builder& IntoLocation(std::optional<TArg>* destination) {
216*795d594fSAndroid Build Coastguard Worker       save_value_ = [destination](TArg& value) {
217*795d594fSAndroid Build Coastguard Worker         *destination = value;
218*795d594fSAndroid Build Coastguard Worker       };
219*795d594fSAndroid Build Coastguard Worker 
220*795d594fSAndroid Build Coastguard Worker       load_value_ = [destination]() -> TArg& {
221*795d594fSAndroid Build Coastguard Worker         return destination->value();
222*795d594fSAndroid Build Coastguard Worker       };
223*795d594fSAndroid Build Coastguard Worker 
224*795d594fSAndroid Build Coastguard Worker       save_value_specified_ = true;
225*795d594fSAndroid Build Coastguard Worker       load_value_specified_ = true;
226*795d594fSAndroid Build Coastguard Worker 
227*795d594fSAndroid Build Coastguard Worker       CompleteArgument();
228*795d594fSAndroid Build Coastguard Worker       return parent_;
229*795d594fSAndroid Build Coastguard Worker     }
230*795d594fSAndroid Build Coastguard Worker 
231*795d594fSAndroid Build Coastguard Worker     // Ensure we always move this when returning a new builder.
232*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder(ArgumentBuilder&&) noexcept = default;
233*795d594fSAndroid Build Coastguard Worker 
234*795d594fSAndroid Build Coastguard Worker    protected:
235*795d594fSAndroid Build Coastguard Worker     // Used by builder to internally ignore arguments by dropping them on the floor after parsing.
IntoIgnoreCmdlineParser::ArgumentBuilder236*795d594fSAndroid Build Coastguard Worker     CmdlineParser::Builder& IntoIgnore() {
237*795d594fSAndroid Build Coastguard Worker       save_value_ = [](TArg& value) {
238*795d594fSAndroid Build Coastguard Worker         CMDLINE_DEBUG_LOG << "Ignored value '" << detail::ToStringAny(value) << "'" << std::endl;
239*795d594fSAndroid Build Coastguard Worker       };
240*795d594fSAndroid Build Coastguard Worker       load_value_ = []() -> TArg& {
241*795d594fSAndroid Build Coastguard Worker         assert(false && "Should not be appending values to ignored arguments");
242*795d594fSAndroid Build Coastguard Worker         __builtin_trap();  // Blow up.
243*795d594fSAndroid Build Coastguard Worker       };
244*795d594fSAndroid Build Coastguard Worker 
245*795d594fSAndroid Build Coastguard Worker       save_value_specified_ = true;
246*795d594fSAndroid Build Coastguard Worker       load_value_specified_ = true;
247*795d594fSAndroid Build Coastguard Worker 
248*795d594fSAndroid Build Coastguard Worker       CompleteArgument();
249*795d594fSAndroid Build Coastguard Worker       return parent_;
250*795d594fSAndroid Build Coastguard Worker     }
251*795d594fSAndroid Build Coastguard Worker 
SetValuesInternalCmdlineParser::ArgumentBuilder252*795d594fSAndroid Build Coastguard Worker     void SetValuesInternal(const std::vector<TArg>&& value_list) {
253*795d594fSAndroid Build Coastguard Worker       assert(!argument_info_.has_value_map_);
254*795d594fSAndroid Build Coastguard Worker 
255*795d594fSAndroid Build Coastguard Worker       argument_info_.has_value_list_ = true;
256*795d594fSAndroid Build Coastguard Worker       argument_info_.value_list_ = value_list;
257*795d594fSAndroid Build Coastguard Worker     }
258*795d594fSAndroid Build Coastguard Worker 
SetNamesCmdlineParser::ArgumentBuilder259*795d594fSAndroid Build Coastguard Worker     void SetNames(std::vector<const char*>&& names) {
260*795d594fSAndroid Build Coastguard Worker       argument_info_.names_ = names;
261*795d594fSAndroid Build Coastguard Worker     }
262*795d594fSAndroid Build Coastguard Worker 
SetNamesCmdlineParser::ArgumentBuilder263*795d594fSAndroid Build Coastguard Worker     void SetNames(std::initializer_list<const char*> names) {
264*795d594fSAndroid Build Coastguard Worker       argument_info_.names_ = names;
265*795d594fSAndroid Build Coastguard Worker     }
266*795d594fSAndroid Build Coastguard Worker 
SetHelpCmdlineParser::ArgumentBuilder267*795d594fSAndroid Build Coastguard Worker     void SetHelp(std::optional<const char*>&& val) {
268*795d594fSAndroid Build Coastguard Worker       argument_info_.help_ = val;
269*795d594fSAndroid Build Coastguard Worker     }
270*795d594fSAndroid Build Coastguard Worker 
SetCategoryCmdlineParser::ArgumentBuilder271*795d594fSAndroid Build Coastguard Worker     void SetCategory(std::optional<const char*>&& val) {
272*795d594fSAndroid Build Coastguard Worker       argument_info_.category_ = val;
273*795d594fSAndroid Build Coastguard Worker     }
SetMetavarCmdlineParser::ArgumentBuilder274*795d594fSAndroid Build Coastguard Worker     void SetMetavar(std::optional<const char*>&& val) {
275*795d594fSAndroid Build Coastguard Worker       argument_info_.metavar_ = val;
276*795d594fSAndroid Build Coastguard Worker     }
277*795d594fSAndroid Build Coastguard Worker 
278*795d594fSAndroid Build Coastguard Worker    private:
279*795d594fSAndroid Build Coastguard Worker     // Copying is bad. Move only.
280*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder(const ArgumentBuilder&) = delete;
281*795d594fSAndroid Build Coastguard Worker 
282*795d594fSAndroid Build Coastguard Worker     // Called by any function that doesn't chain back into this builder.
283*795d594fSAndroid Build Coastguard Worker     // Completes the argument builder and save the information into the main builder.
CompleteArgumentCmdlineParser::ArgumentBuilder284*795d594fSAndroid Build Coastguard Worker     void CompleteArgument() {
285*795d594fSAndroid Build Coastguard Worker       assert(save_value_specified_ &&
286*795d594fSAndroid Build Coastguard Worker              "No Into... function called, nowhere to save parsed values to");
287*795d594fSAndroid Build Coastguard Worker       assert(load_value_specified_ &&
288*795d594fSAndroid Build Coastguard Worker              "No Into... function called, nowhere to load parsed values from");
289*795d594fSAndroid Build Coastguard Worker 
290*795d594fSAndroid Build Coastguard Worker       argument_info_.CompleteArgument();
291*795d594fSAndroid Build Coastguard Worker 
292*795d594fSAndroid Build Coastguard Worker       // Appending the completed argument is destructive. The object is no longer
293*795d594fSAndroid Build Coastguard Worker       // usable since all the useful information got moved out of it.
294*795d594fSAndroid Build Coastguard Worker       AppendCompletedArgument(parent_,
295*795d594fSAndroid Build Coastguard Worker                               new detail::CmdlineParseArgument<TArg>(
296*795d594fSAndroid Build Coastguard Worker                                   std::move(argument_info_),
297*795d594fSAndroid Build Coastguard Worker                                   std::move(save_value_),
298*795d594fSAndroid Build Coastguard Worker                                   std::move(load_value_)));
299*795d594fSAndroid Build Coastguard Worker     }
300*795d594fSAndroid Build Coastguard Worker 
301*795d594fSAndroid Build Coastguard Worker     friend struct CmdlineParser;
302*795d594fSAndroid Build Coastguard Worker     friend struct CmdlineParser::Builder;
303*795d594fSAndroid Build Coastguard Worker     friend struct CmdlineParser::UntypedArgumentBuilder;
304*795d594fSAndroid Build Coastguard Worker 
ArgumentBuilderCmdlineParser::ArgumentBuilder305*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder(CmdlineParser::Builder& parser,
306*795d594fSAndroid Build Coastguard Worker                     std::shared_ptr<SaveDestination> save_destination)
307*795d594fSAndroid Build Coastguard Worker         : parent_(parser),
308*795d594fSAndroid Build Coastguard Worker           save_value_specified_(false),
309*795d594fSAndroid Build Coastguard Worker           load_value_specified_(false),
310*795d594fSAndroid Build Coastguard Worker           save_destination_(save_destination) {
311*795d594fSAndroid Build Coastguard Worker       save_value_ = [](TArg&) {
312*795d594fSAndroid Build Coastguard Worker         assert(false && "No save value function defined");
313*795d594fSAndroid Build Coastguard Worker       };
314*795d594fSAndroid Build Coastguard Worker 
315*795d594fSAndroid Build Coastguard Worker       load_value_ = []() -> TArg& {
316*795d594fSAndroid Build Coastguard Worker         assert(false && "No load value function defined");
317*795d594fSAndroid Build Coastguard Worker         __builtin_trap();  // Blow up.
318*795d594fSAndroid Build Coastguard Worker       };
319*795d594fSAndroid Build Coastguard Worker     }
320*795d594fSAndroid Build Coastguard Worker 
321*795d594fSAndroid Build Coastguard Worker     CmdlineParser::Builder& parent_;
322*795d594fSAndroid Build Coastguard Worker     std::function<void(TArg&)> save_value_;
323*795d594fSAndroid Build Coastguard Worker     std::function<TArg&(void)> load_value_;
324*795d594fSAndroid Build Coastguard Worker     bool save_value_specified_;
325*795d594fSAndroid Build Coastguard Worker     bool load_value_specified_;
326*795d594fSAndroid Build Coastguard Worker     detail::CmdlineParserArgumentInfo<TArg> argument_info_;
327*795d594fSAndroid Build Coastguard Worker 
328*795d594fSAndroid Build Coastguard Worker     std::shared_ptr<SaveDestination> save_destination_;
329*795d594fSAndroid Build Coastguard Worker   };
330*795d594fSAndroid Build Coastguard Worker 
331*795d594fSAndroid Build Coastguard Worker   struct UntypedArgumentBuilder {
332*795d594fSAndroid Build Coastguard Worker     // Set a type for this argument. The specific subcommand parser is looked up by the type.
333*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
WithTypeCmdlineParser::UntypedArgumentBuilder334*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg> WithType() {
335*795d594fSAndroid Build Coastguard Worker       return CreateTypedBuilder<TArg>();
336*795d594fSAndroid Build Coastguard Worker     }
337*795d594fSAndroid Build Coastguard Worker 
WithHelpCmdlineParser::UntypedArgumentBuilder338*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder& WithHelp(const char* sv) {
339*795d594fSAndroid Build Coastguard Worker       SetHelp(sv);
340*795d594fSAndroid Build Coastguard Worker       return *this;
341*795d594fSAndroid Build Coastguard Worker     }
342*795d594fSAndroid Build Coastguard Worker 
WithCategoryCmdlineParser::UntypedArgumentBuilder343*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder& WithCategory(const char* sv) {
344*795d594fSAndroid Build Coastguard Worker       SetCategory(sv);
345*795d594fSAndroid Build Coastguard Worker       return *this;
346*795d594fSAndroid Build Coastguard Worker     }
347*795d594fSAndroid Build Coastguard Worker 
WithMetavarCmdlineParser::UntypedArgumentBuilder348*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder& WithMetavar(const char* sv) {
349*795d594fSAndroid Build Coastguard Worker       SetMetavar(sv);
350*795d594fSAndroid Build Coastguard Worker       return *this;
351*795d594fSAndroid Build Coastguard Worker     }
352*795d594fSAndroid Build Coastguard Worker 
353*795d594fSAndroid Build Coastguard Worker     // When used with multiple aliases, map the position of the alias to the value position.
354*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
WithValuesCmdlineParser::UntypedArgumentBuilder355*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg> WithValues(std::initializer_list<TArg> values) {
356*795d594fSAndroid Build Coastguard Worker       auto&& a = CreateTypedBuilder<TArg>();
357*795d594fSAndroid Build Coastguard Worker       a.WithValues(values);
358*795d594fSAndroid Build Coastguard Worker       return std::move(a);
359*795d594fSAndroid Build Coastguard Worker     }
360*795d594fSAndroid Build Coastguard Worker 
361*795d594fSAndroid Build Coastguard Worker     // When used with a single alias, map the alias into this value.
362*795d594fSAndroid Build Coastguard Worker     // Same as 'WithValues({value})' , but allows the omission of the curly braces {}.
363*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
WithValueCmdlineParser::UntypedArgumentBuilder364*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg> WithValue(const TArg& value) {
365*795d594fSAndroid Build Coastguard Worker       return WithValues({ value });
366*795d594fSAndroid Build Coastguard Worker     }
367*795d594fSAndroid Build Coastguard Worker 
368*795d594fSAndroid Build Coastguard Worker     // Set the current building argument to target this key.
369*795d594fSAndroid Build Coastguard Worker     // When this command line argument is parsed, it can be fetched with this key.
IntoKeyCmdlineParser::UntypedArgumentBuilder370*795d594fSAndroid Build Coastguard Worker     Builder& IntoKey(const TVariantMapKey<Unit>& key) {
371*795d594fSAndroid Build Coastguard Worker       return CreateTypedBuilder<Unit>().IntoKey(key);
372*795d594fSAndroid Build Coastguard Worker     }
373*795d594fSAndroid Build Coastguard Worker 
374*795d594fSAndroid Build Coastguard Worker     // Ensure we always move this when returning a new builder.
375*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder(UntypedArgumentBuilder&&) noexcept = default;
376*795d594fSAndroid Build Coastguard Worker 
377*795d594fSAndroid Build Coastguard Worker    protected:
SetNamesCmdlineParser::UntypedArgumentBuilder378*795d594fSAndroid Build Coastguard Worker     void SetNames(std::vector<const char*>&& names) {
379*795d594fSAndroid Build Coastguard Worker       names_ = std::move(names);
380*795d594fSAndroid Build Coastguard Worker     }
381*795d594fSAndroid Build Coastguard Worker 
SetNamesCmdlineParser::UntypedArgumentBuilder382*795d594fSAndroid Build Coastguard Worker     void SetNames(std::initializer_list<const char*> names) {
383*795d594fSAndroid Build Coastguard Worker       names_ = names;
384*795d594fSAndroid Build Coastguard Worker     }
385*795d594fSAndroid Build Coastguard Worker 
SetHelpCmdlineParser::UntypedArgumentBuilder386*795d594fSAndroid Build Coastguard Worker     void SetHelp(std::optional<const char*> sv) {
387*795d594fSAndroid Build Coastguard Worker       help_.swap(sv);
388*795d594fSAndroid Build Coastguard Worker     }
389*795d594fSAndroid Build Coastguard Worker 
SetMetavarCmdlineParser::UntypedArgumentBuilder390*795d594fSAndroid Build Coastguard Worker     void SetMetavar(std::optional<const char*> sv) {
391*795d594fSAndroid Build Coastguard Worker       metavar_.swap(sv);
392*795d594fSAndroid Build Coastguard Worker     }
393*795d594fSAndroid Build Coastguard Worker 
SetCategoryCmdlineParser::UntypedArgumentBuilder394*795d594fSAndroid Build Coastguard Worker     void SetCategory(std::optional<const char*> sv) {
395*795d594fSAndroid Build Coastguard Worker       category_.swap(sv);
396*795d594fSAndroid Build Coastguard Worker     }
397*795d594fSAndroid Build Coastguard Worker 
398*795d594fSAndroid Build Coastguard Worker    private:
399*795d594fSAndroid Build Coastguard Worker     // No copying. Move instead.
400*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder(const UntypedArgumentBuilder&) = delete;
401*795d594fSAndroid Build Coastguard Worker 
402*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
CreateTypedBuilderCmdlineParser::UntypedArgumentBuilder403*795d594fSAndroid Build Coastguard Worker     ArgumentBuilder<TArg> CreateTypedBuilder() {
404*795d594fSAndroid Build Coastguard Worker       auto&& b = CreateArgumentBuilder<TArg>(parent_);
405*795d594fSAndroid Build Coastguard Worker       InitializeTypedBuilder(&b);  // Type-specific initialization
406*795d594fSAndroid Build Coastguard Worker       b.SetNames(std::move(names_));
407*795d594fSAndroid Build Coastguard Worker       b.SetHelp(std::move(help_));
408*795d594fSAndroid Build Coastguard Worker       b.SetCategory(std::move(category_));
409*795d594fSAndroid Build Coastguard Worker       b.SetMetavar(std::move(metavar_));
410*795d594fSAndroid Build Coastguard Worker       return std::move(b);
411*795d594fSAndroid Build Coastguard Worker     }
412*795d594fSAndroid Build Coastguard Worker 
413*795d594fSAndroid Build Coastguard Worker     template <typename TArg = Unit>
414*795d594fSAndroid Build Coastguard Worker     typename std::enable_if<std::is_same<TArg, Unit>::value>::type
InitializeTypedBuilderCmdlineParser::UntypedArgumentBuilder415*795d594fSAndroid Build Coastguard Worker     InitializeTypedBuilder(ArgumentBuilder<TArg>* arg_builder) {
416*795d594fSAndroid Build Coastguard Worker       // Every Unit argument implicitly maps to a runtime value of Unit{}
417*795d594fSAndroid Build Coastguard Worker       std::vector<Unit> values(names_.size(), Unit{});
418*795d594fSAndroid Build Coastguard Worker       arg_builder->SetValuesInternal(std::move(values));
419*795d594fSAndroid Build Coastguard Worker     }
420*795d594fSAndroid Build Coastguard Worker 
421*795d594fSAndroid Build Coastguard Worker     // No extra work for all other types
InitializeTypedBuilderCmdlineParser::UntypedArgumentBuilder422*795d594fSAndroid Build Coastguard Worker     void InitializeTypedBuilder(void*) {}
423*795d594fSAndroid Build Coastguard Worker 
424*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
425*795d594fSAndroid Build Coastguard Worker     friend struct ArgumentBuilder;
426*795d594fSAndroid Build Coastguard Worker     friend struct Builder;
427*795d594fSAndroid Build Coastguard Worker 
UntypedArgumentBuilderCmdlineParser::UntypedArgumentBuilder428*795d594fSAndroid Build Coastguard Worker     explicit UntypedArgumentBuilder(CmdlineParser::Builder& parent) : parent_(parent) {}
429*795d594fSAndroid Build Coastguard Worker     // UntypedArgumentBuilder(UntypedArgumentBuilder&& other) = default;
430*795d594fSAndroid Build Coastguard Worker 
431*795d594fSAndroid Build Coastguard Worker     CmdlineParser::Builder& parent_;
432*795d594fSAndroid Build Coastguard Worker     std::vector<const char*> names_;
433*795d594fSAndroid Build Coastguard Worker     std::optional<const char*> category_;
434*795d594fSAndroid Build Coastguard Worker     std::optional<const char*> help_;
435*795d594fSAndroid Build Coastguard Worker     std::optional<const char*> metavar_;
436*795d594fSAndroid Build Coastguard Worker   };
437*795d594fSAndroid Build Coastguard Worker 
438*795d594fSAndroid Build Coastguard Worker   // Build a new parser given a chain of calls to define arguments.
439*795d594fSAndroid Build Coastguard Worker   struct Builder {
BuilderCmdlineParser::Builder440*795d594fSAndroid Build Coastguard Worker     Builder() : save_destination_(new SaveDestination()) {}
441*795d594fSAndroid Build Coastguard Worker 
442*795d594fSAndroid Build Coastguard Worker     // Define a single argument. The default type is Unit.
DefineCmdlineParser::Builder443*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder Define(const char* name) {
444*795d594fSAndroid Build Coastguard Worker       return Define({name});
445*795d594fSAndroid Build Coastguard Worker     }
446*795d594fSAndroid Build Coastguard Worker 
ClearCategoryCmdlineParser::Builder447*795d594fSAndroid Build Coastguard Worker     Builder& ClearCategory() {
448*795d594fSAndroid Build Coastguard Worker       default_category_.reset();
449*795d594fSAndroid Build Coastguard Worker       return *this;
450*795d594fSAndroid Build Coastguard Worker     }
451*795d594fSAndroid Build Coastguard Worker 
SetCategoryCmdlineParser::Builder452*795d594fSAndroid Build Coastguard Worker     Builder& SetCategory(const char* sv) {
453*795d594fSAndroid Build Coastguard Worker       default_category_ = sv;
454*795d594fSAndroid Build Coastguard Worker       return *this;
455*795d594fSAndroid Build Coastguard Worker     }
456*795d594fSAndroid Build Coastguard Worker 
OrderCategoriesCmdlineParser::Builder457*795d594fSAndroid Build Coastguard Worker     Builder& OrderCategories(std::vector<const char*> categories) {
458*795d594fSAndroid Build Coastguard Worker       category_order_.swap(categories);
459*795d594fSAndroid Build Coastguard Worker       return *this;
460*795d594fSAndroid Build Coastguard Worker     }
461*795d594fSAndroid Build Coastguard Worker 
462*795d594fSAndroid Build Coastguard Worker     // Define a single argument with multiple aliases.
DefineCmdlineParser::Builder463*795d594fSAndroid Build Coastguard Worker     UntypedArgumentBuilder Define(std::initializer_list<const char*> names) {
464*795d594fSAndroid Build Coastguard Worker       auto&& b = UntypedArgumentBuilder(*this);
465*795d594fSAndroid Build Coastguard Worker       b.SetNames(names);
466*795d594fSAndroid Build Coastguard Worker       b.SetCategory(default_category_);
467*795d594fSAndroid Build Coastguard Worker       return std::move(b);
468*795d594fSAndroid Build Coastguard Worker     }
469*795d594fSAndroid Build Coastguard Worker 
470*795d594fSAndroid Build Coastguard Worker     // Whether the parser should give up on unrecognized arguments. Not recommended.
IgnoreUnrecognizedCmdlineParser::Builder471*795d594fSAndroid Build Coastguard Worker     Builder& IgnoreUnrecognized(bool ignore_unrecognized) {
472*795d594fSAndroid Build Coastguard Worker       ignore_unrecognized_ = ignore_unrecognized;
473*795d594fSAndroid Build Coastguard Worker       return *this;
474*795d594fSAndroid Build Coastguard Worker     }
475*795d594fSAndroid Build Coastguard Worker 
476*795d594fSAndroid Build Coastguard Worker     // Provide a list of arguments to ignore for backwards compatibility.
IgnoreCmdlineParser::Builder477*795d594fSAndroid Build Coastguard Worker     Builder& Ignore(std::initializer_list<const char*> ignore_list) {
478*795d594fSAndroid Build Coastguard Worker       auto current_cat = default_category_;
479*795d594fSAndroid Build Coastguard Worker       default_category_ = "Ignored";
480*795d594fSAndroid Build Coastguard Worker       for (auto&& ignore_name : ignore_list) {
481*795d594fSAndroid Build Coastguard Worker         std::string ign = ignore_name;
482*795d594fSAndroid Build Coastguard Worker 
483*795d594fSAndroid Build Coastguard Worker         // Ignored arguments are just like a regular definition which have very
484*795d594fSAndroid Build Coastguard Worker         // liberal parsing requirements (no range checks, no value checks).
485*795d594fSAndroid Build Coastguard Worker         // Unlike regular argument definitions, when a value gets parsed into its
486*795d594fSAndroid Build Coastguard Worker         // stronger type, we just throw it away.
487*795d594fSAndroid Build Coastguard Worker 
488*795d594fSAndroid Build Coastguard Worker         if (ign.find('_') != std::string::npos) {  // Does the arg-def have a wildcard?
489*795d594fSAndroid Build Coastguard Worker           // pretend this is a string, e.g. -Xjitconfig:<anythinggoeshere>
490*795d594fSAndroid Build Coastguard Worker           auto&& builder = Define(ignore_name).template WithType<std::string>().IntoIgnore();
491*795d594fSAndroid Build Coastguard Worker           assert(&builder == this);
492*795d594fSAndroid Build Coastguard Worker           (void)builder;  // Ignore pointless unused warning, it's used in the assert.
493*795d594fSAndroid Build Coastguard Worker         } else {
494*795d594fSAndroid Build Coastguard Worker           // pretend this is a unit, e.g. -Xjitblocking
495*795d594fSAndroid Build Coastguard Worker           auto&& builder = Define(ignore_name).template WithType<Unit>().IntoIgnore();
496*795d594fSAndroid Build Coastguard Worker           assert(&builder == this);
497*795d594fSAndroid Build Coastguard Worker           (void)builder;  // Ignore pointless unused warning, it's used in the assert.
498*795d594fSAndroid Build Coastguard Worker         }
499*795d594fSAndroid Build Coastguard Worker       }
500*795d594fSAndroid Build Coastguard Worker       ignore_list_ = ignore_list;
501*795d594fSAndroid Build Coastguard Worker       default_category_ = current_cat;
502*795d594fSAndroid Build Coastguard Worker       return *this;
503*795d594fSAndroid Build Coastguard Worker     }
504*795d594fSAndroid Build Coastguard Worker 
505*795d594fSAndroid Build Coastguard Worker     // Finish building the parser; performs a check of the validity. Return value is moved, not
506*795d594fSAndroid Build Coastguard Worker     // copied. Do not call this more than once.
BuildCmdlineParser::Builder507*795d594fSAndroid Build Coastguard Worker     CmdlineParser Build() {
508*795d594fSAndroid Build Coastguard Worker       assert(!built_);
509*795d594fSAndroid Build Coastguard Worker       built_ = true;
510*795d594fSAndroid Build Coastguard Worker 
511*795d594fSAndroid Build Coastguard Worker       auto&& p = CmdlineParser(ignore_unrecognized_,
512*795d594fSAndroid Build Coastguard Worker                                std::move(ignore_list_),
513*795d594fSAndroid Build Coastguard Worker                                save_destination_,
514*795d594fSAndroid Build Coastguard Worker                                std::move(completed_arguments_),
515*795d594fSAndroid Build Coastguard Worker                                std::move(category_order_));
516*795d594fSAndroid Build Coastguard Worker 
517*795d594fSAndroid Build Coastguard Worker       return std::move(p);
518*795d594fSAndroid Build Coastguard Worker     }
519*795d594fSAndroid Build Coastguard Worker 
520*795d594fSAndroid Build Coastguard Worker    protected:
AppendCompletedArgumentCmdlineParser::Builder521*795d594fSAndroid Build Coastguard Worker     void AppendCompletedArgument(detail::CmdlineParseArgumentAny* arg) {
522*795d594fSAndroid Build Coastguard Worker       auto smart_ptr = std::unique_ptr<detail::CmdlineParseArgumentAny>(arg);
523*795d594fSAndroid Build Coastguard Worker       completed_arguments_.push_back(std::move(smart_ptr));
524*795d594fSAndroid Build Coastguard Worker     }
525*795d594fSAndroid Build Coastguard Worker 
526*795d594fSAndroid Build Coastguard Worker    private:
527*795d594fSAndroid Build Coastguard Worker     // No copying now!
528*795d594fSAndroid Build Coastguard Worker     Builder(const Builder& other) = delete;
529*795d594fSAndroid Build Coastguard Worker 
530*795d594fSAndroid Build Coastguard Worker     template <typename TArg>
531*795d594fSAndroid Build Coastguard Worker     friend struct ArgumentBuilder;
532*795d594fSAndroid Build Coastguard Worker     friend struct UntypedArgumentBuilder;
533*795d594fSAndroid Build Coastguard Worker     friend struct CmdlineParser;
534*795d594fSAndroid Build Coastguard Worker 
535*795d594fSAndroid Build Coastguard Worker     bool built_ = false;
536*795d594fSAndroid Build Coastguard Worker     bool ignore_unrecognized_ = false;
537*795d594fSAndroid Build Coastguard Worker     std::vector<const char*> ignore_list_;
538*795d594fSAndroid Build Coastguard Worker     std::shared_ptr<SaveDestination> save_destination_;
539*795d594fSAndroid Build Coastguard Worker     std::optional<const char*> default_category_;
540*795d594fSAndroid Build Coastguard Worker     std::vector<const char*> category_order_;
541*795d594fSAndroid Build Coastguard Worker 
542*795d594fSAndroid Build Coastguard Worker     std::vector<std::unique_ptr<detail::CmdlineParseArgumentAny>> completed_arguments_;
543*795d594fSAndroid Build Coastguard Worker   };
544*795d594fSAndroid Build Coastguard Worker 
545*795d594fSAndroid Build Coastguard Worker   void DumpHelp(VariableIndentationOutputStream& vios);
546*795d594fSAndroid Build Coastguard Worker 
ParseCmdlineParser547*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(const std::string& argv) {
548*795d594fSAndroid Build Coastguard Worker     std::vector<std::string> tokenized;
549*795d594fSAndroid Build Coastguard Worker     Split(argv, ' ', &tokenized);
550*795d594fSAndroid Build Coastguard Worker 
551*795d594fSAndroid Build Coastguard Worker     return Parse(TokenRange(std::move(tokenized)));
552*795d594fSAndroid Build Coastguard Worker   }
553*795d594fSAndroid Build Coastguard Worker 
554*795d594fSAndroid Build Coastguard Worker   // Parse the arguments; storing results into the arguments map. Returns success value.
ParseCmdlineParser555*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(const char* argv) {
556*795d594fSAndroid Build Coastguard Worker     return Parse(std::string(argv));
557*795d594fSAndroid Build Coastguard Worker   }
558*795d594fSAndroid Build Coastguard Worker 
559*795d594fSAndroid Build Coastguard Worker   // Parse the arguments; storing the results into the arguments map. Returns success value.
560*795d594fSAndroid Build Coastguard Worker   // Assumes that argv[0] is a valid argument (i.e. not the program name).
ParseCmdlineParser561*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(const std::vector<const char*>& argv) {
562*795d594fSAndroid Build Coastguard Worker     return Parse(TokenRange(argv.begin(), argv.end()));
563*795d594fSAndroid Build Coastguard Worker   }
564*795d594fSAndroid Build Coastguard Worker 
565*795d594fSAndroid Build Coastguard Worker   // Parse the arguments; storing the results into the arguments map. Returns success value.
566*795d594fSAndroid Build Coastguard Worker   // Assumes that argv[0] is a valid argument (i.e. not the program name).
ParseCmdlineParser567*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(const std::vector<std::string>& argv) {
568*795d594fSAndroid Build Coastguard Worker     return Parse(TokenRange(argv.begin(), argv.end()));
569*795d594fSAndroid Build Coastguard Worker   }
570*795d594fSAndroid Build Coastguard Worker 
571*795d594fSAndroid Build Coastguard Worker   // Parse the arguments (directly from an int main(argv,argc)). Returns success value.
572*795d594fSAndroid Build Coastguard Worker   // Assumes that argv[0] is the program name, and ignores it.
ParseCmdlineParser573*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(const char* argv[], int argc) {
574*795d594fSAndroid Build Coastguard Worker     return Parse(TokenRange(&argv[1], argc - 1));  // ignore argv[0] because it's the program name
575*795d594fSAndroid Build Coastguard Worker   }
576*795d594fSAndroid Build Coastguard Worker 
577*795d594fSAndroid Build Coastguard Worker   // Look up the arguments that have been parsed; use the target keys to lookup individual args.
GetArgumentsMapCmdlineParser578*795d594fSAndroid Build Coastguard Worker   const TVariantMap& GetArgumentsMap() const {
579*795d594fSAndroid Build Coastguard Worker     return save_destination_->GetMap();
580*795d594fSAndroid Build Coastguard Worker   }
581*795d594fSAndroid Build Coastguard Worker 
582*795d594fSAndroid Build Coastguard Worker   // Release the arguments map that has been parsed; useful for move semantics.
ReleaseArgumentsMapCmdlineParser583*795d594fSAndroid Build Coastguard Worker   TVariantMap&& ReleaseArgumentsMap() {
584*795d594fSAndroid Build Coastguard Worker     return save_destination_->ReleaseMap();
585*795d594fSAndroid Build Coastguard Worker   }
586*795d594fSAndroid Build Coastguard Worker 
587*795d594fSAndroid Build Coastguard Worker   // How many arguments were defined?
CountDefinedArgumentsCmdlineParser588*795d594fSAndroid Build Coastguard Worker   size_t CountDefinedArguments() const {
589*795d594fSAndroid Build Coastguard Worker     return completed_arguments_.size();
590*795d594fSAndroid Build Coastguard Worker   }
591*795d594fSAndroid Build Coastguard Worker 
592*795d594fSAndroid Build Coastguard Worker   // Ensure we have a default move constructor.
593*795d594fSAndroid Build Coastguard Worker   CmdlineParser(CmdlineParser&&) noexcept = default;
594*795d594fSAndroid Build Coastguard Worker   // Ensure we have a default move assignment operator.
595*795d594fSAndroid Build Coastguard Worker   CmdlineParser& operator=(CmdlineParser&&) noexcept = default;
596*795d594fSAndroid Build Coastguard Worker 
597*795d594fSAndroid Build Coastguard Worker  private:
598*795d594fSAndroid Build Coastguard Worker   friend struct Builder;
599*795d594fSAndroid Build Coastguard Worker 
600*795d594fSAndroid Build Coastguard Worker   // Construct a new parser from the builder. Move all the arguments.
CmdlineParserCmdlineParser601*795d594fSAndroid Build Coastguard Worker   CmdlineParser(bool ignore_unrecognized,
602*795d594fSAndroid Build Coastguard Worker                 std::vector<const char*>&& ignore_list,
603*795d594fSAndroid Build Coastguard Worker                 std::shared_ptr<SaveDestination> save_destination,
604*795d594fSAndroid Build Coastguard Worker                 std::vector<std::unique_ptr<detail::CmdlineParseArgumentAny>>&& completed_arguments,
605*795d594fSAndroid Build Coastguard Worker                 std::vector<const char*>&& category_order)
606*795d594fSAndroid Build Coastguard Worker     : ignore_unrecognized_(ignore_unrecognized),
607*795d594fSAndroid Build Coastguard Worker       ignore_list_(std::move(ignore_list)),
608*795d594fSAndroid Build Coastguard Worker       save_destination_(save_destination),
609*795d594fSAndroid Build Coastguard Worker       completed_arguments_(std::move(completed_arguments)),
610*795d594fSAndroid Build Coastguard Worker       category_order_(category_order) {
611*795d594fSAndroid Build Coastguard Worker     assert(save_destination != nullptr);
612*795d594fSAndroid Build Coastguard Worker   }
613*795d594fSAndroid Build Coastguard Worker 
614*795d594fSAndroid Build Coastguard Worker   // Parse the arguments; storing results into the arguments map. Returns success value.
615*795d594fSAndroid Build Coastguard Worker   // The parsing will fail on the first non-success parse result and return that error.
616*795d594fSAndroid Build Coastguard Worker   //
617*795d594fSAndroid Build Coastguard Worker   // All previously-parsed arguments are cleared out.
618*795d594fSAndroid Build Coastguard Worker   // Otherwise, all parsed arguments will be stored into SaveDestination as a side-effect.
619*795d594fSAndroid Build Coastguard Worker   // A partial parse will result only in a partial save of the arguments.
ParseCmdlineParser620*795d594fSAndroid Build Coastguard Worker   CmdlineResult Parse(TokenRange&& arguments_list) {
621*795d594fSAndroid Build Coastguard Worker     save_destination_->Clear();
622*795d594fSAndroid Build Coastguard Worker 
623*795d594fSAndroid Build Coastguard Worker     for (size_t i = 0; i < arguments_list.Size(); ) {
624*795d594fSAndroid Build Coastguard Worker       TokenRange possible_name = arguments_list.Slice(i);
625*795d594fSAndroid Build Coastguard Worker 
626*795d594fSAndroid Build Coastguard Worker       size_t best_match_size = 0;  // How many tokens were matched in the best case.
627*795d594fSAndroid Build Coastguard Worker       size_t best_match_arg_idx = 0;
628*795d594fSAndroid Build Coastguard Worker       bool matched = false;  // At least one argument definition has been matched?
629*795d594fSAndroid Build Coastguard Worker 
630*795d594fSAndroid Build Coastguard Worker       // Find the closest argument definition for the remaining token range.
631*795d594fSAndroid Build Coastguard Worker       size_t arg_idx = 0;
632*795d594fSAndroid Build Coastguard Worker       for (auto&& arg : completed_arguments_) {
633*795d594fSAndroid Build Coastguard Worker         size_t local_match = arg->MaybeMatches(possible_name);
634*795d594fSAndroid Build Coastguard Worker 
635*795d594fSAndroid Build Coastguard Worker         if (local_match > best_match_size) {
636*795d594fSAndroid Build Coastguard Worker           best_match_size = local_match;
637*795d594fSAndroid Build Coastguard Worker           best_match_arg_idx = arg_idx;
638*795d594fSAndroid Build Coastguard Worker           matched = true;
639*795d594fSAndroid Build Coastguard Worker         }
640*795d594fSAndroid Build Coastguard Worker         arg_idx++;
641*795d594fSAndroid Build Coastguard Worker       }
642*795d594fSAndroid Build Coastguard Worker 
643*795d594fSAndroid Build Coastguard Worker       // Saw some kind of unknown argument
644*795d594fSAndroid Build Coastguard Worker       if (matched == false) {
645*795d594fSAndroid Build Coastguard Worker         if (UNLIKELY(ignore_unrecognized_)) {  // This is usually off, we only need it for JNI.
646*795d594fSAndroid Build Coastguard Worker           // Consume 1 token and keep going, hopefully the next token is a good one.
647*795d594fSAndroid Build Coastguard Worker           ++i;
648*795d594fSAndroid Build Coastguard Worker           continue;
649*795d594fSAndroid Build Coastguard Worker         }
650*795d594fSAndroid Build Coastguard Worker         // Common case:
651*795d594fSAndroid Build Coastguard Worker         // Bail out on the first unknown argument with an error.
652*795d594fSAndroid Build Coastguard Worker         return CmdlineResult(CmdlineResult::kUnknown,
653*795d594fSAndroid Build Coastguard Worker                              std::string("Unknown argument: ") + possible_name[0]);
654*795d594fSAndroid Build Coastguard Worker       }
655*795d594fSAndroid Build Coastguard Worker 
656*795d594fSAndroid Build Coastguard Worker       // Look at the best-matched argument definition and try to parse against that.
657*795d594fSAndroid Build Coastguard Worker       auto&& arg = completed_arguments_[best_match_arg_idx];
658*795d594fSAndroid Build Coastguard Worker 
659*795d594fSAndroid Build Coastguard Worker       assert(arg->MaybeMatches(possible_name) == best_match_size);
660*795d594fSAndroid Build Coastguard Worker 
661*795d594fSAndroid Build Coastguard Worker       // Try to parse the argument now, if we have enough tokens.
662*795d594fSAndroid Build Coastguard Worker       std::pair<size_t, size_t> num_tokens = arg->GetNumTokens();
663*795d594fSAndroid Build Coastguard Worker       size_t min_tokens;
664*795d594fSAndroid Build Coastguard Worker       size_t max_tokens;
665*795d594fSAndroid Build Coastguard Worker 
666*795d594fSAndroid Build Coastguard Worker       std::tie(min_tokens, max_tokens) = num_tokens;
667*795d594fSAndroid Build Coastguard Worker 
668*795d594fSAndroid Build Coastguard Worker       if ((i + min_tokens) > arguments_list.Size()) {
669*795d594fSAndroid Build Coastguard Worker         // expected longer command line but it was too short
670*795d594fSAndroid Build Coastguard Worker         // e.g. if the argv was only "-Xms" without specifying a memory option
671*795d594fSAndroid Build Coastguard Worker         CMDLINE_DEBUG_LOG << "Parse failure, i = " << i << ", arg list " << arguments_list.Size() <<
672*795d594fSAndroid Build Coastguard Worker             " num tokens in arg_def: " << min_tokens << "," << max_tokens << std::endl;
673*795d594fSAndroid Build Coastguard Worker         return CmdlineResult(CmdlineResult::kFailure,
674*795d594fSAndroid Build Coastguard Worker                              std::string("Argument ") +
675*795d594fSAndroid Build Coastguard Worker                              possible_name[0] + ": incomplete command line arguments, expected "
676*795d594fSAndroid Build Coastguard Worker                              + std::to_string(size_t(i + min_tokens) - arguments_list.Size()) +
677*795d594fSAndroid Build Coastguard Worker                              " more tokens");
678*795d594fSAndroid Build Coastguard Worker       }
679*795d594fSAndroid Build Coastguard Worker 
680*795d594fSAndroid Build Coastguard Worker       if (best_match_size > max_tokens || best_match_size < min_tokens) {
681*795d594fSAndroid Build Coastguard Worker         // Even our best match was out of range, so parsing would fail instantly.
682*795d594fSAndroid Build Coastguard Worker         return CmdlineResult(CmdlineResult::kFailure,
683*795d594fSAndroid Build Coastguard Worker                              std::string("Argument ") + possible_name[0] + ": too few tokens "
684*795d594fSAndroid Build Coastguard Worker                              "matched " + std::to_string(best_match_size)
685*795d594fSAndroid Build Coastguard Worker                              + " but wanted " + std::to_string(num_tokens.first));
686*795d594fSAndroid Build Coastguard Worker       }
687*795d594fSAndroid Build Coastguard Worker 
688*795d594fSAndroid Build Coastguard Worker       // We have enough tokens to begin exact parsing.
689*795d594fSAndroid Build Coastguard Worker       TokenRange exact_range = possible_name.Slice(0, max_tokens);
690*795d594fSAndroid Build Coastguard Worker 
691*795d594fSAndroid Build Coastguard Worker       size_t consumed_tokens = 1;  // At least 1 if we ever want to try to resume parsing on error
692*795d594fSAndroid Build Coastguard Worker       CmdlineResult parse_attempt = arg->ParseArgument(exact_range, &consumed_tokens);
693*795d594fSAndroid Build Coastguard Worker 
694*795d594fSAndroid Build Coastguard Worker       if (parse_attempt.IsError()) {
695*795d594fSAndroid Build Coastguard Worker         // We may also want to continue parsing the other tokens to gather more errors.
696*795d594fSAndroid Build Coastguard Worker         return parse_attempt;
697*795d594fSAndroid Build Coastguard Worker       }  // else the value has been successfully stored into the map
698*795d594fSAndroid Build Coastguard Worker 
699*795d594fSAndroid Build Coastguard Worker       assert(consumed_tokens > 0);  // Don't hang in an infinite loop trying to parse
700*795d594fSAndroid Build Coastguard Worker       i += consumed_tokens;
701*795d594fSAndroid Build Coastguard Worker 
702*795d594fSAndroid Build Coastguard Worker       // TODO: also handle ignoring arguments for backwards compatibility
703*795d594fSAndroid Build Coastguard Worker     }  // for
704*795d594fSAndroid Build Coastguard Worker 
705*795d594fSAndroid Build Coastguard Worker     return CmdlineResult(CmdlineResult::kSuccess);
706*795d594fSAndroid Build Coastguard Worker   }
707*795d594fSAndroid Build Coastguard Worker 
708*795d594fSAndroid Build Coastguard Worker   bool ignore_unrecognized_ = false;
709*795d594fSAndroid Build Coastguard Worker   std::vector<const char*> ignore_list_;
710*795d594fSAndroid Build Coastguard Worker   std::shared_ptr<SaveDestination> save_destination_;
711*795d594fSAndroid Build Coastguard Worker   std::vector<std::unique_ptr<detail::CmdlineParseArgumentAny>> completed_arguments_;
712*795d594fSAndroid Build Coastguard Worker   std::vector<const char*> category_order_;
713*795d594fSAndroid Build Coastguard Worker };
714*795d594fSAndroid Build Coastguard Worker 
715*795d594fSAndroid Build Coastguard Worker // This has to be defined after everything else, since we want the builders to call this.
716*795d594fSAndroid Build Coastguard Worker template <typename TVariantMap,
717*795d594fSAndroid Build Coastguard Worker           template <typename TKeyValue> class TVariantMapKey>
718*795d594fSAndroid Build Coastguard Worker template <typename TArg>
719*795d594fSAndroid Build Coastguard Worker typename CmdlineParser<TVariantMap, TVariantMapKey>::template ArgumentBuilder<TArg>
CreateArgumentBuilder(CmdlineParser<TVariantMap,TVariantMapKey>::Builder & parent)720*795d594fSAndroid Build Coastguard Worker CmdlineParser<TVariantMap, TVariantMapKey>::CreateArgumentBuilder(
721*795d594fSAndroid Build Coastguard Worker     CmdlineParser<TVariantMap, TVariantMapKey>::Builder& parent) {
722*795d594fSAndroid Build Coastguard Worker   return CmdlineParser<TVariantMap, TVariantMapKey>::ArgumentBuilder<TArg>(
723*795d594fSAndroid Build Coastguard Worker       parent, parent.save_destination_);
724*795d594fSAndroid Build Coastguard Worker }
725*795d594fSAndroid Build Coastguard Worker 
726*795d594fSAndroid Build Coastguard Worker // This has to be defined after everything else, since we want the builders to call this.
727*795d594fSAndroid Build Coastguard Worker template <typename TVariantMap,
728*795d594fSAndroid Build Coastguard Worker           template <typename TKeyValue> class TVariantMapKey>
AppendCompletedArgument(CmdlineParser<TVariantMap,TVariantMapKey>::Builder & builder,detail::CmdlineParseArgumentAny * arg)729*795d594fSAndroid Build Coastguard Worker void CmdlineParser<TVariantMap, TVariantMapKey>::AppendCompletedArgument(
730*795d594fSAndroid Build Coastguard Worker     CmdlineParser<TVariantMap, TVariantMapKey>::Builder& builder,
731*795d594fSAndroid Build Coastguard Worker     detail::CmdlineParseArgumentAny* arg) {
732*795d594fSAndroid Build Coastguard Worker   builder.AppendCompletedArgument(arg);
733*795d594fSAndroid Build Coastguard Worker }
734*795d594fSAndroid Build Coastguard Worker 
735*795d594fSAndroid Build Coastguard Worker template <typename TVariantMap,
736*795d594fSAndroid Build Coastguard Worker           template <typename TKeyValue> class TVariantMapKey>
DumpHelp(VariableIndentationOutputStream & vios)737*795d594fSAndroid Build Coastguard Worker void CmdlineParser<TVariantMap, TVariantMapKey>::DumpHelp(VariableIndentationOutputStream& vios) {
738*795d594fSAndroid Build Coastguard Worker   std::vector<detail::CmdlineParseArgumentAny*> uncat;
739*795d594fSAndroid Build Coastguard Worker   std::unordered_map<std::string, std::vector<detail::CmdlineParseArgumentAny*>> args;
740*795d594fSAndroid Build Coastguard Worker   for (const std::unique_ptr<detail::CmdlineParseArgumentAny>& it : completed_arguments_) {
741*795d594fSAndroid Build Coastguard Worker     auto cat = it->GetCategory();
742*795d594fSAndroid Build Coastguard Worker     if (cat.has_value()) {
743*795d594fSAndroid Build Coastguard Worker       if (args.find(*cat) == args.end()) {
744*795d594fSAndroid Build Coastguard Worker         args[*cat] = {};
745*795d594fSAndroid Build Coastguard Worker       }
746*795d594fSAndroid Build Coastguard Worker       args.at(*cat).push_back(it.get());
747*795d594fSAndroid Build Coastguard Worker     } else {
748*795d594fSAndroid Build Coastguard Worker       uncat.push_back(it.get());
749*795d594fSAndroid Build Coastguard Worker     }
750*795d594fSAndroid Build Coastguard Worker   }
751*795d594fSAndroid Build Coastguard Worker   args.erase("Ignored");
752*795d594fSAndroid Build Coastguard Worker   for (auto arg : uncat) {
753*795d594fSAndroid Build Coastguard Worker     arg->DumpHelp(vios);
754*795d594fSAndroid Build Coastguard Worker     vios.Stream();
755*795d594fSAndroid Build Coastguard Worker   }
756*795d594fSAndroid Build Coastguard Worker   for (auto it : category_order_) {
757*795d594fSAndroid Build Coastguard Worker     auto cur = args.find(it);
758*795d594fSAndroid Build Coastguard Worker     if (cur != args.end() && !cur->second.empty()) {
759*795d594fSAndroid Build Coastguard Worker       vios.Stream() << "The following " << it << " arguments are supported:" << std::endl;
760*795d594fSAndroid Build Coastguard Worker       ScopedIndentation si(&vios);
761*795d594fSAndroid Build Coastguard Worker       for (detail::CmdlineParseArgumentAny* arg : cur->second) {
762*795d594fSAndroid Build Coastguard Worker         arg->DumpHelp(vios);
763*795d594fSAndroid Build Coastguard Worker         vios.Stream();
764*795d594fSAndroid Build Coastguard Worker       }
765*795d594fSAndroid Build Coastguard Worker       args.erase(cur->first);
766*795d594fSAndroid Build Coastguard Worker     }
767*795d594fSAndroid Build Coastguard Worker   }
768*795d594fSAndroid Build Coastguard Worker   for (auto [cat, lst] : args) {
769*795d594fSAndroid Build Coastguard Worker     vios.Stream() << "The following " << cat << " arguments are supported:" << std::endl;
770*795d594fSAndroid Build Coastguard Worker     ScopedIndentation si(&vios);
771*795d594fSAndroid Build Coastguard Worker     for (auto& arg : completed_arguments_) {
772*795d594fSAndroid Build Coastguard Worker       arg->DumpHelp(vios);
773*795d594fSAndroid Build Coastguard Worker       vios.Stream();
774*795d594fSAndroid Build Coastguard Worker     }
775*795d594fSAndroid Build Coastguard Worker   }
776*795d594fSAndroid Build Coastguard Worker   if (!ignore_list_.empty()) {
777*795d594fSAndroid Build Coastguard Worker     vios.Stream() << "The following arguments are ignored for compatibility:" << std::endl;
778*795d594fSAndroid Build Coastguard Worker     ScopedIndentation si(&vios);
779*795d594fSAndroid Build Coastguard Worker     for (auto ign : ignore_list_) {
780*795d594fSAndroid Build Coastguard Worker       vios.Stream() << ign << std::endl;
781*795d594fSAndroid Build Coastguard Worker     }
782*795d594fSAndroid Build Coastguard Worker   }
783*795d594fSAndroid Build Coastguard Worker }
784*795d594fSAndroid Build Coastguard Worker 
785*795d594fSAndroid Build Coastguard Worker }  // namespace art
786*795d594fSAndroid Build Coastguard Worker 
787*795d594fSAndroid Build Coastguard Worker #endif  // ART_CMDLINE_CMDLINE_PARSER_H_
788