Browse Source

Add a string(FIND) sub-command (#11795)

Tim Hütz 14 years ago
parent
commit
1462561a8c

+ 67 - 1
Source/cmStringCommand.cxx

@@ -72,7 +72,11 @@ bool cmStringCommand
     {
     return this->HandleRandomCommand(args);
     }
-  
+  else if(subCommand == "FIND")
+    {
+    return this->HandleFindCommand(args);
+    }
+
   std::string e = "does not recognize sub-command "+subCommand;
   this->SetError(e.c_str());
   return false;
@@ -498,6 +502,68 @@ void cmStringCommand::StoreMatches(cmMakefile* mf,cmsys::RegularExpression& re)
     }
 }
 
+//----------------------------------------------------------------------------
+bool cmStringCommand::HandleFindCommand(std::vector<std::string> const&
+                                           args)
+{
+  // check if all required parameters were passed
+  if(args.size() < 4 || args.size() > 5)
+    {
+    this->SetError("sub-command FIND requires 3 or 4 parameters.");
+    return false;
+    }
+
+  // check if the reverse flag was set or not
+  bool reverseMode = false;
+  if(args.size() == 5 && args[4] == "REVERSE")
+    {
+    reverseMode = true;
+    }
+
+  // if we have 5 arguments the last one must be REVERSE
+  if(args.size() == 5 && args[4] != "REVERSE")
+    {
+    this->SetError("sub-command FIND: unknown last parameter");
+    return false;
+    }
+
+  // local parameter names.
+  const std::string& sstring = args[1];
+  const std::string& schar = args[2];
+  const std::string& outvar = args[3];
+
+  // ensure that the user cannot accidentally specify REVERSE as a variable
+  if(outvar == "REVERSE")
+    {
+    this->SetError("sub-command FIND does not allow to select REVERSE as "
+                   "the output variable.  "
+                   "Maybe you missed the actual output variable?");
+    return false;
+    }
+
+  // try to find the character and return its position
+  size_t pos;
+  if(!reverseMode)
+    {
+    pos = sstring.find(schar);
+    }
+  else
+    {
+    pos = sstring.rfind(schar);
+    }
+  if(std::string::npos != pos)
+    {
+    std::stringstream s;
+    s << pos;
+    this->Makefile->AddDefinition(outvar.c_str(), s.str().c_str());
+    return true;
+    }
+
+  // the character was not found, but this is not really an error
+  this->Makefile->AddDefinition(outvar.c_str(), "-1");
+  return true;
+}
+
 //----------------------------------------------------------------------------
 bool cmStringCommand::HandleCompareCommand(std::vector<std::string> const&
                                            args)

+ 6 - 0
Source/cmStringCommand.h

@@ -90,6 +90,7 @@ public:
       "  string(STRIP <string> <output variable>)\n"
       "  string(RANDOM [LENGTH <length>] [ALPHABET <alphabet>]\n"
       "         [RANDOM_SEED <seed>] <output variable>)\n"
+      "  string(FIND <string> <substring> <output variable> [REVERSE])\n"
       "REGEX MATCH will match the regular expression once and store the "
       "match in the output variable.\n"
       "REGEX MATCHALL will match the regular expression as many times as "
@@ -117,6 +118,10 @@ public:
       "characters and default alphabet is all numbers and upper and "
       "lower case letters.  If an integer RANDOM_SEED is given, its "
       "value will be used to seed the random number generator.\n"
+      "FIND will return the position where the given substring was found "
+      "in the supplied string. If the REVERSE flag was used, the command "
+      "will search for the position of the last occurrence of the "
+      "specified substring.\n"
       "The following characters have special meaning in regular expressions:\n"
       "   ^         Matches at beginning of a line\n"
       "   $         Matches at end of a line\n"
@@ -152,6 +157,7 @@ protected:
   bool HandleSubstringCommand(std::vector<std::string> const& args);
   bool HandleStripCommand(std::vector<std::string> const& args);
   bool HandleRandomCommand(std::vector<std::string> const& args);
+  bool HandleFindCommand(std::vector<std::string> const& args);
 
   class RegexReplacement
   {

+ 1 - 1
Tests/CMakeTests/StringTest.cmake.in

@@ -1,7 +1,7 @@
 # Execute each test listed in StringTestScript.cmake:
 #
 set(scriptname "@CMAKE_CURRENT_SOURCE_DIR@/StringTestScript.cmake")
-set(number_of_tests_expected 52)
+set(number_of_tests_expected 69)
 
 include("@CMAKE_CURRENT_SOURCE_DIR@/ExecuteScriptTests.cmake")
 execute_all_script_tests(${scriptname} number_of_tests_executed)

+ 77 - 0
Tests/CMakeTests/StringTestScript.cmake

@@ -194,6 +194,83 @@ elseif(testname STREQUAL random_with_various_alphabets) # pass
   string(RANDOM LENGTH 78 ALPHABET "~`!@#$%^&*()_-+={}[]\\|:\\;'\",.<>/?" v)
   message(STATUS "v='${v}'")
 
+elseif(testname STREQUAL string_find_with_no_parameter) # fail
+  string(FIND)
+
+elseif(testname STREQUAL string_find_with_one_parameter) # fail
+  string(FIND "CMake is great.")
+
+elseif(testname STREQUAL string_find_with_two_parameters) # fail
+  string(FIND "CMake is great." "a")
+
+elseif(testname STREQUAL string_find_with_three_parameters) # pass
+  string(FIND "CMake is great." "a" v)
+  message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL string_find_with_four_parameters) # fail
+  string(FIND "CMake is great." "a" v v2)
+
+elseif(testname STREQUAL string_find_reverse_with_no_parameter) # fail
+  string(FIND REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_one_parameter) # fail
+  string(FIND "CMake is great." REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_two_parameters) # fail
+  string(FIND "CMake is great." "a" REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_three_parameters) # pass
+  string(FIND "CMake is great." "a" v REVERSE)
+  message(STATUS "v='${v}'")
+
+elseif(testname STREQUAL string_find_reverse_with_four_parameters_part1) # fail
+  string(FIND "CMake is great." "a" v v2 REVERSE)
+
+elseif(testname STREQUAL string_find_reverse_with_four_parameters_part2) # fail
+  string(FIND "CMake is great." "a" v REVERSE v2)
+
+elseif(testname STREQUAL string_find_with_no_possible_result) # pass
+  string(FIND "CMake is a great application." "z" v)
+  message(STATUS "v='${v}'")
+  if(NOT(-1 EQUAL ${v}))
+    message(SEND_ERROR "FIND sub-command should return -1 but returned ${v}.")
+  endif(NOT(-1 EQUAL ${v}))
+
+elseif(testname STREQUAL string_find_reverse_with_no_possible_result) # pass
+  string(FIND "CMake is a great application." "z" v REVERSE)
+  message(STATUS "v='${v}'")
+  if(NOT(-1 EQUAL ${v}))
+    message(SEND_ERROR "FIND REVERSE sub-command should return -1 but returned ${v}.")
+  endif(NOT(-1 EQUAL ${v}))
+
+elseif(testname STREQUAL string_find_with_required_result) # pass
+  string(FIND "CMake is a great application." "g" v)
+  message(STATUS "v='${v}'")
+  if(NOT(11 EQUAL ${v}))
+    message(SEND_ERROR "FIND sub-command should return 11 but returned ${v}.")
+  endif(NOT(11 EQUAL ${v}))
+
+elseif(testname STREQUAL string_find_reverse_with_required_result) # pass
+  string(FIND "CMake is a great application." "e" v REVERSE)
+  message(STATUS "v='${v}'")
+  if(NOT(13 EQUAL ${v}))
+    message(SEND_ERROR "FIND REVERSE sub-command should return 13 but returned ${v}.")
+  endif(NOT(13 EQUAL ${v}))
+
+elseif(testname STREQUAL string_find_word_reverse_with_required_result) # pass
+  string(FIND "The command should find REVERSE in this string. Or maybe this REVERSE?!" "REVERSE" v)
+  message(STATUS "v='${v}'")
+  if(NOT(24 EQUAL ${v}))
+    message(SEND_ERROR "FIND sub-command should return 24 but returned ${v}.")
+  endif(NOT(24 EQUAL ${v}))
+
+elseif(testname STREQUAL string_find_reverse_word_reverse_with_required_result) # pass
+  string(FIND "The command should find REVERSE in this string. Or maybe this REVERSE?!" "REVERSE" v REVERSE)
+  message(STATUS "v='${v}'")
+  if(NOT(62 EQUAL ${v}))
+    message(SEND_ERROR "FIND sub-command should return 62 but returned ${v}.")
+  endif(NOT(62 EQUAL ${v}))
+
 else() # fail
   message(FATAL_ERROR "testname='${testname}' - error: no such test in '${CMAKE_CURRENT_LIST_FILE}'")