func.cc revision 65dce5461745a58fe5a294527aaaf6fc8f8b73ee
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 <errno.h>
20#include <limits.h>
21#include <stdio.h>
22#include <stdlib.h>
23#include <unistd.h>
24
25#include <algorithm>
26#include <iterator>
27#include <memory>
28#include <unordered_map>
29
30#include "ast.h"
31#include "eval.h"
32#include "fileutil.h"
33#include "find.h"
34#include "log.h"
35#include "parser.h"
36#include "stats.h"
37#include "strutil.h"
38#include "symtab.h"
39#include "var.h"
40
41namespace {
42
43void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
44  shared_ptr<string> pat_str = args[0]->Eval(ev);
45  shared_ptr<string> repl = args[1]->Eval(ev);
46  shared_ptr<string> str = args[2]->Eval(ev);
47  WordWriter ww(s);
48  Pattern pat(*pat_str);
49  for (StringPiece tok : WordScanner(*str)) {
50    ww.MaybeAddWhitespace();
51    pat.AppendSubst(tok, *repl, s);
52  }
53}
54
55void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
56  shared_ptr<string> str = args[0]->Eval(ev);
57  WordWriter ww(s);
58  for (StringPiece tok : WordScanner(*str)) {
59    ww.Write(tok);
60  }
61}
62
63void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
64  shared_ptr<string> pat = args[0]->Eval(ev);
65  shared_ptr<string> repl = args[1]->Eval(ev);
66  shared_ptr<string> str = args[2]->Eval(ev);
67  if (pat->empty()) {
68    *s += *str;
69    *s += *repl;
70    return;
71  }
72  size_t index = 0;
73  while (index < str->size()) {
74    size_t found = str->find(*pat, index);
75    if (found == string::npos)
76      break;
77    AppendString(StringPiece(*str).substr(index, found - index), s);
78    AppendString(*repl, s);
79    index = found + pat->size();
80  }
81  AppendString(StringPiece(*str).substr(index), s);
82}
83
84void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
85  shared_ptr<string> find = args[0]->Eval(ev);
86  shared_ptr<string> in = args[1]->Eval(ev);
87  if (in->find(*find) != string::npos)
88    AppendString(*find, s);
89}
90
91void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
92  shared_ptr<string> pat_buf = args[0]->Eval(ev);
93  shared_ptr<string> text = args[1]->Eval(ev);
94  vector<Pattern> pats;
95  for (StringPiece pat : WordScanner(*pat_buf)) {
96    pats.push_back(Pattern(pat));
97  }
98  WordWriter ww(s);
99  for (StringPiece tok : WordScanner(*text)) {
100    for (const Pattern& pat : pats) {
101      if (pat.Match(tok)) {
102        ww.Write(tok);
103        break;
104      }
105    }
106  }
107}
108
109void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
110  shared_ptr<string> pat_buf = args[0]->Eval(ev);
111  shared_ptr<string> text = args[1]->Eval(ev);
112  vector<Pattern> pats;
113  for (StringPiece pat : WordScanner(*pat_buf)) {
114    pats.push_back(Pattern(pat));
115  }
116  WordWriter ww(s);
117  for (StringPiece tok : WordScanner(*text)) {
118    bool matched = false;
119    for (const Pattern& pat : pats) {
120      if (pat.Match(tok)) {
121        matched = true;
122        break;
123      }
124    }
125    if (!matched)
126      ww.Write(tok);
127  }
128}
129
130void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
131  shared_ptr<string> list = args[0]->Eval(ev);
132  vector<StringPiece> toks;
133  WordScanner(*list).Split(&toks);
134  sort(toks.begin(), toks.end());
135  WordWriter ww(s);
136  StringPiece prev;
137  for (StringPiece tok : toks) {
138    if (prev != tok) {
139      ww.Write(tok);
140      prev = tok;
141    }
142  }
143}
144
145static int GetNumericValueForFunc(const string& buf) {
146  StringPiece s = TrimLeftSpace(buf);
147  char* end;
148  long n = strtol(s.data(), &end, 10);
149  if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) {
150    return -1;
151  }
152  return n;
153}
154
155void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
156  shared_ptr<string> n_str = args[0]->Eval(ev);
157  int n = GetNumericValueForFunc(*n_str);
158  if (n < 0) {
159    ev->Error(StringPrintf(
160        "*** non-numeric first argument to `word' function: '%s'.",
161        n_str->c_str()));
162  }
163  if (n == 0) {
164    ev->Error("*** first argument to `word' function must be greater than 0.");
165  }
166
167  shared_ptr<string> text = args[1]->Eval(ev);
168  for (StringPiece tok : WordScanner(*text)) {
169    n--;
170    if (n == 0) {
171      AppendString(tok, s);
172      break;
173    }
174  }
175}
176
177void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
178  shared_ptr<string> s_str = args[0]->Eval(ev);
179  int si = GetNumericValueForFunc(*s_str);
180  if (si < 0) {
181    ev->Error(StringPrintf(
182        "*** non-numeric first argument to `wordlist' function: '%s'.",
183        s_str->c_str()));
184  }
185  if (si == 0) {
186    ev->Error(StringPrintf(
187        "*** invalid first argument to `wordlist' function: %s`",
188        s_str->c_str()));
189  }
190
191  shared_ptr<string> e_str = args[1]->Eval(ev);
192  int ei = GetNumericValueForFunc(*e_str);
193  if (ei < 0) {
194    ev->Error(StringPrintf(
195        "*** non-numeric second argument to `wordlist' function: '%s'.",
196        e_str->c_str()));
197  }
198
199  shared_ptr<string> text = args[2]->Eval(ev);
200  int i = 0;
201  WordWriter ww(s);
202  for (StringPiece tok : WordScanner(*text)) {
203    i++;
204    if (si <= i && i <= ei) {
205      ww.Write(tok);
206    }
207  }
208}
209
210void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
211  shared_ptr<string> text = args[0]->Eval(ev);
212  WordScanner ws(*text);
213  int n = 0;
214  for (auto iter = ws.begin(); iter != ws.end(); ++iter)
215    n++;
216  char buf[32];
217  sprintf(buf, "%d", n);
218  *s += buf;
219}
220
221void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
222  shared_ptr<string> text = args[0]->Eval(ev);
223  for (StringPiece tok : WordScanner(*text)) {
224    AppendString(tok, s);
225    return;
226  }
227}
228
229void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
230  shared_ptr<string> text = args[0]->Eval(ev);
231  StringPiece last;
232  for (StringPiece tok : WordScanner(*text)) {
233    last = tok;
234  }
235  AppendString(last, s);
236}
237
238void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
239  shared_ptr<string> list1 = args[0]->Eval(ev);
240  shared_ptr<string> list2 = args[1]->Eval(ev);
241  WordScanner ws1(*list1);
242  WordScanner ws2(*list2);
243  WordWriter ww(s);
244  for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin();
245       iter1 != ws1.end() && iter2 != ws2.end();
246       ++iter1, ++iter2) {
247    ww.Write(*iter1);
248    // Use |AppendString| not to append extra ' '.
249    AppendString(*iter2, s);
250  }
251}
252
253void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
254  COLLECT_STATS("func wildcard time");
255  shared_ptr<string> pat = args[0]->Eval(ev);
256  // Note GNU make does not delay the execution of $(wildcard) so we
257  // do not need to check avoid_io here.
258  WordWriter ww(s);
259  vector<string>* files;
260  for (StringPiece tok : WordScanner(*pat)) {
261    ScopedTerminator st(tok);
262    Glob(tok.data(), &files);
263    sort(files->begin(), files->end());
264    for (const string& file : *files) {
265      ww.Write(file);
266    }
267  }
268}
269
270void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
271  shared_ptr<string> text = args[0]->Eval(ev);
272  WordWriter ww(s);
273  for (StringPiece tok : WordScanner(*text)) {
274    ww.Write(Dirname(tok));
275    s->push_back('/');
276  }
277}
278
279void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
280  shared_ptr<string> text = args[0]->Eval(ev);
281  WordWriter ww(s);
282  for (StringPiece tok : WordScanner(*text)) {
283    if (tok == "/") {
284      ww.Write(StringPiece(""));
285    } else {
286      ww.Write(Basename(tok));
287    }
288  }
289}
290
291void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
292  shared_ptr<string> text = args[0]->Eval(ev);
293  WordWriter ww(s);
294  for (StringPiece tok : WordScanner(*text)) {
295    StringPiece suf = GetExt(tok);
296    if (!suf.empty())
297      ww.Write(suf);
298  }
299}
300
301void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
302  shared_ptr<string> text = args[0]->Eval(ev);
303  WordWriter ww(s);
304  for (StringPiece tok : WordScanner(*text)) {
305    ww.Write(StripExt(tok));
306  }
307}
308
309void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
310  shared_ptr<string> suf = args[0]->Eval(ev);
311  shared_ptr<string> text = args[1]->Eval(ev);
312  WordWriter ww(s);
313  for (StringPiece tok : WordScanner(*text)) {
314    ww.Write(tok);
315    *s += *suf;
316  }
317}
318
319void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
320  shared_ptr<string> pre = args[0]->Eval(ev);
321  shared_ptr<string> text = args[1]->Eval(ev);
322  WordWriter ww(s);
323  for (StringPiece tok : WordScanner(*text)) {
324    ww.Write(*pre);
325    AppendString(tok, s);
326  }
327}
328
329void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
330  shared_ptr<string> text = args[0]->Eval(ev);
331  if (ev->avoid_io()) {
332    *s += "$(realpath ";
333    *s += *text;
334    *s += " 2> /dev/null)";
335    return;
336  }
337
338  WordWriter ww(s);
339  for (StringPiece tok : WordScanner(*text)) {
340    ScopedTerminator st(tok);
341    char buf[PATH_MAX];
342    if (realpath(tok.data(), buf))
343      *s += buf;
344  }
345}
346
347void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
348  shared_ptr<string> text = args[0]->Eval(ev);
349  WordWriter ww(s);
350  string buf;
351  for (StringPiece tok : WordScanner(*text)) {
352    AbsPath(tok, &buf);
353    ww.Write(buf);
354  }
355}
356
357void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
358  shared_ptr<string> cond = args[0]->Eval(ev);
359  if (cond->empty()) {
360    if (args.size() > 2)
361      args[2]->Eval(ev, s);
362  } else {
363    args[1]->Eval(ev, s);
364  }
365}
366
367void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
368  shared_ptr<string> cond;
369  for (Value* a : args) {
370    cond = a->Eval(ev);
371    if (cond->empty())
372      return;
373  }
374  if (cond.get()) {
375    *s += *cond;
376  }
377}
378
379void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
380  for (Value* a : args) {
381    shared_ptr<string> cond = a->Eval(ev);
382    if (!cond->empty()) {
383      *s += *cond;
384      return;
385    }
386  }
387}
388
389void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
390  shared_ptr<string> var_name = args[0]->Eval(ev);
391  Var* var = ev->LookupVar(Intern(*var_name));
392  AppendString(var->String().as_string(), s);
393}
394
395void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
396  // TODO: eval leaks everything... for now.
397  //shared_ptr<string> text = args[0]->Eval(ev);
398  string* text = new string;
399  args[0]->Eval(ev, text);
400  vector<AST*> asts;
401  Parse(*text, ev->loc(), &asts);
402  for (AST* ast : asts) {
403    LOG("%s", ast->DebugString().c_str());
404    ast->Eval(ev);
405    //delete ast;
406  }
407}
408
409//#define TEST_FIND_EMULATOR
410
411#ifdef TEST_FIND_EMULATOR
412static string SortWordsInString(StringPiece s) {
413  vector<string> toks;
414  for (StringPiece tok : WordScanner(s)) {
415    toks.push_back(tok.as_string());
416  }
417  sort(toks.begin(), toks.end());
418  return JoinStrings(toks, " ");
419}
420#endif
421
422
423// A hack for Android build. We need to evaluate things like $((3+4))
424// when we emit ninja file, because the result of such expressions
425// will be passed to other make functions.
426// TODO: Maybe we should introduce a helper binary which evaluate
427// make expressions at ninja-time.
428static bool HasNoIoInShellScript(const string& cmd) {
429  if (cmd.empty())
430    return true;
431  if (HasPrefix(cmd, "echo $((") && cmd[cmd.size()-1] == ')')
432    return true;
433  return false;
434}
435
436void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
437  shared_ptr<string> cmd = args[0]->Eval(ev);
438  if (ev->avoid_io() && !HasNoIoInShellScript(*cmd)) {
439    *s += "$(";
440    *s += *cmd;
441    *s += ")";
442    return;
443  }
444
445  LOG("ShellFunc: %s", cmd->c_str());
446
447#ifdef TEST_FIND_EMULATOR
448  bool need_check = false;
449  string out2;
450  if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, &out2)) {
451    need_check = true;
452  }
453#else
454  if (FindEmulator::Get() && FindEmulator::Get()->HandleFind(*cmd, s))
455    return;
456#endif
457
458  COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd->c_str());
459  string out;
460  shared_ptr<string> shell = ev->EvalVar(kShellSym);
461  RunCommand(*shell, *cmd, false, &out);
462
463  while (out[out.size()-1] == '\n')
464    out.pop_back();
465  for (size_t i = 0; i < out.size(); i++) {
466    if (out[i] == '\n')
467      out[i] = ' ';
468  }
469
470#ifdef TEST_FIND_EMULATOR
471  if (need_check) {
472    string sorted = SortWordsInString(out);
473    out2 = SortWordsInString(out2);
474    if (sorted != out2) {
475      ERROR("FindEmulator is broken: %s\n%s\nvs\n%s",
476            cmd->c_str(), sorted.c_str(), out2.c_str());
477    }
478  }
479#endif
480
481  *s += out;
482}
483
484void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
485  static const string tmpvar_names[] = {
486    "0", "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9"
487  };
488
489  shared_ptr<string> func_name = args[0]->Eval(ev);
490  Var* func = ev->LookupVar(Intern(*func_name));
491  vector<unique_ptr<SimpleVar>> av;
492  for (size_t i = 1; i < args.size(); i++) {
493    unique_ptr<SimpleVar> s(
494        new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
495    av.push_back(move(s));
496  }
497  vector<unique_ptr<ScopedVar>> sv;
498  for (size_t i = 1; i < args.size(); i++) {
499    string s;
500    StringPiece tmpvar_name;
501    if (i < sizeof(tmpvar_names)/sizeof(tmpvar_names[0])) {
502      tmpvar_name = tmpvar_names[i];
503    } else {
504      s = StringPrintf("%d", i);
505      tmpvar_name = s;
506    }
507    sv.push_back(move(unique_ptr<ScopedVar>(
508        new ScopedVar(ev->mutable_vars(),
509                      Intern(tmpvar_name), av[i-1].get()))));
510  }
511  func->Eval(ev, s);
512}
513
514void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
515  shared_ptr<string> varname = args[0]->Eval(ev);
516  shared_ptr<string> list = args[1]->Eval(ev);
517  WordWriter ww(s);
518  for (StringPiece tok : WordScanner(*list)) {
519    unique_ptr<SimpleVar> v(new SimpleVar(
520        make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC));
521    ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get());
522    ww.MaybeAddWhitespace();
523    args[2]->Eval(ev, s);
524  }
525}
526
527void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
528  shared_ptr<string> var_name = args[0]->Eval(ev);
529  Var* var = ev->LookupVar(Intern(*var_name));
530  *s += GetOriginStr(var->Origin());
531}
532
533void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
534  shared_ptr<string> var_name = args[0]->Eval(ev);
535  Var* var = ev->LookupVar(Intern(*var_name));
536  *s += var->Flavor();
537}
538
539void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
540  shared_ptr<string> a = args[0]->Eval(ev);
541  if (ev->avoid_io()) {
542    ev->add_delayed_output_command(StringPrintf("echo '%s'", a->c_str()));
543    return;
544  }
545  printf("%s\n", a->c_str());
546  fflush(stdout);
547}
548
549void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
550  shared_ptr<string> a = args[0]->Eval(ev);
551  if (ev->avoid_io()) {
552    ev->add_delayed_output_command(
553        StringPrintf("echo '%s:%d: %s' 2>&1", LOCF(ev->loc()), a->c_str()));
554    return;
555  }
556  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
557  fflush(stdout);
558}
559
560void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
561  shared_ptr<string> a = args[0]->Eval(ev);
562  if (ev->avoid_io()) {
563    ev->add_delayed_output_command(
564        StringPrintf("echo '%s:%d: *** %s.' 2>&1 && false",
565                     LOCF(ev->loc()), a->c_str()));
566    return;
567  }
568  ev->Error(StringPrintf("*** %s.", a->c_str()));
569}
570
571FuncInfo g_func_infos[] = {
572  { "patsubst", &PatsubstFunc, 3, 3, false, false },
573  { "strip", &StripFunc, 1, 1, false, false },
574  { "subst", &SubstFunc, 3, 3, false, false },
575  { "findstring", &FindstringFunc, 2, 2, false, false },
576  { "filter", &FilterFunc, 2, 2, false, false },
577  { "filter-out", &FilterOutFunc, 2, 2, false, false },
578  { "sort", &SortFunc, 1, 1, false, false },
579  { "word", &WordFunc, 2, 2, false, false },
580  { "wordlist", &WordlistFunc, 3, 3, false, false },
581  { "words", &WordsFunc, 1, 1, false, false },
582  { "firstword", &FirstwordFunc, 1, 1, false, false },
583  { "lastword", &LastwordFunc, 1, 1, false, false },
584
585  { "join", &JoinFunc, 2, 2, false, false },
586  { "wildcard", &WildcardFunc, 1, 1, false, false },
587  { "dir", &DirFunc, 1, 1, false, false },
588  { "notdir", &NotdirFunc, 1, 1, false, false },
589  { "suffix", &SuffixFunc, 1, 1, false, false },
590  { "basename", &BasenameFunc, 1, 1, false, false },
591  { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
592  { "addprefix", &AddprefixFunc, 2, 2, false, false },
593  { "realpath", &RealpathFunc, 1, 1, false, false },
594  { "abspath", &AbspathFunc, 1, 1, false, false },
595
596  { "if", &IfFunc, 3, 2, false, true },
597  { "and", &AndFunc, 0, 0, true, false },
598  { "or", &OrFunc, 0, 0, true, false },
599
600  { "value", &ValueFunc, 1, 1, false, false },
601  { "eval", &EvalFunc, 1, 1, false, false },
602  { "shell", &ShellFunc, 1, 1, false, false },
603  { "call", &CallFunc, 0, 0, false, false },
604  { "foreach", &ForeachFunc, 3, 3, false, false },
605
606  { "origin", &OriginFunc, 1, 1, false, false },
607  { "flavor", &FlavorFunc, 1, 1, false, false },
608
609  { "info", &InfoFunc, 1, 1, false, false },
610  { "warning", &WarningFunc, 1, 1, false, false },
611  { "error", &ErrorFunc, 1, 1, false, false },
612};
613
614unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
615
616}  // namespace
617
618void InitFuncTable() {
619  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
620  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
621    FuncInfo* fi = &g_func_infos[i];
622    bool ok = g_func_info_map->emplace(fi->name, fi).second;
623    CHECK(ok);
624  }
625}
626
627void QuitFuncTable() {
628  delete g_func_info_map;
629}
630
631FuncInfo* GetFuncInfo(StringPiece name) {
632  auto found = g_func_info_map->find(name);
633  if (found == g_func_info_map->end())
634    return NULL;
635  return found->second;
636}
637