blob: fa078f462ac14686279a5f48d4f66c5bea7b6991 [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>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090020#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090021#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090022#include <stdlib.h>
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090023#include <unistd.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090024
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090025#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090026#include <iterator>
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090027#include <memory>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090028#include <unordered_map>
29
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090030#include "ast.h"
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090031#include "eval.h"
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090032#include "fileutil.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090033#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090034#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090035#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090036#include "stats.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090037#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090038#include "symtab.h"
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090039#include "var.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090040
41namespace {
42
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090043// TODO: This code is very similar to
44// NinjaGenerator::TranslateCommand. Factor them out.
45shared_ptr<string> StripShellComment(shared_ptr<string> cmd) {
46 if (cmd->find('#') == string::npos)
47 return cmd;
48
49 shared_ptr<string> res = make_shared<string>();
50 bool prev_backslash = false;
51 // Set space as an initial value so the leading comment will be
52 // stripped out.
53 char prev_char = ' ';
54 char quote = 0;
55 bool done = false;
56 const char* in = cmd->c_str();
57 for (; *in && !done; in++) {
58 switch (*in) {
59 case '#':
60 if (quote == 0 && isspace(prev_char)) {
61 while (*in && *in != '\n')
62 in++;
63 break;
64 }
65
66 case '\'':
67 case '"':
68 case '`':
69 if (quote) {
70 if (quote == *in)
71 quote = 0;
72 } else if (!prev_backslash) {
73 quote = *in;
74 }
75 *res += *in;
76 break;
77
78 case '\\':
79 *res += '\\';
80 break;
81
82 default:
83 *res += *in;
84 }
85
86 if (*in == '\\') {
87 prev_backslash = !prev_backslash;
88 } else {
89 prev_backslash = false;
90 }
91
92 prev_char = *in;
93 }
94 return res;
95}
96
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090097void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090098 shared_ptr<string> pat_str = args[0]->Eval(ev);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090099 shared_ptr<string> repl = args[1]->Eval(ev);
100 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900101 WordWriter ww(s);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900102 Pattern pat(*pat_str);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900103 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900104 ww.MaybeAddWhitespace();
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900105 pat.AppendSubst(tok, *repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900106 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900107}
108
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900109void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
110 shared_ptr<string> str = args[0]->Eval(ev);
111 WordWriter ww(s);
112 for (StringPiece tok : WordScanner(*str)) {
113 ww.Write(tok);
114 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900115}
116
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900117void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
118 shared_ptr<string> pat = args[0]->Eval(ev);
119 shared_ptr<string> repl = args[1]->Eval(ev);
120 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +0900121 if (pat->empty()) {
122 *s += *str;
123 *s += *repl;
124 return;
125 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900126 size_t index = 0;
127 while (index < str->size()) {
128 size_t found = str->find(*pat, index);
129 if (found == string::npos)
130 break;
131 AppendString(StringPiece(*str).substr(index, found - index), s);
132 AppendString(*repl, s);
133 index = found + pat->size();
134 }
135 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900136}
137
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900138void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
139 shared_ptr<string> find = args[0]->Eval(ev);
140 shared_ptr<string> in = args[1]->Eval(ev);
141 if (in->find(*find) != string::npos)
142 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900143}
144
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900145void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
146 shared_ptr<string> pat_buf = args[0]->Eval(ev);
147 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900148 vector<Pattern> pats;
149 for (StringPiece pat : WordScanner(*pat_buf)) {
150 pats.push_back(Pattern(pat));
151 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900152 WordWriter ww(s);
153 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900154 for (const Pattern& pat : pats) {
155 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900156 ww.Write(tok);
157 break;
158 }
159 }
160 }
161}
162
163void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
164 shared_ptr<string> pat_buf = args[0]->Eval(ev);
165 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900166 vector<Pattern> pats;
167 for (StringPiece pat : WordScanner(*pat_buf)) {
168 pats.push_back(Pattern(pat));
169 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900170 WordWriter ww(s);
171 for (StringPiece tok : WordScanner(*text)) {
172 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900173 for (const Pattern& pat : pats) {
174 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900175 matched = true;
176 break;
177 }
178 }
179 if (!matched)
180 ww.Write(tok);
181 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900182}
183
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900184void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
185 shared_ptr<string> list = args[0]->Eval(ev);
186 vector<StringPiece> toks;
187 WordScanner(*list).Split(&toks);
188 sort(toks.begin(), toks.end());
189 WordWriter ww(s);
190 StringPiece prev;
191 for (StringPiece tok : toks) {
192 if (prev != tok) {
193 ww.Write(tok);
194 prev = tok;
195 }
196 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900197}
198
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900199static int GetNumericValueForFunc(const string& buf) {
200 StringPiece s = TrimLeftSpace(buf);
201 char* end;
202 long n = strtol(s.data(), &end, 10);
203 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
204 return -1;
205 }
206 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900207}
208
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900209void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
210 shared_ptr<string> n_str = args[0]->Eval(ev);
211 int n = GetNumericValueForFunc(*n_str);
212 if (n < 0) {
213 ev->Error(StringPrintf(
214 "*** non-numeric first argument to `word' function: '%s'.",
215 n_str->c_str()));
216 }
217 if (n == 0) {
218 ev->Error("*** first argument to `word' function must be greater than 0.");
219 }
220
221 shared_ptr<string> text = args[1]->Eval(ev);
222 for (StringPiece tok : WordScanner(*text)) {
223 n--;
224 if (n == 0) {
225 AppendString(tok, s);
226 break;
227 }
228 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900229}
230
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900231void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
232 shared_ptr<string> s_str = args[0]->Eval(ev);
233 int si = GetNumericValueForFunc(*s_str);
234 if (si < 0) {
235 ev->Error(StringPrintf(
236 "*** non-numeric first argument to `wordlist' function: '%s'.",
237 s_str->c_str()));
238 }
239 if (si == 0) {
240 ev->Error(StringPrintf(
241 "*** invalid first argument to `wordlist' function: %s`",
242 s_str->c_str()));
243 }
244
245 shared_ptr<string> e_str = args[1]->Eval(ev);
246 int ei = GetNumericValueForFunc(*e_str);
247 if (ei < 0) {
248 ev->Error(StringPrintf(
249 "*** non-numeric second argument to `wordlist' function: '%s'.",
250 e_str->c_str()));
251 }
252
253 shared_ptr<string> text = args[2]->Eval(ev);
254 int i = 0;
255 WordWriter ww(s);
256 for (StringPiece tok : WordScanner(*text)) {
257 i++;
258 if (si <= i && i <= ei) {
259 ww.Write(tok);
260 }
261 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900262}
263
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900264void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
265 shared_ptr<string> text = args[0]->Eval(ev);
266 WordScanner ws(*text);
267 int n = 0;
268 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
269 n++;
270 char buf[32];
271 sprintf(buf, "%d", n);
272 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900273}
274
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900275void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
276 shared_ptr<string> text = args[0]->Eval(ev);
277 for (StringPiece tok : WordScanner(*text)) {
278 AppendString(tok, s);
279 return;
280 }
281}
282
283void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
284 shared_ptr<string> text = args[0]->Eval(ev);
285 StringPiece last;
286 for (StringPiece tok : WordScanner(*text)) {
287 last = tok;
288 }
289 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900290}
291
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900292void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
293 shared_ptr<string> list1 = args[0]->Eval(ev);
294 shared_ptr<string> list2 = args[1]->Eval(ev);
295 WordScanner ws1(*list1);
296 WordScanner ws2(*list2);
297 WordWriter ww(s);
298 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
299 iter1 != ws1.end() && iter2 != ws2.end();
300 ++iter1, ++iter2) {
301 ww.Write(*iter1);
302 // Use |AppendString| not to append extra ' '.
303 AppendString(*iter2, s);
304 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900305}
306
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900307void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +0900308 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900309 shared_ptr<string> pat = args[0]->Eval(ev);
Shinichiro Hamaji7409aee2015-07-28 14:52:37 +0900310 // Note GNU make does not delay the execution of $(wildcard) so we
311 // do not need to check avoid_io here.
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900312 WordWriter ww(s);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900313 vector<string>* files;
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900314 for (StringPiece tok : WordScanner(*pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900315 ScopedTerminator st(tok);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900316 Glob(tok.data(), &files);
317 sort(files->begin(), files->end());
318 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900319 ww.Write(file);
320 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900321 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900322}
323
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900324void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
325 shared_ptr<string> text = args[0]->Eval(ev);
326 WordWriter ww(s);
327 for (StringPiece tok : WordScanner(*text)) {
328 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900329 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900330 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900331}
332
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900333void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
334 shared_ptr<string> text = args[0]->Eval(ev);
335 WordWriter ww(s);
336 for (StringPiece tok : WordScanner(*text)) {
337 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900338 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900339 } else {
340 ww.Write(Basename(tok));
341 }
342 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900343}
344
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900345void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
346 shared_ptr<string> text = args[0]->Eval(ev);
347 WordWriter ww(s);
348 for (StringPiece tok : WordScanner(*text)) {
349 StringPiece suf = GetExt(tok);
350 if (!suf.empty())
351 ww.Write(suf);
352 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900353}
354
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900355void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
356 shared_ptr<string> text = args[0]->Eval(ev);
357 WordWriter ww(s);
358 for (StringPiece tok : WordScanner(*text)) {
359 ww.Write(StripExt(tok));
360 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900361}
362
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900363void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
364 shared_ptr<string> suf = args[0]->Eval(ev);
365 shared_ptr<string> text = args[1]->Eval(ev);
366 WordWriter ww(s);
367 for (StringPiece tok : WordScanner(*text)) {
368 ww.Write(tok);
369 *s += *suf;
370 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900371}
372
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900373void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
374 shared_ptr<string> pre = args[0]->Eval(ev);
375 shared_ptr<string> text = args[1]->Eval(ev);
376 WordWriter ww(s);
377 for (StringPiece tok : WordScanner(*text)) {
378 ww.Write(*pre);
379 AppendString(tok, s);
380 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900381}
382
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900383void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
384 shared_ptr<string> text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900385 if (ev->avoid_io()) {
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900386 *s += "$(realpath ";
387 *s += *text;
388 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900389 return;
390 }
391
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900392 WordWriter ww(s);
393 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900394 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900395 char buf[PATH_MAX];
396 if (realpath(tok.data(), buf))
397 *s += buf;
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900398 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900399}
400
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900401void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
402 shared_ptr<string> text = args[0]->Eval(ev);
403 WordWriter ww(s);
404 string buf;
405 for (StringPiece tok : WordScanner(*text)) {
406 AbsPath(tok, &buf);
407 ww.Write(buf);
408 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900409}
410
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900411void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
412 shared_ptr<string> cond = args[0]->Eval(ev);
413 if (cond->empty()) {
414 if (args.size() > 2)
415 args[2]->Eval(ev, s);
416 } else {
417 args[1]->Eval(ev, s);
418 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900419}
420
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900421void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
422 shared_ptr<string> cond;
423 for (Value* a : args) {
424 cond = a->Eval(ev);
425 if (cond->empty())
426 return;
427 }
428 if (cond.get()) {
429 *s += *cond;
430 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900431}
432
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900433void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
434 for (Value* a : args) {
435 shared_ptr<string> cond = a->Eval(ev);
436 if (!cond->empty()) {
437 *s += *cond;
438 return;
439 }
440 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900441}
442
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900443void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
444 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900445 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900446 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900447}
448
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900449void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900450 // TODO: eval leaks everything... for now.
451 //shared_ptr<string> text = args[0]->Eval(ev);
452 string* text = new string;
453 args[0]->Eval(ev, text);
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900454 vector<AST*> asts;
455 Parse(*text, ev->loc(), &asts);
456 for (AST* ast : asts) {
457 LOG("%s", ast->DebugString().c_str());
458 ast->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900459 //delete ast;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900460 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900461}
462
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900463//#define TEST_FIND_EMULATOR
464
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900465// A hack for Android build. We need to evaluate things like $((3+4))
466// when we emit ninja file, because the result of such expressions
467// will be passed to other make functions.
468// TODO: Maybe we should introduce a helper binary which evaluate
469// make expressions at ninja-time.
470static bool HasNoIoInShellScript(const string& cmd) {
471 if (cmd.empty())
472 return true;
473 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size()-1] == ')')
474 return true;
475 return false;
476}
477
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900478static void ShellFuncImpl(const string& shell, const string& cmd,
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900479 string* s, FindCommand** fc) {
480 LOG("ShellFunc: %s", cmd.c_str());
481
482#ifdef TEST_FIND_EMULATOR
483 bool need_check = false;
484 string out2;
485#endif
486 if (FindEmulator::Get()) {
487 *fc = new FindCommand();
488 if ((*fc)->Parse(cmd)) {
489#ifdef TEST_FIND_EMULATOR
490 if (FindEmulator::Get()->HandleFind(cmd, **fc, &out2)) {
491 need_check = true;
492 }
493#else
494 if (FindEmulator::Get()->HandleFind(cmd, **fc, s)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900495 return;
496 }
497#endif
498 }
499 delete *fc;
500 *fc = NULL;
501 }
502
503 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd.c_str());
504 RunCommand(shell, cmd, RedirectStderr::NONE, s);
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700505 FormatForCommandSubstitution(s);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900506
507#ifdef TEST_FIND_EMULATOR
508 if (need_check) {
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700509 if (*s != out2) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900510 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700511 cmd.c_str(), s->c_str(), out2.c_str());
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900512 }
513 }
514#endif
515}
516
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900517static vector<CommandResult*> g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900518
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900519bool ShouldStoreCommandResult(StringPiece cmd) {
520 if (HasWord(cmd, "date") || HasWord(cmd, "echo"))
521 return false;
522 if (g_ignore_dirty_pattern) {
523 Pattern pat(g_ignore_dirty_pattern);
524 for (StringPiece tok : WordScanner(cmd)) {
525 if (pat.Match(tok))
526 return false;
527 }
528 }
529 return true;
530}
531
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900532void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
533 shared_ptr<string> cmd = args[0]->Eval(ev);
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900534 if (ev->avoid_io() && !HasNoIoInShellScript(*cmd)) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900535 *s += "$(";
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +0900536 *s += *StripShellComment(cmd);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900537 *s += ")";
538 return;
539 }
540
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900541 shared_ptr<string> shell = ev->EvalVar(kShellSym);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900542
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900543 string out;
544 FindCommand* fc = NULL;
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700545 ShellFuncImpl(*shell, *cmd, &out, &fc);
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900546 if (ShouldStoreCommandResult(*cmd)) {
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900547 CommandResult* cr = new CommandResult();
548 cr->cmd = *cmd;
549 cr->find.reset(fc);
550 cr->result = out;
551 g_command_results.push_back(cr);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900552 }
553 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900554}
555
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900556void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700557 static const string tmpvar_names[] = {
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900558 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
559 };
560
561 shared_ptr<string> func_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900562 Var* func = ev->LookupVar(Intern(*func_name));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900563 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900564 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900565 unique_ptr<SimpleVar> s(
Shinichiro Hamaji5081c712015-08-14 16:49:20 +0900566 new SimpleVar(*args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900567 av.push_back(move(s));
568 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900569 vector<unique_ptr<ScopedVar>> sv;
Dan Willemsenb4467962015-08-06 23:59:22 -0700570 for (size_t i = 1; ; i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700571 string s;
572 StringPiece tmpvar_name;
573 if (i < sizeof(tmpvar_names)/sizeof(tmpvar_names[0])) {
574 tmpvar_name = tmpvar_names[i];
575 } else {
576 s = StringPrintf("%d", i);
577 tmpvar_name = s;
578 }
Dan Willemsenb4467962015-08-06 23:59:22 -0700579 if (i < args.size()) {
580 sv.push_back(move(unique_ptr<ScopedVar>(
581 new ScopedVar(ev->mutable_vars(),
582 Intern(tmpvar_name), av[i-1].get()))));
583 } else {
584 // We need to blank further automatic vars
585 Var *v = ev->LookupVar(Intern(tmpvar_name));
586 if (!v->IsDefined()) break;
587 if (v->Origin() != VarOrigin::AUTOMATIC) break;
588
589 av.push_back(move(unique_ptr<SimpleVar>(
Shinichiro Hamaji5081c712015-08-14 16:49:20 +0900590 new SimpleVar("", VarOrigin::AUTOMATIC))));
Dan Willemsenb4467962015-08-06 23:59:22 -0700591 sv.push_back(move(unique_ptr<ScopedVar>(
592 new ScopedVar(ev->mutable_vars(),
593 Intern(tmpvar_name), av[i-1].get()))));
594 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900595 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900596 func->Eval(ev, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900597}
598
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900599void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
600 shared_ptr<string> varname = args[0]->Eval(ev);
601 shared_ptr<string> list = args[1]->Eval(ev);
602 WordWriter ww(s);
603 for (StringPiece tok : WordScanner(*list)) {
604 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamaji5081c712015-08-14 16:49:20 +0900605 tok.as_string(), VarOrigin::AUTOMATIC));
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900606 ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900607 ww.MaybeAddWhitespace();
608 args[2]->Eval(ev, s);
609 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900610}
611
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900612void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
613 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900614 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900615 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900616}
617
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900618void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
619 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900620 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900621 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900622}
623
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900624void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900625 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900626 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900627 ev->add_delayed_output_command(StringPrintf("echo '%s'", a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900628 return;
629 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900630 printf("%s\n", a->c_str());
631 fflush(stdout);
632}
633
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900634void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900635 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900636 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900637 ev->add_delayed_output_command(
638 StringPrintf("echo '%s:%d: %s' 2>&1", LOCF(ev->loc()), a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900639 return;
640 }
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900641 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900642 fflush(stdout);
643}
644
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900645void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900646 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900647 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900648 ev->add_delayed_output_command(
649 StringPrintf("echo '%s:%d: *** %s.' 2>&1 && false",
650 LOCF(ev->loc()), a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900651 return;
652 }
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900653 ev->Error(StringPrintf("*** %s.", a->c_str()));
654}
655
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900656FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900657 { "patsubst", &PatsubstFunc, 3, 3, false, false },
658 { "strip", &StripFunc, 1, 1, false, false },
659 { "subst", &SubstFunc, 3, 3, false, false },
660 { "findstring", &FindstringFunc, 2, 2, false, false },
661 { "filter", &FilterFunc, 2, 2, false, false },
662 { "filter-out", &FilterOutFunc, 2, 2, false, false },
663 { "sort", &SortFunc, 1, 1, false, false },
664 { "word", &WordFunc, 2, 2, false, false },
665 { "wordlist", &WordlistFunc, 3, 3, false, false },
666 { "words", &WordsFunc, 1, 1, false, false },
667 { "firstword", &FirstwordFunc, 1, 1, false, false },
668 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900669
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900670 { "join", &JoinFunc, 2, 2, false, false },
671 { "wildcard", &WildcardFunc, 1, 1, false, false },
672 { "dir", &DirFunc, 1, 1, false, false },
673 { "notdir", &NotdirFunc, 1, 1, false, false },
674 { "suffix", &SuffixFunc, 1, 1, false, false },
675 { "basename", &BasenameFunc, 1, 1, false, false },
676 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
677 { "addprefix", &AddprefixFunc, 2, 2, false, false },
678 { "realpath", &RealpathFunc, 1, 1, false, false },
679 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900680
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900681 { "if", &IfFunc, 3, 2, false, true },
682 { "and", &AndFunc, 0, 0, true, false },
683 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900684
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900685 { "value", &ValueFunc, 1, 1, false, false },
686 { "eval", &EvalFunc, 1, 1, false, false },
687 { "shell", &ShellFunc, 1, 1, false, false },
688 { "call", &CallFunc, 0, 0, false, false },
689 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900690
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900691 { "origin", &OriginFunc, 1, 1, false, false },
692 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900693
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900694 { "info", &InfoFunc, 1, 1, false, false },
695 { "warning", &WarningFunc, 1, 1, false, false },
696 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900697};
698
699unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
700
701} // namespace
702
703void InitFuncTable() {
704 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
705 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
706 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900707 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900708 CHECK(ok);
709 }
710}
711
712void QuitFuncTable() {
713 delete g_func_info_map;
714}
715
716FuncInfo* GetFuncInfo(StringPiece name) {
717 auto found = g_func_info_map->find(name);
718 if (found == g_func_info_map->end())
719 return NULL;
720 return found->second;
721}
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900722
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900723const vector<CommandResult*>& GetShellCommandResults() {
724 return g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900725}