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