blob: b9faa8a9675da6c3fdee2eb1559ba6f55ecb3962 [file] [log] [blame]
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09001#include "func.h"
2
Shinichiro Hamajid5271452015-06-17 18:50:03 +09003#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09004#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +09005#include <stdlib.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09006
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +09007#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +09008#include <iterator>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +09009#include <unordered_map>
10
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090011#include "eval.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090012#include "log.h"
13#include "strutil.h"
14
15namespace {
16
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090017void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
18 shared_ptr<string> pat = args[0]->Eval(ev);
19 shared_ptr<string> repl = args[1]->Eval(ev);
20 shared_ptr<string> str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090021 WordWriter ww(s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090022 for (StringPiece tok : WordScanner(*str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090023 ww.MaybeAddWhitespace();
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090024 AppendSubstPattern(tok, *pat, *repl, s);
25 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090026}
27
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090028void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
29 shared_ptr<string> str = args[0]->Eval(ev);
30 WordWriter ww(s);
31 for (StringPiece tok : WordScanner(*str)) {
32 ww.Write(tok);
33 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090034}
35
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +090036void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
37 shared_ptr<string> pat = args[0]->Eval(ev);
38 shared_ptr<string> repl = args[1]->Eval(ev);
39 shared_ptr<string> str = args[2]->Eval(ev);
40 size_t index = 0;
41 while (index < str->size()) {
42 size_t found = str->find(*pat, index);
43 if (found == string::npos)
44 break;
45 AppendString(StringPiece(*str).substr(index, found - index), s);
46 AppendString(*repl, s);
47 index = found + pat->size();
48 }
49 AppendString(StringPiece(*str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090050}
51
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090052void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
53 shared_ptr<string> find = args[0]->Eval(ev);
54 shared_ptr<string> in = args[1]->Eval(ev);
55 if (in->find(*find) != string::npos)
56 AppendString(*find, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090057}
58
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090059void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
60 shared_ptr<string> pat_buf = args[0]->Eval(ev);
61 shared_ptr<string> text = args[1]->Eval(ev);
62 vector<StringPiece> pats;
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090063 WordScanner(*pat_buf).Split(&pats);
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090064 WordWriter ww(s);
65 for (StringPiece tok : WordScanner(*text)) {
66 for (StringPiece pat : pats) {
67 if (MatchPattern(tok, pat)) {
68 ww.Write(tok);
69 break;
70 }
71 }
72 }
73}
74
75void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
76 shared_ptr<string> pat_buf = args[0]->Eval(ev);
77 shared_ptr<string> text = args[1]->Eval(ev);
78 vector<StringPiece> pats;
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090079 WordScanner(*pat_buf).Split(&pats);
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +090080 WordWriter ww(s);
81 for (StringPiece tok : WordScanner(*text)) {
82 bool matched = false;
83 for (StringPiece pat : pats) {
84 if (MatchPattern(tok, pat)) {
85 matched = true;
86 break;
87 }
88 }
89 if (!matched)
90 ww.Write(tok);
91 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +090092}
93
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090094void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
95 shared_ptr<string> list = args[0]->Eval(ev);
96 vector<StringPiece> toks;
97 WordScanner(*list).Split(&toks);
98 sort(toks.begin(), toks.end());
99 WordWriter ww(s);
100 StringPiece prev;
101 for (StringPiece tok : toks) {
102 if (prev != tok) {
103 ww.Write(tok);
104 prev = tok;
105 }
106 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900107}
108
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900109static int GetNumericValueForFunc(const string& buf) {
110 StringPiece s = TrimLeftSpace(buf);
111 char* end;
112 long n = strtol(s.data(), &end, 10);
113 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
114 return -1;
115 }
116 return n;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900117}
118
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900119void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
120 shared_ptr<string> n_str = args[0]->Eval(ev);
121 int n = GetNumericValueForFunc(*n_str);
122 if (n < 0) {
123 ev->Error(StringPrintf(
124 "*** non-numeric first argument to `word' function: '%s'.",
125 n_str->c_str()));
126 }
127 if (n == 0) {
128 ev->Error("*** first argument to `word' function must be greater than 0.");
129 }
130
131 shared_ptr<string> text = args[1]->Eval(ev);
132 for (StringPiece tok : WordScanner(*text)) {
133 n--;
134 if (n == 0) {
135 AppendString(tok, s);
136 break;
137 }
138 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900139}
140
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900141void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
142 shared_ptr<string> s_str = args[0]->Eval(ev);
143 int si = GetNumericValueForFunc(*s_str);
144 if (si < 0) {
145 ev->Error(StringPrintf(
146 "*** non-numeric first argument to `wordlist' function: '%s'.",
147 s_str->c_str()));
148 }
149 if (si == 0) {
150 ev->Error(StringPrintf(
151 "*** invalid first argument to `wordlist' function: %s`",
152 s_str->c_str()));
153 }
154
155 shared_ptr<string> e_str = args[1]->Eval(ev);
156 int ei = GetNumericValueForFunc(*e_str);
157 if (ei < 0) {
158 ev->Error(StringPrintf(
159 "*** non-numeric second argument to `wordlist' function: '%s'.",
160 e_str->c_str()));
161 }
162
163 shared_ptr<string> text = args[2]->Eval(ev);
164 int i = 0;
165 WordWriter ww(s);
166 for (StringPiece tok : WordScanner(*text)) {
167 i++;
168 if (si <= i && i <= ei) {
169 ww.Write(tok);
170 }
171 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900172}
173
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900174void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
175 shared_ptr<string> text = args[0]->Eval(ev);
176 WordScanner ws(*text);
177 int n = 0;
178 for (auto iter = ws.begin(); iter != ws.end(); ++iter)
179 n++;
180 char buf[32];
181 sprintf(buf, "%d", n);
182 *s += buf;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900183}
184
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900185void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
186 shared_ptr<string> text = args[0]->Eval(ev);
187 for (StringPiece tok : WordScanner(*text)) {
188 AppendString(tok, s);
189 return;
190 }
191}
192
193void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
194 shared_ptr<string> text = args[0]->Eval(ev);
195 StringPiece last;
196 for (StringPiece tok : WordScanner(*text)) {
197 last = tok;
198 }
199 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900200}
201
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900202void JoinFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900203 printf("TODO(join)");
204}
205
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900206void WildcardFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900207 printf("TODO(wildcard)");
208}
209
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900210void DirFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900211 printf("TODO(dir)");
212}
213
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900214void NotdirFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900215 printf("TODO(notdir)");
216}
217
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900218void SuffixFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900219 printf("TODO(suffix)");
220}
221
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900222void BasenameFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900223 printf("TODO(basename)");
224}
225
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900226void AddsuffixFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900227 printf("TODO(addsuffix)");
228}
229
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900230void AddprefixFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900231 printf("TODO(addprefix)");
232}
233
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900234void RealpathFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900235 printf("TODO(realpath)");
236}
237
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900238void AbspathFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900239 printf("TODO(abspath)");
240}
241
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900242void IfFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900243 printf("TODO(if)");
244}
245
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900246void AndFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900247 printf("TODO(and)");
248}
249
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900250void OrFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900251 printf("TODO(or)");
252}
253
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900254void ValueFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900255 printf("TODO(value)");
256}
257
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900258void EvalFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900259 printf("TODO(eval)");
260}
261
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900262void ShellFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900263 printf("TODO(shell)");
264}
265
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900266void CallFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900267 printf("TODO(call)");
268}
269
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900270void ForeachFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900271 printf("TODO(foreach)");
272}
273
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900274void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900275 printf("TODO(origin)");
276}
277
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900278void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900279 printf("TODO(flavor)");
280}
281
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900282void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900283 shared_ptr<string> a = args[0]->Eval(ev);
284 printf("%s\n", a->c_str());
285 fflush(stdout);
286}
287
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900288void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900289 shared_ptr<string> a = args[0]->Eval(ev);
Shinichiro Hamaji8ee8c372015-06-16 16:19:40 +0900290 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900291 fflush(stdout);
292}
293
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900294void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900295 shared_ptr<string> a = args[0]->Eval(ev);
296 ev->Error(StringPrintf("*** %s.", a->c_str()));
297}
298
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900299FuncInfo g_func_infos[] = {
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900300 { "patsubst", &PatsubstFunc, 3 },
301 { "strip", &StripFunc, 1 },
302 { "subst", &SubstFunc, 3 },
303 { "findstring", &FindstringFunc, 2 },
304 { "filter", &FilterFunc, 2 },
305 { "filter-out", &FilterOutFunc, 2 },
306 { "sort", &SortFunc, 1 },
307 { "word", &WordFunc, 2 },
308 { "wordlist", &WordlistFunc, 3 },
309 { "words", &WordsFunc, 1 },
310 { "firstword", &FirstwordFunc, 1 },
311 { "lastword", &LastwordFunc, 1 },
312 { "join", &JoinFunc, 2 },
313
314 { "wildcard", &WildcardFunc, 1 },
315 { "dir", &DirFunc, 1 },
316 { "notdir", &NotdirFunc, 1 },
317 { "suffix", &SuffixFunc, 1 },
318 { "basename", &BasenameFunc, 1 },
319 { "addsuffix", &AddsuffixFunc, 1 },
320 { "addprefix", &AddprefixFunc, 1 },
321 { "realpath", &RealpathFunc, 1 },
322 { "abspath", &AbspathFunc, 1 },
323 { "if", &IfFunc, 1 },
324 { "and", &AndFunc, 1 },
325 { "or", &OrFunc, 1 },
326 { "value", &ValueFunc, 1 },
327 { "eval", &EvalFunc, 1 },
328 { "shell", &ShellFunc, 1 },
329 { "call", &CallFunc, 1 },
330 { "foreach", &ForeachFunc, 1 },
331 { "origin", &OriginFunc, 1 },
332 { "flavor", &FlavorFunc, 1 },
333 { "info", &InfoFunc, 1 },
334 { "warning", &WarningFunc, 1 },
335 { "error", &ErrorFunc, 1 },
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900336};
337
338unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
339
340} // namespace
341
342void InitFuncTable() {
343 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
344 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
345 FuncInfo* fi = &g_func_infos[i];
346 bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
347 CHECK(ok);
348 }
349}
350
351void QuitFuncTable() {
352 delete g_func_info_map;
353}
354
355FuncInfo* GetFuncInfo(StringPiece name) {
356 auto found = g_func_info_map->find(name);
357 if (found == g_func_info_map->end())
358 return NULL;
359 return found->second;
360}