blob: 5c5cf302fe10621eb76287cafa0f47cf46e129e2 [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 Hamaji14436892016-02-12 16:32:42 +090033#include "lcp_msort.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 Hamaji645cca72015-09-24 17:04:21 +090037#include "stmt.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090038#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090039#include "symtab.h"
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090040#include "var.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090041
42namespace {
43
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090044// TODO: This code is very similar to
45// NinjaGenerator::TranslateCommand. Factor them out.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090046void StripShellComment(string* cmd) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090047 if (cmd->find('#') == string::npos)
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090048 return;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090049
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090050 string res;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090051 bool prev_backslash = false;
52 // Set space as an initial value so the leading comment will be
53 // stripped out.
54 char prev_char = ' ';
55 char quote = 0;
56 bool done = false;
57 const char* in = cmd->c_str();
58 for (; *in && !done; in++) {
59 switch (*in) {
60 case '#':
61 if (quote == 0 && isspace(prev_char)) {
Shinichiro Hamaji212b7a52015-10-05 17:02:29 +090062 while (in[1] && *in != '\n')
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090063 in++;
64 break;
65 }
66
67 case '\'':
68 case '"':
69 case '`':
70 if (quote) {
71 if (quote == *in)
72 quote = 0;
73 } else if (!prev_backslash) {
74 quote = *in;
75 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090076 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090077 break;
78
79 case '\\':
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090080 res += '\\';
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090081 break;
82
83 default:
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090084 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090085 }
86
87 if (*in == '\\') {
88 prev_backslash = !prev_backslash;
89 } else {
90 prev_backslash = false;
91 }
92
93 prev_char = *in;
94 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090095 cmd->swap(res);
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090096}
97
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090098void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090099 const string&& pat_str = args[0]->Eval(ev);
100 const string&& repl = args[1]->Eval(ev);
101 const string&& str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900102 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900103 Pattern pat(pat_str);
104 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900105 ww.MaybeAddWhitespace();
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900106 pat.AppendSubst(tok, repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900107 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900108}
109
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900110void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900111 const string&& str = args[0]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900112 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900113 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900114 ww.Write(tok);
115 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900116}
117
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900118void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900119 const string&& pat = args[0]->Eval(ev);
120 const string&& repl = args[1]->Eval(ev);
121 const string&& str = args[2]->Eval(ev);
122 if (pat.empty()) {
123 *s += str;
124 *s += repl;
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +0900125 return;
126 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900127 size_t index = 0;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900128 while (index < str.size()) {
129 size_t found = str.find(pat, index);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900130 if (found == string::npos)
131 break;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900132 AppendString(StringPiece(str).substr(index, found - index), s);
133 AppendString(repl, s);
134 index = found + pat.size();
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900135 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900136 AppendString(StringPiece(str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900137}
138
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900139void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900140 const string&& find = args[0]->Eval(ev);
141 const string&& in = args[1]->Eval(ev);
142 if (in.find(find) != string::npos)
143 AppendString(find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900144}
145
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900146void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900147 const string&& pat_buf = args[0]->Eval(ev);
148 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900149 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900150 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900151 pats.push_back(Pattern(pat));
152 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900153 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900154 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900155 for (const Pattern& pat : pats) {
156 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900157 ww.Write(tok);
158 break;
159 }
160 }
161 }
162}
163
164void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900165 const string&& pat_buf = args[0]->Eval(ev);
166 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900167 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900168 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900169 pats.push_back(Pattern(pat));
170 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900171 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900172 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900173 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900174 for (const Pattern& pat : pats) {
175 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900176 matched = true;
177 break;
178 }
179 }
180 if (!matched)
181 ww.Write(tok);
182 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900183}
184
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900185void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900186 string list;
187 args[0]->Eval(ev, &list);
188 COLLECT_STATS("func sort time");
189 // TODO(hamaji): Probably we could make LCP merge sort faster than
190 // stable_sort.
191#if __APPLE___
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900192 vector<StringPiece> toks;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900193 WordScanner(list).Split(&toks);
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900194 stable_sort(toks.begin(), toks.end());
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900195 WordWriter ww(s);
196 StringPiece prev;
197 for (StringPiece tok : toks) {
198 if (prev != tok) {
199 ww.Write(tok);
200 prev = tok;
201 }
202 }
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900203#else
204 StringSortByLcpMsort(&list, s);
205#endif
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) {
222 ev->Error(StringPrintf(
223 "*** non-numeric first argument to `word' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900224 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) {
249 ev->Error(StringPrintf(
250 "*** invalid first argument to `wordlist' function: %s`",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900251 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);
307 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
308 iter1 != ws1.end() && iter2 != ws2.end();
309 ++iter1, ++iter2) {
310 ww.Write(*iter1);
311 // Use |AppendString| not to append extra ' '.
312 AppendString(*iter2, s);
313 }
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);
326 sort(files->begin(), files->end());
327 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900328 ww.Write(file);
329 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900330 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900331}
332
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900333void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900334 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900335 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900336 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900337 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900338 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900339 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900340}
341
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900342void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900343 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900344 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900345 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900346 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900347 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900348 } else {
349 ww.Write(Basename(tok));
350 }
351 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900352}
353
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900354void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900355 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900356 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900357 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900358 StringPiece suf = GetExt(tok);
359 if (!suf.empty())
360 ww.Write(suf);
361 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900362}
363
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900364void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900365 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900366 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900367 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900368 ww.Write(StripExt(tok));
369 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900370}
371
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900372void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900373 const string&& suf = args[0]->Eval(ev);
374 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900375 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900376 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900377 ww.Write(tok);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900378 *s += suf;
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900379 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900380}
381
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900382void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900383 const string&& pre = args[0]->Eval(ev);
384 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900385 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900386 for (StringPiece tok : WordScanner(text)) {
387 ww.Write(pre);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900388 AppendString(tok, s);
389 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900390}
391
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900392void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900393 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900394 if (ev->avoid_io()) {
Shinichiro Hamaji71cf60b2015-10-08 18:00:07 +0900395 *s += "$(";
396 string kati_binary;
397 GetExecutablePath(&kati_binary);
398 *s += kati_binary;
399 *s += " --realpath ";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900400 *s += text;
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900401 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900402 return;
403 }
404
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900405 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900406 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900407 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900408 char buf[PATH_MAX];
409 if (realpath(tok.data(), buf))
Shinichiro Hamajicb4724e2015-10-08 17:52:49 +0900410 ww.Write(buf);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900411 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900412}
413
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900414void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900415 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900416 WordWriter ww(s);
417 string buf;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900418 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900419 AbsPath(tok, &buf);
420 ww.Write(buf);
421 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900422}
423
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900424void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900425 const string&& cond = args[0]->Eval(ev);
426 if (cond.empty()) {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900427 if (args.size() > 2)
428 args[2]->Eval(ev, s);
429 } else {
430 args[1]->Eval(ev, s);
431 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900432}
433
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900434void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900435 string cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900436 for (Value* a : args) {
437 cond = a->Eval(ev);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900438 if (cond.empty())
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900439 return;
440 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900441 if (!cond.empty()) {
442 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900443 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900444}
445
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900446void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
447 for (Value* a : args) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900448 const string&& cond = a->Eval(ev);
449 if (!cond.empty()) {
450 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900451 return;
452 }
453 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900454}
455
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900456void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900457 const string&& var_name = args[0]->Eval(ev);
458 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900459 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900460}
461
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900462void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900463 // TODO: eval leaks everything... for now.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900464 //const string text = args[0]->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900465 string* text = new string;
466 args[0]->Eval(ev, text);
Shinichiro Hamajibbe55482015-11-17 14:50:29 +0900467 if ((*text)[0] == '#') {
468 delete text;
469 return;
470 }
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900471 if (ev->avoid_io()) {
472 KATI_WARN("%s:%d: *warning*: $(eval) in a recipe is not recommended: %s",
473 LOCF(ev->loc()), text->c_str());
474 }
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900475 vector<Stmt*> stmts;
476 Parse(*text, ev->loc(), &stmts);
477 for (Stmt* stmt : stmts) {
478 LOG("%s", stmt->DebugString().c_str());
479 stmt->Eval(ev);
480 //delete stmt;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900481 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900482}
483
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900484//#define TEST_FIND_EMULATOR
485
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900486// A hack for Android build. We need to evaluate things like $((3+4))
487// when we emit ninja file, because the result of such expressions
488// will be passed to other make functions.
489// TODO: Maybe we should introduce a helper binary which evaluate
490// make expressions at ninja-time.
491static bool HasNoIoInShellScript(const string& cmd) {
492 if (cmd.empty())
493 return true;
494 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size()-1] == ')')
495 return true;
496 return false;
497}
498
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900499static void ShellFuncImpl(const string& shell, const string& cmd,
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900500 string* s, FindCommand** fc) {
501 LOG("ShellFunc: %s", cmd.c_str());
502
503#ifdef TEST_FIND_EMULATOR
504 bool need_check = false;
505 string out2;
506#endif
507 if (FindEmulator::Get()) {
508 *fc = new FindCommand();
509 if ((*fc)->Parse(cmd)) {
510#ifdef TEST_FIND_EMULATOR
511 if (FindEmulator::Get()->HandleFind(cmd, **fc, &out2)) {
512 need_check = true;
513 }
514#else
515 if (FindEmulator::Get()->HandleFind(cmd, **fc, s)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900516 return;
517 }
518#endif
519 }
520 delete *fc;
521 *fc = NULL;
522 }
523
524 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd.c_str());
525 RunCommand(shell, cmd, RedirectStderr::NONE, s);
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700526 FormatForCommandSubstitution(s);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900527
528#ifdef TEST_FIND_EMULATOR
529 if (need_check) {
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700530 if (*s != out2) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900531 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700532 cmd.c_str(), s->c_str(), out2.c_str());
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900533 }
534 }
535#endif
536}
537
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900538static vector<CommandResult*> g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900539
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900540bool ShouldStoreCommandResult(StringPiece cmd) {
541 if (HasWord(cmd, "date") || HasWord(cmd, "echo"))
542 return false;
Colin Crossf23ae8c2015-11-12 17:05:32 -0800543
544 Pattern pat(g_flags.ignore_dirty_pattern);
545 Pattern nopat(g_flags.no_ignore_dirty_pattern);
546 for (StringPiece tok : WordScanner(cmd)) {
547 if (pat.Match(tok) && !nopat.Match(tok)) {
548 return false;
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900549 }
550 }
Colin Crossf23ae8c2015-11-12 17:05:32 -0800551
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900552 return true;
553}
554
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900555void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900556 string cmd = args[0]->Eval(ev);
557 if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900558 if (ev->eval_depth() > 1) {
Shinichiro Hamajicbb801c2015-12-18 15:37:14 +0900559 ERROR("%s:%d: kati doesn't support passing results of $(shell) "
560 "to other make constructs: %s",
561 LOCF(ev->loc()), cmd.c_str());
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900562 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900563 StripShellComment(&cmd);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900564 *s += "$(";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900565 *s += cmd;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900566 *s += ")";
567 return;
568 }
569
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900570 const string&& shell = ev->EvalVar(kShellSym);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900571
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900572 string out;
573 FindCommand* fc = NULL;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900574 ShellFuncImpl(shell, cmd, &out, &fc);
575 if (ShouldStoreCommandResult(cmd)) {
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900576 CommandResult* cr = new CommandResult();
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900577 cr->cmd = cmd;
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900578 cr->find.reset(fc);
579 cr->result = out;
580 g_command_results.push_back(cr);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900581 }
582 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900583}
584
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900585void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900586 static const Symbol tmpvar_names[] = {
587 Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
588 Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900589 };
590
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900591 const string&& func_name = args[0]->Eval(ev);
592 Var* func = ev->LookupVar(Intern(func_name));
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900593 if (!func->IsDefined()) {
594 KATI_WARN("%s:%d: *warning*: undefined user function: %s",
595 ev->loc(), func_name.c_str());
596 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900597 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900598 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900599 unique_ptr<SimpleVar> s(
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900600 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900601 av.push_back(move(s));
602 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900603 vector<unique_ptr<ScopedVar>> sv;
Dan Willemsenb4467962015-08-06 23:59:22 -0700604 for (size_t i = 1; ; i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700605 string s;
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900606 Symbol tmpvar_name_sym(Symbol::IsUninitialized{});
Colin Cross580cc1f2015-07-27 13:18:18 -0700607 if (i < sizeof(tmpvar_names)/sizeof(tmpvar_names[0])) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900608 tmpvar_name_sym = tmpvar_names[i];
Colin Cross580cc1f2015-07-27 13:18:18 -0700609 } else {
610 s = StringPrintf("%d", i);
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900611 tmpvar_name_sym = Intern(s);
Colin Cross580cc1f2015-07-27 13:18:18 -0700612 }
Dan Willemsenb4467962015-08-06 23:59:22 -0700613 if (i < args.size()) {
Shinichiro Hamajie978a892015-08-17 16:53:40 +0900614 sv.emplace_back(new ScopedVar(ev->mutable_vars(),
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900615 tmpvar_name_sym, av[i-1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700616 } else {
617 // We need to blank further automatic vars
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900618 Var *v = ev->LookupVar(tmpvar_name_sym);
Dan Willemsenb4467962015-08-06 23:59:22 -0700619 if (!v->IsDefined()) break;
620 if (v->Origin() != VarOrigin::AUTOMATIC) break;
621
Shinichiro Hamajie978a892015-08-17 16:53:40 +0900622 av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
623 sv.emplace_back(new ScopedVar(ev->mutable_vars(),
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900624 tmpvar_name_sym, av[i-1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700625 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900626 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900627
628 ev->DecrementEvalDepth();
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900629 func->Eval(ev, s);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900630 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900631}
632
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900633void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900634 const string&& varname = args[0]->Eval(ev);
635 const string&& list = args[1]->Eval(ev);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900636 ev->DecrementEvalDepth();
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900637 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900638 for (StringPiece tok : WordScanner(list)) {
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900639 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamaji5081c712015-08-14 16:49:20 +0900640 tok.as_string(), VarOrigin::AUTOMATIC));
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900641 ScopedVar sv(ev->mutable_vars(), Intern(varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900642 ww.MaybeAddWhitespace();
643 args[2]->Eval(ev, s);
644 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900645 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900646}
647
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900648void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900649 const string&& var_name = args[0]->Eval(ev);
650 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900651 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900652}
653
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900654void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900655 const string&& var_name = args[0]->Eval(ev);
656 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900657 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900658}
659
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900660void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900661 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900662 if (ev->avoid_io()) {
Dan Willemsene6f68582015-08-21 11:13:28 -0700663 ev->add_delayed_output_command(StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900664 return;
665 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900666 printf("%s\n", a.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900667 fflush(stdout);
668}
669
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900670void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900671 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900672 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900673 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700674 StringPrintf("echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900675 return;
676 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900677 printf("%s:%d: %s\n", LOCF(ev->loc()), a.c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900678 fflush(stdout);
679}
680
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900681void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900682 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900683 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900684 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700685 StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
686 LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900687 return;
688 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900689 ev->Error(StringPrintf("*** %s.", a.c_str()));
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900690}
691
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900692FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900693 { "patsubst", &PatsubstFunc, 3, 3, false, false },
694 { "strip", &StripFunc, 1, 1, false, false },
695 { "subst", &SubstFunc, 3, 3, false, false },
696 { "findstring", &FindstringFunc, 2, 2, false, false },
697 { "filter", &FilterFunc, 2, 2, false, false },
698 { "filter-out", &FilterOutFunc, 2, 2, false, false },
699 { "sort", &SortFunc, 1, 1, false, false },
700 { "word", &WordFunc, 2, 2, false, false },
701 { "wordlist", &WordlistFunc, 3, 3, false, false },
702 { "words", &WordsFunc, 1, 1, false, false },
703 { "firstword", &FirstwordFunc, 1, 1, false, false },
704 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900705
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900706 { "join", &JoinFunc, 2, 2, false, false },
707 { "wildcard", &WildcardFunc, 1, 1, false, false },
708 { "dir", &DirFunc, 1, 1, false, false },
709 { "notdir", &NotdirFunc, 1, 1, false, false },
710 { "suffix", &SuffixFunc, 1, 1, false, false },
711 { "basename", &BasenameFunc, 1, 1, false, false },
712 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
713 { "addprefix", &AddprefixFunc, 2, 2, false, false },
714 { "realpath", &RealpathFunc, 1, 1, false, false },
715 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900716
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900717 { "if", &IfFunc, 3, 2, false, true },
718 { "and", &AndFunc, 0, 0, true, false },
719 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900720
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900721 { "value", &ValueFunc, 1, 1, false, false },
722 { "eval", &EvalFunc, 1, 1, false, false },
723 { "shell", &ShellFunc, 1, 1, false, false },
724 { "call", &CallFunc, 0, 0, false, false },
725 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900726
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900727 { "origin", &OriginFunc, 1, 1, false, false },
728 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900729
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900730 { "info", &InfoFunc, 1, 1, false, false },
731 { "warning", &WarningFunc, 1, 1, false, false },
732 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900733};
734
735unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
736
737} // namespace
738
739void InitFuncTable() {
740 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
741 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
742 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900743 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900744 CHECK(ok);
745 }
746}
747
748void QuitFuncTable() {
749 delete g_func_info_map;
750}
751
752FuncInfo* GetFuncInfo(StringPiece name) {
753 auto found = g_func_info_map->find(name);
754 if (found == g_func_info_map->end())
755 return NULL;
756 return found->second;
757}
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900758
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900759const vector<CommandResult*>& GetShellCommandResults() {
760 return g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900761}