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.
StripShellComment(string * cmd)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 
PatsubstFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
StripFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
SubstFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
FindstringFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
FilterFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
FilterOutFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
SortFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
GetNumericValueForFunc(const string & buf)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 
WordFunc(const vector<Value * > & args,Evaluator * ev,string * s)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(
220         StringPrintf("*** 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 
WordlistFunc(const vector<Value * > & args,Evaluator * ev,string * s)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(
247         StringPrintf("*** 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 
WordsFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
FirstwordFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
LastwordFunc(const vector<Value * > & args,Evaluator * ev,string * s)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 
JoinFunc(const vector<Value * > & args,Evaluator * ev,string * s)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(); ++iter1, ++iter2) {
307     ww.Write(*iter1);
308     // Use |AppendString| not to append extra ' '.
309     AppendString(*iter2, s);
310   }
311   for (; iter1 != ws1.end(); ++iter1)
312     ww.Write(*iter1);
313   for (; iter2 != ws2.end(); ++iter2)
314     ww.Write(*iter2);
315 }
316 
WildcardFunc(const vector<Value * > & args,Evaluator * ev,string * s)317 void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
318   const string&& pat = args[0]->Eval(ev);
319   COLLECT_STATS("func wildcard time");
320   // Note GNU make does not delay the execution of $(wildcard) so we
321   // do not need to check avoid_io here.
322   WordWriter ww(s);
323   vector<string>* files;
324   for (StringPiece tok : WordScanner(pat)) {
325     ScopedTerminator st(tok);
326     Glob(tok.data(), &files);
327     for (const string& file : *files) {
328       ww.Write(file);
329     }
330   }
331 }
332 
DirFunc(const vector<Value * > & args,Evaluator * ev,string * s)333 void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
334   const string&& text = args[0]->Eval(ev);
335   WordWriter ww(s);
336   for (StringPiece tok : WordScanner(text)) {
337     ww.Write(Dirname(tok));
338     s->push_back('/');
339   }
340 }
341 
NotdirFunc(const vector<Value * > & args,Evaluator * ev,string * s)342 void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
343   const string&& text = args[0]->Eval(ev);
344   WordWriter ww(s);
345   for (StringPiece tok : WordScanner(text)) {
346     if (tok == "/") {
347       ww.Write(StringPiece(""));
348     } else {
349       ww.Write(Basename(tok));
350     }
351   }
352 }
353 
SuffixFunc(const vector<Value * > & args,Evaluator * ev,string * s)354 void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
355   const string&& text = args[0]->Eval(ev);
356   WordWriter ww(s);
357   for (StringPiece tok : WordScanner(text)) {
358     StringPiece suf = GetExt(tok);
359     if (!suf.empty())
360       ww.Write(suf);
361   }
362 }
363 
BasenameFunc(const vector<Value * > & args,Evaluator * ev,string * s)364 void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
365   const string&& text = args[0]->Eval(ev);
366   WordWriter ww(s);
367   for (StringPiece tok : WordScanner(text)) {
368     ww.Write(StripExt(tok));
369   }
370 }
371 
AddsuffixFunc(const vector<Value * > & args,Evaluator * ev,string * s)372 void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
373   const string&& suf = args[0]->Eval(ev);
374   const string&& text = args[1]->Eval(ev);
375   WordWriter ww(s);
376   for (StringPiece tok : WordScanner(text)) {
377     ww.Write(tok);
378     *s += suf;
379   }
380 }
381 
AddprefixFunc(const vector<Value * > & args,Evaluator * ev,string * s)382 void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
383   const string&& pre = args[0]->Eval(ev);
384   const string&& text = args[1]->Eval(ev);
385   WordWriter ww(s);
386   for (StringPiece tok : WordScanner(text)) {
387     ww.Write(pre);
388     AppendString(tok, s);
389   }
390 }
391 
RealpathFunc(const vector<Value * > & args,Evaluator * ev,string * s)392 void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
393   const string&& text = args[0]->Eval(ev);
394   if (ev->avoid_io()) {
395     *s += "$(";
396     string kati_binary;
397     GetExecutablePath(&kati_binary);
398     *s += kati_binary;
399     *s += " --realpath ";
400     *s += text;
401     *s += " 2> /dev/null)";
402     return;
403   }
404 
405   WordWriter ww(s);
406   for (StringPiece tok : WordScanner(text)) {
407     ScopedTerminator st(tok);
408     char buf[PATH_MAX];
409     if (realpath(tok.data(), buf))
410       ww.Write(buf);
411   }
412 }
413 
AbspathFunc(const vector<Value * > & args,Evaluator * ev,string * s)414 void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
415   const string&& text = args[0]->Eval(ev);
416   WordWriter ww(s);
417   string buf;
418   for (StringPiece tok : WordScanner(text)) {
419     AbsPath(tok, &buf);
420     ww.Write(buf);
421   }
422 }
423 
IfFunc(const vector<Value * > & args,Evaluator * ev,string * s)424 void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
425   const string&& cond = args[0]->Eval(ev);
426   if (cond.empty()) {
427     if (args.size() > 2)
428       args[2]->Eval(ev, s);
429   } else {
430     args[1]->Eval(ev, s);
431   }
432 }
433 
AndFunc(const vector<Value * > & args,Evaluator * ev,string * s)434 void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
435   string cond;
436   for (Value* a : args) {
437     cond = a->Eval(ev);
438     if (cond.empty())
439       return;
440   }
441   if (!cond.empty()) {
442     *s += cond;
443   }
444 }
445 
OrFunc(const vector<Value * > & args,Evaluator * ev,string * s)446 void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
447   for (Value* a : args) {
448     const string&& cond = a->Eval(ev);
449     if (!cond.empty()) {
450       *s += cond;
451       return;
452     }
453   }
454 }
455 
ValueFunc(const vector<Value * > & args,Evaluator * ev,string * s)456 void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
457   const string&& var_name = args[0]->Eval(ev);
458   Var* var = ev->LookupVar(Intern(var_name));
459   AppendString(var->String().as_string(), s);
460 }
461 
EvalFunc(const vector<Value * > & args,Evaluator * ev,string *)462 void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
463   // TODO: eval leaks everything... for now.
464   // const string text = args[0]->Eval(ev);
465   ev->CheckStack();
466   string* text = new string;
467   args[0]->Eval(ev, text);
468   if (ev->avoid_io()) {
469     KATI_WARN_LOC(ev->loc(),
470                   "*warning*: $(eval) in a recipe is not recommended: %s",
471                   text->c_str());
472   }
473   vector<Stmt*> stmts;
474   Parse(*text, ev->loc(), &stmts);
475   for (Stmt* stmt : stmts) {
476     LOG("%s", stmt->DebugString().c_str());
477     stmt->Eval(ev);
478     // delete stmt;
479   }
480 }
481 
482 //#define TEST_FIND_EMULATOR
483 
484 // A hack for Android build. We need to evaluate things like $((3+4))
485 // when we emit ninja file, because the result of such expressions
486 // will be passed to other make functions.
487 // TODO: Maybe we should introduce a helper binary which evaluate
488 // make expressions at ninja-time.
HasNoIoInShellScript(const string & cmd)489 static bool HasNoIoInShellScript(const string& cmd) {
490   if (cmd.empty())
491     return true;
492   if (HasPrefix(cmd, "echo $((") && cmd[cmd.size() - 1] == ')')
493     return true;
494   return false;
495 }
496 
ShellFuncImpl(const string & shell,const string & shellflag,const string & cmd,const Loc & loc,string * s,FindCommand ** fc)497 static void ShellFuncImpl(const string& shell,
498                           const string& shellflag,
499                           const string& cmd,
500                           const Loc& loc,
501                           string* s,
502                           FindCommand** fc) {
503   LOG("ShellFunc: %s", cmd.c_str());
504 
505 #ifdef TEST_FIND_EMULATOR
506   bool need_check = false;
507   string out2;
508 #endif
509   if (FindEmulator::Get()) {
510     *fc = new FindCommand();
511     if ((*fc)->Parse(cmd)) {
512 #ifdef TEST_FIND_EMULATOR
513       if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, &out2)) {
514         need_check = true;
515       }
516 #else
517       if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, s)) {
518         return;
519       }
520 #endif
521     }
522     delete *fc;
523     *fc = NULL;
524   }
525 
526   COLLECT_STATS_WITH_SLOW_REPORT("func shell time", cmd.c_str());
527   RunCommand(shell, shellflag, cmd, RedirectStderr::NONE, s);
528   FormatForCommandSubstitution(s);
529 
530 #ifdef TEST_FIND_EMULATOR
531   if (need_check) {
532     if (*s != out2) {
533       ERROR("FindEmulator is broken: %s\n%s\nvs\n%s", cmd.c_str(), s->c_str(),
534             out2.c_str());
535     }
536   }
537 #endif
538 }
539 
540 static vector<CommandResult*> g_command_results;
541 
ShouldStoreCommandResult(StringPiece cmd)542 bool ShouldStoreCommandResult(StringPiece cmd) {
543   // We really just want to ignore this one, or remove BUILD_DATETIME from
544   // Android completely
545   if (cmd == "date +%s")
546     return false;
547 
548   Pattern pat(g_flags.ignore_dirty_pattern);
549   Pattern nopat(g_flags.no_ignore_dirty_pattern);
550   for (StringPiece tok : WordScanner(cmd)) {
551     if (pat.Match(tok) && !nopat.Match(tok)) {
552       return false;
553     }
554   }
555 
556   return true;
557 }
558 
ShellFunc(const vector<Value * > & args,Evaluator * ev,string * s)559 void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
560   string cmd = args[0]->Eval(ev);
561   if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
562     if (ev->eval_depth() > 1) {
563       ERROR_LOC(ev->loc(),
564                 "kati doesn't support passing results of $(shell) "
565                 "to other make constructs: %s",
566                 cmd.c_str());
567     }
568     StripShellComment(&cmd);
569     *s += "$(";
570     *s += cmd;
571     *s += ")";
572     return;
573   }
574 
575   const string&& shell = ev->GetShell();
576   const string&& shellflag = ev->GetShellFlag();
577 
578   string out;
579   FindCommand* fc = NULL;
580   ShellFuncImpl(shell, shellflag, cmd, ev->loc(), &out, &fc);
581   if (ShouldStoreCommandResult(cmd)) {
582     CommandResult* cr = new CommandResult();
583     cr->op = (fc == NULL) ? CommandOp::SHELL : CommandOp::FIND,
584     cr->shell = shell;
585     cr->shellflag = shellflag;
586     cr->cmd = cmd;
587     cr->find.reset(fc);
588     cr->result = out;
589     g_command_results.push_back(cr);
590   }
591   *s += out;
592 }
593 
CallFunc(const vector<Value * > & args,Evaluator * ev,string * s)594 void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
595   static const Symbol tmpvar_names[] = {
596       Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
597       Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")};
598 
599   ev->CheckStack();
600   const string&& func_name_buf = args[0]->Eval(ev);
601   const StringPiece func_name = TrimSpace(func_name_buf);
602   Var* func = ev->LookupVar(Intern(func_name));
603   if (!func->IsDefined()) {
604     KATI_WARN_LOC(ev->loc(), "*warning*: undefined user function: %s",
605                   func_name.as_string().c_str());
606   }
607   vector<unique_ptr<SimpleVar>> av;
608   for (size_t i = 1; i < args.size(); i++) {
609     unique_ptr<SimpleVar> s(
610         new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
611     av.push_back(move(s));
612   }
613   vector<unique_ptr<ScopedGlobalVar>> sv;
614   for (size_t i = 1;; i++) {
615     string s;
616     Symbol tmpvar_name_sym(Symbol::IsUninitialized{});
617     if (i < sizeof(tmpvar_names) / sizeof(tmpvar_names[0])) {
618       tmpvar_name_sym = tmpvar_names[i];
619     } else {
620       s = StringPrintf("%d", i);
621       tmpvar_name_sym = Intern(s);
622     }
623     if (i < args.size()) {
624       sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
625     } else {
626       // We need to blank further automatic vars
627       Var* v = ev->LookupVar(tmpvar_name_sym);
628       if (!v->IsDefined())
629         break;
630       if (v->Origin() != VarOrigin::AUTOMATIC)
631         break;
632 
633       av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
634       sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
635     }
636   }
637 
638   ev->DecrementEvalDepth();
639   func->Eval(ev, s);
640   ev->IncrementEvalDepth();
641 }
642 
ForeachFunc(const vector<Value * > & args,Evaluator * ev,string * s)643 void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
644   const string&& varname = args[0]->Eval(ev);
645   const string&& list = args[1]->Eval(ev);
646   ev->DecrementEvalDepth();
647   WordWriter ww(s);
648   for (StringPiece tok : WordScanner(list)) {
649     unique_ptr<SimpleVar> v(
650         new SimpleVar(tok.as_string(), VarOrigin::AUTOMATIC));
651     ScopedGlobalVar sv(Intern(varname), v.get());
652     ww.MaybeAddWhitespace();
653     args[2]->Eval(ev, s);
654   }
655   ev->IncrementEvalDepth();
656 }
657 
OriginFunc(const vector<Value * > & args,Evaluator * ev,string * s)658 void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
659   const string&& var_name = args[0]->Eval(ev);
660   Var* var = ev->LookupVar(Intern(var_name));
661   *s += GetOriginStr(var->Origin());
662 }
663 
FlavorFunc(const vector<Value * > & args,Evaluator * ev,string * s)664 void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
665   const string&& var_name = args[0]->Eval(ev);
666   Var* var = ev->LookupVar(Intern(var_name));
667   *s += var->Flavor();
668 }
669 
InfoFunc(const vector<Value * > & args,Evaluator * ev,string *)670 void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
671   const string&& a = args[0]->Eval(ev);
672   if (ev->avoid_io()) {
673     ev->add_delayed_output_command(
674         StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
675     return;
676   }
677   printf("%s\n", a.c_str());
678   fflush(stdout);
679 }
680 
WarningFunc(const vector<Value * > & args,Evaluator * ev,string *)681 void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
682   const string&& a = args[0]->Eval(ev);
683   if (ev->avoid_io()) {
684     ev->add_delayed_output_command(StringPrintf(
685         "echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
686     return;
687   }
688   WARN_LOC(ev->loc(), "%s", a.c_str());
689 }
690 
ErrorFunc(const vector<Value * > & args,Evaluator * ev,string *)691 void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
692   const string&& a = args[0]->Eval(ev);
693   if (ev->avoid_io()) {
694     ev->add_delayed_output_command(
695         StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
696                      LOCF(ev->loc()), EchoEscape(a).c_str()));
697     return;
698   }
699   ev->Error(StringPrintf("*** %s.", a.c_str()));
700 }
701 
FileReadFunc(Evaluator * ev,const string & filename,string * s)702 static void FileReadFunc(Evaluator* ev, const string& filename, string* s) {
703   int fd = open(filename.c_str(), O_RDONLY);
704   if (fd < 0) {
705     if (errno == ENOENT) {
706       if (ShouldStoreCommandResult(filename)) {
707         CommandResult* cr = new CommandResult();
708         cr->op = CommandOp::READ_MISSING;
709         cr->cmd = filename;
710         g_command_results.push_back(cr);
711       }
712       return;
713     } else {
714       ev->Error("*** open failed.");
715     }
716   }
717 
718   struct stat st;
719   if (fstat(fd, &st) < 0) {
720     ev->Error("*** fstat failed.");
721   }
722 
723   size_t len = st.st_size;
724   string out;
725   out.resize(len);
726   ssize_t r = HANDLE_EINTR(read(fd, &out[0], len));
727   if (r != static_cast<ssize_t>(len)) {
728     ev->Error("*** read failed.");
729   }
730 
731   if (close(fd) < 0) {
732     ev->Error("*** close failed.");
733   }
734 
735   if (out.back() == '\n') {
736     out.pop_back();
737   }
738 
739   if (ShouldStoreCommandResult(filename)) {
740     CommandResult* cr = new CommandResult();
741     cr->op = CommandOp::READ;
742     cr->cmd = filename;
743     g_command_results.push_back(cr);
744   }
745   *s += out;
746 }
747 
FileWriteFunc(Evaluator * ev,const string & filename,bool append,string text)748 static void FileWriteFunc(Evaluator* ev,
749                           const string& filename,
750                           bool append,
751                           string text) {
752   FILE* f = fopen(filename.c_str(), append ? "ab" : "wb");
753   if (f == NULL) {
754     ev->Error("*** fopen failed.");
755   }
756 
757   if (fwrite(&text[0], text.size(), 1, f) != 1) {
758     ev->Error("*** fwrite failed.");
759   }
760 
761   if (fclose(f) != 0) {
762     ev->Error("*** fclose failed.");
763   }
764 
765   if (ShouldStoreCommandResult(filename)) {
766     CommandResult* cr = new CommandResult();
767     cr->op = CommandOp::WRITE;
768     cr->cmd = filename;
769     cr->result = text;
770     g_command_results.push_back(cr);
771   }
772 }
773 
FileFunc(const vector<Value * > & args,Evaluator * ev,string * s)774 void FileFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
775   if (ev->avoid_io()) {
776     ev->Error("*** $(file ...) is not supported in rules.");
777   }
778 
779   string arg = args[0]->Eval(ev);
780   StringPiece filename = TrimSpace(arg);
781 
782   if (filename.size() <= 1) {
783     ev->Error("*** Missing filename");
784   }
785 
786   if (filename[0] == '<') {
787     filename = TrimLeftSpace(filename.substr(1));
788     if (!filename.size()) {
789       ev->Error("*** Missing filename");
790     }
791     if (args.size() > 1) {
792       ev->Error("*** invalid argument");
793     }
794 
795     FileReadFunc(ev, filename.as_string(), s);
796   } else if (filename[0] == '>') {
797     bool append = false;
798     if (filename[1] == '>') {
799       append = true;
800       filename = filename.substr(2);
801     } else {
802       filename = filename.substr(1);
803     }
804     filename = TrimLeftSpace(filename);
805     if (!filename.size()) {
806       ev->Error("*** Missing filename");
807     }
808 
809     string text;
810     if (args.size() > 1) {
811       text = args[1]->Eval(ev);
812       if (text.size() == 0 || text.back() != '\n') {
813         text.push_back('\n');
814       }
815     }
816 
817     FileWriteFunc(ev, filename.as_string(), append, text);
818   } else {
819     ev->Error(StringPrintf("*** Invalid file operation: %s.  Stop.",
820                            filename.as_string().c_str()));
821   }
822 }
823 
DeprecatedVarFunc(const vector<Value * > & args,Evaluator * ev,string *)824 void DeprecatedVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
825   string vars_str = args[0]->Eval(ev);
826   string msg;
827 
828   if (args.size() == 2) {
829     msg = ". " + args[1]->Eval(ev);
830   }
831 
832   if (ev->avoid_io()) {
833     ev->Error("*** $(KATI_deprecated_var ...) is not supported in rules.");
834   }
835 
836   for (StringPiece var : WordScanner(vars_str)) {
837     Symbol sym = Intern(var);
838     Var* v = ev->PeekVar(sym);
839     if (!v->IsDefined()) {
840       v = new SimpleVar(VarOrigin::FILE);
841       sym.SetGlobalVar(v, false, nullptr);
842     }
843 
844     if (v->Deprecated()) {
845       ev->Error(
846           StringPrintf("*** Cannot call KATI_deprecated_var on already "
847                        "deprecated variable: %s.",
848                        sym.c_str()));
849     } else if (v->Obsolete()) {
850       ev->Error(
851           StringPrintf("*** Cannot call KATI_deprecated_var on already "
852                        "obsolete variable: %s.",
853                        sym.c_str()));
854     }
855 
856     v->SetDeprecated(msg);
857   }
858 }
859 
ObsoleteVarFunc(const vector<Value * > & args,Evaluator * ev,string *)860 void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
861   string vars_str = args[0]->Eval(ev);
862   string msg;
863 
864   if (args.size() == 2) {
865     msg = ". " + args[1]->Eval(ev);
866   }
867 
868   if (ev->avoid_io()) {
869     ev->Error("*** $(KATI_obsolete_var ...) is not supported in rules.");
870   }
871 
872   for (StringPiece var : WordScanner(vars_str)) {
873     Symbol sym = Intern(var);
874     Var* v = ev->PeekVar(sym);
875     if (!v->IsDefined()) {
876       v = new SimpleVar(VarOrigin::FILE);
877       sym.SetGlobalVar(v, false, nullptr);
878     }
879 
880     if (v->Deprecated()) {
881       ev->Error(
882           StringPrintf("*** Cannot call KATI_obsolete_var on already "
883                        "deprecated variable: %s.",
884                        sym.c_str()));
885     } else if (v->Obsolete()) {
886       ev->Error(StringPrintf(
887           "*** Cannot call KATI_obsolete_var on already obsolete variable: %s.",
888           sym.c_str()));
889     }
890 
891     v->SetObsolete(msg);
892   }
893 }
894 
DeprecateExportFunc(const vector<Value * > & args,Evaluator * ev,string *)895 void DeprecateExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
896   string msg = ". " + args[0]->Eval(ev);
897 
898   if (ev->avoid_io()) {
899     ev->Error("*** $(KATI_deprecate_export) is not supported in rules.");
900   }
901 
902   if (ev->ExportObsolete()) {
903     ev->Error("*** Export is already obsolete.");
904   } else if (ev->ExportDeprecated()) {
905     ev->Error("*** Export is already deprecated.");
906   }
907 
908   ev->SetExportDeprecated(msg);
909 }
910 
ObsoleteExportFunc(const vector<Value * > & args,Evaluator * ev,string *)911 void ObsoleteExportFunc(const vector<Value*>& args, Evaluator* ev, string*) {
912   string msg = ". " + args[0]->Eval(ev);
913 
914   if (ev->avoid_io()) {
915     ev->Error("*** $(KATI_obsolete_export) is not supported in rules.");
916   }
917 
918   if (ev->ExportObsolete()) {
919     ev->Error("*** Export is already obsolete.");
920   }
921 
922   ev->SetExportObsolete(msg);
923 }
924 
925 FuncInfo g_func_infos[] = {
926     {"patsubst", &PatsubstFunc, 3, 3, false, false},
927     {"strip", &StripFunc, 1, 1, false, false},
928     {"subst", &SubstFunc, 3, 3, false, false},
929     {"findstring", &FindstringFunc, 2, 2, false, false},
930     {"filter", &FilterFunc, 2, 2, false, false},
931     {"filter-out", &FilterOutFunc, 2, 2, false, false},
932     {"sort", &SortFunc, 1, 1, false, false},
933     {"word", &WordFunc, 2, 2, false, false},
934     {"wordlist", &WordlistFunc, 3, 3, false, false},
935     {"words", &WordsFunc, 1, 1, false, false},
936     {"firstword", &FirstwordFunc, 1, 1, false, false},
937     {"lastword", &LastwordFunc, 1, 1, false, false},
938 
939     {"join", &JoinFunc, 2, 2, false, false},
940     {"wildcard", &WildcardFunc, 1, 1, false, false},
941     {"dir", &DirFunc, 1, 1, false, false},
942     {"notdir", &NotdirFunc, 1, 1, false, false},
943     {"suffix", &SuffixFunc, 1, 1, false, false},
944     {"basename", &BasenameFunc, 1, 1, false, false},
945     {"addsuffix", &AddsuffixFunc, 2, 2, false, false},
946     {"addprefix", &AddprefixFunc, 2, 2, false, false},
947     {"realpath", &RealpathFunc, 1, 1, false, false},
948     {"abspath", &AbspathFunc, 1, 1, false, false},
949 
950     {"if", &IfFunc, 3, 2, false, true},
951     {"and", &AndFunc, 0, 0, true, false},
952     {"or", &OrFunc, 0, 0, true, false},
953 
954     {"value", &ValueFunc, 1, 1, false, false},
955     {"eval", &EvalFunc, 1, 1, false, false},
956     {"shell", &ShellFunc, 1, 1, false, false},
957     {"call", &CallFunc, 0, 0, false, false},
958     {"foreach", &ForeachFunc, 3, 3, false, false},
959 
960     {"origin", &OriginFunc, 1, 1, false, false},
961     {"flavor", &FlavorFunc, 1, 1, false, false},
962 
963     {"info", &InfoFunc, 1, 1, false, false},
964     {"warning", &WarningFunc, 1, 1, false, false},
965     {"error", &ErrorFunc, 1, 1, false, false},
966 
967     {"file", &FileFunc, 2, 1, false, false},
968 
969     /* Kati custom extension functions */
970     {"KATI_deprecated_var", &DeprecatedVarFunc, 2, 1, false, false},
971     {"KATI_obsolete_var", &ObsoleteVarFunc, 2, 1, false, false},
972     {"KATI_deprecate_export", &DeprecateExportFunc, 1, 1, false, false},
973     {"KATI_obsolete_export", &ObsoleteExportFunc, 1, 1, false, false},
974 };
975 
976 unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
977 
978 }  // namespace
979 
InitFuncTable()980 void InitFuncTable() {
981   g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
982   for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
983     FuncInfo* fi = &g_func_infos[i];
984     bool ok = g_func_info_map->emplace(fi->name, fi).second;
985     CHECK(ok);
986   }
987 }
988 
QuitFuncTable()989 void QuitFuncTable() {
990   delete g_func_info_map;
991 }
992 
GetFuncInfo(StringPiece name)993 FuncInfo* GetFuncInfo(StringPiece name) {
994   auto found = g_func_info_map->find(name);
995   if (found == g_func_info_map->end())
996     return NULL;
997   return found->second;
998 }
999 
GetShellCommandResults()1000 const vector<CommandResult*>& GetShellCommandResults() {
1001   return g_command_results;
1002 }
1003