func.cc revision 8a96358d16ab0c435820d07472e301e9d3b2c03a
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 "eval.h"
13#include "log.h"
14#include "strutil.h"
15
16namespace {
17
18void 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);
22  WordWriter ww(s);
23  for (StringPiece tok : WordScanner(*str)) {
24    ww.MaybeAddWhitespace();
25    AppendSubstPattern(tok, *pat, *repl, s);
26  }
27}
28
29void 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  }
35}
36
37void 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);
51}
52
53void 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);
58}
59
60void 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;
64  WordScanner(*pat_buf).Split(&pats);
65  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;
80  WordScanner(*pat_buf).Split(&pats);
81  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  }
93}
94
95void 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  }
108}
109
110static 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;
118}
119
120void 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  }
140}
141
142void 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  }
173}
174
175void 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;
184}
185
186void 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);
201}
202
203void 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  }
216}
217
218void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
219  shared_ptr<string> pat = args[0]->Eval(ev);
220  WordWriter ww(s);
221  for (StringPiece tok : WordScanner(*pat)) {
222    char orig = tok[tok.size()];
223    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;
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    char orig = tok[tok.size()];
302    const_cast<char*>(tok.data())[tok.size()] = '\0';
303    char buf[PATH_MAX];
304    if (realpath(tok.data(), buf))
305      *s += buf;
306    const_cast<char*>(tok.data())[tok.size()] = orig;
307  }
308}
309
310void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
311  shared_ptr<string> text = args[0]->Eval(ev);
312  WordWriter ww(s);
313  string buf;
314  for (StringPiece tok : WordScanner(*text)) {
315    AbsPath(tok, &buf);
316    ww.Write(buf);
317  }
318}
319
320void IfFunc(const vector<Value*>&, Evaluator*, string*) {
321  printf("TODO(if)");
322}
323
324void AndFunc(const vector<Value*>&, Evaluator*, string*) {
325  printf("TODO(and)");
326}
327
328void OrFunc(const vector<Value*>&, Evaluator*, string*) {
329  printf("TODO(or)");
330}
331
332void ValueFunc(const vector<Value*>&, Evaluator*, string*) {
333  printf("TODO(value)");
334}
335
336void EvalFunc(const vector<Value*>&, Evaluator*, string*) {
337  printf("TODO(eval)");
338}
339
340void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
341  shared_ptr<string> cmd = args[0]->Eval(ev);
342  LOG("ShellFunc: %s", cmd->c_str());
343  string out;
344  // TODO: Handle $(SHELL).
345  FILE* fp = popen(cmd->c_str(), "r");
346  while (true) {
347    char buf[4096];
348    size_t r = fread(buf, 1, 4096, fp);
349    out.append(buf, buf+r);
350    if (r == 0) {
351      fclose(fp);
352      break;
353    }
354  }
355
356  while (out[out.size()-1] == '\n')
357    out.pop_back();
358  for (size_t i = 0; i < out.size(); i++) {
359    if (out[i] == '\n')
360      out[i] = ' ';
361  }
362  *s += out;
363}
364
365void CallFunc(const vector<Value*>&, Evaluator*, string*) {
366  printf("TODO(call)");
367}
368
369void ForeachFunc(const vector<Value*>&, Evaluator*, string*) {
370  printf("TODO(foreach)");
371}
372
373void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
374  printf("TODO(origin)");
375}
376
377void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
378  printf("TODO(flavor)");
379}
380
381void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
382  shared_ptr<string> a = args[0]->Eval(ev);
383  printf("%s\n", a->c_str());
384  fflush(stdout);
385}
386
387void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
388  shared_ptr<string> a = args[0]->Eval(ev);
389  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
390  fflush(stdout);
391}
392
393void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
394  shared_ptr<string> a = args[0]->Eval(ev);
395  ev->Error(StringPrintf("*** %s.", a->c_str()));
396}
397
398FuncInfo g_func_infos[] = {
399  { "patsubst", &PatsubstFunc, 3 },
400  { "strip", &StripFunc, 1 },
401  { "subst", &SubstFunc, 3 },
402  { "findstring", &FindstringFunc, 2 },
403  { "filter", &FilterFunc, 2 },
404  { "filter-out", &FilterOutFunc, 2 },
405  { "sort", &SortFunc, 1 },
406  { "word", &WordFunc, 2 },
407  { "wordlist", &WordlistFunc, 3 },
408  { "words", &WordsFunc, 1 },
409  { "firstword", &FirstwordFunc, 1 },
410  { "lastword", &LastwordFunc, 1 },
411
412  { "join", &JoinFunc, 2 },
413  { "wildcard", &WildcardFunc, 1 },
414  { "dir", &DirFunc, 1 },
415  { "notdir", &NotdirFunc, 1 },
416  { "suffix", &SuffixFunc, 1 },
417  { "basename", &BasenameFunc, 1 },
418  { "addsuffix", &AddsuffixFunc, 2 },
419  { "addprefix", &AddprefixFunc, 2 },
420  { "realpath", &RealpathFunc, 1 },
421  { "abspath", &AbspathFunc, 1 },
422
423  { "if", &IfFunc, 1 },
424  { "and", &AndFunc, 1 },
425  { "or", &OrFunc, 1 },
426  { "value", &ValueFunc, 1 },
427  { "eval", &EvalFunc, 1 },
428  { "shell", &ShellFunc, 1 },
429  { "call", &CallFunc, 1 },
430  { "foreach", &ForeachFunc, 1 },
431  { "origin", &OriginFunc, 1 },
432  { "flavor", &FlavorFunc, 1 },
433  { "info", &InfoFunc, 1 },
434  { "warning", &WarningFunc, 1 },
435  { "error", &ErrorFunc, 1 },
436};
437
438unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
439
440}  // namespace
441
442void InitFuncTable() {
443  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
444  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
445    FuncInfo* fi = &g_func_infos[i];
446    bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
447    CHECK(ok);
448  }
449}
450
451void QuitFuncTable() {
452  delete g_func_info_map;
453}
454
455FuncInfo* GetFuncInfo(StringPiece name) {
456  auto found = g_func_info_map->find(name);
457  if (found == g_func_info_map->end())
458    return NULL;
459  return found->second;
460}
461