func.cc revision 30b8e60d2c6871d3fa501262c0ea347a8d337bb6
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*>&, Evaluator*, string*) {
219  printf("TODO(wildcard)");
220}
221
222void DirFunc(const vector<Value*>&, Evaluator*, string*) {
223  printf("TODO(dir)");
224}
225
226void NotdirFunc(const vector<Value*>&, Evaluator*, string*) {
227  printf("TODO(notdir)");
228}
229
230void SuffixFunc(const vector<Value*>&, Evaluator*, string*) {
231  printf("TODO(suffix)");
232}
233
234void BasenameFunc(const vector<Value*>&, Evaluator*, string*) {
235  printf("TODO(basename)");
236}
237
238void AddsuffixFunc(const vector<Value*>&, Evaluator*, string*) {
239  printf("TODO(addsuffix)");
240}
241
242void AddprefixFunc(const vector<Value*>&, Evaluator*, string*) {
243  printf("TODO(addprefix)");
244}
245
246void RealpathFunc(const vector<Value*>&, Evaluator*, string*) {
247  printf("TODO(realpath)");
248}
249
250void AbspathFunc(const vector<Value*>&, Evaluator*, string*) {
251  printf("TODO(abspath)");
252}
253
254void IfFunc(const vector<Value*>&, Evaluator*, string*) {
255  printf("TODO(if)");
256}
257
258void AndFunc(const vector<Value*>&, Evaluator*, string*) {
259  printf("TODO(and)");
260}
261
262void OrFunc(const vector<Value*>&, Evaluator*, string*) {
263  printf("TODO(or)");
264}
265
266void ValueFunc(const vector<Value*>&, Evaluator*, string*) {
267  printf("TODO(value)");
268}
269
270void EvalFunc(const vector<Value*>&, Evaluator*, string*) {
271  printf("TODO(eval)");
272}
273
274void ShellFunc(const vector<Value*>&, Evaluator*, string*) {
275  printf("TODO(shell)");
276}
277
278void CallFunc(const vector<Value*>&, Evaluator*, string*) {
279  printf("TODO(call)");
280}
281
282void ForeachFunc(const vector<Value*>&, Evaluator*, string*) {
283  printf("TODO(foreach)");
284}
285
286void OriginFunc(const vector<Value*>&, Evaluator*, string*) {
287  printf("TODO(origin)");
288}
289
290void FlavorFunc(const vector<Value*>&, Evaluator*, string*) {
291  printf("TODO(flavor)");
292}
293
294void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
295  shared_ptr<string> a = args[0]->Eval(ev);
296  printf("%s\n", a->c_str());
297  fflush(stdout);
298}
299
300void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
301  shared_ptr<string> a = args[0]->Eval(ev);
302  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
303  fflush(stdout);
304}
305
306void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
307  shared_ptr<string> a = args[0]->Eval(ev);
308  ev->Error(StringPrintf("*** %s.", a->c_str()));
309}
310
311FuncInfo g_func_infos[] = {
312  { "patsubst", &PatsubstFunc, 3 },
313  { "strip", &StripFunc, 1 },
314  { "subst", &SubstFunc, 3 },
315  { "findstring", &FindstringFunc, 2 },
316  { "filter", &FilterFunc, 2 },
317  { "filter-out", &FilterOutFunc, 2 },
318  { "sort", &SortFunc, 1 },
319  { "word", &WordFunc, 2 },
320  { "wordlist", &WordlistFunc, 3 },
321  { "words", &WordsFunc, 1 },
322  { "firstword", &FirstwordFunc, 1 },
323  { "lastword", &LastwordFunc, 1 },
324
325  { "join", &JoinFunc, 2 },
326  { "wildcard", &WildcardFunc, 1 },
327  { "dir", &DirFunc, 1 },
328  { "notdir", &NotdirFunc, 1 },
329  { "suffix", &SuffixFunc, 1 },
330  { "basename", &BasenameFunc, 1 },
331  { "addsuffix", &AddsuffixFunc, 2 },
332  { "addprefix", &AddprefixFunc, 2 },
333  { "realpath", &RealpathFunc, 1 },
334  { "abspath", &AbspathFunc, 1 },
335
336  { "if", &IfFunc, 1 },
337  { "and", &AndFunc, 1 },
338  { "or", &OrFunc, 1 },
339  { "value", &ValueFunc, 1 },
340  { "eval", &EvalFunc, 1 },
341  { "shell", &ShellFunc, 1 },
342  { "call", &CallFunc, 1 },
343  { "foreach", &ForeachFunc, 1 },
344  { "origin", &OriginFunc, 1 },
345  { "flavor", &FlavorFunc, 1 },
346  { "info", &InfoFunc, 1 },
347  { "warning", &WarningFunc, 1 },
348  { "error", &ErrorFunc, 1 },
349};
350
351unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
352
353}  // namespace
354
355void InitFuncTable() {
356  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
357  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
358    FuncInfo* fi = &g_func_infos[i];
359    bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
360    CHECK(ok);
361  }
362}
363
364void QuitFuncTable() {
365  delete g_func_info_map;
366}
367
368FuncInfo* GetFuncInfo(StringPiece name) {
369  auto found = g_func_info_map->find(name);
370  if (found == g_func_info_map->end())
371    return NULL;
372  return found->second;
373}
374