diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/Support/CommandLine.h | 3 | ||||
-rw-r--r-- | llvm/lib/Support/CommandLine.cpp | 60 | ||||
-rw-r--r-- | llvm/unittests/Support/CommandLineTest.cpp | 73 |
3 files changed, 115 insertions, 21 deletions
diff --git a/llvm/include/llvm/Support/CommandLine.h b/llvm/include/llvm/Support/CommandLine.h index 68cbebe5de8..d144c9b0f0f 100644 --- a/llvm/include/llvm/Support/CommandLine.h +++ b/llvm/include/llvm/Support/CommandLine.h @@ -66,7 +66,8 @@ namespace cl { bool ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview = "", raw_ostream *Errs = nullptr, - const char *EnvVar = nullptr); + const char *EnvVar = nullptr, + bool LongOptionsUseDoubleDash = false); //===----------------------------------------------------------------------===// // ParseEnvironmentOptions - Environment variable option processing alternate diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index 28516476d58..4e63a07673a 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -105,6 +105,16 @@ static StringRef argPrefix(StringRef ArgName) { return ArgPrefixLong; } +// Option predicates... +static inline bool isGrouping(const Option *O) { + return O->getMiscFlags() & cl::Grouping; +} +static inline bool isPrefixedOrGrouping(const Option *O) { + return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || + O->getFormattingFlag() == cl::AlwaysPrefix; +} + + namespace { class PrintArg { @@ -148,7 +158,8 @@ public: void ResetAllOptionOccurrences(); bool ParseCommandLineOptions(int argc, const char *const *argv, - StringRef Overview, raw_ostream *Errs = nullptr); + StringRef Overview, raw_ostream *Errs = nullptr, + bool LongOptionsUseDoubleDash = false); void addLiteralOption(Option &Opt, SubCommand *SC, StringRef Name) { if (Opt.hasArgStr()) @@ -394,6 +405,13 @@ private: SubCommand *ActiveSubCommand; Option *LookupOption(SubCommand &Sub, StringRef &Arg, StringRef &Value); + Option *LookupLongOption(SubCommand &Sub, StringRef &Arg, StringRef &Value, + bool LongOptionsUseDoubleDash, bool HaveDoubleDash) { + Option *Opt = LookupOption(Sub, Arg, Value); + if (Opt && LongOptionsUseDoubleDash && !HaveDoubleDash && !isGrouping(Opt)) + return nullptr; + return Opt; + } SubCommand *LookupSubCommand(StringRef Name); }; @@ -679,15 +697,6 @@ static bool ProvidePositionalOption(Option *Handler, StringRef Arg, int i) { return ProvideOption(Handler, Handler->ArgStr, Arg, 0, nullptr, Dummy); } -// Option predicates... -static inline bool isGrouping(const Option *O) { - return O->getMiscFlags() & cl::Grouping; -} -static inline bool isPrefixedOrGrouping(const Option *O) { - return isGrouping(O) || O->getFormattingFlag() == cl::Prefix || - O->getFormattingFlag() == cl::AlwaysPrefix; -} - // getOptionPred - Check to see if there are any options that satisfy the // specified predicate with names that are the prefixes in Name. This is // checked by progressively stripping characters off of the name, checking to @@ -697,8 +706,9 @@ static inline bool isPrefixedOrGrouping(const Option *O) { static Option *getOptionPred(StringRef Name, size_t &Length, bool (*Pred)(const Option *), const StringMap<Option *> &OptionsMap) { - StringMap<Option *>::const_iterator OMI = OptionsMap.find(Name); + if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) + OMI = OptionsMap.end(); // Loop while we haven't found an option and Name still has at least two // characters in it (so that the next iteration will not be the empty @@ -706,6 +716,8 @@ static Option *getOptionPred(StringRef Name, size_t &Length, while (OMI == OptionsMap.end() && Name.size() > 1) { Name = Name.substr(0, Name.size() - 1); // Chop off the last character. OMI = OptionsMap.find(Name); + if (OMI != OptionsMap.end() && !Pred(OMI->getValue())) + OMI = OptionsMap.end(); } if (OMI != OptionsMap.end() && Pred(OMI->second)) { @@ -1166,7 +1178,8 @@ void cl::ParseEnvironmentOptions(const char *progName, const char *envVar, bool cl::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, raw_ostream *Errs, - const char *EnvVar) { + const char *EnvVar, + bool LongOptionsUseDoubleDash) { SmallVector<const char *, 20> NewArgv; BumpPtrAllocator A; StringSaver Saver(A); @@ -1186,7 +1199,7 @@ bool cl::ParseCommandLineOptions(int argc, const char *const *argv, // Parse all options. return GlobalParser->ParseCommandLineOptions(NewArgc, &NewArgv[0], Overview, - Errs); + Errs, LongOptionsUseDoubleDash); } void CommandLineParser::ResetAllOptionOccurrences() { @@ -1201,7 +1214,8 @@ void CommandLineParser::ResetAllOptionOccurrences() { bool CommandLineParser::ParseCommandLineOptions(int argc, const char *const *argv, StringRef Overview, - raw_ostream *Errs) { + raw_ostream *Errs, + bool LongOptionsUseDoubleDash) { assert(hasOptions() && "No options specified!"); // Expand response files. @@ -1311,6 +1325,7 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, std::string NearestHandlerString; StringRef Value; StringRef ArgName = ""; + bool HaveDoubleDash = false; // Check to see if this is a positional argument. This argument is // considered to be positional if it doesn't start with '-', if it is "-" @@ -1349,25 +1364,30 @@ bool CommandLineParser::ParseCommandLineOptions(int argc, // otherwise feed it to the eating positional. ArgName = StringRef(argv[i] + 1); // Eat second dash. - if (!ArgName.empty() && ArgName[0] == '-') + if (!ArgName.empty() && ArgName[0] == '-') { + HaveDoubleDash = true; ArgName = ArgName.substr(1); + } - Handler = LookupOption(*ChosenSubCommand, ArgName, Value); + Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, + LongOptionsUseDoubleDash, HaveDoubleDash); if (!Handler || Handler->getFormattingFlag() != cl::Positional) { ProvidePositionalOption(ActivePositionalArg, StringRef(argv[i]), i); continue; // We are done! } - } else { // We start with a '-', must be an argument. ArgName = StringRef(argv[i] + 1); // Eat second dash. - if (!ArgName.empty() && ArgName[0] == '-') + if (!ArgName.empty() && ArgName[0] == '-') { + HaveDoubleDash = true; ArgName = ArgName.substr(1); + } - Handler = LookupOption(*ChosenSubCommand, ArgName, Value); + Handler = LookupLongOption(*ChosenSubCommand, ArgName, Value, + LongOptionsUseDoubleDash, HaveDoubleDash); // Check to see if this "option" is really a prefixed or grouped argument. - if (!Handler) + if (!Handler && !(LongOptionsUseDoubleDash && HaveDoubleDash)) Handler = HandlePrefixedOrGroupedOption(ArgName, Value, ErrorParsing, OptionsMap); diff --git a/llvm/unittests/Support/CommandLineTest.cpp b/llvm/unittests/Support/CommandLineTest.cpp index 8869674372e..2bf07e37494 100644 --- a/llvm/unittests/Support/CommandLineTest.cpp +++ b/llvm/unittests/Support/CommandLineTest.cpp @@ -1527,4 +1527,77 @@ TEST(CommandLineTest, GroupingAndPrefix) { cl::ResetAllOptionOccurrences(); } +TEST(CommandLineTest, LongOptions) { + cl::ResetCommandLineParser(); + + StackOption<bool> OptA("a", cl::desc("Some flag")); + StackOption<bool> OptBLong("long-flag", cl::desc("Some long flag")); + StackOption<bool, cl::alias> OptB("b", cl::desc("Alias to --long-flag"), + cl::aliasopt(OptBLong)); + StackOption<std::string> OptAB("ab", cl::desc("Another long option")); + + std::string Errs; + raw_string_ostream OS(Errs); + + const char *args1[] = {"prog", "-a", "-ab", "val1"}; + const char *args2[] = {"prog", "-a", "--ab", "val1"}; + const char *args3[] = {"prog", "-ab", "--ab", "val1"}; + + // + // The following tests treat `-` and `--` the same, and always match the + // longest string. + // + + EXPECT_TRUE( + cl::ParseCommandLineOptions(4, args1, StringRef(), &OS)); OS.flush(); + EXPECT_TRUE(OptA); + EXPECT_FALSE(OptBLong); + EXPECT_STREQ("val1", OptAB.c_str()); + EXPECT_TRUE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); + + EXPECT_TRUE( + cl::ParseCommandLineOptions(4, args2, StringRef(), &OS)); OS.flush(); + EXPECT_TRUE(OptA); + EXPECT_FALSE(OptBLong); + EXPECT_STREQ("val1", OptAB.c_str()); + EXPECT_TRUE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); + + // Fails because `-ab` and `--ab` are treated the same and appear more than + // once. Also, `val1` is unexpected. + EXPECT_FALSE( + cl::ParseCommandLineOptions(4, args3, StringRef(), &OS)); OS.flush(); + outs()<< Errs << "\n"; + EXPECT_FALSE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); + + // + // The following tests treat `-` and `--` differently, with `-` for short, and + // `--` for long options. + // + + // Fails because `-ab` is treated as `-a -b`, so `-a` is seen twice, and + // `val1` is unexpected. + EXPECT_FALSE(cl::ParseCommandLineOptions(4, args1, StringRef(), + &OS, nullptr, true)); OS.flush(); + EXPECT_FALSE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); + + // Works because `-a` is treated differently than `--ab`. + EXPECT_TRUE(cl::ParseCommandLineOptions(4, args2, StringRef(), + &OS, nullptr, true)); OS.flush(); + EXPECT_TRUE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); + + // Works because `-ab` is treated as `-a -b`, and `--ab` is a long option. + EXPECT_TRUE(cl::ParseCommandLineOptions(4, args3, StringRef(), + &OS, nullptr, true)); + EXPECT_TRUE(OptA); + EXPECT_TRUE(OptBLong); + EXPECT_STREQ("val1", OptAB.c_str()); + OS.flush(); + EXPECT_TRUE(Errs.empty()); Errs.clear(); + cl::ResetAllOptionOccurrences(); +} } // anonymous namespace |