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