1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
/* 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 <algorithm>
#include <array>
#include <cstddef>
#include <memory>
#include <string>
#include <cm/string_view>
#include <cmext/string_view>
#include "cmExecutionStatus.h"
#include "cmListFileCache.h"
#include "cmMakefile.h"
#include "cmRange.h"
#include "cmStringAlgorithms.h"
#include "cmSystemTools.h"
namespace {
std::array<cm::static_string_view, 12> 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 cmCMakeLanguageCommandCALL(std::vector<cmListFileArgument> const& args,
std::string const& callCommand,
size_t startArg, cmExecutionStatus& status)
{
// 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;
}
cmMakefile& makefile = status.GetMakefile();
cmListFileContext context = makefile.GetBacktrace().Top();
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);
}
return makefile.ExecuteCommand(func, status);
}
bool cmCMakeLanguageCommandEVAL(std::vector<cmListFileArgument> const& args,
cmExecutionStatus& status)
{
cmMakefile& makefile = status.GetMakefile();
cmListFileContext context = makefile.GetBacktrace().Top();
std::vector<std::string> 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()), " ");
return makefile.ReadListFileAsString(
code, cmStrCat(context.FilePath, ":", context.Line, ":EVAL"));
}
}
bool cmCMakeLanguageCommand(std::vector<cmListFileArgument> const& args,
cmExecutionStatus& status)
{
std::vector<std::string> expArgs;
size_t rawArg = 0;
size_t expArg = 0;
// Helper to consume and expand one raw argument at a time.
auto moreArgs = [&]() -> bool {
while (expArg >= expArgs.size()) {
if (rawArg >= args.size()) {
return false;
}
std::vector<cmListFileArgument> tmpArg;
tmpArg.emplace_back(args[rawArg++]);
status.GetMakefile().ExpandArguments(tmpArg, expArgs);
}
return true;
};
if (!moreArgs()) {
status.SetError("called with incorrect number of arguments");
return false;
}
if (expArgs[expArg] == "CALL") {
++expArg; // Consume "CALL".
// CALL requires a command name.
if (!moreArgs()) {
status.SetError("CALL missing command name");
return false;
}
std::string const& callCommand = expArgs[expArg++];
// CALL accepts no further expanded arguments.
if (expArg != expArgs.size()) {
status.SetError("CALL command's arguments must be literal");
return false;
}
// Run the CALL.
return cmCMakeLanguageCommandCALL(args, callCommand, rawArg, status);
}
if (expArgs[expArg] == "EVAL") {
return cmCMakeLanguageCommandEVAL(args, status);
}
status.SetError("called with unknown meta-operation");
return false;
}
|