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