/* Distributed under the OSI-approved BSD 3-Clause License. See accompanying file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmCMakeLanguageCommand.h" #include #include #include #include #include #include #include #include "cmExecutionStatus.h" #include "cmListFileCache.h" #include "cmMakefile.h" #include "cmRange.h" #include "cmStringAlgorithms.h" #include "cmSystemTools.h" namespace { std::array InvalidCommands{ { // clang-format off "function"_s, "endfunction"_s, "macro"_s, "endmacro"_s, "if"_s, "elseif"_s, "else"_s, "endif"_s, "while"_s, "endwhile"_s, "foreach"_s, "endforeach"_s } // clang-format on }; } bool cmCMakeLanguageCommand(std::vector const& args, cmExecutionStatus& status) { if (args.empty()) { status.SetError("called with incorrect number of arguments"); return false; } cmMakefile& makefile = status.GetMakefile(); cmListFileContext context = makefile.GetExecutionContext(); bool result = false; std::vector dispatchExpandedArgs; std::vector dispatchArgs; dispatchArgs.emplace_back(args[0]); makefile.ExpandArguments(dispatchArgs, dispatchExpandedArgs); if (dispatchExpandedArgs.empty()) { status.SetError("called with incorrect number of arguments"); return false; } if (dispatchExpandedArgs[0] == "CALL") { if ((args.size() == 1 && dispatchExpandedArgs.size() != 2) || dispatchExpandedArgs.size() > 2) { status.SetError("called with incorrect number of arguments"); return false; } // First argument is the name of the function to call std::string callCommand; size_t startArg; if (dispatchExpandedArgs.size() == 1) { std::vector functionExpandedArg; std::vector functionArg; functionArg.emplace_back(args[1]); makefile.ExpandArguments(functionArg, functionExpandedArg); if (functionExpandedArg.size() != 1) { status.SetError("called with incorrect number of arguments"); return false; } callCommand = functionExpandedArg[0]; startArg = 2; } else { callCommand = dispatchExpandedArgs[1]; startArg = 1; } // ensure specified command is valid // start/end flow control commands are not allowed auto cmd = cmSystemTools::LowerCase(callCommand); if (std::find(InvalidCommands.cbegin(), InvalidCommands.cend(), cmd) != InvalidCommands.cend()) { status.SetError(cmStrCat("invalid command specified: "_s, callCommand)); return false; } cmListFileFunction func; func.Name = callCommand; func.Line = context.Line; // The rest of the arguments are passed to the function call above for (size_t i = startArg; i < args.size(); ++i) { cmListFileArgument lfarg; lfarg.Delim = args[i].Delim; lfarg.Line = context.Line; lfarg.Value = args[i].Value; func.Arguments.emplace_back(lfarg); } result = makefile.ExecuteCommand(func, status); } else if (dispatchExpandedArgs[0] == "EVAL") { std::vector expandedArgs; makefile.ExpandArguments(args, expandedArgs); if (expandedArgs.size() < 2) { status.SetError("called with incorrect number of arguments"); return false; } if (expandedArgs[1] != "CODE") { auto code_iter = std::find(expandedArgs.begin() + 2, expandedArgs.end(), "CODE"); if (code_iter == expandedArgs.end()) { status.SetError("called without CODE argument"); } else { status.SetError( "called with unsupported arguments between EVAL and CODE arguments"); } return false; } const std::string code = cmJoin(cmMakeRange(expandedArgs.begin() + 2, expandedArgs.end()), " "); result = makefile.ReadListFileAsString( code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL")); } else { status.SetError("called with unknown meta-operation"); } return result; }