blob: 3dbd97081fd8ca0c76a5623989f1516e02b277ca [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "func.h"
2
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +09003#include <glob.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +09004#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09005#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +09006#include <stdlib.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09007
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +09008#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +09009#include <iterator>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090010#include <unordered_map>
11
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090012#include "eval.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090013#include "log.h"
14#include "strutil.h"
15
16namespace {
17
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090018void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
19 shared_ptr<string> pat = args[0]->Eval(ev);
20 shared_ptr<string> repl = args[1]->Eval(ev);
21 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090022 WordWriter ww(s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090023 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090024 ww.MaybeAddWhitespace();
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090025 AppendSubstPattern(tok, *pat, *repl, s);
26 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090027}
28
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090029void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
30 shared_ptr<string> str = args[0]->Eval(ev);
31 WordWriter ww(s);
32 for (StringPiece tok : WordScanner(*str)) {
33 ww.Write(tok);
34 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090035}
36
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090037void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
38 shared_ptr<string> pat = args[0]->Eval(ev);
39 shared_ptr<string> repl = args[1]->Eval(ev);
40 shared_ptr<string> str = args[2]->Eval(ev);
41 size_t index = 0;
42 while (index < str->size()) {
43 size_t found = str->find(*pat, index);
44 if (found == string::npos)
45 break;
46 AppendString(StringPiece(*str).substr(index, found - index), s);
47 AppendString(*repl, s);
48 index = found + pat->size();
49 }
50 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090051}
52
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090053void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
54 shared_ptr<string> find = args[0]->Eval(ev);
55 shared_ptr<string> in = args[1]->Eval(ev);
56 if (in->find(*find) != string::npos)
57 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090058}
59
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090060void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
61 shared_ptr<string> pat_buf = args[0]->Eval(ev);
62 shared_ptr<string> text = args[1]->Eval(ev);
63 vector<StringPiece> pats;
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090064 WordScanner(*pat_buf).Split(&pats);
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090065 WordWriter ww(s);
66 for (StringPiece tok : WordScanner(*text)) {
67 for (StringPiece pat : pats) {
68 if (MatchPattern(tok, pat)) {
69 ww.Write(tok);
70 break;
71 }
72 }
73 }
74}
75
76void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
77 shared_ptr<string> pat_buf = args[0]->Eval(ev);
78 shared_ptr<string> text = args[1]->Eval(ev);
79 vector<StringPiece> pats;
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090080 WordScanner(*pat_buf).Split(&pats);
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090081 WordWriter ww(s);
82 for (StringPiece tok : WordScanner(*text)) {
83 bool matched = false;
84 for (StringPiece pat : pats) {
85 if (MatchPattern(tok, pat)) {
86 matched = true;
87 break;
88 }
89 }
90 if (!matched)
91 ww.Write(tok);
92 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090093}
94
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090095void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
96 shared_ptr<string> list = args[0]->Eval(ev);
97 vector<StringPiece> toks;
98 WordScanner(*list).Split(&toks);
99 sort(toks.begin(), toks.end());
100 WordWriter ww(s);
101 StringPiece prev;
102 for (StringPiece tok : toks) {
103 if (prev != tok) {
104 ww.Write(tok);
105 prev = tok;
106 }
107 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900108}
109
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900110static int GetNumericValueForFunc(const string& buf) {
111 StringPiece s = TrimLeftSpace(buf);
112 char* end;
113 long n = strtol(s.data(), &end, 10);
114 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
115 return -1;
116 }
117 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900118}
119
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900120void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
121 shared_ptr<string> n_str = args[0]->Eval(ev);
122 int n = GetNumericValueForFunc(*n_str);
123 if (n < 0) {
124 ev->Error(StringPrintf(
125 "*** non-numeric first argument to `word' function: '%s'.",
126 n_str->c_str()));
127 }
128 if (n == 0) {
129 ev->Error("*** first argument to `word' function must be greater than 0.");
130 }
131
132 shared_ptr<string> text = args[1]->Eval(ev);
133 for (StringPiece tok : WordScanner(*text)) {
134 n--;
135 if (n == 0) {
136 AppendString(tok, s);
137 break;
138 }
139 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900140}
141
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900142void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
143 shared_ptr<string> s_str = args[0]->Eval(ev);
144 int si = GetNumericValueForFunc(*s_str);
145 if (si < 0) {
146 ev->Error(StringPrintf(
147 "*** non-numeric first argument to `wordlist' function: '%s'.",
148 s_str->c_str()));
149 }
150 if (si == 0) {
151 ev->Error(StringPrintf(
152 "*** invalid first argument to `wordlist' function: %s`",
153 s_str->c_str()));
154 }
155
156 shared_ptr<string> e_str = args[1]->Eval(ev);
157 int ei = GetNumericValueForFunc(*e_str);
158 if (ei < 0) {
159 ev->Error(StringPrintf(
160 "*** non-numeric second argument to `wordlist' function: '%s'.",
161 e_str->c_str()));
162 }
163
164 shared_ptr<string> text = args[2]->Eval(ev);
165 int i = 0;
166 WordWriter ww(s);
167 for (StringPiece tok : WordScanner(*text)) {
168 i++;
169 if (si <= i && i <= ei) {
170 ww.Write(tok);
171 }
172 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900173}
174
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900175void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
176 shared_ptr<string> text = args[0]->Eval(ev);
177 WordScanner ws(*text);
178 int n = 0;
179 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
180 n++;
181 char buf[32];
182 sprintf(buf, "%d", n);
183 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900184}
185
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900186void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
187 shared_ptr<string> text = args[0]->Eval(ev);
188 for (StringPiece tok : WordScanner(*text)) {
189 AppendString(tok, s);
190 return;
191 }
192}
193
194void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
195 shared_ptr<string> text = args[0]->Eval(ev);
196 StringPiece last;
197 for (StringPiece tok : WordScanner(*text)) {
198 last = tok;
199 }
200 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900201}
202
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900203void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
204 shared_ptr<string> list1 = args[0]->Eval(ev);
205 shared_ptr<string> list2 = args[1]->Eval(ev);
206 WordScanner ws1(*list1);
207 WordScanner ws2(*list2);
208 WordWriter ww(s);
209 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
210 iter1 != ws1.end() && iter2 != ws2.end();
211 ++iter1, ++iter2) {
212 ww.Write(*iter1);
213 // Use |AppendString| not to append extra ' '.
214 AppendString(*iter2, s);
215 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900216}
217
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900218void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900219 shared_ptr<string> pat = args[0]->Eval(ev);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900220 WordWriter ww(s);
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900221 for (StringPiece tok : WordScanner(*pat)) {
222 char orig = tok[tok.size()];
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900223 const_cast<char*>(tok.data())[tok.size()] = '\0';
224
225 // TODO: Make this faster by not always using glob.
226 glob_t gl;
227 glob(tok.data(), GLOB_NOSORT, NULL, &gl);
228 for (size_t i = 0; i < gl.gl_pathc; i++) {
229 ww.Write(gl.gl_pathv[i]);
230 }
231 globfree(&gl);
232
233 const_cast<char*>(tok.data())[tok.size()] = orig;
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900234 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900235}
236
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900237void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
238 shared_ptr<string> text = args[0]->Eval(ev);
239 WordWriter ww(s);
240 for (StringPiece tok : WordScanner(*text)) {
241 ww.Write(Dirname(tok));
242 if (tok != "/")
243 s->push_back('/');
244 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900245}
246
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900247void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
248 shared_ptr<string> text = args[0]->Eval(ev);
249 WordWriter ww(s);
250 for (StringPiece tok : WordScanner(*text)) {
251 if (tok == "/") {
252 ww.Write(STRING_PIECE(""));
253 } else {
254 ww.Write(Basename(tok));
255 }
256 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900257}
258
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900259void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
260 shared_ptr<string> text = args[0]->Eval(ev);
261 WordWriter ww(s);
262 for (StringPiece tok : WordScanner(*text)) {
263 StringPiece suf = GetExt(tok);
264 if (!suf.empty())
265 ww.Write(suf);
266 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900267}
268
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900269void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
270 shared_ptr<string> text = args[0]->Eval(ev);
271 WordWriter ww(s);
272 for (StringPiece tok : WordScanner(*text)) {
273 ww.Write(StripExt(tok));
274 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900275}
276
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900277void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
278 shared_ptr<string> suf = args[0]->Eval(ev);
279 shared_ptr<string> text = args[1]->Eval(ev);
280 WordWriter ww(s);
281 for (StringPiece tok : WordScanner(*text)) {
282 ww.Write(tok);
283 *s += *suf;
284 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900285}
286
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900287void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
288 shared_ptr<string> pre = args[0]->Eval(ev);
289 shared_ptr<string> text = args[1]->Eval(ev);
290 WordWriter ww(s);
291 for (StringPiece tok : WordScanner(*text)) {
292 ww.Write(*pre);
293 AppendString(tok, s);
294 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900295}
296
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900297void RealpathFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900298 printf("TODO(realpath)");
299}
300
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900301void AbspathFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900302 printf("TODO(abspath)");
303}
304
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900305void IfFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900306 printf("TODO(if)");
307}
308
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900309void AndFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900310 printf("TODO(and)");
311}
312
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900313void OrFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900314 printf("TODO(or)");
315}
316
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900317void ValueFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900318 printf("TODO(value)");
319}
320
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900321void EvalFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900322 printf("TODO(eval)");
323}
324
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900325void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
326 shared_ptr<string> cmd = args[0]->Eval(ev);
327 LOG("ShellFunc: %s", cmd->c_str());
328 string out;
329 // TODO: Handle $(SHELL).
330 FILE* fp = popen(cmd->c_str(), "r");
331 while (true) {
332 char buf[4096];
333 size_t r = fread(buf, 1, 4096, fp);
334 out.append(buf, buf+r);
335 if (r == 0) {
336 fclose(fp);
337 break;
338 }
339 }
340
341 while (out[out.size()-1] == '\n')
342 out.pop_back();
343 for (size_t i = 0; i < out.size(); i++) {
344 if (out[i] == '\n')
345 out[i] = ' ';
346 }
347 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900348}
349
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900350void CallFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900351 printf("TODO(call)");
352}
353
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900354void ForeachFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900355 printf("TODO(foreach)");
356}
357
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900358void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900359 printf("TODO(origin)");
360}
361
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900362void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900363 printf("TODO(flavor)");
364}
365
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900366void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900367 shared_ptr<string> a = args[0]->Eval(ev);
368 printf("%s\n", a->c_str());
369 fflush(stdout);
370}
371
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900372void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900373 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900374 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900375 fflush(stdout);
376}
377
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900378void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900379 shared_ptr<string> a = args[0]->Eval(ev);
380 ev->Error(StringPrintf("*** %s.", a->c_str()));
381}
382
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900383FuncInfo g_func_infos[] = {
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900384 { "patsubst", &PatsubstFunc, 3 },
385 { "strip", &StripFunc, 1 },
386 { "subst", &SubstFunc, 3 },
387 { "findstring", &FindstringFunc, 2 },
388 { "filter", &FilterFunc, 2 },
389 { "filter-out", &FilterOutFunc, 2 },
390 { "sort", &SortFunc, 1 },
391 { "word", &WordFunc, 2 },
392 { "wordlist", &WordlistFunc, 3 },
393 { "words", &WordsFunc, 1 },
394 { "firstword", &FirstwordFunc, 1 },
395 { "lastword", &LastwordFunc, 1 },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900396
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900397 { "join", &JoinFunc, 2 },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900398 { "wildcard", &WildcardFunc, 1 },
399 { "dir", &DirFunc, 1 },
400 { "notdir", &NotdirFunc, 1 },
401 { "suffix", &SuffixFunc, 1 },
402 { "basename", &BasenameFunc, 1 },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900403 { "addsuffix", &AddsuffixFunc, 2 },
404 { "addprefix", &AddprefixFunc, 2 },
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900405 { "realpath", &RealpathFunc, 1 },
406 { "abspath", &AbspathFunc, 1 },
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900407
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900408 { "if", &IfFunc, 1 },
409 { "and", &AndFunc, 1 },
410 { "or", &OrFunc, 1 },
411 { "value", &ValueFunc, 1 },
412 { "eval", &EvalFunc, 1 },
413 { "shell", &ShellFunc, 1 },
414 { "call", &CallFunc, 1 },
415 { "foreach", &ForeachFunc, 1 },
416 { "origin", &OriginFunc, 1 },
417 { "flavor", &FlavorFunc, 1 },
418 { "info", &InfoFunc, 1 },
419 { "warning", &WarningFunc, 1 },
420 { "error", &ErrorFunc, 1 },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900421};
422
423unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
424
425} // namespace
426
427void InitFuncTable() {
428 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
429 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
430 FuncInfo* fi = &g_func_infos[i];
431 bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
432 CHECK(ok);
433 }
434}
435
436void QuitFuncTable() {
437 delete g_func_info_map;
438}
439
440FuncInfo* GetFuncInfo(StringPiece name) {
441 auto found = g_func_info_map->find(name);
442 if (found == g_func_info_map->end())
443 return NULL;
444 return found->second;
445}