From 1462561a8cab7cf3cad9979019778f3c13b0bdf9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20H=C3=BCtz?= Date: Tue, 15 Feb 2011 11:20:47 +0100 Subject: [PATCH] Add a string(FIND) sub-command (#11795) --- Source/cmStringCommand.cxx | 68 +++++++++++++++++++++- Source/cmStringCommand.h | 6 ++ Tests/CMakeTests/StringTest.cmake.in | 2 +- Tests/CMakeTests/StringTestScript.cmake | 77 +++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 2 deletions(-) diff --git a/Source/cmStringCommand.cxx b/Source/cmStringCommand.cxx index 949fcf5ef..1f873e208 100644 --- a/Source/cmStringCommand.cxx +++ b/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 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 const& args) diff --git a/Source/cmStringCommand.h b/Source/cmStringCommand.h index 2a916b407..958644941 100644 --- a/Source/cmStringCommand.h +++ b/Source/cmStringCommand.h @@ -90,6 +90,7 @@ public: " string(STRIP )\n" " string(RANDOM [LENGTH ] [ALPHABET ]\n" " [RANDOM_SEED ] )\n" + " string(FIND [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 const& args); bool HandleStripCommand(std::vector const& args); bool HandleRandomCommand(std::vector const& args); + bool HandleFindCommand(std::vector const& args); class RegexReplacement { diff --git a/Tests/CMakeTests/StringTest.cmake.in b/Tests/CMakeTests/StringTest.cmake.in index 54fee7f4c..6bb60f4fe 100644 --- a/Tests/CMakeTests/StringTest.cmake.in +++ b/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) diff --git a/Tests/CMakeTests/StringTestScript.cmake b/Tests/CMakeTests/StringTestScript.cmake index 37038561d..8dfdc8926 100644 --- a/Tests/CMakeTests/StringTestScript.cmake +++ b/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}'")