func.cc revision 80456fb15d4c0cef3df83a96f35d3b1220394066
1#include "func.h"
2
3#include <glob.h>
4#include <limits.h>
5#include <stdio.h>
6#include <stdlib.h>
7
8#include <algorithm>
9#include <iterator>
10#include <unordered_map>
11
12#include "ast.h"
13#include "eval.h"
14#include "log.h"
15#include "parser.h"
16#include "strutil.h"
17
18namespace {
19
20void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
21  shared_ptr<string> pat = args[0]->Eval(ev);
22  shared_ptr<string> repl = args[1]->Eval(ev);
23  shared_ptr<string> str = args[2]->Eval(ev);
24  WordWriter ww(s);
25  for (StringPiece tok : WordScanner(*str)) {
26    ww.MaybeAddWhitespace();
27    AppendSubstPattern(tok, *pat, *repl, s);
28  }
29}
30
31void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
32  shared_ptr<string> str = args[0]->Eval(ev);
33  WordWriter ww(s);
34  for (StringPiece tok : WordScanner(*str)) {
35    ww.Write(tok);
36  }
37}
38
39void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
40  shared_ptr<string> pat = args[0]->Eval(ev);
41  shared_ptr<string> repl = args[1]->Eval(ev);
42  shared_ptr<string> str = args[2]->Eval(ev);
43  size_t index = 0;
44  while (index < str->size()) {
45    size_t found = str->find(*pat, index);
46    if (found == string::npos)
47      break;
48    AppendString(StringPiece(*str).substr(index, found - index), s);
49    AppendString(*repl, s);
50    index = found + pat->size();
51  }
52  AppendString(StringPiece(*str).substr(index), s);
53}
54
55void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
56  shared_ptr<string> find = args[0]->Eval(ev);
57  shared_ptr<string> in = args[1]->Eval(ev);
58  if (in->find(*find) != string::npos)
59    AppendString(*find, s);
60}
61
62void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
63  shared_ptr<string> pat_buf = args[0]->Eval(ev);
64  shared_ptr<string> text = args[1]->Eval(ev);
65  vector<StringPiece> pats;
66  WordScanner(*pat_buf).Split(&pats);
67  WordWriter ww(s);
68  for (StringPiece tok : WordScanner(*text)) {
69    for (StringPiece pat : pats) {
70      if (MatchPattern(tok, pat)) {
71        ww.Write(tok);
72        break;
73      }
74    }
75  }
76}
77
78void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
79  shared_ptr<string> pat_buf = args[0]->Eval(ev);
80  shared_ptr<string> text = args[1]->Eval(ev);
81  vector<StringPiece> pats;
82  WordScanner(*pat_buf).Split(&pats);
83  WordWriter ww(s);
84  for (StringPiece tok : WordScanner(*text)) {
85    bool matched = false;
86    for (StringPiece pat : pats) {
87      if (MatchPattern(tok, pat)) {
88        matched = true;
89        break;
90      }
91    }
92    if (!matched)
93      ww.Write(tok);
94  }
95}
96
97void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
98  shared_ptr<string> list = args[0]->Eval(ev);
99  vector<StringPiece> toks;
100  WordScanner(*list).Split(&toks);
101  sort(toks.begin(), toks.end());
102  WordWriter ww(s);
103  StringPiece prev;
104  for (StringPiece tok : toks) {
105    if (prev != tok) {
106      ww.Write(tok);
107      prev = tok;
108    }
109  }
110}
111
112static int GetNumericValueForFunc(const string& buf) {
113  StringPiece s = TrimLeftSpace(buf);
114  char* end;
115  long n = strtol(s.data(), &end, 10);
116  if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
117    return -1;
118  }
119  return n;
120}
121
122void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
123  shared_ptr<string> n_str = args[0]->Eval(ev);
124  int n = GetNumericValueForFunc(*n_str);
125  if (n < 0) {
126    ev->Error(StringPrintf(
127        "*** non-numeric first argument to `word' function: '%s'.",
128        n_str->c_str()));
129  }
130  if (n == 0) {
131    ev->Error("*** first argument to `word' function must be greater than 0.");
132  }
133
134  shared_ptr<string> text = args[1]->Eval(ev);
135  for (StringPiece tok : WordScanner(*text)) {
136    n--;
137    if (n == 0) {
138      AppendString(tok, s);
139      break;
140    }
141  }
142}
143
144void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
145  shared_ptr<string> s_str = args[0]->Eval(ev);
146  int si = GetNumericValueForFunc(*s_str);
147  if (si < 0) {
148    ev->Error(StringPrintf(
149        "*** non-numeric first argument to `wordlist' function: '%s'.",
150        s_str->c_str()));
151  }
152  if (si == 0) {
153    ev->Error(StringPrintf(
154        "*** invalid first argument to `wordlist' function: %s`",
155        s_str->c_str()));
156  }
157
158  shared_ptr<string> e_str = args[1]->Eval(ev);
159  int ei = GetNumericValueForFunc(*e_str);
160  if (ei < 0) {
161    ev->Error(StringPrintf(
162        "*** non-numeric second argument to `wordlist' function: '%s'.",
163        e_str->c_str()));
164  }
165
166  shared_ptr<string> text = args[2]->Eval(ev);
167  int i = 0;
168  WordWriter ww(s);
169  for (StringPiece tok : WordScanner(*text)) {
170    i++;
171    if (si <= i && i <= ei) {
172      ww.Write(tok);
173    }
174  }
175}
176
177void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
178  shared_ptr<string> text = args[0]->Eval(ev);
179  WordScanner ws(*text);
180  int n = 0;
181  for (auto iter = ws.begin(); iter != ws.end(); ++iter)
182    n++;
183  char buf[32];
184  sprintf(buf, "%d", n);
185  *s += buf;
186}
187
188void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
189  shared_ptr<string> text = args[0]->Eval(ev);
190  for (StringPiece tok : WordScanner(*text)) {
191    AppendString(tok, s);
192    return;
193  }
194}
195
196void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
197  shared_ptr<string> text = args[0]->Eval(ev);
198  StringPiece last;
199  for (StringPiece tok : WordScanner(*text)) {
200    last = tok;
201  }
202  AppendString(last, s);
203}
204
205void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
206  shared_ptr<string> list1 = args[0]->Eval(ev);
207  shared_ptr<string> list2 = args[1]->Eval(ev);
208  WordScanner ws1(*list1);
209  WordScanner ws2(*list2);
210  WordWriter ww(s);
211  for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
212       iter1 != ws1.end() && iter2 != ws2.end();
213       ++iter1, ++iter2) {
214    ww.Write(*iter1);
215    // Use |AppendString| not to append extra ' '.
216    AppendString(*iter2, s);
217  }
218}
219
220void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
221  shared_ptr<string> pat = args[0]->Eval(ev);
222  WordWriter ww(s);
223  for (StringPiece tok : WordScanner(*pat)) {
224    ScopedTerminator st(tok);
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}
234
235void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
236  shared_ptr<string> text = args[0]->Eval(ev);
237  WordWriter ww(s);
238  for (StringPiece tok : WordScanner(*text)) {
239    ww.Write(Dirname(tok));
240    if (tok != "/")
241      s->push_back('/');
242  }
243}
244
245void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
246  shared_ptr<string> text = args[0]->Eval(ev);
247  WordWriter ww(s);
248  for (StringPiece tok : WordScanner(*text)) {
249    if (tok == "/") {
250      ww.Write(STRING_PIECE(""));
251    } else {
252      ww.Write(Basename(tok));
253    }
254  }
255}
256
257void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
258  shared_ptr<string> text = args[0]->Eval(ev);
259  WordWriter ww(s);
260  for (StringPiece tok : WordScanner(*text)) {
261    StringPiece suf = GetExt(tok);
262    if (!suf.empty())
263      ww.Write(suf);
264  }
265}
266
267void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
268  shared_ptr<string> text = args[0]->Eval(ev);
269  WordWriter ww(s);
270  for (StringPiece tok : WordScanner(*text)) {
271    ww.Write(StripExt(tok));
272  }
273}
274
275void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
276  shared_ptr<string> suf = args[0]->Eval(ev);
277  shared_ptr<string> text = args[1]->Eval(ev);
278  WordWriter ww(s);
279  for (StringPiece tok : WordScanner(*text)) {
280    ww.Write(tok);
281    *s += *suf;
282  }
283}
284
285void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
286  shared_ptr<string> pre = args[0]->Eval(ev);
287  shared_ptr<string> text = args[1]->Eval(ev);
288  WordWriter ww(s);
289  for (StringPiece tok : WordScanner(*text)) {
290    ww.Write(*pre);
291    AppendString(tok, s);
292  }
293}
294
295void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
296  shared_ptr<string> text = args[0]->Eval(ev);
297  WordWriter ww(s);
298  for (StringPiece tok : WordScanner(*text)) {
299    ScopedTerminator st(tok);
300    char buf[PATH_MAX];
301    if (realpath(tok.data(), buf))
302      *s += buf;
303  }
304}
305
306void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
307  shared_ptr<string> text = args[0]->Eval(ev);
308  WordWriter ww(s);
309  string buf;
310  for (StringPiece tok : WordScanner(*text)) {
311    AbsPath(tok, &buf);
312    ww.Write(buf);
313  }
314}
315
316void IfFunc(const vector<Value*>&, Evaluator*, string*) {
317  printf("TODO(if)");
318}
319
320void AndFunc(const vector<Value*>&, Evaluator*, string*) {
321  printf("TODO(and)");
322}
323
324void OrFunc(const vector<Value*>&, Evaluator*, string*) {
325  printf("TODO(or)");
326}
327
328void ValueFunc(const vector<Value*>&, Evaluator*, string*) {
329  printf("TODO(value)");
330}
331
332void EvalFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
333  shared_ptr<string> text = args[0]->Eval(ev);
334  vector<AST*> asts;
335  Parse(*text, ev->loc(), &asts);
336  for (AST* ast : asts) {
337    LOG("%s", ast->DebugString().c_str());
338    ast->Eval(ev);
339    delete ast;
340  }
341}
342
343void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
344  shared_ptr<string> cmd = args[0]->Eval(ev);
345  LOG("ShellFunc: %s", cmd->c_str());
346  string out;
347  // TODO: Handle $(SHELL).
348  FILE* fp = popen(cmd->c_str(), "r");
349  while (true) {
350    char buf[4096];
351    size_t r = fread(buf, 1, 4096, fp);
352    out.append(buf, buf+r);
353    if (r == 0) {
354      fclose(fp);
355      break;
356    }
357  }
358
359  while (out[out.size()-1] == '\n')
360    out.pop_back();
361  for (size_t i = 0; i < out.size(); i++) {
362    if (out[i] == '\n')
363      out[i] = ' ';
364  }
365  *s += out;
366}
367
368void CallFunc(const vector<Value*>&, Evaluator*, string*) {
369  printf("TODO(call)");
370}
371
372void ForeachFunc(const vector<Value*>&, Evaluator*, string*) {
373  printf("TODO(foreach)");
374}
375
376void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
377  printf("TODO(origin)");
378}
379
380void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
381  printf("TODO(flavor)");
382}
383
384void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
385  shared_ptr<string> a = args[0]->Eval(ev);
386  printf("%s\n", a->c_str());
387  fflush(stdout);
388}
389
390void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
391  shared_ptr<string> a = args[0]->Eval(ev);
392  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
393  fflush(stdout);
394}
395
396void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
397  shared_ptr<string> a = args[0]->Eval(ev);
398  ev->Error(StringPrintf("*** %s.", a->c_str()));
399}
400
401FuncInfo g_func_infos[] = {
402  { "patsubst", &PatsubstFunc, 3 },
403  { "strip", &StripFunc, 1 },
404  { "subst", &SubstFunc, 3 },
405  { "findstring", &FindstringFunc, 2 },
406  { "filter", &FilterFunc, 2 },
407  { "filter-out", &FilterOutFunc, 2 },
408  { "sort", &SortFunc, 1 },
409  { "word", &WordFunc, 2 },
410  { "wordlist", &WordlistFunc, 3 },
411  { "words", &WordsFunc, 1 },
412  { "firstword", &FirstwordFunc, 1 },
413  { "lastword", &LastwordFunc, 1 },
414
415  { "join", &JoinFunc, 2 },
416  { "wildcard", &WildcardFunc, 1 },
417  { "dir", &DirFunc, 1 },
418  { "notdir", &NotdirFunc, 1 },
419  { "suffix", &SuffixFunc, 1 },
420  { "basename", &BasenameFunc, 1 },
421  { "addsuffix", &AddsuffixFunc, 2 },
422  { "addprefix", &AddprefixFunc, 2 },
423  { "realpath", &RealpathFunc, 1 },
424  { "abspath", &AbspathFunc, 1 },
425
426  { "if", &IfFunc, 1 },
427  { "and", &AndFunc, 1 },
428  { "or", &OrFunc, 1 },
429
430  { "value", &ValueFunc, 1 },
431  { "eval", &EvalFunc, 1 },
432  { "shell", &ShellFunc, 1 },
433  { "call", &CallFunc, 1 },
434  { "foreach", &ForeachFunc, 1 },
435
436  { "origin", &OriginFunc, 1 },
437  { "flavor", &FlavorFunc, 1 },
438
439  { "info", &InfoFunc, 1 },
440  { "warning", &WarningFunc, 1 },
441  { "error", &ErrorFunc, 1 },
442};
443
444unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
445
446}  // namespace
447
448void InitFuncTable() {
449  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
450  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
451    FuncInfo* fi = &g_func_infos[i];
452    bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
453    CHECK(ok);
454  }
455}
456
457void QuitFuncTable() {
458  delete g_func_info_map;
459}
460
461FuncInfo* GetFuncInfo(StringPiece name) {
462  auto found = g_func_info_map->find(name);
463  if (found == g_func_info_map->end())
464    return NULL;
465  return found->second;
466}
467