blob: 9309ed3e5a10c1e498a95ee1cd5059e4ccc876e7 [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 <sys/types.h>
25#include <sys/wait.h>
26#include <unistd.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090027
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090028#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090029#include <iterator>
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090030#include <memory>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090031#include <unordered_map>
32
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090033#include "ast.h"
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090034#include "eval.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090035#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090037#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090038#include "stats.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090039#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090040#include "symtab.h"
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090041#include "var.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090042
43namespace {
44
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090045void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090046 shared_ptr<string> pat_str = args[0]->Eval(ev);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090047 shared_ptr<string> repl = args[1]->Eval(ev);
48 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090049 WordWriter ww(s);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090050 Pattern pat(*pat_str);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090051 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090052 ww.MaybeAddWhitespace();
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090053 pat.AppendSubst(tok, *repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090054 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090055}
56
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090057void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
58 shared_ptr<string> str = args[0]->Eval(ev);
59 WordWriter ww(s);
60 for (StringPiece tok : WordScanner(*str)) {
61 ww.Write(tok);
62 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090063}
64
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090065void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
66 shared_ptr<string> pat = args[0]->Eval(ev);
67 shared_ptr<string> repl = args[1]->Eval(ev);
68 shared_ptr<string> str = args[2]->Eval(ev);
69 size_t index = 0;
70 while (index < str->size()) {
71 size_t found = str->find(*pat, index);
72 if (found == string::npos)
73 break;
74 AppendString(StringPiece(*str).substr(index, found - index), s);
75 AppendString(*repl, s);
76 index = found + pat->size();
77 }
78 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090079}
80
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090081void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
82 shared_ptr<string> find = args[0]->Eval(ev);
83 shared_ptr<string> in = args[1]->Eval(ev);
84 if (in->find(*find) != string::npos)
85 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090086}
87
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090088void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
89 shared_ptr<string> pat_buf = args[0]->Eval(ev);
90 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090091 vector<Pattern> pats;
92 for (StringPiece pat : WordScanner(*pat_buf)) {
93 pats.push_back(Pattern(pat));
94 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090095 WordWriter ww(s);
96 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +090097 for (const Pattern& pat : pats) {
98 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090099 ww.Write(tok);
100 break;
101 }
102 }
103 }
104}
105
106void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
107 shared_ptr<string> pat_buf = args[0]->Eval(ev);
108 shared_ptr<string> text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900109 vector<Pattern> pats;
110 for (StringPiece pat : WordScanner(*pat_buf)) {
111 pats.push_back(Pattern(pat));
112 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900113 WordWriter ww(s);
114 for (StringPiece tok : WordScanner(*text)) {
115 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900116 for (const Pattern& pat : pats) {
117 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900118 matched = true;
119 break;
120 }
121 }
122 if (!matched)
123 ww.Write(tok);
124 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900125}
126
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900127void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
128 shared_ptr<string> list = args[0]->Eval(ev);
129 vector<StringPiece> toks;
130 WordScanner(*list).Split(&toks);
131 sort(toks.begin(), toks.end());
132 WordWriter ww(s);
133 StringPiece prev;
134 for (StringPiece tok : toks) {
135 if (prev != tok) {
136 ww.Write(tok);
137 prev = tok;
138 }
139 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900140}
141
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900142static int GetNumericValueForFunc(const string& buf) {
143 StringPiece s = TrimLeftSpace(buf);
144 char* end;
145 long n = strtol(s.data(), &end, 10);
146 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
147 return -1;
148 }
149 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900150}
151
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900152void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
153 shared_ptr<string> n_str = args[0]->Eval(ev);
154 int n = GetNumericValueForFunc(*n_str);
155 if (n < 0) {
156 ev->Error(StringPrintf(
157 "*** non-numeric first argument to `word' function: '%s'.",
158 n_str->c_str()));
159 }
160 if (n == 0) {
161 ev->Error("*** first argument to `word' function must be greater than 0.");
162 }
163
164 shared_ptr<string> text = args[1]->Eval(ev);
165 for (StringPiece tok : WordScanner(*text)) {
166 n--;
167 if (n == 0) {
168 AppendString(tok, s);
169 break;
170 }
171 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900172}
173
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900174void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
175 shared_ptr<string> s_str = args[0]->Eval(ev);
176 int si = GetNumericValueForFunc(*s_str);
177 if (si < 0) {
178 ev->Error(StringPrintf(
179 "*** non-numeric first argument to `wordlist' function: '%s'.",
180 s_str->c_str()));
181 }
182 if (si == 0) {
183 ev->Error(StringPrintf(
184 "*** invalid first argument to `wordlist' function: %s`",
185 s_str->c_str()));
186 }
187
188 shared_ptr<string> e_str = args[1]->Eval(ev);
189 int ei = GetNumericValueForFunc(*e_str);
190 if (ei < 0) {
191 ev->Error(StringPrintf(
192 "*** non-numeric second argument to `wordlist' function: '%s'.",
193 e_str->c_str()));
194 }
195
196 shared_ptr<string> text = args[2]->Eval(ev);
197 int i = 0;
198 WordWriter ww(s);
199 for (StringPiece tok : WordScanner(*text)) {
200 i++;
201 if (si <= i && i <= ei) {
202 ww.Write(tok);
203 }
204 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900205}
206
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900207void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
208 shared_ptr<string> text = args[0]->Eval(ev);
209 WordScanner ws(*text);
210 int n = 0;
211 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
212 n++;
213 char buf[32];
214 sprintf(buf, "%d", n);
215 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900216}
217
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900218void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
219 shared_ptr<string> text = args[0]->Eval(ev);
220 for (StringPiece tok : WordScanner(*text)) {
221 AppendString(tok, s);
222 return;
223 }
224}
225
226void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
227 shared_ptr<string> text = args[0]->Eval(ev);
228 StringPiece last;
229 for (StringPiece tok : WordScanner(*text)) {
230 last = tok;
231 }
232 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900233}
234
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900235void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
236 shared_ptr<string> list1 = args[0]->Eval(ev);
237 shared_ptr<string> list2 = args[1]->Eval(ev);
238 WordScanner ws1(*list1);
239 WordScanner ws2(*list2);
240 WordWriter ww(s);
241 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
242 iter1 != ws1.end() && iter2 != ws2.end();
243 ++iter1, ++iter2) {
244 ww.Write(*iter1);
245 // Use |AppendString| not to append extra ' '.
246 AppendString(*iter2, s);
247 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900248}
249
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900250void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +0900251 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900252 shared_ptr<string> pat = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900253 if (ev->avoid_io()) {
254 *s += "$(/bin/ls -d ";
255 *s += *pat;
256 *s += " 2> /dev/null)";
257 return;
258 }
259
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900260 WordWriter ww(s);
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900261 vector<const char*> files;
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900262 for (StringPiece tok : WordScanner(*pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900263 ScopedTerminator st(tok);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900264 // TODO: Make this faster by not always using glob.
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900265 files.clear();
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900266 glob_t gl;
267 glob(tok.data(), GLOB_NOSORT, NULL, &gl);
268 for (size_t i = 0; i < gl.gl_pathc; i++) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900269 files.push_back(gl.gl_pathv[i]);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900270 }
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900271 sort(files.begin(), files.end(),
272 [](const char* a, const char* b) {
273 return strcmp(a, b) < 0;
274 });
275 for (const char* file : files) {
276 ww.Write(file);
277 }
278
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900279 globfree(&gl);
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900280 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900281}
282
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900283void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
284 shared_ptr<string> text = args[0]->Eval(ev);
285 WordWriter ww(s);
286 for (StringPiece tok : WordScanner(*text)) {
287 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900288 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900289 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900290}
291
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900292void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
293 shared_ptr<string> text = args[0]->Eval(ev);
294 WordWriter ww(s);
295 for (StringPiece tok : WordScanner(*text)) {
296 if (tok == "/") {
297 ww.Write(STRING_PIECE(""));
298 } else {
299 ww.Write(Basename(tok));
300 }
301 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900302}
303
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900304void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
305 shared_ptr<string> text = args[0]->Eval(ev);
306 WordWriter ww(s);
307 for (StringPiece tok : WordScanner(*text)) {
308 StringPiece suf = GetExt(tok);
309 if (!suf.empty())
310 ww.Write(suf);
311 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900312}
313
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900314void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
315 shared_ptr<string> text = args[0]->Eval(ev);
316 WordWriter ww(s);
317 for (StringPiece tok : WordScanner(*text)) {
318 ww.Write(StripExt(tok));
319 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900320}
321
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900322void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
323 shared_ptr<string> suf = args[0]->Eval(ev);
324 shared_ptr<string> text = args[1]->Eval(ev);
325 WordWriter ww(s);
326 for (StringPiece tok : WordScanner(*text)) {
327 ww.Write(tok);
328 *s += *suf;
329 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900330}
331
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900332void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
333 shared_ptr<string> pre = args[0]->Eval(ev);
334 shared_ptr<string> text = args[1]->Eval(ev);
335 WordWriter ww(s);
336 for (StringPiece tok : WordScanner(*text)) {
337 ww.Write(*pre);
338 AppendString(tok, s);
339 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900340}
341
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900342void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
343 shared_ptr<string> text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900344 if (ev->avoid_io()) {
345 *s += "KATI_TODO(realpath)";
346 return;
347 }
348
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900349 WordWriter ww(s);
350 for (StringPiece tok : WordScanner(*text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900351 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900352 char buf[PATH_MAX];
353 if (realpath(tok.data(), buf))
354 *s += buf;
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900355 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900356}
357
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900358void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
359 shared_ptr<string> text = args[0]->Eval(ev);
360 WordWriter ww(s);
361 string buf;
362 for (StringPiece tok : WordScanner(*text)) {
363 AbsPath(tok, &buf);
364 ww.Write(buf);
365 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900366}
367
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900368void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
369 shared_ptr<string> cond = args[0]->Eval(ev);
370 if (cond->empty()) {
371 if (args.size() > 2)
372 args[2]->Eval(ev, s);
373 } else {
374 args[1]->Eval(ev, s);
375 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900376}
377
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900378void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
379 shared_ptr<string> cond;
380 for (Value* a : args) {
381 cond = a->Eval(ev);
382 if (cond->empty())
383 return;
384 }
385 if (cond.get()) {
386 *s += *cond;
387 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900388}
389
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900390void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
391 for (Value* a : args) {
392 shared_ptr<string> cond = a->Eval(ev);
393 if (!cond->empty()) {
394 *s += *cond;
395 return;
396 }
397 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900398}
399
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900400void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
401 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900402 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900403 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900404}
405
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900406void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900407 // TODO: eval leaks everything... for now.
408 //shared_ptr<string> text = args[0]->Eval(ev);
409 string* text = new string;
410 args[0]->Eval(ev, text);
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900411 vector<AST*> asts;
412 Parse(*text, ev->loc(), &asts);
413 for (AST* ast : asts) {
414 LOG("%s", ast->DebugString().c_str());
415 ast->Eval(ev);
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900416 //delete ast;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900417 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900418}
419
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900420//#define TEST_FIND_EMULATOR
421
422#ifdef TEST_FIND_EMULATOR
423static string SortWordsInString(StringPiece s) {
424 vector<string> toks;
425 for (StringPiece tok : WordScanner(s)) {
426 toks.push_back(tok.as_string());
427 }
428 sort(toks.begin(), toks.end());
429 return JoinStrings(toks, " ");
430}
431#endif
432
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +0900433static void RunCommand(const string& cmd, string* s) {
434 int pipefd[2];
435 if (pipe(pipefd) != 0)
436 PERROR("pipe failed");
437 int pid;
438 if ((pid = vfork())) {
439 close(pipefd[1]);
440 while (true) {
441 int status;
442 int result = waitpid(pid, &status, WNOHANG);
443 if (result < 0)
444 PERROR("waitpid failed");
445
446 while (true) {
447 char buf[4096];
448 ssize_t r = read(pipefd[0], buf, 4096);
449 if (r < 0)
450 PERROR("read failed");
451 if (r == 0)
452 break;
453 s->append(buf, buf+r);
454 }
455
456 if (result != 0) {
457 break;
458 }
459 }
460 close(pipefd[0]);
461 } else {
462 close(pipefd[0]);
463 if (dup2(pipefd[1], 1) < 0)
464 PERROR("dup2 failed");
465 close(pipefd[1]);
466
467 const char* argv[] = {
468 // TODO: Handle $(SHELL).
469 "/bin/sh", "-c", cmd.c_str(), NULL
470 };
471 execvp(argv[0], const_cast<char**>(argv));
472 }
473}
474
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900475void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
476 shared_ptr<string> cmd = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900477 if (ev->avoid_io()) {
478 *s += "$(";
479 *s += *cmd;
480 *s += ")";
481 return;
482 }
483
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900484 LOG("ShellFunc: %s", cmd->c_str());
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900485
486#ifdef TEST_FIND_EMULATOR
487 bool need_check = false;
488 string out2;
489 if (FindEmulator::Get()->HandleFind(*cmd, &out2)) {
490 need_check = true;
491 }
492#else
493 if (FindEmulator::Get()->HandleFind(*cmd, s))
494 return;
495#endif
496
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900497 COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd->c_str());
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900498 string out;
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +0900499#if 0
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900500 // TODO: Handle $(SHELL).
501 FILE* fp = popen(cmd->c_str(), "r");
502 while (true) {
503 char buf[4096];
504 size_t r = fread(buf, 1, 4096, fp);
505 out.append(buf, buf+r);
506 if (r == 0) {
507 fclose(fp);
508 break;
509 }
510 }
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +0900511#else
512 RunCommand(*cmd, &out);
513#endif
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900514
515 while (out[out.size()-1] == '\n')
516 out.pop_back();
517 for (size_t i = 0; i < out.size(); i++) {
518 if (out[i] == '\n')
519 out[i] = ' ';
520 }
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900521
522#ifdef TEST_FIND_EMULATOR
523 if (need_check) {
524 string sorted = SortWordsInString(out);
525 out2 = SortWordsInString(out2);
526 if (sorted != out2) {
527 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
528 cmd->c_str(), sorted.c_str(), out2.c_str());
529 }
530 }
531#endif
532
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900533 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900534}
535
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900536void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
537 static const char* tmpvar_names[] = {
538 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"
539 };
540
541 shared_ptr<string> func_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900542 Var* func = ev->LookupVar(Intern(*func_name));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900543 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900544 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900545 unique_ptr<SimpleVar> s(
546 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900547 av.push_back(move(s));
548 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900549 vector<unique_ptr<ScopedVar>> sv;
550 for (size_t i = 1; i < args.size(); i++) {
551 sv.push_back(move(unique_ptr<ScopedVar>(
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900552 new ScopedVar(ev->mutable_vars(),
553 Intern(tmpvar_names[i]), av[i-1].get()))));
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900554 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900555 func->Eval(ev, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900556}
557
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900558void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
559 shared_ptr<string> varname = args[0]->Eval(ev);
560 shared_ptr<string> list = args[1]->Eval(ev);
561 WordWriter ww(s);
562 for (StringPiece tok : WordScanner(*list)) {
563 unique_ptr<SimpleVar> v(new SimpleVar(
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900564 make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC));
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900565 ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900566 ww.MaybeAddWhitespace();
567 args[2]->Eval(ev, s);
568 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900569}
570
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900571void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
572 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900573 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900574 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900575}
576
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900577void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
578 shared_ptr<string> var_name = args[0]->Eval(ev);
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900579 Var* var = ev->LookupVar(Intern(*var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900580 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900581}
582
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900583void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900584 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900585 if (ev->avoid_io()) {
586 *s += "KATI_TODO(info)";
587 return;
588 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900589 printf("%s\n", a->c_str());
590 fflush(stdout);
591}
592
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900593void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900594 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900595 if (ev->avoid_io()) {
596 *s += "KATI_TODO(warning)";
597 return;
598 }
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900599 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900600 fflush(stdout);
601}
602
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900603void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900604 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900605 if (ev->avoid_io()) {
606 *s += "KATI_TODO(error)";
607 return;
608 }
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900609 ev->Error(StringPrintf("*** %s.", a->c_str()));
610}
611
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900612FuncInfo g_func_infos[] = {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900613 { "patsubst", &PatsubstFunc, 3, 3, false, false },
614 { "strip", &StripFunc, 1, 1, false, false },
615 { "subst", &SubstFunc, 3, 3, false, false },
616 { "findstring", &FindstringFunc, 2, 2, false, false },
617 { "filter", &FilterFunc, 2, 2, false, false },
618 { "filter-out", &FilterOutFunc, 2, 2, false, false },
619 { "sort", &SortFunc, 1, 1, false, false },
620 { "word", &WordFunc, 2, 2, false, false },
621 { "wordlist", &WordlistFunc, 3, 3, false, false },
622 { "words", &WordsFunc, 1, 1, false, false },
623 { "firstword", &FirstwordFunc, 1, 1, false, false },
624 { "lastword", &LastwordFunc, 1, 1, false, false },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900625
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900626 { "join", &JoinFunc, 2, 2, false, false },
627 { "wildcard", &WildcardFunc, 1, 1, false, false },
628 { "dir", &DirFunc, 1, 1, false, false },
629 { "notdir", &NotdirFunc, 1, 1, false, false },
630 { "suffix", &SuffixFunc, 1, 1, false, false },
631 { "basename", &BasenameFunc, 1, 1, false, false },
632 { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
633 { "addprefix", &AddprefixFunc, 2, 2, false, false },
634 { "realpath", &RealpathFunc, 1, 1, false, false },
635 { "abspath", &AbspathFunc, 1, 1, false, false },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900636
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900637 { "if", &IfFunc, 3, 2, false, true },
638 { "and", &AndFunc, 0, 0, true, false },
639 { "or", &OrFunc, 0, 0, true, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900640
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900641 { "value", &ValueFunc, 1, 1, false, false },
642 { "eval", &EvalFunc, 1, 1, false, false },
643 { "shell", &ShellFunc, 1, 1, false, false },
644 { "call", &CallFunc, 0, 0, false, false },
645 { "foreach", &ForeachFunc, 3, 3, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900646
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900647 { "origin", &OriginFunc, 1, 1, false, false },
648 { "flavor", &FlavorFunc, 1, 1, false, false },
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900649
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900650 { "info", &InfoFunc, 1, 1, false, false },
651 { "warning", &WarningFunc, 1, 1, false, false },
652 { "error", &ErrorFunc, 1, 1, false, false },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900653};
654
655unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
656
657} // namespace
658
659void InitFuncTable() {
660 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
661 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
662 FuncInfo* fi = &g_func_infos[i];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900663 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900664 CHECK(ok);
665 }
666}
667
668void QuitFuncTable() {
669 delete g_func_info_map;
670}
671
672FuncInfo* GetFuncInfo(StringPiece name) {
673 auto found = g_func_info_map->find(name);
674 if (found == g_func_info_map->end())
675 return NULL;
676 return found->second;
677}