diff options
17 files changed, 139 insertions, 4 deletions
diff --git a/Help/command/cmake_parse_arguments.rst b/Help/command/cmake_parse_arguments.rst index 6206611..ec4ffed 100644 --- a/Help/command/cmake_parse_arguments.rst +++ b/Help/command/cmake_parse_arguments.rst @@ -11,6 +11,17 @@ respective options. cmake_parse_arguments(<prefix> <options> <one_value_keywords> <multi_value_keywords> args...) + cmake_parse_arguments(PARSE_ARGV N <prefix> <options> <one_value_keywords> + <multi_value_keywords>) + +The first signature reads processes arguments passed in the ``args...``. +This may be used in either a :command:`macro` or a :command:`function`. + +The ``PARSE_ARGV`` signature is only for use in a :command:`function` +body. In this case the arguments that are parsed come from the +``ARGV#`` variables of the calling function. The parsing starts with +the Nth argument, where ``N`` is an unsigned integer. This allows for +the values to have special characters like ``;`` in them. The ``<options>`` argument contains all options for the respective macro, i.e. keywords which can be used when calling the macro without any value diff --git a/Help/release/dev/parse_arguments_argv_n.rst b/Help/release/dev/parse_arguments_argv_n.rst new file mode 100644 index 0000000..758b72a --- /dev/null +++ b/Help/release/dev/parse_arguments_argv_n.rst @@ -0,0 +1,6 @@ +parse_arguments_argv_n +---------------------- + +* The :command:`cmake_parse_arguments` command gained a new + mode to read arguments directly from ``ARGC`` and ``ARGV#`` + variables inside a :command:`function` body. diff --git a/Source/cmParseArgumentsCommand.cxx b/Source/cmParseArgumentsCommand.cxx index 8f524ec..f9313c5 100644 --- a/Source/cmParseArgumentsCommand.cxx +++ b/Source/cmParseArgumentsCommand.cxx @@ -20,6 +20,8 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, { // cmake_parse_arguments(prefix options single multi <ARGN>) // 1 2 3 4 + // or + // cmake_parse_arguments(PARSE_ARGV N prefix options single multi) if (args.size() < 4) { this->SetError("must be called with at least 4 arguments."); return false; @@ -27,6 +29,27 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, std::vector<std::string>::const_iterator argIter = args.begin(), argEnd = args.end(); + bool parseFromArgV = false; + unsigned long argvStart = 0; + if (*argIter == "PARSE_ARGV") { + if (args.size() != 6) { + this->Makefile->IssueMessage( + cmake::FATAL_ERROR, + "PARSE_ARGV must be called with exactly 6 arguments."); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + parseFromArgV = true; + argIter++; // move past PARSE_ARGV + if (!cmSystemTools::StringToULong(argIter->c_str(), &argvStart)) { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, "PARSE_ARGV index '" + + *argIter + + "' is not an unsigned integer"); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + argIter++; // move past N + } // the first argument is the prefix const std::string prefix = (*argIter++) + "_"; @@ -90,11 +113,37 @@ bool cmParseArgumentsCommand::InitialPass(std::vector<std::string> const& args, } insideValues = NONE; std::string currentArgName; - // Flatten ;-lists in the arguments into a single list as was done - // by the original function(CMAKE_PARSE_ARGUMENTS). list.clear(); - for (; argIter != argEnd; ++argIter) { - cmSystemTools::ExpandListArgument(*argIter, list); + if (!parseFromArgV) { + // Flatten ;-lists in the arguments into a single list as was done + // by the original function(CMAKE_PARSE_ARGUMENTS). + for (; argIter != argEnd; ++argIter) { + cmSystemTools::ExpandListArgument(*argIter, list); + } + } else { + // in the PARSE_ARGV move read the arguments from ARGC and ARGV# + std::string argc = this->Makefile->GetSafeDefinition("ARGC"); + unsigned long count; + if (!cmSystemTools::StringToULong(argc.c_str(), &count)) { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "PARSE_ARGV called with ARGC='" + argc + + "' that is not an unsigned integer"); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + for (unsigned long i = argvStart; i < count; ++i) { + std::ostringstream argName; + argName << "ARGV" << i; + const char* arg = this->Makefile->GetDefinition(argName.str()); + if (!arg) { + this->Makefile->IssueMessage(cmake::FATAL_ERROR, + "PARSE_ARGV called with " + + argName.str() + " not set"); + cmSystemTools::SetFatalErrorOccured(); + return true; + } + list.push_back(arg); + } } // iterate over the arguments list and fill in the values where applicable diff --git a/Tests/RunCMake/cmake_parse_arguments/ArgvN.cmake b/Tests/RunCMake/cmake_parse_arguments/ArgvN.cmake new file mode 100644 index 0000000..61bde03 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/ArgvN.cmake @@ -0,0 +1,30 @@ +include(${CMAKE_CURRENT_LIST_DIR}/test_utils.cmake) + +function(test1) + cmake_parse_arguments(PARSE_ARGV 0 + pref "OPT1;OPT2" "SINGLE1;SINGLE2" "MULTI1;MULTI2") + + TEST(pref_OPT1 TRUE) + TEST(pref_OPT2 FALSE) + TEST(pref_SINGLE1 "foo;bar") + TEST(pref_SINGLE2 UNDEFINED) + TEST(pref_MULTI1 bar foo bar) + TEST(pref_MULTI2 UNDEFINED) + TEST(pref_UNPARSED_ARGUMENTS UNDEFINED) +endfunction() +test1(OPT1 SINGLE1 "foo;bar" MULTI1 bar foo bar) + +function(test2 arg1) + cmake_parse_arguments(PARSE_ARGV 1 + pref "OPT1;OPT2" "SINGLE1;SINGLE2" "MULTI1;MULTI2") + + TEST(arg1 "first named") + TEST(pref_OPT1 TRUE) + TEST(pref_OPT2 FALSE) + TEST(pref_SINGLE1 "foo;bar") + TEST(pref_SINGLE2 UNDEFINED) + TEST(pref_MULTI1 bar foo bar) + TEST(pref_MULTI2 UNDEFINED) + TEST(pref_UNPARSED_ARGUMENTS UNDEFINED) +endfunction() +test2("first named" OPT1 SINGLE1 "foo;bar" MULTI1 bar foo bar) diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-result.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-stderr.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-stderr.txt new file mode 100644 index 0000000..e44ab4d --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at BadArgvN1.cmake:[0-9]+ \(cmake_parse_arguments\): + PARSE_ARGV must be called with exactly 6 arguments. +Call Stack \(most recent call first\): + BadArgvN1.cmake:[0-9]+ \(test1\) + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN1.cmake b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1.cmake new file mode 100644 index 0000000..f894130 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN1.cmake @@ -0,0 +1,4 @@ +function(test1) + cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "" extra) +endfunction() +test1() diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-result.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-stderr.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-stderr.txt new file mode 100644 index 0000000..1dde86d --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2-stderr.txt @@ -0,0 +1,5 @@ +^CMake Error at BadArgvN2.cmake:[0-9]+ \(cmake_parse_arguments\): + PARSE_ARGV index 'pref' is not an unsigned integer +Call Stack \(most recent call first\): + BadArgvN2.cmake:[0-9]+ \(test2\) + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN2.cmake b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2.cmake new file mode 100644 index 0000000..d20c2c8 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN2.cmake @@ -0,0 +1,4 @@ +function(test2) + cmake_parse_arguments(PARSE_ARGV pref "" "" "" extra) +endfunction() +test2() diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-result.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-stderr.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-stderr.txt new file mode 100644 index 0000000..5a30dc9 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at BadArgvN3.cmake:[0-9]+ \(cmake_parse_arguments\): + PARSE_ARGV called with ARGC='' that is not an unsigned integer +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN3.cmake b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3.cmake new file mode 100644 index 0000000..8fb3fdd --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN3.cmake @@ -0,0 +1 @@ +cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "") diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-result.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-stderr.txt b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-stderr.txt new file mode 100644 index 0000000..f4bdac4 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at BadArgvN4.cmake:[0-9]+ \(cmake_parse_arguments\): + PARSE_ARGV called with ARGV0 not set +Call Stack \(most recent call first\): + CMakeLists.txt:[0-9]+ \(include\)$ diff --git a/Tests/RunCMake/cmake_parse_arguments/BadArgvN4.cmake b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4.cmake new file mode 100644 index 0000000..b887a28 --- /dev/null +++ b/Tests/RunCMake/cmake_parse_arguments/BadArgvN4.cmake @@ -0,0 +1,3 @@ +set(ARGC 1) +cmake_parse_arguments(PARSE_ARGV 0 pref "" "" "") +unset(ARGC) diff --git a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake index b89f1a5..22d7ee4 100644 --- a/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake +++ b/Tests/RunCMake/cmake_parse_arguments/RunCMakeTest.cmake @@ -5,3 +5,8 @@ run_cmake(Initialization) run_cmake(Mix) run_cmake(CornerCases) run_cmake(Errors) +run_cmake(ArgvN) +run_cmake(BadArgvN1) +run_cmake(BadArgvN2) +run_cmake(BadArgvN3) +run_cmake(BadArgvN4) |