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