Skip to content

Commit a38432c

Browse files
committed
[CommandLine] Allow grouping options which can have values.
This patch allows all forms of values for options to be used at the end of a group. With the fix, it is possible to follow the way GNU binutils tools handle grouping options better. For example, the -j option can be used with objdump in any of the following ways: $ objdump -d -j .text a.o $ objdump -d -j.text a.o $ objdump -dj .text a.o $ objdump -dj.text a.o Differential Revision: https://reviews.llvm.org/D58711 llvm-svn: 355185
1 parent 875f058 commit a38432c

File tree

5 files changed

+236
-52
lines changed

5 files changed

+236
-52
lines changed

llvm/docs/CommandLine.rst

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,12 +1168,18 @@ As usual, you can only specify one of these arguments at most.
11681168
.. _grouping:
11691169
.. _cl::Grouping:
11701170

1171-
* The **cl::Grouping** modifier is used to implement Unix-style tools (like
1172-
``ls``) that have lots of single letter arguments, but only require a single
1173-
dash. For example, the '``ls -labF``' command actually enables four different
1174-
options, all of which are single letters. Note that **cl::Grouping** options
1175-
can have values only if they are used separately or at the end of the groups.
1176-
It is a runtime error if such an option is used elsewhere in the group.
1171+
Controlling options grouping
1172+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
1173+
1174+
The **cl::Grouping** modifier can be combined with any formatting types except
1175+
for `cl::Positional`_. It is used to implement Unix-style tools (like ``ls``)
1176+
that have lots of single letter arguments, but only require a single dash.
1177+
For example, the '``ls -labF``' command actually enables four different options,
1178+
all of which are single letters.
1179+
1180+
Note that **cl::Grouping** options can have values only if they are used
1181+
separately or at the end of the groups. For `cl::ValueRequired`_, it is
1182+
a runtime error if such an option is used elsewhere in the group.
11771183

11781184
The CommandLine library does not restrict how you use the **cl::Prefix** or
11791185
**cl::Grouping** modifiers, but it is possible to specify ambiguous argument
@@ -1188,19 +1194,24 @@ basically looks like this:
11881194

11891195
parse(string OrigInput) {
11901196

1191-
1. string input = OrigInput;
1192-
2. if (isOption(input)) return getOption(input).parse(); // Normal option
1193-
3. while (!isOption(input) && !input.empty()) input.pop_back(); // Remove the last letter
1194-
4. if (input.empty()) return error(); // No matching option
1195-
5. if (getOption(input).isPrefix())
1196-
return getOption(input).parse(input);
1197-
6. while (!input.empty()) { // Must be grouping options
1198-
getOption(input).parse();
1199-
OrigInput.erase(OrigInput.begin(), OrigInput.begin()+input.length());
1200-
input = OrigInput;
1201-
while (!isOption(input) && !input.empty()) input.pop_back();
1197+
1. string Input = OrigInput;
1198+
2. if (isOption(Input)) return getOption(Input).parse(); // Normal option
1199+
3. while (!Input.empty() && !isOption(Input)) Input.pop_back(); // Remove the last letter
1200+
4. while (!Input.empty()) {
1201+
string MaybeValue = OrigInput.substr(Input.length())
1202+
if (getOption(Input).isPrefix())
1203+
return getOption(Input).parse(MaybeValue)
1204+
if (!MaybeValue.empty() && MaybeValue[0] == '=')
1205+
return getOption(Input).parse(MaybeValue.substr(1))
1206+
if (!getOption(Input).isGrouping())
1207+
return error()
1208+
getOption(Input).parse()
1209+
Input = OrigInput = MaybeValue
1210+
while (!Input.empty() && !isOption(Input)) Input.pop_back();
1211+
if (!Input.empty() && !getOption(Input).isGrouping())
1212+
return error()
12021213
}
1203-
7. if (!OrigInput.empty()) error();
1214+
5. if (!OrigInput.empty()) error();
12041215

12051216
}
12061217

@@ -1240,8 +1251,6 @@ specify boolean properties that modify the option.
12401251
with ``cl::CommaSeparated``, this modifier only makes sense with a `cl::list`_
12411252
option.
12421253

1243-
So far, these are the only three miscellaneous option modifiers.
1244-
12451254
.. _response files:
12461255

12471256
Response files

llvm/include/llvm/Support/CommandLine.h

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -158,23 +158,24 @@ enum OptionHidden { // Control whether -help shows this option
158158
// AlwaysPrefix - Only allow the behavior enabled by the Prefix flag and reject
159159
// the Option=Value form.
160160
//
161-
// Grouping - With this option enabled, multiple letter options are allowed to
162-
// bunch together with only a single hyphen for the whole group. This allows
163-
// emulation of the behavior that ls uses for example: ls -la === ls -l -a
164-
//
165161

166162
enum FormattingFlags {
167163
NormalFormatting = 0x00, // Nothing special
168164
Positional = 0x01, // Is a positional argument, no '-' required
169165
Prefix = 0x02, // Can this option directly prefix its value?
170-
AlwaysPrefix = 0x03, // Can this option only directly prefix its value?
171-
Grouping = 0x04 // Can this option group with other options?
166+
AlwaysPrefix = 0x03 // Can this option only directly prefix its value?
172167
};
173168

174169
enum MiscFlags { // Miscellaneous flags to adjust argument
175170
CommaSeparated = 0x01, // Should this cl::list split between commas?
176171
PositionalEatsArgs = 0x02, // Should this positional cl::list eat -args?
177-
Sink = 0x04 // Should this cl::list eat all unknown options?
172+
Sink = 0x04, // Should this cl::list eat all unknown options?
173+
174+
// Grouping - Can this option group with other options?
175+
// If this is enabled, multiple letter options are allowed to bunch together
176+
// with only a single hyphen for the whole group. This allows emulation
177+
// of the behavior that ls uses for example: ls -la === ls -l -a
178+
Grouping = 0x08
178179
};
179180

180181
//===----------------------------------------------------------------------===//
@@ -268,8 +269,8 @@ class Option {
268269
// detail representing the non-value
269270
unsigned Value : 2;
270271
unsigned HiddenFlag : 2; // enum OptionHidden
271-
unsigned Formatting : 3; // enum FormattingFlags
272-
unsigned Misc : 3;
272+
unsigned Formatting : 2; // enum FormattingFlags
273+
unsigned Misc : 4;
273274
unsigned Position = 0; // Position of last occurrence of the option
274275
unsigned AdditionalVals = 0; // Greater than 0 for multi-valued option.
275276

llvm/lib/Support/CommandLine.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -600,7 +600,7 @@ static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) {
600600

601601
// Option predicates...
602602
static inline bool isGrouping(const Option *O) {
603-
return O->getFormattingFlag() == cl::Grouping;
603+
return O->getMiscFlags() & cl::Grouping;
604604
}
605605
static inline bool isPrefixedOrGrouping(const Option *O) {
606606
return isGrouping(O) || O->getFormattingFlag() == cl::Prefix ||
@@ -651,26 +651,29 @@ HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value,
651651
if (!PGOpt)
652652
return nullptr;
653653

654-
// If the option is a prefixed option, then the value is simply the
655-
// rest of the name... so fall through to later processing, by
656-
// setting up the argument name flags and value fields.
657-
if (PGOpt->getFormattingFlag() == cl::Prefix ||
658-
PGOpt->getFormattingFlag() == cl::AlwaysPrefix) {
659-
Value = Arg.substr(Length);
654+
do {
655+
StringRef MaybeValue =
656+
(Length < Arg.size()) ? Arg.substr(Length) : StringRef();
660657
Arg = Arg.substr(0, Length);
661658
assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt);
662-
return PGOpt;
663-
}
664659

665-
// This must be a grouped option... handle them now. Grouping options can't
666-
// have values.
667-
assert(isGrouping(PGOpt) && "Broken getOptionPred!");
660+
// cl::Prefix options do not preserve '=' when used separately.
661+
// The behavior for them with grouped options should be the same.
662+
if (MaybeValue.empty() || PGOpt->getFormattingFlag() == cl::AlwaysPrefix ||
663+
(PGOpt->getFormattingFlag() == cl::Prefix && MaybeValue[0] != '=')) {
664+
Value = MaybeValue;
665+
return PGOpt;
666+
}
667+
668+
if (MaybeValue[0] == '=') {
669+
Value = MaybeValue.substr(1);
670+
return PGOpt;
671+
}
668672

669-
do {
670-
// Move current arg name out of Arg into OneArgName.
671-
StringRef OneArgName = Arg.substr(0, Length);
672-
Arg = Arg.substr(Length);
673+
// This must be a grouped option.
674+
assert(isGrouping(PGOpt) && "Broken getOptionPred!");
673675

676+
// Grouping options inside a group can't have values.
674677
if (PGOpt->getValueExpectedFlag() == cl::ValueRequired) {
675678
ErrorParsing |= PGOpt->error("may not occur within a group!");
676679
return nullptr;
@@ -679,15 +682,15 @@ HandlePrefixedOrGroupedOption(StringRef &Arg, StringRef &Value,
679682
// Because the value for the option is not required, we don't need to pass
680683
// argc/argv in.
681684
int Dummy = 0;
682-
ErrorParsing |=
683-
ProvideOption(PGOpt, OneArgName, StringRef(), 0, nullptr, Dummy);
685+
ErrorParsing |= ProvideOption(PGOpt, Arg, StringRef(), 0, nullptr, Dummy);
684686

685687
// Get the next grouping option.
688+
Arg = MaybeValue;
686689
PGOpt = getOptionPred(Arg, Length, isGrouping, OptionsMap);
687-
} while (PGOpt && Length != Arg.size());
690+
} while (PGOpt);
688691

689-
// Return the last option with Arg cut down to just the last one.
690-
return PGOpt;
692+
// We could not find a grouping option in the remainder of Arg.
693+
return nullptr;
691694
}
692695

693696
static bool RequiresValue(const Option *O) {

llvm/tools/llvm-readobj/llvm-readobj.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,7 @@ static void registerReadelfAliases() {
688688
StringRef ArgName = OptEntry.getKey();
689689
cl::Option *Option = OptEntry.getValue();
690690
if (ArgName.size() == 1)
691-
Option->setFormattingFlag(cl::Grouping);
691+
apply(Option, cl::Grouping);
692692
}
693693
}
694694

llvm/unittests/Support/CommandLineTest.cpp

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,8 +1132,13 @@ TEST(CommandLineTest, GroupingWithValue) {
11321132
cl::ResetCommandLineParser();
11331133

11341134
StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1135+
StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1136+
StackOption<bool> OptD("d", cl::Grouping, cl::ValueDisallowed,
1137+
cl::desc("ValueDisallowed option"));
11351138
StackOption<std::string> OptV("v", cl::Grouping,
1136-
cl::desc("Grouping option with a value"));
1139+
cl::desc("ValueRequired option"));
1140+
StackOption<std::string> OptO("o", cl::Grouping, cl::ValueOptional,
1141+
cl::desc("ValueOptional option"));
11371142

11381143
// Should be possible to use an option which requires a value
11391144
// at the end of a group.
@@ -1142,12 +1147,178 @@ TEST(CommandLineTest, GroupingWithValue) {
11421147
cl::ParseCommandLineOptions(3, args1, StringRef(), &llvm::nulls()));
11431148
EXPECT_TRUE(OptF);
11441149
EXPECT_STREQ("val1", OptV.c_str());
1150+
OptV.clear();
11451151
cl::ResetAllOptionOccurrences();
11461152

11471153
// Should not crash if it is accidentally used elsewhere in the group.
11481154
const char *args2[] = {"prog", "-vf", "val2"};
11491155
EXPECT_FALSE(
11501156
cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1157+
OptV.clear();
1158+
cl::ResetAllOptionOccurrences();
1159+
1160+
// Should allow the "opt=value" form at the end of the group
1161+
const char *args3[] = {"prog", "-fv=val3"};
1162+
EXPECT_TRUE(
1163+
cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1164+
EXPECT_TRUE(OptF);
1165+
EXPECT_STREQ("val3", OptV.c_str());
1166+
OptV.clear();
1167+
cl::ResetAllOptionOccurrences();
1168+
1169+
// Should allow assigning a value for a ValueOptional option
1170+
// at the end of the group
1171+
const char *args4[] = {"prog", "-fo=val4"};
1172+
EXPECT_TRUE(
1173+
cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1174+
EXPECT_TRUE(OptF);
1175+
EXPECT_STREQ("val4", OptO.c_str());
1176+
OptO.clear();
1177+
cl::ResetAllOptionOccurrences();
1178+
1179+
// Should assign an empty value if a ValueOptional option is used elsewhere
1180+
// in the group.
1181+
const char *args5[] = {"prog", "-fob"};
1182+
EXPECT_TRUE(
1183+
cl::ParseCommandLineOptions(2, args5, StringRef(), &llvm::nulls()));
1184+
EXPECT_TRUE(OptF);
1185+
EXPECT_EQ(1, OptO.getNumOccurrences());
1186+
EXPECT_EQ(1, OptB.getNumOccurrences());
1187+
EXPECT_TRUE(OptO.empty());
1188+
cl::ResetAllOptionOccurrences();
1189+
1190+
// Should not allow an assignment for a ValueDisallowed option.
1191+
const char *args6[] = {"prog", "-fd=false"};
1192+
EXPECT_FALSE(
1193+
cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1194+
}
1195+
1196+
TEST(CommandLineTest, GroupingAndPrefix) {
1197+
cl::ResetCommandLineParser();
1198+
1199+
StackOption<bool> OptF("f", cl::Grouping, cl::desc("Some flag"));
1200+
StackOption<bool> OptB("b", cl::Grouping, cl::desc("Another flag"));
1201+
StackOption<std::string> OptP("p", cl::Prefix, cl::Grouping,
1202+
cl::desc("Prefix and Grouping"));
1203+
StackOption<std::string> OptA("a", cl::AlwaysPrefix, cl::Grouping,
1204+
cl::desc("AlwaysPrefix and Grouping"));
1205+
1206+
// Should be possible to use a cl::Prefix option without grouping.
1207+
const char *args1[] = {"prog", "-pval1"};
1208+
EXPECT_TRUE(
1209+
cl::ParseCommandLineOptions(2, args1, StringRef(), &llvm::nulls()));
1210+
EXPECT_STREQ("val1", OptP.c_str());
1211+
OptP.clear();
1212+
cl::ResetAllOptionOccurrences();
1213+
1214+
// Should be possible to pass a value in a separate argument.
1215+
const char *args2[] = {"prog", "-p", "val2"};
1216+
EXPECT_TRUE(
1217+
cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
1218+
EXPECT_STREQ("val2", OptP.c_str());
1219+
OptP.clear();
1220+
cl::ResetAllOptionOccurrences();
1221+
1222+
// The "-opt=value" form should work, too.
1223+
const char *args3[] = {"prog", "-p=val3"};
1224+
EXPECT_TRUE(
1225+
cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
1226+
EXPECT_STREQ("val3", OptP.c_str());
1227+
OptP.clear();
1228+
cl::ResetAllOptionOccurrences();
1229+
1230+
// All three previous cases should work the same way if an option with both
1231+
// cl::Prefix and cl::Grouping modifiers is used at the end of a group.
1232+
const char *args4[] = {"prog", "-fpval4"};
1233+
EXPECT_TRUE(
1234+
cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
1235+
EXPECT_TRUE(OptF);
1236+
EXPECT_STREQ("val4", OptP.c_str());
1237+
OptP.clear();
1238+
cl::ResetAllOptionOccurrences();
1239+
1240+
const char *args5[] = {"prog", "-fp", "val5"};
1241+
EXPECT_TRUE(
1242+
cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
1243+
EXPECT_TRUE(OptF);
1244+
EXPECT_STREQ("val5", OptP.c_str());
1245+
OptP.clear();
1246+
cl::ResetAllOptionOccurrences();
1247+
1248+
const char *args6[] = {"prog", "-fp=val6"};
1249+
EXPECT_TRUE(
1250+
cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
1251+
EXPECT_TRUE(OptF);
1252+
EXPECT_STREQ("val6", OptP.c_str());
1253+
OptP.clear();
1254+
cl::ResetAllOptionOccurrences();
1255+
1256+
// Should assign a value even if the part after a cl::Prefix option is equal
1257+
// to the name of another option.
1258+
const char *args7[] = {"prog", "-fpb"};
1259+
EXPECT_TRUE(
1260+
cl::ParseCommandLineOptions(2, args7, StringRef(), &llvm::nulls()));
1261+
EXPECT_TRUE(OptF);
1262+
EXPECT_STREQ("b", OptP.c_str());
1263+
EXPECT_FALSE(OptB);
1264+
OptP.clear();
1265+
cl::ResetAllOptionOccurrences();
1266+
1267+
// Should be possible to use a cl::AlwaysPrefix option without grouping.
1268+
const char *args8[] = {"prog", "-aval8"};
1269+
EXPECT_TRUE(
1270+
cl::ParseCommandLineOptions(2, args8, StringRef(), &llvm::nulls()));
1271+
EXPECT_STREQ("val8", OptA.c_str());
1272+
OptA.clear();
1273+
cl::ResetAllOptionOccurrences();
1274+
1275+
// Should not be possible to pass a value in a separate argument.
1276+
const char *args9[] = {"prog", "-a", "val9"};
1277+
EXPECT_FALSE(
1278+
cl::ParseCommandLineOptions(3, args9, StringRef(), &llvm::nulls()));
1279+
cl::ResetAllOptionOccurrences();
1280+
1281+
// With the "-opt=value" form, the "=" symbol should be preserved.
1282+
const char *args10[] = {"prog", "-a=val10"};
1283+
EXPECT_TRUE(
1284+
cl::ParseCommandLineOptions(2, args10, StringRef(), &llvm::nulls()));
1285+
EXPECT_STREQ("=val10", OptA.c_str());
1286+
OptA.clear();
1287+
cl::ResetAllOptionOccurrences();
1288+
1289+
// All three previous cases should work the same way if an option with both
1290+
// cl::AlwaysPrefix and cl::Grouping modifiers is used at the end of a group.
1291+
const char *args11[] = {"prog", "-faval11"};
1292+
EXPECT_TRUE(
1293+
cl::ParseCommandLineOptions(2, args11, StringRef(), &llvm::nulls()));
1294+
EXPECT_TRUE(OptF);
1295+
EXPECT_STREQ("val11", OptA.c_str());
1296+
OptA.clear();
1297+
cl::ResetAllOptionOccurrences();
1298+
1299+
const char *args12[] = {"prog", "-fa", "val12"};
1300+
EXPECT_FALSE(
1301+
cl::ParseCommandLineOptions(3, args12, StringRef(), &llvm::nulls()));
1302+
cl::ResetAllOptionOccurrences();
1303+
1304+
const char *args13[] = {"prog", "-fa=val13"};
1305+
EXPECT_TRUE(
1306+
cl::ParseCommandLineOptions(2, args13, StringRef(), &llvm::nulls()));
1307+
EXPECT_TRUE(OptF);
1308+
EXPECT_STREQ("=val13", OptA.c_str());
1309+
OptA.clear();
1310+
cl::ResetAllOptionOccurrences();
1311+
1312+
// Should assign a value even if the part after a cl::AlwaysPrefix option
1313+
// is equal to the name of another option.
1314+
const char *args14[] = {"prog", "-fab"};
1315+
EXPECT_TRUE(
1316+
cl::ParseCommandLineOptions(2, args14, StringRef(), &llvm::nulls()));
1317+
EXPECT_TRUE(OptF);
1318+
EXPECT_STREQ("b", OptA.c_str());
1319+
EXPECT_FALSE(OptB);
1320+
OptA.clear();
1321+
cl::ResetAllOptionOccurrences();
11511322
}
11521323

11531324
} // anonymous namespace

0 commit comments

Comments
 (0)