blob: 41d3471ad1a5eaf7082912a648417bf61932f18f [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 Hamaji2e6cbfc2015-06-16 18:46:50 +090043void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090044 shared_ptr<string> pat_str = args[0]->Eval(ev);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090045 shared_ptr<string> repl = args[1]->Eval(ev);
46 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090047 WordWriter ww(s);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090048 Pattern pat(*pat_str);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090049 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090050 ww.MaybeAddWhitespace();
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090051 pat.AppendSubst(tok, *repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090052 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090053}
54
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090055void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
56 shared_ptr<string> str = args[0]->Eval(ev);
57 WordWriter ww(s);
58 for (StringPiece tok : WordScanner(*str)) {
59 ww.Write(tok);
60 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090061}
62
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090063void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
64 shared_ptr<string> pat = args[0]->Eval(ev);
65 shared_ptr<string> repl = args[1]->Eval(ev);
66 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +090067 if (pat->empty()) {
68 *s += *str;
69 *s += *repl;
70 return;
71 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090072 size_t index = 0;
73 while (index < str->size()) {
74 size_t found = str->find(*pat, index);
75 if (found == string::npos)
76 break;
77 AppendString(StringPiece(*str).substr(index, found - index), s);
78 AppendString(*repl, s);
79 index = found + pat->size();
80 }
81 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090082}
83
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090084void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
85 shared_ptr<string> find = args[0]->Eval(ev);
86 shared_ptr<string> in = args[1]->Eval(ev);
87 if (in->find(*find) != string::npos)
88 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090089}
90
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090091void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
92 shared_ptr<string> pat_buf = args[0]->Eval(ev);
93 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090094 vector<Pattern> pats;
95 for (StringPiece pat : WordScanner(*pat_buf)) {
96 pats.push_back(Pattern(pat));
97 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090098 WordWriter ww(s);
99 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900100 for (const Pattern& pat : pats) {
101 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900102 ww.Write(tok);
103 break;
104 }
105 }
106 }
107}
108
109void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
110 shared_ptr<string> pat_buf = args[0]->Eval(ev);
111 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900112 vector<Pattern> pats;
113 for (StringPiece pat : WordScanner(*pat_buf)) {
114 pats.push_back(Pattern(pat));
115 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900116 WordWriter ww(s);
117 for (StringPiece tok : WordScanner(*text)) {
118 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900119 for (const Pattern& pat : pats) {
120 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900121 matched = true;
122 break;
123 }
124 }
125 if (!matched)
126 ww.Write(tok);
127 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900128}
129
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900130void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
131 shared_ptr<string> list = args[0]->Eval(ev);
132 vector<StringPiece> toks;
133 WordScanner(*list).Split(&toks);
134 sort(toks.begin(), toks.end());
135 WordWriter ww(s);
136 StringPiece prev;
137 for (StringPiece tok : toks) {
138 if (prev != tok) {
139 ww.Write(tok);
140 prev = tok;
141 }
142 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900143}
144
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900145static int GetNumericValueForFunc(const string& buf) {
146 StringPiece s = TrimLeftSpace(buf);
147 char* end;
148 long n = strtol(s.data(), &end, 10);
149 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
150 return -1;
151 }
152 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900153}
154
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900155void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
156 shared_ptr<string> n_str = args[0]->Eval(ev);
157 int n = GetNumericValueForFunc(*n_str);
158 if (n < 0) {
159 ev->Error(StringPrintf(
160 "*** non-numeric first argument to `word' function: '%s'.",
161 n_str->c_str()));
162 }
163 if (n == 0) {
164 ev->Error("*** first argument to `word' function must be greater than 0.");
165 }
166
167 shared_ptr<string> text = args[1]->Eval(ev);
168 for (StringPiece tok : WordScanner(*text)) {
169 n--;
170 if (n == 0) {
171 AppendString(tok, s);
172 break;
173 }
174 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900175}
176
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900177void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
178 shared_ptr<string> s_str = args[0]->Eval(ev);
179 int si = GetNumericValueForFunc(*s_str);
180 if (si < 0) {
181 ev->Error(StringPrintf(
182 "*** non-numeric first argument to `wordlist' function: '%s'.",
183 s_str->c_str()));
184 }
185 if (si == 0) {
186 ev->Error(StringPrintf(
187 "*** invalid first argument to `wordlist' function: %s`",
188 s_str->c_str()));
189 }
190
191 shared_ptr<string> e_str = args[1]->Eval(ev);
192 int ei = GetNumericValueForFunc(*e_str);
193 if (ei < 0) {
194 ev->Error(StringPrintf(
195 "*** non-numeric second argument to `wordlist' function: '%s'.",
196 e_str->c_str()));
197 }
198
199 shared_ptr<string> text = args[2]->Eval(ev);
200 int i = 0;
201 WordWriter ww(s);
202 for (StringPiece tok : WordScanner(*text)) {
203 i++;
204 if (si <= i && i <= ei) {
205 ww.Write(tok);
206 }
207 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900208}
209
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900210void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
211 shared_ptr<string> text = args[0]->Eval(ev);
212 WordScanner ws(*text);
213 int n = 0;
214 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
215 n++;
216 char buf[32];
217 sprintf(buf, "%d", n);
218 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900219}
220
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900221void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
222 shared_ptr<string> text = args[0]->Eval(ev);
223 for (StringPiece tok : WordScanner(*text)) {
224 AppendString(tok, s);
225 return;
226 }
227}
228
229void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
230 shared_ptr<string> text = args[0]->Eval(ev);
231 StringPiece last;
232 for (StringPiece tok : WordScanner(*text)) {
233 last = tok;
234 }
235 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900236}
237
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900238void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
239 shared_ptr<string> list1 = args[0]->Eval(ev);
240 shared_ptr<string> list2 = args[1]->Eval(ev);
241 WordScanner ws1(*list1);
242 WordScanner ws2(*list2);
243 WordWriter ww(s);
244 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
245 iter1 != ws1.end() && iter2 != ws2.end();
246 ++iter1, ++iter2) {
247 ww.Write(*iter1);
248 // Use |AppendString| not to append extra ' '.
249 AppendString(*iter2, s);
250 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900251}
252
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900253void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +0900254 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900255 shared_ptr<string> pat = args[0]->Eval(ev);
Shinichiro Hamaji7409aee2015-07-28 14:52:37 +0900256 // Note GNU make does not delay the execution of $(wildcard) so we
257 // do not need to check avoid_io here.
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900258 WordWriter ww(s);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900259 vector<string>* files;
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900260 for (StringPiece tok : WordScanner(*pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900261 ScopedTerminator st(tok);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900262 Glob(tok.data(), &files);
263 sort(files->begin(), files->end());
264 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900265 ww.Write(file);
266 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900267 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900268}
269
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900270void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
271 shared_ptr<string> text = args[0]->Eval(ev);
272 WordWriter ww(s);
273 for (StringPiece tok : WordScanner(*text)) {
274 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900275 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900276 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900277}
278
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900279void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
280 shared_ptr<string> text = args[0]->Eval(ev);
281 WordWriter ww(s);
282 for (StringPiece tok : WordScanner(*text)) {
283 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900284 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900285 } else {
286 ww.Write(Basename(tok));
287 }
288 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900289}
290
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900291void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
292 shared_ptr<string> text = args[0]->Eval(ev);
293 WordWriter ww(s);
294 for (StringPiece tok : WordScanner(*text)) {
295 StringPiece suf = GetExt(tok);
296 if (!suf.empty())
297 ww.Write(suf);
298 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900299}
300
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900301void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
302 shared_ptr<string> text = args[0]->Eval(ev);
303 WordWriter ww(s);
304 for (StringPiece tok : WordScanner(*text)) {
305 ww.Write(StripExt(tok));
306 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900307}
308
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900309void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
310 shared_ptr<string> suf = args[0]->Eval(ev);
311 shared_ptr<string> text = args[1]->Eval(ev);
312 WordWriter ww(s);
313 for (StringPiece tok : WordScanner(*text)) {
314 ww.Write(tok);
315 *s += *suf;
316 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900317}
318
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900319void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
320 shared_ptr<string> pre = args[0]->Eval(ev);
321 shared_ptr<string> text = args[1]->Eval(ev);
322 WordWriter ww(s);
323 for (StringPiece tok : WordScanner(*text)) {
324 ww.Write(*pre);
325 AppendString(tok, s);
326 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900327}
328
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900329void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
330 shared_ptr<string> text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900331 if (ev->avoid_io()) {
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900332 *s += "$(realpath ";
333 *s += *text;
334 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900335 return;
336 }
337
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900338 WordWriter ww(s);
339 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900340 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900341 char buf[PATH_MAX];
342 if (realpath(tok.data(), buf))
343 *s += buf;
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900344 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900345}
346
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900347void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
348 shared_ptr<string> text = args[0]->Eval(ev);
349 WordWriter ww(s);
350 string buf;
351 for (StringPiece tok : WordScanner(*text)) {
352 AbsPath(tok, &buf);
353 ww.Write(buf);
354 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900355}
356
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900357void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
358 shared_ptr<string> cond = args[0]->Eval(ev);
359 if (cond->empty()) {
360 if (args.size() > 2)
361 args[2]->Eval(ev, s);
362 } else {
363 args[1]->Eval(ev, s);
364 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900365}
366
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900367void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
368 shared_ptr<string> cond;
369 for (Value* a : args) {
370 cond = a->Eval(ev);
371 if (cond->empty())
372 return;
373 }
374 if (cond.get()) {
375 *s += *cond;
376 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900377}
378
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900379void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
380 for (Value* a : args) {
381 shared_ptr<string> cond = a->Eval(ev);
382 if (!cond->empty()) {
383 *s += *cond;
384 return;
385 }
386 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900387}
388
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900389void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
390 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900391 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900392 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900393}
394
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900395void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900396 // TODO: eval leaks everything... for now.
397 //shared_ptr<string> text = args[0]->Eval(ev);
398 string* text = new string;
399 args[0]->Eval(ev, text);
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900400 vector<AST*> asts;
401 Parse(*text, ev->loc(), &asts);
402 for (AST* ast : asts) {
403 LOG("%s", ast->DebugString().c_str());
404 ast->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900405 //delete ast;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900406 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900407}
408
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900409//#define TEST_FIND_EMULATOR
410
411#ifdef TEST_FIND_EMULATOR
412static string SortWordsInString(StringPiece s) {
413 vector<string> toks;
414 for (StringPiece tok : WordScanner(s)) {
415 toks.push_back(tok.as_string());
416 }
417 sort(toks.begin(), toks.end());
418 return JoinStrings(toks, " ");
419}
420#endif
421
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900422
423// A hack for Android build. We need to evaluate things like $((3+4))
424// when we emit ninja file, because the result of such expressions
425// will be passed to other make functions.
426// TODO: Maybe we should introduce a helper binary which evaluate
427// make expressions at ninja-time.
428static bool HasNoIoInShellScript(const string& cmd) {
429 if (cmd.empty())
430 return true;
431 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size()-1] == ')')
432 return true;
433 return false;
434}
435
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900436void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
437 shared_ptr<string> cmd = args[0]->Eval(ev);
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900438 if (ev->avoid_io() && !HasNoIoInShellScript(*cmd)) {
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900439 *s += "$(";
440 *s += *cmd;
441 *s += ")";
442 return;
443 }
444
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900445 LOG("ShellFunc: %s", cmd->c_str());
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900446
447#ifdef TEST_FIND_EMULATOR
448 bool need_check = false;
449 string out2;
Shinichiro Hamaji4e950e62015-07-02 02:59:55 +0900450 if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, &out2)) {
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900451 need_check = true;
452 }
453#else
Shinichiro Hamaji4e950e62015-07-02 02:59:55 +0900454 if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, s))
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900455 return;
456#endif
457
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900458 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd->c_str());
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900459 string out;
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900460 shared_ptr<string> shell = ev->EvalVar(kShellSym);
461 RunCommand(*shell, *cmd, false, &out);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900462
463 while (out[out.size()-1] == '\n')
464 out.pop_back();
465 for (size_t i = 0; i < out.size(); i++) {
466 if (out[i] == '\n')
467 out[i] = ' ';
468 }
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900469
470#ifdef TEST_FIND_EMULATOR
471 if (need_check) {
472 string sorted = SortWordsInString(out);
473 out2 = SortWordsInString(out2);
474 if (sorted != out2) {
475 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
476 cmd->c_str(), sorted.c_str(), out2.c_str());
477 }
478 }
479#endif
480
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900481 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900482}
483
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900484void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700485 static const string tmpvar_names[] = {
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900486 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
487 };
488
489 shared_ptr<string> func_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900490 Var* func = ev->LookupVar(Intern(*func_name));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900491 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900492 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900493 unique_ptr<SimpleVar> s(
494 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900495 av.push_back(move(s));
496 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900497 vector<unique_ptr<ScopedVar>> sv;
498 for (size_t i = 1; i < args.size(); i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700499 string s;
500 StringPiece tmpvar_name;
501 if (i < sizeof(tmpvar_names)/sizeof(tmpvar_names[0])) {
502 tmpvar_name = tmpvar_names[i];
503 } else {
504 s = StringPrintf("%d", i);
505 tmpvar_name = s;
506 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900507 sv.push_back(move(unique_ptr<ScopedVar>(
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900508 new ScopedVar(ev->mutable_vars(),
Colin Cross580cc1f2015-07-27 13:18:18 -0700509 Intern(tmpvar_name), av[i-1].get()))));
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900510 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900511 func->Eval(ev, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900512}
513
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900514void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
515 shared_ptr<string> varname = args[0]->Eval(ev);
516 shared_ptr<string> list = args[1]->Eval(ev);
517 WordWriter ww(s);
518 for (StringPiece tok : WordScanner(*list)) {
519 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900520 make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC));
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900521 ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900522 ww.MaybeAddWhitespace();
523 args[2]->Eval(ev, s);
524 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900525}
526
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900527void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
528 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900529 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900530 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900531}
532
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900533void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
534 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900535 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900536 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900537}
538
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900539void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900540 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900541 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900542 ev->add_delayed_output_command(StringPrintf("echo '%s'", a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900543 return;
544 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900545 printf("%s\n", a->c_str());
546 fflush(stdout);
547}
548
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900549void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900550 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900551 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900552 ev->add_delayed_output_command(
553 StringPrintf("echo '%s:%d: %s' 2>&1", LOCF(ev->loc()), a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900554 return;
555 }
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900556 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900557 fflush(stdout);
558}
559
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900560void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900561 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900562 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900563 ev->add_delayed_output_command(
564 StringPrintf("echo '%s:%d: *** %s.' 2>&1 && false",
565 LOCF(ev->loc()), a->c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900566 return;
567 }
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900568 ev->Error(StringPrintf("*** %s.", a->c_str()));
569}
570
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900571FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900572 { "patsubst", &PatsubstFunc, 3, 3, false, false },
573 { "strip", &StripFunc, 1, 1, false, false },
574 { "subst", &SubstFunc, 3, 3, false, false },
575 { "findstring", &FindstringFunc, 2, 2, false, false },
576 { "filter", &FilterFunc, 2, 2, false, false },
577 { "filter-out", &FilterOutFunc, 2, 2, false, false },
578 { "sort", &SortFunc, 1, 1, false, false },
579 { "word", &WordFunc, 2, 2, false, false },
580 { "wordlist", &WordlistFunc, 3, 3, false, false },
581 { "words", &WordsFunc, 1, 1, false, false },
582 { "firstword", &FirstwordFunc, 1, 1, false, false },
583 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900584
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900585 { "join", &JoinFunc, 2, 2, false, false },
586 { "wildcard", &WildcardFunc, 1, 1, false, false },
587 { "dir", &DirFunc, 1, 1, false, false },
588 { "notdir", &NotdirFunc, 1, 1, false, false },
589 { "suffix", &SuffixFunc, 1, 1, false, false },
590 { "basename", &BasenameFunc, 1, 1, false, false },
591 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
592 { "addprefix", &AddprefixFunc, 2, 2, false, false },
593 { "realpath", &RealpathFunc, 1, 1, false, false },
594 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900595
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900596 { "if", &IfFunc, 3, 2, false, true },
597 { "and", &AndFunc, 0, 0, true, false },
598 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900599
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900600 { "value", &ValueFunc, 1, 1, false, false },
601 { "eval", &EvalFunc, 1, 1, false, false },
602 { "shell", &ShellFunc, 1, 1, false, false },
603 { "call", &CallFunc, 0, 0, false, false },
604 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900605
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900606 { "origin", &OriginFunc, 1, 1, false, false },
607 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900608
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900609 { "info", &InfoFunc, 1, 1, false, false },
610 { "warning", &WarningFunc, 1, 1, false, false },
611 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900612};
613
614unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
615
616} // namespace
617
618void InitFuncTable() {
619 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
620 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
621 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900622 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900623 CHECK(ok);
624 }
625}
626
627void QuitFuncTable() {
628 delete g_func_info_map;
629}
630
631FuncInfo* GetFuncInfo(StringPiece name) {
632 auto found = g_func_info_map->find(name);
633 if (found == g_func_info_map->end())
634 return NULL;
635 return found->second;
636}