blob: 623e56ec91b0e7d36fc0f28810a8f6d6b1183457 [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 Hamaji9619b362015-06-16 16:13:25 +090030#include "eval.h"
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090031#include "fileutil.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090032#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090033#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090034#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090035#include "stats.h"
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090036#include "stmt.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.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090045void StripShellComment(string* cmd) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090046 if (cmd->find('#') == string::npos)
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090047 return;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090048
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090049 string res;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090050 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)) {
Shinichiro Hamaji212b7a52015-10-05 17:02:29 +090061 while (in[1] && *in != '\n')
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090062 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 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090075 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090076 break;
77
78 case '\\':
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090079 res += '\\';
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090080 break;
81
82 default:
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090083 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090084 }
85
86 if (*in == '\\') {
87 prev_backslash = !prev_backslash;
88 } else {
89 prev_backslash = false;
90 }
91
92 prev_char = *in;
93 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090094 cmd->swap(res);
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090095}
96
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090097void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090098 const string&& pat_str = args[0]->Eval(ev);
99 const string&& repl = args[1]->Eval(ev);
100 const string&& str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900101 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900102 Pattern pat(pat_str);
103 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900104 ww.MaybeAddWhitespace();
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +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) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900110 const string&& str = args[0]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900111 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900112 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900113 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) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900118 const string&& pat = args[0]->Eval(ev);
119 const string&& repl = args[1]->Eval(ev);
120 const string&& str = args[2]->Eval(ev);
121 if (pat.empty()) {
122 *s += str;
123 *s += repl;
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +0900124 return;
125 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900126 size_t index = 0;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900127 while (index < str.size()) {
128 size_t found = str.find(pat, index);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900129 if (found == string::npos)
130 break;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900131 AppendString(StringPiece(str).substr(index, found - index), s);
132 AppendString(repl, s);
133 index = found + pat.size();
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900134 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900135 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) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900139 const string&& find = args[0]->Eval(ev);
140 const 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) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900146 const string&& pat_buf = args[0]->Eval(ev);
147 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900148 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900149 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900150 pats.push_back(Pattern(pat));
151 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900152 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900153 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) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900164 const string&& pat_buf = args[0]->Eval(ev);
165 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900166 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900167 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900168 pats.push_back(Pattern(pat));
169 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900170 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900171 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900172 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) {
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900185 string list;
186 args[0]->Eval(ev, &list);
187 COLLECT_STATS("func sort time");
Shinichiro Hamaji2d353a02016-02-15 18:24:42 +0900188 // TODO(hamaji): Probably we could use a faster string-specific sort
189 // algorithm.
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900190 vector<StringPiece> toks;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900191 WordScanner(list).Split(&toks);
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900192 stable_sort(toks.begin(), toks.end());
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900193 WordWriter ww(s);
194 StringPiece prev;
195 for (StringPiece tok : toks) {
196 if (prev != tok) {
197 ww.Write(tok);
198 prev = tok;
199 }
200 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900201}
202
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900203static int GetNumericValueForFunc(const string& buf) {
204 StringPiece s = TrimLeftSpace(buf);
205 char* end;
206 long n = strtol(s.data(), &end, 10);
207 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
208 return -1;
209 }
210 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900211}
212
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900213void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900214 const string&& n_str = args[0]->Eval(ev);
215 int n = GetNumericValueForFunc(n_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900216 if (n < 0) {
217 ev->Error(StringPrintf(
218 "*** non-numeric first argument to `word' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900219 n_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900220 }
221 if (n == 0) {
222 ev->Error("*** first argument to `word' function must be greater than 0.");
223 }
224
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900225 const string&& text = args[1]->Eval(ev);
226 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900227 n--;
228 if (n == 0) {
229 AppendString(tok, s);
230 break;
231 }
232 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900233}
234
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900235void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900236 const string&& s_str = args[0]->Eval(ev);
237 int si = GetNumericValueForFunc(s_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900238 if (si < 0) {
239 ev->Error(StringPrintf(
240 "*** non-numeric first argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900241 s_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900242 }
243 if (si == 0) {
244 ev->Error(StringPrintf(
245 "*** invalid 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
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900249 const string&& e_str = args[1]->Eval(ev);
250 int ei = GetNumericValueForFunc(e_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900251 if (ei < 0) {
252 ev->Error(StringPrintf(
253 "*** non-numeric second argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900254 e_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900255 }
256
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900257 const string&& text = args[2]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900258 int i = 0;
259 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900260 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900261 i++;
262 if (si <= i && i <= ei) {
263 ww.Write(tok);
264 }
265 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900266}
267
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900268void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900269 const string&& text = args[0]->Eval(ev);
270 WordScanner ws(text);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900271 int n = 0;
272 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
273 n++;
274 char buf[32];
275 sprintf(buf, "%d", n);
276 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900277}
278
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900279void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900280 const string&& text = args[0]->Eval(ev);
281 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900282 AppendString(tok, s);
283 return;
284 }
285}
286
287void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900288 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900289 StringPiece last;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900290 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900291 last = tok;
292 }
293 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900294}
295
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900296void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900297 const string&& list1 = args[0]->Eval(ev);
298 const string&& list2 = args[1]->Eval(ev);
299 WordScanner ws1(list1);
300 WordScanner ws2(list2);
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900301 WordWriter ww(s);
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900302 WordScanner::Iterator iter1, iter2;
303 for (iter1 = ws1.begin(), iter2 = ws2.begin();
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900304 iter1 != ws1.end() && iter2 != ws2.end();
305 ++iter1, ++iter2) {
306 ww.Write(*iter1);
307 // Use |AppendString| not to append extra ' '.
308 AppendString(*iter2, s);
309 }
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900310 for (; iter1 != ws1.end(); ++iter1)
311 ww.Write(*iter1);
312 for (; iter2 != ws2.end(); ++iter2)
313 ww.Write(*iter2);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900314}
315
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900316void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900317 const string&& pat = args[0]->Eval(ev);
Shinichiro Hamajib67a2992015-11-07 14:11:09 +0900318 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji7409aee2015-07-28 14:52:37 +0900319 // Note GNU make does not delay the execution of $(wildcard) so we
320 // do not need to check avoid_io here.
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900321 WordWriter ww(s);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900322 vector<string>* files;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900323 for (StringPiece tok : WordScanner(pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900324 ScopedTerminator st(tok);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900325 Glob(tok.data(), &files);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900326 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900327 ww.Write(file);
328 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900329 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900330}
331
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900332void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900333 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900334 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900335 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900336 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900337 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900338 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900339}
340
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900341void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900342 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900343 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900344 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900345 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900346 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900347 } else {
348 ww.Write(Basename(tok));
349 }
350 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900351}
352
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900353void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900354 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900355 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900356 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900357 StringPiece suf = GetExt(tok);
358 if (!suf.empty())
359 ww.Write(suf);
360 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900361}
362
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900363void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900364 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900365 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900366 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900367 ww.Write(StripExt(tok));
368 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900369}
370
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900371void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900372 const string&& suf = args[0]->Eval(ev);
373 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900374 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900375 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900376 ww.Write(tok);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900377 *s += suf;
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900378 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900379}
380
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900381void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900382 const string&& pre = args[0]->Eval(ev);
383 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900384 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900385 for (StringPiece tok : WordScanner(text)) {
386 ww.Write(pre);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900387 AppendString(tok, s);
388 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900389}
390
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900391void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900392 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900393 if (ev->avoid_io()) {
Shinichiro Hamaji71cf60b2015-10-08 18:00:07 +0900394 *s += "$(";
395 string kati_binary;
396 GetExecutablePath(&kati_binary);
397 *s += kati_binary;
398 *s += " --realpath ";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900399 *s += text;
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900400 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900401 return;
402 }
403
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900404 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900405 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900406 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900407 char buf[PATH_MAX];
408 if (realpath(tok.data(), buf))
Shinichiro Hamajicb4724e2015-10-08 17:52:49 +0900409 ww.Write(buf);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900410 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900411}
412
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900413void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900414 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900415 WordWriter ww(s);
416 string buf;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900417 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900418 AbsPath(tok, &buf);
419 ww.Write(buf);
420 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900421}
422
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900423void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900424 const string&& cond = args[0]->Eval(ev);
425 if (cond.empty()) {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900426 if (args.size() > 2)
427 args[2]->Eval(ev, s);
428 } else {
429 args[1]->Eval(ev, s);
430 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900431}
432
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900433void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900434 string cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900435 for (Value* a : args) {
436 cond = a->Eval(ev);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900437 if (cond.empty())
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900438 return;
439 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900440 if (!cond.empty()) {
441 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900442 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900443}
444
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900445void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
446 for (Value* a : args) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900447 const string&& cond = a->Eval(ev);
448 if (!cond.empty()) {
449 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900450 return;
451 }
452 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900453}
454
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900455void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900456 const string&& var_name = args[0]->Eval(ev);
457 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900458 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900459}
460
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900461void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900462 // TODO: eval leaks everything... for now.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900463 //const string text = args[0]->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900464 string* text = new string;
465 args[0]->Eval(ev, text);
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900466 if (ev->avoid_io()) {
467 KATI_WARN("%s:%d: *warning*: $(eval) in a recipe is not recommended: %s",
468 LOCF(ev->loc()), text->c_str());
469 }
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900470 vector<Stmt*> stmts;
471 Parse(*text, ev->loc(), &stmts);
472 for (Stmt* stmt : stmts) {
473 LOG("%s", stmt->DebugString().c_str());
474 stmt->Eval(ev);
475 //delete stmt;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900476 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900477}
478
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900479//#define TEST_FIND_EMULATOR
480
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900481// A hack for Android build. We need to evaluate things like $((3+4))
482// when we emit ninja file, because the result of such expressions
483// will be passed to other make functions.
484// TODO: Maybe we should introduce a helper binary which evaluate
485// make expressions at ninja-time.
486static bool HasNoIoInShellScript(const string& cmd) {
487 if (cmd.empty())
488 return true;
489 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size()-1] == ')')
490 return true;
491 return false;
492}
493
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900494static void ShellFuncImpl(const string& shell, const string& cmd,
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900495 string* s, FindCommand** fc) {
496 LOG("ShellFunc: %s", cmd.c_str());
497
498#ifdef TEST_FIND_EMULATOR
499 bool need_check = false;
500 string out2;
501#endif
502 if (FindEmulator::Get()) {
503 *fc = new FindCommand();
504 if ((*fc)->Parse(cmd)) {
505#ifdef TEST_FIND_EMULATOR
506 if (FindEmulator::Get()->HandleFind(cmd, **fc, &out2)) {
507 need_check = true;
508 }
509#else
510 if (FindEmulator::Get()->HandleFind(cmd, **fc, s)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900511 return;
512 }
513#endif
514 }
515 delete *fc;
516 *fc = NULL;
517 }
518
519 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd.c_str());
520 RunCommand(shell, cmd, RedirectStderr::NONE, s);
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700521 FormatForCommandSubstitution(s);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900522
523#ifdef TEST_FIND_EMULATOR
524 if (need_check) {
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700525 if (*s != out2) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900526 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700527 cmd.c_str(), s->c_str(), out2.c_str());
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900528 }
529 }
530#endif
531}
532
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900533static vector<CommandResult*> g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900534
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900535bool ShouldStoreCommandResult(StringPiece cmd) {
Dan Willemsen40e5a3d2016-09-16 19:35:32 -0700536 // We really just want to ignore this one, or remove BUILD_DATETIME from
537 // Android completely
538 if (cmd == "date +%s")
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900539 return false;
Colin Crossf23ae8c2015-11-12 17:05:32 -0800540
541 Pattern pat(g_flags.ignore_dirty_pattern);
542 Pattern nopat(g_flags.no_ignore_dirty_pattern);
543 for (StringPiece tok : WordScanner(cmd)) {
544 if (pat.Match(tok) && !nopat.Match(tok)) {
545 return false;
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900546 }
547 }
Colin Crossf23ae8c2015-11-12 17:05:32 -0800548
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900549 return true;
550}
551
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900552void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900553 string cmd = args[0]->Eval(ev);
554 if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900555 if (ev->eval_depth() > 1) {
Shinichiro Hamajicbb801c2015-12-18 15:37:14 +0900556 ERROR("%s:%d: kati doesn't support passing results of $(shell) "
557 "to other make constructs: %s",
558 LOCF(ev->loc()), cmd.c_str());
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900559 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900560 StripShellComment(&cmd);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900561 *s += "$(";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900562 *s += cmd;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900563 *s += ")";
564 return;
565 }
566
Shinichiro Hamaji2941ea02016-04-27 17:26:21 +0900567 const string&& shell = ev->GetShellAndFlag();
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900568
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900569 string out;
570 FindCommand* fc = NULL;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900571 ShellFuncImpl(shell, cmd, &out, &fc);
572 if (ShouldStoreCommandResult(cmd)) {
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900573 CommandResult* cr = new CommandResult();
Stefan Beckerd4f28712016-04-07 13:29:36 +0300574 cr->shell = shell;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900575 cr->cmd = cmd;
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900576 cr->find.reset(fc);
577 cr->result = out;
578 g_command_results.push_back(cr);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900579 }
580 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900581}
582
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900583void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900584 static const Symbol tmpvar_names[] = {
585 Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
586 Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900587 };
588
Shinichiro Hamajid8d43ea2016-04-27 16:10:47 +0900589 const string&& func_name_buf = args[0]->Eval(ev);
590 const StringPiece func_name = TrimSpace(func_name_buf);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900591 Var* func = ev->LookupVar(Intern(func_name));
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900592 if (!func->IsDefined()) {
593 KATI_WARN("%s:%d: *warning*: undefined user function: %s",
Shinichiro Hamajid8d43ea2016-04-27 16:10:47 +0900594 ev->loc(), func_name.as_string().c_str());
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900595 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900596 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900597 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900598 unique_ptr<SimpleVar> s(
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900599 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900600 av.push_back(move(s));
601 }
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900602 vector<unique_ptr<ScopedGlobalVar>> sv;
Dan Willemsenb4467962015-08-06 23:59:22 -0700603 for (size_t i = 1; ; i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700604 string s;
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900605 Symbol tmpvar_name_sym(Symbol::IsUninitialized{});
Colin Cross580cc1f2015-07-27 13:18:18 -0700606 if (i < sizeof(tmpvar_names)/sizeof(tmpvar_names[0])) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900607 tmpvar_name_sym = tmpvar_names[i];
Colin Cross580cc1f2015-07-27 13:18:18 -0700608 } else {
609 s = StringPrintf("%d", i);
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900610 tmpvar_name_sym = Intern(s);
Colin Cross580cc1f2015-07-27 13:18:18 -0700611 }
Dan Willemsenb4467962015-08-06 23:59:22 -0700612 if (i < args.size()) {
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900613 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i-1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700614 } else {
615 // We need to blank further automatic vars
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900616 Var *v = ev->LookupVar(tmpvar_name_sym);
Dan Willemsenb4467962015-08-06 23:59:22 -0700617 if (!v->IsDefined()) break;
618 if (v->Origin() != VarOrigin::AUTOMATIC) break;
619
Shinichiro Hamajie978a892015-08-17 16:53:40 +0900620 av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900621 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i-1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700622 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900623 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900624
625 ev->DecrementEvalDepth();
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900626 func->Eval(ev, s);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900627 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900628}
629
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900630void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900631 const string&& varname = args[0]->Eval(ev);
632 const string&& list = args[1]->Eval(ev);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900633 ev->DecrementEvalDepth();
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900634 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900635 for (StringPiece tok : WordScanner(list)) {
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900636 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamaji5081c712015-08-14 16:49:20 +0900637 tok.as_string(), VarOrigin::AUTOMATIC));
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900638 ScopedGlobalVar sv(Intern(varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900639 ww.MaybeAddWhitespace();
640 args[2]->Eval(ev, s);
641 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900642 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900643}
644
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900645void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900646 const string&& var_name = args[0]->Eval(ev);
647 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900648 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900649}
650
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900651void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900652 const string&& var_name = args[0]->Eval(ev);
653 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900654 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900655}
656
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900657void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900658 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900659 if (ev->avoid_io()) {
Dan Willemsene6f68582015-08-21 11:13:28 -0700660 ev->add_delayed_output_command(StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900661 return;
662 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900663 printf("%s\n", a.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900664 fflush(stdout);
665}
666
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900667void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900668 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900669 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900670 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700671 StringPrintf("echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900672 return;
673 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900674 printf("%s:%d: %s\n", LOCF(ev->loc()), a.c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900675 fflush(stdout);
676}
677
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900678void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900679 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900680 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900681 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700682 StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
683 LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900684 return;
685 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900686 ev->Error(StringPrintf("*** %s.", a.c_str()));
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900687}
688
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900689FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900690 { "patsubst", &PatsubstFunc, 3, 3, false, false },
691 { "strip", &StripFunc, 1, 1, false, false },
692 { "subst", &SubstFunc, 3, 3, false, false },
693 { "findstring", &FindstringFunc, 2, 2, false, false },
694 { "filter", &FilterFunc, 2, 2, false, false },
695 { "filter-out", &FilterOutFunc, 2, 2, false, false },
696 { "sort", &SortFunc, 1, 1, false, false },
697 { "word", &WordFunc, 2, 2, false, false },
698 { "wordlist", &WordlistFunc, 3, 3, false, false },
699 { "words", &WordsFunc, 1, 1, false, false },
700 { "firstword", &FirstwordFunc, 1, 1, false, false },
701 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900702
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900703 { "join", &JoinFunc, 2, 2, false, false },
704 { "wildcard", &WildcardFunc, 1, 1, false, false },
705 { "dir", &DirFunc, 1, 1, false, false },
706 { "notdir", &NotdirFunc, 1, 1, false, false },
707 { "suffix", &SuffixFunc, 1, 1, false, false },
708 { "basename", &BasenameFunc, 1, 1, false, false },
709 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
710 { "addprefix", &AddprefixFunc, 2, 2, false, false },
711 { "realpath", &RealpathFunc, 1, 1, false, false },
712 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900713
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900714 { "if", &IfFunc, 3, 2, false, true },
715 { "and", &AndFunc, 0, 0, true, false },
716 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900717
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900718 { "value", &ValueFunc, 1, 1, false, false },
719 { "eval", &EvalFunc, 1, 1, false, false },
720 { "shell", &ShellFunc, 1, 1, false, false },
721 { "call", &CallFunc, 0, 0, false, false },
722 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900723
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900724 { "origin", &OriginFunc, 1, 1, false, false },
725 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900726
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900727 { "info", &InfoFunc, 1, 1, false, false },
728 { "warning", &WarningFunc, 1, 1, false, false },
729 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900730};
731
732unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
733
734} // namespace
735
736void InitFuncTable() {
737 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
738 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
739 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900740 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900741 CHECK(ok);
742 }
743}
744
745void QuitFuncTable() {
746 delete g_func_info_map;
747}
748
749FuncInfo* GetFuncInfo(StringPiece name) {
750 auto found = g_func_info_map->find(name);
751 if (found == g_func_info_map->end())
752 return NULL;
753 return found->second;
754}
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900755
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900756const vector<CommandResult*>& GetShellCommandResults() {
757 return g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900758}