blob: 9b0560e043d8df0150bdefca9e651ee27a45ac59 [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "func.h"
18
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090019#include <errno.h>
Dan Willemsenf06d8012016-10-03 00:16:07 -070020#include <fcntl.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090021#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090023#include <stdlib.h>
Dan Willemsenf06d8012016-10-03 00:16:07 -070024#include <sys/stat.h>
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090025#include <unistd.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090026
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090027#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090028#include <iterator>
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090029#include <memory>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090030#include <unordered_map>
31
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090032#include "eval.h"
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090033#include "fileutil.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090034#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090035#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090036#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090037#include "stats.h"
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090038#include "stmt.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090039#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090040#include "symtab.h"
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090041#include "var.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090042
43namespace {
44
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090045// TODO: This code is very similar to
46// NinjaGenerator::TranslateCommand. Factor them out.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090047void StripShellComment(string* cmd) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090048 if (cmd->find('#') == string::npos)
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090049 return;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090050
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090051 string res;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090052 bool prev_backslash = false;
53 // Set space as an initial value so the leading comment will be
54 // stripped out.
55 char prev_char = ' ';
56 char quote = 0;
57 bool done = false;
58 const char* in = cmd->c_str();
59 for (; *in && !done; in++) {
60 switch (*in) {
61 case '#':
62 if (quote == 0 && isspace(prev_char)) {
Shinichiro Hamaji212b7a52015-10-05 17:02:29 +090063 while (in[1] && *in != '\n')
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090064 in++;
65 break;
66 }
Dan Willemsen72887f22018-10-09 18:04:38 -070067#if defined(__has_cpp_attribute) && __has_cpp_attribute(clang::fallthrough)
Dan Willemsenee57a3f2018-11-05 16:18:44 -080068 [[clang::fallthrough]];
Dan Willemsen72887f22018-10-09 18:04:38 -070069#endif
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090070
71 case '\'':
72 case '"':
73 case '`':
74 if (quote) {
75 if (quote == *in)
76 quote = 0;
77 } else if (!prev_backslash) {
78 quote = *in;
79 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090080 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090081 break;
82
83 case '\\':
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090084 res += '\\';
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090085 break;
86
87 default:
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090088 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090089 }
90
91 if (*in == '\\') {
92 prev_backslash = !prev_backslash;
93 } else {
94 prev_backslash = false;
95 }
96
97 prev_char = *in;
98 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090099 cmd->swap(res);
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900100}
101
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900102void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900103 const string&& pat_str = args[0]->Eval(ev);
104 const string&& repl = args[1]->Eval(ev);
105 const string&& str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900106 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900107 Pattern pat(pat_str);
108 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900109 ww.MaybeAddWhitespace();
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900110 pat.AppendSubst(tok, repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900111 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900112}
113
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900114void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900115 const string&& str = args[0]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900116 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900117 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900118 ww.Write(tok);
119 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900120}
121
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900122void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900123 const string&& pat = args[0]->Eval(ev);
124 const string&& repl = args[1]->Eval(ev);
125 const string&& str = args[2]->Eval(ev);
126 if (pat.empty()) {
127 *s += str;
128 *s += repl;
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +0900129 return;
130 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900131 size_t index = 0;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900132 while (index < str.size()) {
133 size_t found = str.find(pat, index);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900134 if (found == string::npos)
135 break;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900136 AppendString(StringPiece(str).substr(index, found - index), s);
137 AppendString(repl, s);
138 index = found + pat.size();
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900139 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900140 AppendString(StringPiece(str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900141}
142
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900143void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900144 const string&& find = args[0]->Eval(ev);
145 const string&& in = args[1]->Eval(ev);
146 if (in.find(find) != string::npos)
147 AppendString(find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900148}
149
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900150void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900151 const string&& pat_buf = args[0]->Eval(ev);
152 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900153 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900154 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900155 pats.push_back(Pattern(pat));
156 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900157 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900158 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900159 for (const Pattern& pat : pats) {
160 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900161 ww.Write(tok);
162 break;
163 }
164 }
165 }
166}
167
168void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900169 const string&& pat_buf = args[0]->Eval(ev);
170 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900171 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900172 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900173 pats.push_back(Pattern(pat));
174 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900175 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900176 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900177 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900178 for (const Pattern& pat : pats) {
179 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900180 matched = true;
181 break;
182 }
183 }
184 if (!matched)
185 ww.Write(tok);
186 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900187}
188
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900189void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900190 string list;
191 args[0]->Eval(ev, &list);
192 COLLECT_STATS("func sort time");
Shinichiro Hamaji2d353a02016-02-15 18:24:42 +0900193 // TODO(hamaji): Probably we could use a faster string-specific sort
194 // algorithm.
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900195 vector<StringPiece> toks;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900196 WordScanner(list).Split(&toks);
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900197 stable_sort(toks.begin(), toks.end());
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900198 WordWriter ww(s);
199 StringPiece prev;
200 for (StringPiece tok : toks) {
201 if (prev != tok) {
202 ww.Write(tok);
203 prev = tok;
204 }
205 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900206}
207
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900208static int GetNumericValueForFunc(const string& buf) {
209 StringPiece s = TrimLeftSpace(buf);
210 char* end;
211 long n = strtol(s.data(), &end, 10);
212 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
213 return -1;
214 }
215 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900216}
217
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900218void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900219 const string&& n_str = args[0]->Eval(ev);
220 int n = GetNumericValueForFunc(n_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900221 if (n < 0) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700222 ev->Error(
223 StringPrintf("*** non-numeric first argument to `word' function: '%s'.",
224 n_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900225 }
226 if (n == 0) {
227 ev->Error("*** first argument to `word' function must be greater than 0.");
228 }
229
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900230 const string&& text = args[1]->Eval(ev);
231 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900232 n--;
233 if (n == 0) {
234 AppendString(tok, s);
235 break;
236 }
237 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900238}
239
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900240void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900241 const string&& s_str = args[0]->Eval(ev);
242 int si = GetNumericValueForFunc(s_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900243 if (si < 0) {
244 ev->Error(StringPrintf(
245 "*** non-numeric first argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900246 s_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900247 }
248 if (si == 0) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700249 ev->Error(
250 StringPrintf("*** invalid first argument to `wordlist' function: %s`",
251 s_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900252 }
253
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900254 const string&& e_str = args[1]->Eval(ev);
255 int ei = GetNumericValueForFunc(e_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900256 if (ei < 0) {
257 ev->Error(StringPrintf(
258 "*** non-numeric second argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900259 e_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900260 }
261
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900262 const string&& text = args[2]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900263 int i = 0;
264 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900265 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900266 i++;
267 if (si <= i && i <= ei) {
268 ww.Write(tok);
269 }
270 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900271}
272
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900273void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900274 const string&& text = args[0]->Eval(ev);
275 WordScanner ws(text);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900276 int n = 0;
277 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
278 n++;
279 char buf[32];
280 sprintf(buf, "%d", n);
281 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900282}
283
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900284void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900285 const string&& text = args[0]->Eval(ev);
286 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900287 AppendString(tok, s);
288 return;
289 }
290}
291
292void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900293 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900294 StringPiece last;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900295 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900296 last = tok;
297 }
298 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900299}
300
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900301void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900302 const string&& list1 = args[0]->Eval(ev);
303 const string&& list2 = args[1]->Eval(ev);
304 WordScanner ws1(list1);
305 WordScanner ws2(list2);
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900306 WordWriter ww(s);
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900307 WordScanner::Iterator iter1, iter2;
308 for (iter1 = ws1.begin(), iter2 = ws2.begin();
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700309 iter1 != ws1.end() && iter2 != ws2.end(); ++iter1, ++iter2) {
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900310 ww.Write(*iter1);
311 // Use |AppendString| not to append extra ' '.
312 AppendString(*iter2, s);
313 }
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900314 for (; iter1 != ws1.end(); ++iter1)
315 ww.Write(*iter1);
316 for (; iter2 != ws2.end(); ++iter2)
317 ww.Write(*iter2);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900318}
319
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900320void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900321 const string&& pat = args[0]->Eval(ev);
Shinichiro Hamajib67a2992015-11-07 14:11:09 +0900322 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji7409aee2015-07-28 14:52:37 +0900323 // Note GNU make does not delay the execution of $(wildcard) so we
324 // do not need to check avoid_io here.
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900325 WordWriter ww(s);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900326 vector<string>* files;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900327 for (StringPiece tok : WordScanner(pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900328 ScopedTerminator st(tok);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900329 Glob(tok.data(), &files);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900330 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900331 ww.Write(file);
332 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900333 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900334}
335
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900336void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900337 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900338 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900339 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900340 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900341 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900342 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900343}
344
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900345void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900346 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900347 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900348 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900349 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900350 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900351 } else {
352 ww.Write(Basename(tok));
353 }
354 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900355}
356
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900357void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900358 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900359 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900360 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900361 StringPiece suf = GetExt(tok);
362 if (!suf.empty())
363 ww.Write(suf);
364 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900365}
366
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900367void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900368 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900369 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900370 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900371 ww.Write(StripExt(tok));
372 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900373}
374
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900375void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900376 const string&& suf = args[0]->Eval(ev);
377 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900378 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900379 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900380 ww.Write(tok);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900381 *s += suf;
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900382 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900383}
384
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900385void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900386 const string&& pre = args[0]->Eval(ev);
387 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900388 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900389 for (StringPiece tok : WordScanner(text)) {
390 ww.Write(pre);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900391 AppendString(tok, s);
392 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900393}
394
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900395void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900396 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900397 if (ev->avoid_io()) {
Shinichiro Hamaji71cf60b2015-10-08 18:00:07 +0900398 *s += "$(";
399 string kati_binary;
400 GetExecutablePath(&kati_binary);
401 *s += kati_binary;
402 *s += " --realpath ";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900403 *s += text;
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900404 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900405 return;
406 }
407
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900408 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900409 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900410 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900411 char buf[PATH_MAX];
412 if (realpath(tok.data(), buf))
Shinichiro Hamajicb4724e2015-10-08 17:52:49 +0900413 ww.Write(buf);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900414 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900415}
416
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900417void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900418 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900419 WordWriter ww(s);
420 string buf;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900421 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900422 AbsPath(tok, &buf);
423 ww.Write(buf);
424 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900425}
426
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900427void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900428 const string&& cond = args[0]->Eval(ev);
429 if (cond.empty()) {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900430 if (args.size() > 2)
431 args[2]->Eval(ev, s);
432 } else {
433 args[1]->Eval(ev, s);
434 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900435}
436
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900437void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900438 string cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900439 for (Value* a : args) {
440 cond = a->Eval(ev);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900441 if (cond.empty())
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900442 return;
443 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900444 if (!cond.empty()) {
445 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900446 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900447}
448
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900449void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
450 for (Value* a : args) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900451 const string&& cond = a->Eval(ev);
452 if (!cond.empty()) {
453 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900454 return;
455 }
456 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900457}
458
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900459void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900460 const string&& var_name = args[0]->Eval(ev);
461 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900462 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900463}
464
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900465void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900466 // TODO: eval leaks everything... for now.
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700467 // const string text = args[0]->Eval(ev);
Dan Willemsen36e57292017-10-09 11:23:32 -0700468 ev->CheckStack();
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900469 string* text = new string;
470 args[0]->Eval(ev, text);
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900471 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700472 KATI_WARN_LOC(ev->loc(),
473 "*warning*: $(eval) in a recipe is not recommended: %s",
Dan Willemsene41c7552017-02-22 14:31:16 -0800474 text->c_str());
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900475 }
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900476 vector<Stmt*> stmts;
477 Parse(*text, ev->loc(), &stmts);
478 for (Stmt* stmt : stmts) {
479 LOG("%s", stmt->DebugString().c_str());
480 stmt->Eval(ev);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700481 // delete stmt;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900482 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900483}
484
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900485//#define TEST_FIND_EMULATOR
486
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900487// A hack for Android build. We need to evaluate things like $((3+4))
488// when we emit ninja file, because the result of such expressions
489// will be passed to other make functions.
490// TODO: Maybe we should introduce a helper binary which evaluate
491// make expressions at ninja-time.
492static bool HasNoIoInShellScript(const string& cmd) {
493 if (cmd.empty())
494 return true;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700495 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size() - 1] == ')')
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900496 return true;
497 return false;
498}
499
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700500static void ShellFuncImpl(const string& shell,
501 const string& shellflag,
502 const string& cmd,
503 const Loc& loc,
504 string* s,
Dan Willemsen692e64e2017-02-22 15:38:33 -0800505 FindCommand** fc) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900506 LOG("ShellFunc: %s", cmd.c_str());
507
508#ifdef TEST_FIND_EMULATOR
509 bool need_check = false;
510 string out2;
511#endif
512 if (FindEmulator::Get()) {
513 *fc = new FindCommand();
514 if ((*fc)->Parse(cmd)) {
515#ifdef TEST_FIND_EMULATOR
Dan Willemsen692e64e2017-02-22 15:38:33 -0800516 if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, &out2)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900517 need_check = true;
518 }
519#else
Dan Willemsen692e64e2017-02-22 15:38:33 -0800520 if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, s)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900521 return;
522 }
523#endif
524 }
525 delete *fc;
526 *fc = NULL;
527 }
528
529 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd.c_str());
Dan Willemsen064be222016-09-30 20:17:14 -0700530 RunCommand(shell, shellflag, cmd, RedirectStderr::NONE, s);
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700531 FormatForCommandSubstitution(s);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900532
533#ifdef TEST_FIND_EMULATOR
534 if (need_check) {
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700535 if (*s != out2) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700536 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s", cmd.c_str(), s->c_str(),
537 out2.c_str());
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900538 }
539 }
540#endif
541}
542
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900543static vector<CommandResult*> g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900544
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900545bool ShouldStoreCommandResult(StringPiece cmd) {
Dan Willemsen40e5a3d2016-09-16 19:35:32 -0700546 // We really just want to ignore this one, or remove BUILD_DATETIME from
547 // Android completely
548 if (cmd == "date +%s")
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900549 return false;
Colin Crossf23ae8c2015-11-12 17:05:32 -0800550
551 Pattern pat(g_flags.ignore_dirty_pattern);
552 Pattern nopat(g_flags.no_ignore_dirty_pattern);
553 for (StringPiece tok : WordScanner(cmd)) {
554 if (pat.Match(tok) && !nopat.Match(tok)) {
555 return false;
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900556 }
557 }
Colin Crossf23ae8c2015-11-12 17:05:32 -0800558
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900559 return true;
560}
561
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900562void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900563 string cmd = args[0]->Eval(ev);
564 if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900565 if (ev->eval_depth() > 1) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700566 ERROR_LOC(ev->loc(),
567 "kati doesn't support passing results of $(shell) "
Dan Willemsene41c7552017-02-22 14:31:16 -0800568 "to other make constructs: %s",
569 cmd.c_str());
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900570 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900571 StripShellComment(&cmd);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900572 *s += "$(";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900573 *s += cmd;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900574 *s += ")";
575 return;
576 }
577
Dan Willemsen064be222016-09-30 20:17:14 -0700578 const string&& shell = ev->GetShell();
579 const string&& shellflag = ev->GetShellFlag();
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900580
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900581 string out;
582 FindCommand* fc = NULL;
Dan Willemsen692e64e2017-02-22 15:38:33 -0800583 ShellFuncImpl(shell, shellflag, cmd, ev->loc(), &out, &fc);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900584 if (ShouldStoreCommandResult(cmd)) {
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900585 CommandResult* cr = new CommandResult();
Dan Willemsenf06d8012016-10-03 00:16:07 -0700586 cr->op = (fc == NULL) ? CommandOp::SHELL : CommandOp::FIND,
Stefan Beckerd4f28712016-04-07 13:29:36 +0300587 cr->shell = shell;
Dan Willemsen064be222016-09-30 20:17:14 -0700588 cr->shellflag = shellflag;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900589 cr->cmd = cmd;
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900590 cr->find.reset(fc);
591 cr->result = out;
592 g_command_results.push_back(cr);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900593 }
594 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900595}
596
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900597void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900598 static const Symbol tmpvar_names[] = {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700599 Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
600 Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")};
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900601
Dan Willemsen36e57292017-10-09 11:23:32 -0700602 ev->CheckStack();
Shinichiro Hamajid8d43ea2016-04-27 16:10:47 +0900603 const string&& func_name_buf = args[0]->Eval(ev);
Dan Willemsencf015302018-09-15 12:57:42 -0700604 Symbol func_sym = Intern(TrimSpace(func_name_buf));
605 Var* func = ev->LookupVar(func_sym);
606 func->Used(ev, func_sym);
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900607 if (!func->IsDefined()) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800608 KATI_WARN_LOC(ev->loc(), "*warning*: undefined user function: %s",
Dan Willemsencf015302018-09-15 12:57:42 -0700609 func_sym.c_str());
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900610 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900611 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900612 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900613 unique_ptr<SimpleVar> s(
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900614 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900615 av.push_back(move(s));
616 }
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900617 vector<unique_ptr<ScopedGlobalVar>> sv;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700618 for (size_t i = 1;; i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700619 string s;
Sasha Smundak8174f9b2018-08-13 11:07:30 -0700620 Symbol tmpvar_name_sym;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700621 if (i < sizeof(tmpvar_names) / sizeof(tmpvar_names[0])) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900622 tmpvar_name_sym = tmpvar_names[i];
Colin Cross580cc1f2015-07-27 13:18:18 -0700623 } else {
624 s = StringPrintf("%d", i);
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900625 tmpvar_name_sym = Intern(s);
Colin Cross580cc1f2015-07-27 13:18:18 -0700626 }
Dan Willemsenb4467962015-08-06 23:59:22 -0700627 if (i < args.size()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700628 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700629 } else {
630 // We need to blank further automatic vars
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700631 Var* v = ev->LookupVar(tmpvar_name_sym);
632 if (!v->IsDefined())
633 break;
634 if (v->Origin() != VarOrigin::AUTOMATIC)
635 break;
Dan Willemsenb4467962015-08-06 23:59:22 -0700636
Shinichiro Hamajie978a892015-08-17 16:53:40 +0900637 av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700638 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700639 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900640 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900641
642 ev->DecrementEvalDepth();
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900643 func->Eval(ev, s);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900644 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900645}
646
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900647void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900648 const string&& varname = args[0]->Eval(ev);
649 const string&& list = args[1]->Eval(ev);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900650 ev->DecrementEvalDepth();
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900651 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900652 for (StringPiece tok : WordScanner(list)) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700653 unique_ptr<SimpleVar> v(
654 new SimpleVar(tok.as_string(), VarOrigin::AUTOMATIC));
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900655 ScopedGlobalVar sv(Intern(varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900656 ww.MaybeAddWhitespace();
657 args[2]->Eval(ev, s);
658 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900659 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900660}
661
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900662void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900663 const string&& var_name = args[0]->Eval(ev);
664 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900665 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900666}
667
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900668void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900669 const string&& var_name = args[0]->Eval(ev);
670 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900671 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900672}
673
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900674void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900675 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900676 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700677 ev->add_delayed_output_command(
678 StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900679 return;
680 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900681 printf("%s\n", a.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900682 fflush(stdout);
683}
684
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900685void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900686 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900687 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700688 ev->add_delayed_output_command(StringPrintf(
689 "echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900690 return;
691 }
Dan Willemsene41c7552017-02-22 14:31:16 -0800692 WARN_LOC(ev->loc(), "%s", a.c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900693}
694
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900695void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900696 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900697 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900698 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700699 StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
700 LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900701 return;
702 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900703 ev->Error(StringPrintf("*** %s.", a.c_str()));
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900704}
705
Dan Willemsenf06d8012016-10-03 00:16:07 -0700706static void FileReadFunc(Evaluator* ev, const string& filename, string* s) {
707 int fd = open(filename.c_str(), O_RDONLY);
708 if (fd < 0) {
709 if (errno == ENOENT) {
710 if (ShouldStoreCommandResult(filename)) {
711 CommandResult* cr = new CommandResult();
712 cr->op = CommandOp::READ_MISSING;
713 cr->cmd = filename;
714 g_command_results.push_back(cr);
715 }
716 return;
717 } else {
718 ev->Error("*** open failed.");
719 }
720 }
721
722 struct stat st;
723 if (fstat(fd, &st) < 0) {
724 ev->Error("*** fstat failed.");
725 }
726
727 size_t len = st.st_size;
728 string out;
729 out.resize(len);
730 ssize_t r = HANDLE_EINTR(read(fd, &out[0], len));
731 if (r != static_cast<ssize_t>(len)) {
732 ev->Error("*** read failed.");
733 }
734
735 if (close(fd) < 0) {
736 ev->Error("*** close failed.");
737 }
738
739 if (out.back() == '\n') {
740 out.pop_back();
741 }
742
743 if (ShouldStoreCommandResult(filename)) {
744 CommandResult* cr = new CommandResult();
745 cr->op = CommandOp::READ;
746 cr->cmd = filename;
747 g_command_results.push_back(cr);
748 }
749 *s += out;
750}
751
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700752static void FileWriteFunc(Evaluator* ev,
753 const string& filename,
754 bool append,
755 string text) {
Dan Willemsenf06d8012016-10-03 00:16:07 -0700756 FILE* f = fopen(filename.c_str(), append ? "ab" : "wb");
757 if (f == NULL) {
758 ev->Error("*** fopen failed.");
759 }
760
761 if (fwrite(&text[0], text.size(), 1, f) != 1) {
762 ev->Error("*** fwrite failed.");
763 }
764
765 if (fclose(f) != 0) {
766 ev->Error("*** fclose failed.");
767 }
768
769 if (ShouldStoreCommandResult(filename)) {
770 CommandResult* cr = new CommandResult();
771 cr->op = CommandOp::WRITE;
772 cr->cmd = filename;
773 cr->result = text;
774 g_command_results.push_back(cr);
775 }
776}
777
778void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
779 if (ev->avoid_io()) {
780 ev->Error("*** $(file ...) is not supported in rules.");
781 }
782
783 string arg = args[0]->Eval(ev);
784 StringPiece filename = TrimSpace(arg);
785
786 if (filename.size() <= 1) {
787 ev->Error("*** Missing filename");
788 }
789
790 if (filename[0] == '<') {
791 filename = TrimLeftSpace(filename.substr(1));
792 if (!filename.size()) {
793 ev->Error("*** Missing filename");
794 }
795 if (args.size() > 1) {
796 ev->Error("*** invalid argument");
797 }
798
799 FileReadFunc(ev, filename.as_string(), s);
800 } else if (filename[0] == '>') {
801 bool append = false;
802 if (filename[1] == '>') {
803 append = true;
804 filename = filename.substr(2);
805 } else {
806 filename = filename.substr(1);
807 }
808 filename = TrimLeftSpace(filename);
809 if (!filename.size()) {
810 ev->Error("*** Missing filename");
811 }
812
813 string text;
814 if (args.size() > 1) {
815 text = args[1]->Eval(ev);
816 if (text.size() == 0 || text.back() != '\n') {
817 text.push_back('\n');
818 }
819 }
820
821 FileWriteFunc(ev, filename.as_string(), append, text);
822 } else {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700823 ev->Error(StringPrintf("*** Invalid file operation: %s. Stop.",
824 filename.as_string().c_str()));
Dan Willemsenf06d8012016-10-03 00:16:07 -0700825 }
826}
827
Dan Willemsen276e96a2017-10-03 14:24:48 -0700828void DeprecatedVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
829 string vars_str = args[0]->Eval(ev);
830 string msg;
831
832 if (args.size() == 2) {
833 msg = ". " + args[1]->Eval(ev);
834 }
835
836 if (ev->avoid_io()) {
837 ev->Error("*** $(KATI_deprecated_var ...) is not supported in rules.");
838 }
839
840 for (StringPiece var : WordScanner(vars_str)) {
841 Symbol sym = Intern(var);
Dan Willemsen74197412017-12-27 16:50:09 -0800842 Var* v = ev->PeekVar(sym);
Dan Willemsen276e96a2017-10-03 14:24:48 -0700843 if (!v->IsDefined()) {
844 v = new SimpleVar(VarOrigin::FILE);
845 sym.SetGlobalVar(v, false, nullptr);
846 }
847
848 if (v->Deprecated()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700849 ev->Error(
850 StringPrintf("*** Cannot call KATI_deprecated_var on already "
851 "deprecated variable: %s.",
852 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700853 } else if (v->Obsolete()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700854 ev->Error(
855 StringPrintf("*** Cannot call KATI_deprecated_var on already "
856 "obsolete variable: %s.",
857 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700858 }
859
860 v->SetDeprecated(msg);
861 }
862}
863
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700864void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Dan Willemsen276e96a2017-10-03 14:24:48 -0700865 string vars_str = args[0]->Eval(ev);
866 string msg;
867
868 if (args.size() == 2) {
869 msg = ". " + args[1]->Eval(ev);
870 }
871
872 if (ev->avoid_io()) {
873 ev->Error("*** $(KATI_obsolete_var ...) is not supported in rules.");
874 }
875
876 for (StringPiece var : WordScanner(vars_str)) {
877 Symbol sym = Intern(var);
Dan Willemsen74197412017-12-27 16:50:09 -0800878 Var* v = ev->PeekVar(sym);
Dan Willemsen276e96a2017-10-03 14:24:48 -0700879 if (!v->IsDefined()) {
880 v = new SimpleVar(VarOrigin::FILE);
881 sym.SetGlobalVar(v, false, nullptr);
882 }
883
884 if (v->Deprecated()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700885 ev->Error(
886 StringPrintf("*** Cannot call KATI_obsolete_var on already "
887 "deprecated variable: %s.",
888 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700889 } else if (v->Obsolete()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700890 ev->Error(StringPrintf(
891 "*** Cannot call KATI_obsolete_var on already obsolete variable: %s.",
892 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700893 }
894
895 v->SetObsolete(msg);
896 }
897}
898
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800899void DeprecateExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
900 string msg = ". " + args[0]->Eval(ev);
901
902 if (ev->avoid_io()) {
903 ev->Error("*** $(KATI_deprecate_export) is not supported in rules.");
904 }
905
906 if (ev->ExportObsolete()) {
907 ev->Error("*** Export is already obsolete.");
908 } else if (ev->ExportDeprecated()) {
909 ev->Error("*** Export is already deprecated.");
910 }
911
912 ev->SetExportDeprecated(msg);
913}
914
915void ObsoleteExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
916 string msg = ". " + args[0]->Eval(ev);
917
918 if (ev->avoid_io()) {
919 ev->Error("*** $(KATI_obsolete_export) is not supported in rules.");
920 }
921
922 if (ev->ExportObsolete()) {
923 ev->Error("*** Export is already obsolete.");
924 }
925
926 ev->SetExportObsolete(msg);
927}
928
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900929FuncInfo g_func_infos[] = {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700930 {"patsubst", &PatsubstFunc, 3, 3, false, false},
931 {"strip", &StripFunc, 1, 1, false, false},
932 {"subst", &SubstFunc, 3, 3, false, false},
933 {"findstring", &FindstringFunc, 2, 2, false, false},
934 {"filter", &FilterFunc, 2, 2, false, false},
935 {"filter-out", &FilterOutFunc, 2, 2, false, false},
936 {"sort", &SortFunc, 1, 1, false, false},
937 {"word", &WordFunc, 2, 2, false, false},
938 {"wordlist", &WordlistFunc, 3, 3, false, false},
939 {"words", &WordsFunc, 1, 1, false, false},
940 {"firstword", &FirstwordFunc, 1, 1, false, false},
941 {"lastword", &LastwordFunc, 1, 1, false, false},
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900942
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700943 {"join", &JoinFunc, 2, 2, false, false},
944 {"wildcard", &WildcardFunc, 1, 1, false, false},
945 {"dir", &DirFunc, 1, 1, false, false},
946 {"notdir", &NotdirFunc, 1, 1, false, false},
947 {"suffix", &SuffixFunc, 1, 1, false, false},
948 {"basename", &BasenameFunc, 1, 1, false, false},
949 {"addsuffix", &AddsuffixFunc, 2, 2, false, false},
950 {"addprefix", &AddprefixFunc, 2, 2, false, false},
951 {"realpath", &RealpathFunc, 1, 1, false, false},
952 {"abspath", &AbspathFunc, 1, 1, false, false},
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900953
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700954 {"if", &IfFunc, 3, 2, false, true},
955 {"and", &AndFunc, 0, 0, true, false},
956 {"or", &OrFunc, 0, 0, true, false},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900957
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700958 {"value", &ValueFunc, 1, 1, false, false},
959 {"eval", &EvalFunc, 1, 1, false, false},
960 {"shell", &ShellFunc, 1, 1, false, false},
961 {"call", &CallFunc, 0, 0, false, false},
962 {"foreach", &ForeachFunc, 3, 3, false, false},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900963
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700964 {"origin", &OriginFunc, 1, 1, false, false},
965 {"flavor", &FlavorFunc, 1, 1, false, false},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900966
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700967 {"info", &InfoFunc, 1, 1, false, false},
968 {"warning", &WarningFunc, 1, 1, false, false},
969 {"error", &ErrorFunc, 1, 1, false, false},
Dan Willemsenf06d8012016-10-03 00:16:07 -0700970
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700971 {"file", &FileFunc, 2, 1, false, false},
Dan Willemsen276e96a2017-10-03 14:24:48 -0700972
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700973 /* Kati custom extension functions */
974 {"KATI_deprecated_var", &DeprecatedVarFunc, 2, 1, false, false},
975 {"KATI_obsolete_var", &ObsoleteVarFunc, 2, 1, false, false},
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800976 {"KATI_deprecate_export", &DeprecateExportFunc, 1, 1, false, false},
977 {"KATI_obsolete_export", &ObsoleteExportFunc, 1, 1, false, false},
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900978};
979
980unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
981
982} // namespace
983
984void InitFuncTable() {
985 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
986 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
987 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900988 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900989 CHECK(ok);
990 }
991}
992
993void QuitFuncTable() {
994 delete g_func_info_map;
995}
996
997FuncInfo* GetFuncInfo(StringPiece name) {
998 auto found = g_func_info_map->find(name);
999 if (found == g_func_info_map->end())
1000 return NULL;
1001 return found->second;
1002}
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +09001003
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +09001004const vector<CommandResult*>& GetShellCommandResults() {
1005 return g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +09001006}