llvm.org GIT mirror llvm / eea49ed
Add support for prefix-only CLI options Summary: Add support for options that always prefix their value, giving an error if the value is in the next argument or if the option is given a value assignment (ie. opt=val). This is the desired behavior for the -D option of FileCheck for instance. Copyright: - Linaro (changes in version 2 of revision D55940) - GraphCore (changes in later versions and introduced when creating D56549) Reviewers: jdenny Subscribers: llvm-commits, probinson, kristina, hiraditya, JonChesterfield Differential Revision: https://reviews.llvm.org/D56549 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351038 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme 1 year, 9 months ago
3 changed file(s) with 95 addition(s) and 8 deletion(s). Raw diff Collapse all Expand all
155155 // enabled, and used, the value for the flag comes from the suffix of the
156156 // argument.
157157 //
158 // AlwaysPrefix - Only allow the behavior enabled by the Prefix flag and reject
159 // the Option=Value form.
160 //
158161 // Grouping - With this option enabled, multiple letter options are allowed to
159162 // bunch together with only a single hyphen for the whole group. This allows
160163 // emulation of the behavior that ls uses for example: ls -la === ls -l -a
164167 NormalFormatting = 0x00, // Nothing special
165168 Positional = 0x01, // Is a positional argument, no '-' required
166169 Prefix = 0x02, // Can this option directly prefix its value?
167 Grouping = 0x03 // Can this option group with other options?
170 AlwaysPrefix = 0x03, // Can this option only directly prefix its value?
171 Grouping = 0x04 // Can this option group with other options?
168172 };
169173
170174 enum MiscFlags { // Miscellaneous flags to adjust argument
264268 // detail representing the non-value
265269 unsigned Value : 2;
266270 unsigned HiddenFlag : 2; // enum OptionHidden
267 unsigned Formatting : 2; // enum FormattingFlags
271 unsigned Formatting : 3; // enum FormattingFlags
268272 unsigned Misc : 3;
269273 unsigned Position = 0; // Position of last occurrence of the option
270274 unsigned AdditionalVals = 0; // Greater than 0 for multi-valued option.
425425 return I != Sub.OptionsMap.end() ? I->second : nullptr;
426426 }
427427
428 // If the argument before the = is a valid option name, we match. If not,
429 // return Arg unmolested.
428 // If the argument before the = is a valid option name and the option allows
429 // non-prefix form (ie is not AlwaysPrefix), we match. If not, signal match
430 // failure by returning nullptr.
430431 auto I = Sub.OptionsMap.find(Arg.substr(0, EqualPos));
431432 if (I == Sub.OptionsMap.end())
433 return nullptr;
434
435 auto O = I->second;
436 if (O->getFormattingFlag() == cl::AlwaysPrefix)
432437 return nullptr;
433438
434439 Value = Arg.substr(EqualPos + 1);
538543 switch (Handler->getValueExpectedFlag()) {
539544 case ValueRequired:
540545 if (!Value.data()) { // No value specified?
541 if (i + 1 >= argc)
546 // If no other argument or the option only supports prefix form, we
547 // cannot look at the next argument.
548 if (i + 1 >= argc || Handler->getFormattingFlag() == cl::AlwaysPrefix)
542549 return Handler->error("requires a value!");
543550 // Steal the next argument, like for '-o filename'
544551 assert(argv && "null check");
596603 return O->getFormattingFlag() == cl::Grouping;
597604 }
598605 static inline bool isPrefixedOrGrouping(const Option *O) {
599 return isGrouping(O) || O->getFormattingFlag() == cl::Prefix;
606 return isGrouping(O) || O->getFormattingFlag() == cl::Prefix ||
607 O->getFormattingFlag() == cl::AlwaysPrefix;
600608 }
601609
602610 // getOptionPred - Check to see if there are any options that satisfy the
646654 // If the option is a prefixed option, then the value is simply the
647655 // rest of the name... so fall through to later processing, by
648656 // setting up the argument name flags and value fields.
649 if (PGOpt->getFormattingFlag() == cl::Prefix) {
657 if (PGOpt->getFormattingFlag() == cl::Prefix ||
658 PGOpt->getFormattingFlag() == cl::AlwaysPrefix) {
650659 Value = Arg.substr(Length);
651660 Arg = Arg.substr(0, Length);
652661 assert(OptionsMap.count(Arg) && OptionsMap.find(Arg)->second == PGOpt);
839839 }
840840 #endif
841841
842 } // anonymous namespace
842 TEST(CommandLineTest, PrefixOptions) {
843 cl::ResetCommandLineParser();
844
845 StackOption> IncludeDirs(
846 "I", cl::Prefix, cl::desc("Declare an include directory"));
847
848 // Test non-prefixed variant works with cl::Prefix options.
849 EXPECT_TRUE(IncludeDirs.empty());
850 const char *args[] = {"prog", "-I=/usr/include"};
851 EXPECT_TRUE(
852 cl::ParseCommandLineOptions(2, args, StringRef(), &llvm::nulls()));
853 EXPECT_TRUE(IncludeDirs.size() == 1);
854 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
855
856 IncludeDirs.erase(IncludeDirs.begin());
857 cl::ResetAllOptionOccurrences();
858
859 // Test non-prefixed variant works with cl::Prefix options when value is
860 // passed in following argument.
861 EXPECT_TRUE(IncludeDirs.empty());
862 const char *args2[] = {"prog", "-I", "/usr/include"};
863 EXPECT_TRUE(
864 cl::ParseCommandLineOptions(3, args2, StringRef(), &llvm::nulls()));
865 EXPECT_TRUE(IncludeDirs.size() == 1);
866 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
867
868 IncludeDirs.erase(IncludeDirs.begin());
869 cl::ResetAllOptionOccurrences();
870
871 // Test prefixed variant works with cl::Prefix options.
872 EXPECT_TRUE(IncludeDirs.empty());
873 const char *args3[] = {"prog", "-I/usr/include"};
874 EXPECT_TRUE(
875 cl::ParseCommandLineOptions(2, args3, StringRef(), &llvm::nulls()));
876 EXPECT_TRUE(IncludeDirs.size() == 1);
877 EXPECT_TRUE(IncludeDirs.front().compare("/usr/include") == 0);
878
879 StackOption> MacroDefs(
880 "D", cl::AlwaysPrefix, cl::desc("Define a macro"),
881 cl::value_desc("MACRO[=VALUE]"));
882
883 cl::ResetAllOptionOccurrences();
884
885 // Test non-prefixed variant does not work with cl::AlwaysPrefix options:
886 // equal sign is part of the value.
887 EXPECT_TRUE(MacroDefs.empty());
888 const char *args4[] = {"prog", "-D=HAVE_FOO"};
889 EXPECT_TRUE(
890 cl::ParseCommandLineOptions(2, args4, StringRef(), &llvm::nulls()));
891 EXPECT_TRUE(MacroDefs.size() == 1);
892 EXPECT_TRUE(MacroDefs.front().compare("=HAVE_FOO") == 0);
893
894 MacroDefs.erase(MacroDefs.begin());
895 cl::ResetAllOptionOccurrences();
896
897 // Test non-prefixed variant does not allow value to be passed in following
898 // argument with cl::AlwaysPrefix options.
899 EXPECT_TRUE(MacroDefs.empty());
900 const char *args5[] = {"prog", "-D", "HAVE_FOO"};
901 EXPECT_FALSE(
902 cl::ParseCommandLineOptions(3, args5, StringRef(), &llvm::nulls()));
903 EXPECT_TRUE(MacroDefs.empty());
904
905 cl::ResetAllOptionOccurrences();
906
907 // Test prefixed variant works with cl::AlwaysPrefix options.
908 EXPECT_TRUE(MacroDefs.empty());
909 const char *args6[] = {"prog", "-DHAVE_FOO"};
910 EXPECT_TRUE(
911 cl::ParseCommandLineOptions(2, args6, StringRef(), &llvm::nulls()));
912 EXPECT_TRUE(MacroDefs.size() == 1);
913 EXPECT_TRUE(MacroDefs.front().compare("HAVE_FOO") == 0);
914 }
915
916 } // anonymous namespace