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