blob: 6988b28b8b22f5dfbed6a3aa32171b25ec6b2f4c [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 Hamaji30b8e602015-06-17 19:28:54 +090020#include <glob.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090021#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090023#include <stdlib.h>
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090024#include <unistd.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090025
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090026#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090027#include <iterator>
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090028#include <memory>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090029#include <unordered_map>
30
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090031#include "ast.h"
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090032#include "eval.h"
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090033#include "fileutil.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090034#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090035#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090036#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090037#include "stats.h"
Shinichiro 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 Hamaji2e6cbfc2015-06-16 18:46:50 +090044void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090045 shared_ptr<string> pat_str = args[0]->Eval(ev);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090046 shared_ptr<string> repl = args[1]->Eval(ev);
47 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090048 WordWriter ww(s);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090049 Pattern pat(*pat_str);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090050 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090051 ww.MaybeAddWhitespace();
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090052 pat.AppendSubst(tok, *repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090053 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090054}
55
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090056void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
57 shared_ptr<string> str = args[0]->Eval(ev);
58 WordWriter ww(s);
59 for (StringPiece tok : WordScanner(*str)) {
60 ww.Write(tok);
61 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090062}
63
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090064void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
65 shared_ptr<string> pat = args[0]->Eval(ev);
66 shared_ptr<string> repl = args[1]->Eval(ev);
67 shared_ptr<string> str = args[2]->Eval(ev);
68 size_t index = 0;
69 while (index < str->size()) {
70 size_t found = str->find(*pat, index);
71 if (found == string::npos)
72 break;
73 AppendString(StringPiece(*str).substr(index, found - index), s);
74 AppendString(*repl, s);
75 index = found + pat->size();
76 }
77 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090078}
79
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090080void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
81 shared_ptr<string> find = args[0]->Eval(ev);
82 shared_ptr<string> in = args[1]->Eval(ev);
83 if (in->find(*find) != string::npos)
84 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090085}
86
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090087void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
88 shared_ptr<string> pat_buf = args[0]->Eval(ev);
89 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090090 vector<Pattern> pats;
91 for (StringPiece pat : WordScanner(*pat_buf)) {
92 pats.push_back(Pattern(pat));
93 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090094 WordWriter ww(s);
95 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090096 for (const Pattern& pat : pats) {
97 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090098 ww.Write(tok);
99 break;
100 }
101 }
102 }
103}
104
105void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
106 shared_ptr<string> pat_buf = args[0]->Eval(ev);
107 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900108 vector<Pattern> pats;
109 for (StringPiece pat : WordScanner(*pat_buf)) {
110 pats.push_back(Pattern(pat));
111 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900112 WordWriter ww(s);
113 for (StringPiece tok : WordScanner(*text)) {
114 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900115 for (const Pattern& pat : pats) {
116 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900117 matched = true;
118 break;
119 }
120 }
121 if (!matched)
122 ww.Write(tok);
123 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900124}
125
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900126void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
127 shared_ptr<string> list = args[0]->Eval(ev);
128 vector<StringPiece> toks;
129 WordScanner(*list).Split(&toks);
130 sort(toks.begin(), toks.end());
131 WordWriter ww(s);
132 StringPiece prev;
133 for (StringPiece tok : toks) {
134 if (prev != tok) {
135 ww.Write(tok);
136 prev = tok;
137 }
138 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900139}
140
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900141static int GetNumericValueForFunc(const string& buf) {
142 StringPiece s = TrimLeftSpace(buf);
143 char* end;
144 long n = strtol(s.data(), &end, 10);
145 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
146 return -1;
147 }
148 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900149}
150
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900151void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
152 shared_ptr<string> n_str = args[0]->Eval(ev);
153 int n = GetNumericValueForFunc(*n_str);
154 if (n < 0) {
155 ev->Error(StringPrintf(
156 "*** non-numeric first argument to `word' function: '%s'.",
157 n_str->c_str()));
158 }
159 if (n == 0) {
160 ev->Error("*** first argument to `word' function must be greater than 0.");
161 }
162
163 shared_ptr<string> text = args[1]->Eval(ev);
164 for (StringPiece tok : WordScanner(*text)) {
165 n--;
166 if (n == 0) {
167 AppendString(tok, s);
168 break;
169 }
170 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900171}
172
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900173void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
174 shared_ptr<string> s_str = args[0]->Eval(ev);
175 int si = GetNumericValueForFunc(*s_str);
176 if (si < 0) {
177 ev->Error(StringPrintf(
178 "*** non-numeric first argument to `wordlist' function: '%s'.",
179 s_str->c_str()));
180 }
181 if (si == 0) {
182 ev->Error(StringPrintf(
183 "*** invalid first argument to `wordlist' function: %s`",
184 s_str->c_str()));
185 }
186
187 shared_ptr<string> e_str = args[1]->Eval(ev);
188 int ei = GetNumericValueForFunc(*e_str);
189 if (ei < 0) {
190 ev->Error(StringPrintf(
191 "*** non-numeric second argument to `wordlist' function: '%s'.",
192 e_str->c_str()));
193 }
194
195 shared_ptr<string> text = args[2]->Eval(ev);
196 int i = 0;
197 WordWriter ww(s);
198 for (StringPiece tok : WordScanner(*text)) {
199 i++;
200 if (si <= i && i <= ei) {
201 ww.Write(tok);
202 }
203 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900204}
205
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900206void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
207 shared_ptr<string> text = args[0]->Eval(ev);
208 WordScanner ws(*text);
209 int n = 0;
210 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
211 n++;
212 char buf[32];
213 sprintf(buf, "%d", n);
214 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900215}
216
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900217void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
218 shared_ptr<string> text = args[0]->Eval(ev);
219 for (StringPiece tok : WordScanner(*text)) {
220 AppendString(tok, s);
221 return;
222 }
223}
224
225void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
226 shared_ptr<string> text = args[0]->Eval(ev);
227 StringPiece last;
228 for (StringPiece tok : WordScanner(*text)) {
229 last = tok;
230 }
231 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900232}
233
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900234void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
235 shared_ptr<string> list1 = args[0]->Eval(ev);
236 shared_ptr<string> list2 = args[1]->Eval(ev);
237 WordScanner ws1(*list1);
238 WordScanner ws2(*list2);
239 WordWriter ww(s);
240 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
241 iter1 != ws1.end() && iter2 != ws2.end();
242 ++iter1, ++iter2) {
243 ww.Write(*iter1);
244 // Use |AppendString| not to append extra ' '.
245 AppendString(*iter2, s);
246 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900247}
248
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900249void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +0900250 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900251 shared_ptr<string> pat = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900252 if (ev->avoid_io()) {
253 *s += "$(/bin/ls -d ";
254 *s += *pat;
255 *s += " 2> /dev/null)";
256 return;
257 }
258
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900259 WordWriter ww(s);
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900260 vector<const char*> files;
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900261 for (StringPiece tok : WordScanner(*pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900262 ScopedTerminator st(tok);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900263 // TODO: Make this faster by not always using glob.
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900264 files.clear();
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900265 glob_t gl;
266 glob(tok.data(), GLOB_NOSORT, NULL, &gl);
267 for (size_t i = 0; i < gl.gl_pathc; i++) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900268 files.push_back(gl.gl_pathv[i]);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900269 }
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900270 sort(files.begin(), files.end(),
271 [](const char* a, const char* b) {
272 return strcmp(a, b) < 0;
273 });
274 for (const char* file : files) {
275 ww.Write(file);
276 }
277
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900278 globfree(&gl);
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900279 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900280}
281
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900282void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
283 shared_ptr<string> text = args[0]->Eval(ev);
284 WordWriter ww(s);
285 for (StringPiece tok : WordScanner(*text)) {
286 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900287 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900288 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900289}
290
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900291void NotdirFunc(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 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900296 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900297 } else {
298 ww.Write(Basename(tok));
299 }
300 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900301}
302
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900303void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
304 shared_ptr<string> text = args[0]->Eval(ev);
305 WordWriter ww(s);
306 for (StringPiece tok : WordScanner(*text)) {
307 StringPiece suf = GetExt(tok);
308 if (!suf.empty())
309 ww.Write(suf);
310 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900311}
312
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900313void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
314 shared_ptr<string> text = args[0]->Eval(ev);
315 WordWriter ww(s);
316 for (StringPiece tok : WordScanner(*text)) {
317 ww.Write(StripExt(tok));
318 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900319}
320
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900321void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
322 shared_ptr<string> suf = args[0]->Eval(ev);
323 shared_ptr<string> text = args[1]->Eval(ev);
324 WordWriter ww(s);
325 for (StringPiece tok : WordScanner(*text)) {
326 ww.Write(tok);
327 *s += *suf;
328 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900329}
330
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900331void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
332 shared_ptr<string> pre = args[0]->Eval(ev);
333 shared_ptr<string> text = args[1]->Eval(ev);
334 WordWriter ww(s);
335 for (StringPiece tok : WordScanner(*text)) {
336 ww.Write(*pre);
337 AppendString(tok, s);
338 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900339}
340
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900341void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
342 shared_ptr<string> text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900343 if (ev->avoid_io()) {
344 *s += "KATI_TODO(realpath)";
345 return;
346 }
347
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900348 WordWriter ww(s);
349 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900350 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900351 char buf[PATH_MAX];
352 if (realpath(tok.data(), buf))
353 *s += buf;
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900354 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900355}
356
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900357void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
358 shared_ptr<string> text = args[0]->Eval(ev);
359 WordWriter ww(s);
360 string buf;
361 for (StringPiece tok : WordScanner(*text)) {
362 AbsPath(tok, &buf);
363 ww.Write(buf);
364 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900365}
366
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900367void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
368 shared_ptr<string> cond = args[0]->Eval(ev);
369 if (cond->empty()) {
370 if (args.size() > 2)
371 args[2]->Eval(ev, s);
372 } else {
373 args[1]->Eval(ev, s);
374 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900375}
376
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900377void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
378 shared_ptr<string> cond;
379 for (Value* a : args) {
380 cond = a->Eval(ev);
381 if (cond->empty())
382 return;
383 }
384 if (cond.get()) {
385 *s += *cond;
386 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900387}
388
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900389void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
390 for (Value* a : args) {
391 shared_ptr<string> cond = a->Eval(ev);
392 if (!cond->empty()) {
393 *s += *cond;
394 return;
395 }
396 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900397}
398
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900399void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
400 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900401 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900402 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900403}
404
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900405void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900406 // TODO: eval leaks everything... for now.
407 //shared_ptr<string> text = args[0]->Eval(ev);
408 string* text = new string;
409 args[0]->Eval(ev, text);
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900410 vector<AST*> asts;
411 Parse(*text, ev->loc(), &asts);
412 for (AST* ast : asts) {
413 LOG("%s", ast->DebugString().c_str());
414 ast->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900415 //delete ast;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900416 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900417}
418
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900419//#define TEST_FIND_EMULATOR
420
421#ifdef TEST_FIND_EMULATOR
422static string SortWordsInString(StringPiece s) {
423 vector<string> toks;
424 for (StringPiece tok : WordScanner(s)) {
425 toks.push_back(tok.as_string());
426 }
427 sort(toks.begin(), toks.end());
428 return JoinStrings(toks, " ");
429}
430#endif
431
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900432void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
433 shared_ptr<string> cmd = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900434 if (ev->avoid_io()) {
435 *s += "$(";
436 *s += *cmd;
437 *s += ")";
438 return;
439 }
440
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900441 LOG("ShellFunc: %s", cmd->c_str());
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900442
443#ifdef TEST_FIND_EMULATOR
444 bool need_check = false;
445 string out2;
Shinichiro Hamaji4e950e62015-07-02 02:59:55 +0900446 if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, &out2)) {
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900447 need_check = true;
448 }
449#else
Shinichiro Hamaji4e950e62015-07-02 02:59:55 +0900450 if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, s))
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900451 return;
452#endif
453
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900454 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd->c_str());
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900455 string out;
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +0900456 shared_ptr<string> shell = ev->EvalVar(kShellSym);
457 RunCommand(*shell, *cmd, false, &out);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900458
459 while (out[out.size()-1] == '\n')
460 out.pop_back();
461 for (size_t i = 0; i < out.size(); i++) {
462 if (out[i] == '\n')
463 out[i] = ' ';
464 }
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900465
466#ifdef TEST_FIND_EMULATOR
467 if (need_check) {
468 string sorted = SortWordsInString(out);
469 out2 = SortWordsInString(out2);
470 if (sorted != out2) {
471 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
472 cmd->c_str(), sorted.c_str(), out2.c_str());
473 }
474 }
475#endif
476
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900477 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900478}
479
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900480void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
481 static const char* tmpvar_names[] = {
482 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
483 };
484
485 shared_ptr<string> func_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900486 Var* func = ev->LookupVar(Intern(*func_name));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900487 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900488 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900489 unique_ptr<SimpleVar> s(
490 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900491 av.push_back(move(s));
492 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900493 vector<unique_ptr<ScopedVar>> sv;
494 for (size_t i = 1; i < args.size(); i++) {
495 sv.push_back(move(unique_ptr<ScopedVar>(
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900496 new ScopedVar(ev->mutable_vars(),
497 Intern(tmpvar_names[i]), av[i-1].get()))));
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900498 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900499 func->Eval(ev, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900500}
501
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900502void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
503 shared_ptr<string> varname = args[0]->Eval(ev);
504 shared_ptr<string> list = args[1]->Eval(ev);
505 WordWriter ww(s);
506 for (StringPiece tok : WordScanner(*list)) {
507 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900508 make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC));
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900509 ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900510 ww.MaybeAddWhitespace();
511 args[2]->Eval(ev, s);
512 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900513}
514
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900515void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
516 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900517 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900518 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900519}
520
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900521void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
522 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900523 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900524 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900525}
526
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900527void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900528 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900529 if (ev->avoid_io()) {
530 *s += "KATI_TODO(info)";
531 return;
532 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900533 printf("%s\n", a->c_str());
534 fflush(stdout);
535}
536
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900537void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900538 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900539 if (ev->avoid_io()) {
540 *s += "KATI_TODO(warning)";
541 return;
542 }
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900543 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900544 fflush(stdout);
545}
546
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900547void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900548 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900549 if (ev->avoid_io()) {
550 *s += "KATI_TODO(error)";
551 return;
552 }
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900553 ev->Error(StringPrintf("*** %s.", a->c_str()));
554}
555
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900556FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900557 { "patsubst", &PatsubstFunc, 3, 3, false, false },
558 { "strip", &StripFunc, 1, 1, false, false },
559 { "subst", &SubstFunc, 3, 3, false, false },
560 { "findstring", &FindstringFunc, 2, 2, false, false },
561 { "filter", &FilterFunc, 2, 2, false, false },
562 { "filter-out", &FilterOutFunc, 2, 2, false, false },
563 { "sort", &SortFunc, 1, 1, false, false },
564 { "word", &WordFunc, 2, 2, false, false },
565 { "wordlist", &WordlistFunc, 3, 3, false, false },
566 { "words", &WordsFunc, 1, 1, false, false },
567 { "firstword", &FirstwordFunc, 1, 1, false, false },
568 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900569
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900570 { "join", &JoinFunc, 2, 2, false, false },
571 { "wildcard", &WildcardFunc, 1, 1, false, false },
572 { "dir", &DirFunc, 1, 1, false, false },
573 { "notdir", &NotdirFunc, 1, 1, false, false },
574 { "suffix", &SuffixFunc, 1, 1, false, false },
575 { "basename", &BasenameFunc, 1, 1, false, false },
576 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
577 { "addprefix", &AddprefixFunc, 2, 2, false, false },
578 { "realpath", &RealpathFunc, 1, 1, false, false },
579 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900580
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900581 { "if", &IfFunc, 3, 2, false, true },
582 { "and", &AndFunc, 0, 0, true, false },
583 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900584
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900585 { "value", &ValueFunc, 1, 1, false, false },
586 { "eval", &EvalFunc, 1, 1, false, false },
587 { "shell", &ShellFunc, 1, 1, false, false },
588 { "call", &CallFunc, 0, 0, false, false },
589 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900590
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900591 { "origin", &OriginFunc, 1, 1, false, false },
592 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900593
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900594 { "info", &InfoFunc, 1, 1, false, false },
595 { "warning", &WarningFunc, 1, 1, false, false },
596 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900597};
598
599unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
600
601} // namespace
602
603void InitFuncTable() {
604 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
605 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
606 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900607 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900608 CHECK(ok);
609 }
610}
611
612void QuitFuncTable() {
613 delete g_func_info_map;
614}
615
616FuncInfo* GetFuncInfo(StringPiece name) {
617 auto found = g_func_info_map->find(name);
618 if (found == g_func_info_map->end())
619 return NULL;
620 return found->second;
621}