func.cc revision cf0cd68ef4d2b8268ade22418c17e0079e9c85e1
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*>&, Evaluator*, string*) {
391  printf("TODO(call)");
392}
393
394void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
395  shared_ptr<string> varname = args[0]->Eval(ev);
396  shared_ptr<string> list = args[1]->Eval(ev);
397  WordWriter ww(s);
398  for (StringPiece tok : WordScanner(*list)) {
399    unique_ptr<SimpleVar> v(new SimpleVar(
400        make_shared<string>(tok.data(), tok.size()), "automatic"));
401    ScopedVar sv(ev->mutable_vars(), *varname, v.get());
402    ww.MaybeAddWhitespace();
403    args[2]->Eval(ev, s);
404  }
405}
406
407void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
408  printf("TODO(origin)");
409}
410
411void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
412  printf("TODO(flavor)");
413}
414
415void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
416  shared_ptr<string> a = args[0]->Eval(ev);
417  printf("%s\n", a->c_str());
418  fflush(stdout);
419}
420
421void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
422  shared_ptr<string> a = args[0]->Eval(ev);
423  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
424  fflush(stdout);
425}
426
427void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
428  shared_ptr<string> a = args[0]->Eval(ev);
429  ev->Error(StringPrintf("*** %s.", a->c_str()));
430}
431
432FuncInfo g_func_infos[] = {
433  { "patsubst", &PatsubstFunc, 3, 3, false, false },
434  { "strip", &StripFunc, 1, 1, false, false },
435  { "subst", &SubstFunc, 3, 3, false, false },
436  { "findstring", &FindstringFunc, 2, 2, false, false },
437  { "filter", &FilterFunc, 2, 2, false, false },
438  { "filter-out", &FilterOutFunc, 2, 2, false, false },
439  { "sort", &SortFunc, 1, 1, false, false },
440  { "word", &WordFunc, 2, 2, false, false },
441  { "wordlist", &WordlistFunc, 3, 3, false, false },
442  { "words", &WordsFunc, 1, 1, false, false },
443  { "firstword", &FirstwordFunc, 1, 1, false, false },
444  { "lastword", &LastwordFunc, 1, 1, false, false },
445
446  { "join", &JoinFunc, 2, 2, false, false },
447  { "wildcard", &WildcardFunc, 1, 1, false, false },
448  { "dir", &DirFunc, 1, 1, false, false },
449  { "notdir", &NotdirFunc, 1, 1, false, false },
450  { "suffix", &SuffixFunc, 1, 1, false, false },
451  { "basename", &BasenameFunc, 1, 1, false, false },
452  { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
453  { "addprefix", &AddprefixFunc, 2, 2, false, false },
454  { "realpath", &RealpathFunc, 1, 1, false, false },
455  { "abspath", &AbspathFunc, 1, 1, false, false },
456
457  { "if", &IfFunc, 3, 2, false, true },
458  { "and", &AndFunc, 0, 0, true, false },
459  { "or", &OrFunc, 0, 0, true, false },
460
461  { "value", &ValueFunc, 1, 1, false, false },
462  { "eval", &EvalFunc, 1, 1, false, false },
463  { "shell", &ShellFunc, 1, 1, false, false },
464  { "call", &CallFunc, 0, 0, false, false },
465  { "foreach", &ForeachFunc, 3, 3, false, false },
466
467  { "origin", &OriginFunc, 1, 1, false, false },
468  { "flavor", &FlavorFunc, 1, 1, false, false },
469
470  { "info", &InfoFunc, 1, 1, false, false },
471  { "warning", &WarningFunc, 1, 1, false, false },
472  { "error", &ErrorFunc, 1, 1, false, false },
473};
474
475unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
476
477}  // namespace
478
479void InitFuncTable() {
480  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
481  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
482    FuncInfo* fi = &g_func_infos[i];
483    bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
484    CHECK(ok);
485  }
486}
487
488void QuitFuncTable() {
489  delete g_func_info_map;
490}
491
492FuncInfo* GetFuncInfo(StringPiece name) {
493  auto found = g_func_info_map->find(name);
494  if (found == g_func_info_map->end())
495    return NULL;
496  return found->second;
497}
498