.. _grouping:
.. _cl::Grouping:
-* The **cl::Grouping** modifier is used to implement Unix-style tools (like
- ``ls``) that have lots of single letter arguments, but only require a single
- dash. For example, the '``ls -labF``' command actually enables four different
- options, all of which are single letters. Note that **cl::Grouping** options
- can have values only if they are used separately or at the end of the groups.
- It is a runtime error if such an option is used elsewhere in the group.
+Controlling options grouping
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The **cl::Grouping** modifier can be combined with any formatting types except
+for `cl::Positional`_. It is used to implement Unix-style tools (like ``ls``)
+that have lots of single letter arguments, but only require a single dash.
+For example, the '``ls -labF``' command actually enables four different options,
+all of which are single letters.
+
+Note that **cl::Grouping** options can have values only if they are used
+separately or at the end of the groups. For `cl::ValueRequired`_, it is
+a runtime error if such an option is used elsewhere in the group.
The CommandLine library does not restrict how you use the **cl::Prefix** or
**cl::Grouping** modifiers, but it is possible to specify ambiguous argument
parse(string OrigInput) {
- 1. string input = OrigInput;
- 2. if (isOption(input)) return getOption(input).parse(); // Normal option
- 3. while (!isOption(input) && !input.empty()) input.pop_back(); // Remove the last letter
- 4. if (input.empty()) return error(); // No matching option
- 5. if (getOption(input).isPrefix())
- return getOption(input).parse(input);
- 6. while (!input.empty()) { // Must be grouping options
- getOption(input).parse();
- OrigInput.erase(OrigInput.begin(), OrigInput.begin()+input.length());
- input = OrigInput;
- while (!isOption(input) && !input.empty()) input.pop_back();
+ 1. string Input = OrigInput;
+ 2. if (isOption(Input)) return getOption(Input).parse(); // Normal option
+ 3. while (!Input.empty() && !isOption(Input)) Input.pop_back(); // Remove the last letter
+ 4. while (!Input.empty()) {
+ string MaybeValue = OrigInput.substr(Input.length())
+ if (getOption(Input).isPrefix())
+ return getOption(Input).parse(MaybeValue)
+ if (!MaybeValue.empty() && MaybeValue[0] == '=')
+ return getOption(Input).parse(MaybeValue.substr(1))
+ if (!getOption(Input).isGrouping())
+ return error()
+ getOption(Input).parse()
+ Input = OrigInput = MaybeValue
+ while (!Input.empty() && !isOption(Input)) Input.pop_back();
+ if (!Input.empty() && !getOption(Input).isGrouping())
+ return error()
}
- 7. if (!OrigInput.empty()) error();
+ 5. if (!OrigInput.empty()) error();
}
with ``cl::CommaSeparated``, this modifier only makes sense with a `cl::list`_
option.
-So far, these are the only three miscellaneous option modifiers.
-
.. _response files:
Response files
// Option predicates...
static inline bool isGrouping(const Option *O) {
- return O->getFormattingFlag() == cl::Grouping;
+ return O->getMiscFlags() & cl::Grouping;
}
static inline bool isPrefixedOrGrouping(const Option *O) {
return isGrouping(O) || O->getFormattingFlag() == cl::Prefix ||
if (!PGOpt)
return nullptr;
- // If the option is a prefixed option, then the value is simply the
- // rest of the name... so fall through to later processing, by
- // setting up the argument name flags and value fields.
- if (PGOpt->getFormattingFlag() == cl::Prefix ||
- PGOpt->getFormattingFlag() == cl::AlwaysPrefix) {
- Value = Arg.substr(Length);
+ do {
+ StringRef MaybeValue =
+ (Length < Arg.size()) ? Arg.substr(Length) : StringRef();
Arg = Arg.substr(0, Length);
assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt);
- return PGOpt;
- }
- // This must be a grouped option... handle them now. Grouping options can't
- // have values.
- assert(isGrouping(PGOpt) && "Broken getOptionPred!");
+ // cl::Prefix options do not preserve '=' when used separately.
+ // The behavior for them with grouped options should be the same.
+ if (MaybeValue.empty() || PGOpt->getFormattingFlag() == cl::AlwaysPrefix ||
+ (PGOpt->getFormattingFlag() == cl::Prefix && MaybeValue[0] != '=')) {
+ Value = MaybeValue;
+ return PGOpt;
+ }
+
+ if (MaybeValue[0] == '=') {
+ Value = MaybeValue.substr(1);
+ return PGOpt;
+ }
- do {
- // Move current arg name out of Arg into OneArgName.
- StringRef OneArgName = Arg.substr(0, Length);
- Arg = Arg.substr(Length);
+ // This must be a grouped option.
+ assert(isGrouping(PGOpt) && "Broken getOptionPred!");
+ // Grouping options inside a group can't have values.
if (PGOpt->getValueExpectedFlag() == cl::ValueRequired) {
ErrorParsing |= PGOpt->error("may not occur within a group!");
return nullptr;
// Because the value for the option is not required, we don't need to pass
// argc/argv in.
int Dummy = 0;
- ErrorParsing |=
- ProvideOption(PGOpt, OneArgName, StringRef(), 0, nullptr, Dummy);
+ ErrorParsing |= ProvideOption(PGOpt, Arg, StringRef(), 0, nullptr, Dummy);
// Get the next grouping option.
+ Arg = MaybeValue;
PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap);
- } while (PGOpt && Length != Arg.size());
+ } while (PGOpt);
- // Return the last option with Arg cut down to just the last one.
- return PGOpt;
+ // We could not find a grouping option in the remainder of Arg.
+ return nullptr;
}
static bool RequiresValue(const Option *O) {
cl::ResetCommandLineParser();
StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
+ StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
+ StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed,
+ cl::desc("ValueDisallowed option"));
StackOption<std::string> OptV("v", cl::Grouping,
- cl::desc("Grouping option with a value"));
+ cl::desc("ValueRequired option"));
+ StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional,
+ cl::desc("ValueOptional option"));
// Should be possible to use an option which requires a value
// at the end of a group.
cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
EXPECT_TRUE(OptF);
EXPECT_STREQ("val1", OptV.c_str());
+ OptV.clear();
cl::ResetAllOptionOccurrences();
// Should not crash if it is accidentally used elsewhere in the group.
const char *args2[] = {"prog", "-vf", "val2"};
EXPECT_FALSE(
cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+ OptV.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should allow the "opt=value" form at the end of the group
+ const char *args3[] = {"prog", "-fv=val3"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val3", OptV.c_str());
+ OptV.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should allow assigning a value for a ValueOptional option
+ // at the end of the group
+ const char *args4[] = {"prog", "-fo=val4"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val4", OptO.c_str());
+ OptO.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should assign an empty value if a ValueOptional option is used elsewhere
+ // in the group.
+ const char *args5[] = {"prog", "-fob"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_EQ(1, OptO.getNumOccurrences());
+ EXPECT_EQ(1, OptB.getNumOccurrences());
+ EXPECT_TRUE(OptO.empty());
+ cl::ResetAllOptionOccurrences();
+
+ // Should not allow an assignment for a ValueDisallowed option.
+ const char *args6[] = {"prog", "-fd=false"};
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
+}
+
+TEST(CommandLineTest, GroupingAndPrefix) {
+ cl::ResetCommandLineParser();
+
+ StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
+ StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
+ StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping,
+ cl::desc("Prefix and Grouping"));
+ StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping,
+ cl::desc("AlwaysPrefix and Grouping"));
+
+ // Should be possible to use a cl::Prefix option without grouping.
+ const char *args1[] = {"prog", "-pval1"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
+ EXPECT_STREQ("val1", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should be possible to pass a value in a separate argument.
+ const char *args2[] = {"prog", "-p", "val2"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
+ EXPECT_STREQ("val2", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // The "-opt=value" form should work, too.
+ const char *args3[] = {"prog", "-p=val3"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
+ EXPECT_STREQ("val3", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // All three previous cases should work the same way if an option with both
+ // cl::Prefix and cl::Grouping modifiers is used at the end of a group.
+ const char *args4[] = {"prog", "-fpval4"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val4", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ const char *args5[] = {"prog", "-fp", "val5"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val5", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ const char *args6[] = {"prog", "-fp=val6"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val6", OptP.c_str());
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should assign a value even if the part after a cl::Prefix option is equal
+ // to the name of another option.
+ const char *args7[] = {"prog", "-fpb"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("b", OptP.c_str());
+ EXPECT_FALSE(OptB);
+ OptP.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should be possible to use a cl::AlwaysPrefix option without grouping.
+ const char *args8[] = {"prog", "-aval8"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls()));
+ EXPECT_STREQ("val8", OptA.c_str());
+ OptA.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should not be possible to pass a value in a separate argument.
+ const char *args9[] = {"prog", "-a", "val9"};
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls()));
+ cl::ResetAllOptionOccurrences();
+
+ // With the "-opt=value" form, the "=" symbol should be preserved.
+ const char *args10[] = {"prog", "-a=val10"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls()));
+ EXPECT_STREQ("=val10", OptA.c_str());
+ OptA.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // All three previous cases should work the same way if an option with both
+ // cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group.
+ const char *args11[] = {"prog", "-faval11"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("val11", OptA.c_str());
+ OptA.clear();
+ cl::ResetAllOptionOccurrences();
+
+ const char *args12[] = {"prog", "-fa", "val12"};
+ EXPECT_FALSE(
+ cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls()));
+ cl::ResetAllOptionOccurrences();
+
+ const char *args13[] = {"prog", "-fa=val13"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("=val13", OptA.c_str());
+ OptA.clear();
+ cl::ResetAllOptionOccurrences();
+
+ // Should assign a value even if the part after a cl::AlwaysPrefix option
+ // is equal to the name of another option.
+ const char *args14[] = {"prog", "-fab"};
+ EXPECT_TRUE(
+ cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls()));
+ EXPECT_TRUE(OptF);
+ EXPECT_STREQ("b", OptA.c_str());
+ EXPECT_FALSE(OptB);
+ OptA.clear();
+ cl::ResetAllOptionOccurrences();
}
} // anonymous namespace