Android-cuttlefish cvd tool
flag_parser.h
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#pragma once
18
19#include <cstdint>
20#include <functional>
21#include <optional>
22#include <ostream>
23#include <string>
24#include <vector>
25
27
28/* Support for parsing individual flags out of a larger list of flags. This
29 * supports externally determining the order that flags are evaluated in, and
30 * incrementally integrating with existing flag parsing implementations.
31 *
32 * Start with Flag() or one of the GflagsCompatFlag(...) functions to create new
33 * flags. These flags should be aggregated through the application through some
34 * other mechanism and then evaluated individually with Flag::Parse or together
35 * with ConsumeFlags on arguments. */
36
37namespace cuttlefish {
38
39/* The matching behavior used with the name in `FlagAlias::name`. */
40enum class FlagAliasMode {
41 /* Match arguments of the form `<name><value>`. In practice, <name> usually
42 * looks like "-flag=" or "--flag=", where the "-" and "=" are included in
43 * parsing. */
45 /* Match arguments of the form `<name>`. In practice, <name> will look like
46 * "-flag" or "--flag". */
48 /* Match a pair of arguments of the form `<name>` `<value>`. In practice,
49 * <name> will look like "-flag" or "--flag". */
51 /* Match a sequence of arguments of the form `<name>` `<value>` `<value>`.
52 * This uses heuristics to try to determine when `<value>` is actually another
53 * flag. */
55};
56
57/* A single matching rule for a `Flag`. One `Flag` can have multiple rules. */
58struct FlagAlias {
60 std::string name;
61};
62
63std::ostream& operator<<(std::ostream&, const FlagAlias&);
64
65/* A successful match in an argument list from a `FlagAlias` inside a `Flag`.
66 * The `key` value corresponds to `FlagAlias::name`. For a match of
67 * `FlagAliasMode::kFlagExact`, `key` and `value` will both be the `name`. */
68struct FlagMatch {
69 std::string key;
70 std::string value;
71};
72
73class Flag {
74 public:
75 /* Add an alias that triggers matches and calls to the `Setter` function. */
76 Flag& Alias(const FlagAlias& alias) &;
77 Flag Alias(const FlagAlias& alias) &&;
78 /* Set help text, visible in the class ostream writer method. Optional. */
79 Flag& Help(const std::string&) &;
80 Flag Help(const std::string&) &&;
81 /* Set a loader that displays the current value in help text. Optional. */
82 Flag& Getter(std::function<std::string()>) &;
83 Flag Getter(std::function<std::string()>) &&;
84 /* Set the callback for matches. The callback may be invoked multiple times.
85 */
86 Flag& Setter(std::function<Result<void>(const FlagMatch&)>) &;
87 Flag Setter(std::function<Result<void>(const FlagMatch&)>) &&;
88
89 /* Examines a list of arguments, removing any matches from the list and
90 * invoking the `Setter` for every match. Returns `false` if the callback ever
91 * returns `false`. Non-matches are left in place. */
92 Result<void> Parse(std::vector<std::string>& arguments) const;
93 Result<void> Parse(std::vector<std::string>&& arguments) const;
94
95 /* Write gflags `--helpxml` style output for a string-type flag. */
96 bool WriteGflagsCompatXml(std::ostream&) const;
97
98 private:
99 /* Reports whether `Process` wants to consume zero, one, or two arguments. */
100 enum class FlagProcessResult {
101 /* Error in handling a flag, exit flag handling with an error result. */
102 kFlagSkip, /* Flag skipped; consume no arguments. */
103 kFlagConsumed, /* Flag processed; consume one argument. */
104 kFlagConsumedWithFollowing, /* Flag processed; consume 2 arguments. */
105 kFlagConsumedOnlyFollowing, /* Flag processed; consume next argument. */
106 };
107
108 void ValidateAlias(const FlagAlias& alias);
109 Flag& UnvalidatedAlias(const FlagAlias& alias) &;
110 Flag UnvalidatedAlias(const FlagAlias& alias) &&;
111
112 /* Attempt to match a single argument. */
114 const std::string& argument,
115 const std::optional<std::string>& next_arg) const;
116
117 bool HasAlias(const FlagAlias&) const;
118
119 friend std::ostream& operator<<(std::ostream&, const Flag&);
120 friend Flag InvalidFlagGuard();
122
123 friend Result<void> ConsumeFlagsConstrained(const std::vector<Flag>& flags,
124 std::vector<std::string>&);
125
126 std::vector<FlagAlias> aliases_;
127 std::optional<std::string> help_;
128 std::optional<std::function<std::string()>> getter_;
129 std::optional<std::function<Result<void>(const FlagMatch&)>> setter_;
130};
131
132std::ostream& operator<<(std::ostream&, const Flag&);
133
134std::vector<std::string> ArgsToVec(int argc, char** argv);
135
136Result<bool> ParseBool(const std::string& value, const std::string& name);
137
138/* Handles a list of flags. Flags are matched in the order given in case two
139 * flags match the same argument. Matched flags are removed, leaving only
140 * unmatched arguments. */
141Result<void> ConsumeFlags(const std::vector<Flag>& flags,
142 std::vector<std::string>& args,
143 bool recognize_end_of_option_mark = false);
144Result<void> ConsumeFlags(const std::vector<Flag>& flags,
145 std::vector<std::string>&&,
146 bool recognize_end_of_option_mark = false);
147
148/* Handles a list of flags. Arguments are handled from the beginning. When an
149 * unrecognized argument is encountered, parsing stops. At most one flag matcher
150 * can handle a particular argument. */
151Result<void> ConsumeFlagsConstrained(const std::vector<Flag>& flags,
152 std::vector<std::string>&);
153Result<void> ConsumeFlagsConstrained(const std::vector<Flag>& flags,
154 std::vector<std::string>&&);
155
156bool WriteGflagsCompatXml(const std::vector<Flag>&, std::ostream&);
157
158/* If -verbosity or --verbosity flags have a value, translates it to an android
159 * LogSeverity */
161
162/* If any of these are used, they should be evaluated after all other flags, and
163 * in the order defined here (help before invalid flags, invalid flags before
164 * unexpected arguments). */
165
166/* If a "-help" or "--help" flag is present, prints all the flags and fails. */
167Flag HelpFlag(const std::vector<Flag>& flags, std::string text = "");
168
169/* If a "-helpxml" is present, prints all the flags in XML and fails. */
170Flag HelpXmlFlag(const std::vector<Flag>& flags, std::ostream&, bool& value,
171 std::string text = "");
172
173/* Catches unrecognized arguments that begin with `-`, and errors out. This
174 * effectively denies unknown flags. */
176/* Catches any arguments not extracted by other Flag matchers and errors out.
177 * This effectively denies unknown flags and any positional arguments. */
179
180// Create a flag resembling a gflags argument of the given type. This includes
181// "-[-]flag=*",support for all types, "-[-]noflag" support for booleans, and
182// "-flag *", "--flag *", support for other types. The value passed in the flag
183// is saved to the defined reference.
184Flag GflagsCompatFlag(const std::string& name);
185Flag GflagsCompatFlag(const std::string& name, std::string& value);
186Flag GflagsCompatFlag(const std::string& name, std::int32_t& value);
187Flag GflagsCompatFlag(const std::string& name, std::size_t& value);
188Flag GflagsCompatFlag(const std::string& name, bool& value);
189Flag GflagsCompatFlag(const std::string& name, std::vector<std::string>& value);
190Flag GflagsCompatFlag(const std::string& name, std::vector<bool>& value,
191 bool default_value);
192
193// e.g. cvd start --help, cvd stop -help, cvd fleet -h
194Result<bool> HasHelpFlag(const std::vector<std::string>& args);
195
196} // namespace cuttlefish
Definition: expected.h:86
Definition: flag_parser.h:73
friend Flag UnexpectedArgumentGuard()
Definition: flag_parser.cpp:572
std::optional< std::function< std::string()> > getter_
Definition: flag_parser.h:128
Result< FlagProcessResult > Process(const std::string &argument, const std::optional< std::string > &next_arg) const
Definition: flag_parser.cpp:168
FlagProcessResult
Definition: flag_parser.h:100
friend Result< void > ConsumeFlagsConstrained(const std::vector< Flag > &flags, std::vector< std::string > &)
Definition: flag_parser.cpp:424
void ValidateAlias(const FlagAlias &alias)
Definition: flag_parser.cpp:88
std::optional< std::function< Result< void >(const FlagMatch &)> > setter_
Definition: flag_parser.h:129
std::vector< FlagAlias > aliases_
Definition: flag_parser.h:126
Result< void > Parse(std::vector< std::string > &arguments) const
Definition: flag_parser.cpp:218
Flag & Getter(std::function< std::string()>) &
Definition: flag_parser.cpp:136
Flag & UnvalidatedAlias(const FlagAlias &alias) &
Definition: flag_parser.cpp:79
bool HasAlias(const FlagAlias &) const
Definition: flag_parser.cpp:247
friend Flag InvalidFlagGuard()
Definition: flag_parser.cpp:561
Flag & Help(const std::string &) &
Definition: flag_parser.cpp:127
bool WriteGflagsCompatXml(std::ostream &) const
Definition: flag_parser.cpp:261
Flag & Setter(std::function< Result< void >(const FlagMatch &)>) &
Definition: flag_parser.cpp:145
friend std::ostream & operator<<(std::ostream &, const Flag &)
Definition: flag_parser.cpp:328
Flag & Alias(const FlagAlias &alias) &
Definition: flag_parser.cpp:116
std::optional< std::string > help_
Definition: flag_parser.h:127
static const char *const text[]
Definition: ext2_err.c:10
static std::string next_arg(std::vector< std::string > *args)
Definition: fastboot.cpp:2036
LogSeverity
Definition: logging.h:87
Definition: alloc_utils.cpp:23
FlagAliasMode
Definition: flag_parser.h:40
Flag InvalidFlagGuard()
Definition: flag_parser.cpp:561
Flag UnexpectedArgumentGuard()
Definition: flag_parser.cpp:572
Flag GflagsCompatFlag(const std::string &name)
Definition: flag_parser.cpp:583
Result< void > ConsumeFlags(const std::vector< Flag > &flags, std::vector< std::string > &args, const bool recognize_end_of_option_mark)
Definition: flag_parser.cpp:394
Result< bool > ParseBool(const std::string &value, const std::string &name)
Definition: flag_parser.cpp:158
Result< void > ConsumeFlagsConstrained(const std::vector< Flag > &flags, std::vector< std::string > &args)
Definition: flag_parser.cpp:424
Flag VerbosityFlag(android::base::LogSeverity &value)
Definition: flag_parser.cpp:476
bool WriteGflagsCompatXml(const std::vector< Flag > &flags, std::ostream &out)
Definition: flag_parser.cpp:467
Flag HelpXmlFlag(const std::vector< Flag > &flags, std::ostream &out, bool &value, std::string text)
Definition: flag_parser.cpp:539
std::vector< std::string > ArgsToVec(int argc, char **argv)
Definition: flag_parser.cpp:346
std::ostream & operator<<(std::ostream &out, Arch arch)
Definition: architecture.cpp:67
Flag HelpFlag(const std::vector< Flag > &flags, std::string text)
Definition: flag_parser.cpp:486
Result< bool > HasHelpFlag(const std::vector< std::string > &args)
Definition: flag_parser.cpp:703
Definition: flag_parser.h:58
FlagAliasMode mode
Definition: flag_parser.h:59
std::string name
Definition: flag_parser.h:60
Definition: flag_parser.h:68
std::string value
Definition: flag_parser.h:70
std::string key
Definition: flag_parser.h:69