blob: c033d3b34812d798756265edee7e8b569f675035 [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// 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
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "func.h"
18
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090019#include <errno.h>
Dan Willemsenf06d8012016-10-03 00:16:07 -070020#include <fcntl.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090021#include <limits.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include <stdio.h>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090023#include <stdlib.h>
Dan Willemsenf06d8012016-10-03 00:16:07 -070024#include <sys/stat.h>
Shinichiro Hamaji62b16e72015-07-02 01:42:31 +090025#include <unistd.h>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090026
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +090027#include <algorithm>
Shinichiro Hamajid5271452015-06-17 18:50:03 +090028#include <iterator>
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090029#include <memory>
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090030#include <unordered_map>
31
Shinichiro Hamaji9619b362015-06-16 16:13:25 +090032#include "eval.h"
Shinichiro Hamaji94d6f2a2015-07-05 05:32:25 +090033#include "fileutil.h"
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +090034#include "find.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090035#include "log.h"
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +090036#include "parser.h"
Shinichiro Hamaji0d8e79b2015-06-30 03:29:35 +090037#include "stats.h"
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090038#include "stmt.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090039#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090040#include "symtab.h"
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +090041#include "var.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090042
43namespace {
44
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090045// TODO: This code is very similar to
46// NinjaGenerator::TranslateCommand. Factor them out.
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090047void StripShellComment(string* cmd) {
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090048 if (cmd->find('#') == string::npos)
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090049 return;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090050
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090051 string res;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090052 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)) {
Shinichiro Hamaji212b7a52015-10-05 17:02:29 +090063 while (in[1] && *in != '\n')
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090064 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 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090077 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090078 break;
79
80 case '\\':
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090081 res += '\\';
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090082 break;
83
84 default:
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090085 res += *in;
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090086 }
87
88 if (*in == '\\') {
89 prev_backslash = !prev_backslash;
90 } else {
91 prev_backslash = false;
92 }
93
94 prev_char = *in;
95 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +090096 cmd->swap(res);
Shinichiro Hamajifc14d5f2015-07-28 17:07:57 +090097}
98
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +090099void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900100 const string&& pat_str = args[0]->Eval(ev);
101 const string&& repl = args[1]->Eval(ev);
102 const string&& str = args[2]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900103 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900104 Pattern pat(pat_str);
105 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900106 ww.MaybeAddWhitespace();
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900107 pat.AppendSubst(tok, repl, s);
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900108 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900109}
110
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900111void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900112 const string&& str = args[0]->Eval(ev);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900113 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900114 for (StringPiece tok : WordScanner(str)) {
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900115 ww.Write(tok);
116 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900117}
118
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900119void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900120 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;
Shinichiro Hamaji5af931d2015-07-06 15:37:59 +0900126 return;
127 }
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900128 size_t index = 0;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900129 while (index < str.size()) {
130 size_t found = str.find(pat, index);
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900131 if (found == string::npos)
132 break;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900133 AppendString(StringPiece(str).substr(index, found - index), s);
134 AppendString(repl, s);
135 index = found + pat.size();
Shinichiro Hamaji37591ce2015-06-16 19:36:05 +0900136 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900137 AppendString(StringPiece(str).substr(index), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900138}
139
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900140void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900141 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);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900145}
146
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900147void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900148 const string&& pat_buf = args[0]->Eval(ev);
149 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900150 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900151 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900152 pats.push_back(Pattern(pat));
153 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900154 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900155 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900156 for (const Pattern& pat : pats) {
157 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900158 ww.Write(tok);
159 break;
160 }
161 }
162 }
163}
164
165void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900166 const string&& pat_buf = args[0]->Eval(ev);
167 const string&& text = args[1]->Eval(ev);
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900168 vector<Pattern> pats;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900169 for (StringPiece pat : WordScanner(pat_buf)) {
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900170 pats.push_back(Pattern(pat));
171 }
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900172 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900173 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900174 bool matched = false;
Shinichiro Hamajia6a17a42015-06-18 20:11:19 +0900175 for (const Pattern& pat : pats) {
176 if (pat.Match(tok)) {
Shinichiro Hamaji00cc6582015-06-17 18:12:46 +0900177 matched = true;
178 break;
179 }
180 }
181 if (!matched)
182 ww.Write(tok);
183 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900184}
185
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900186void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900187 string list;
188 args[0]->Eval(ev, &list);
189 COLLECT_STATS("func sort time");
Shinichiro Hamaji2d353a02016-02-15 18:24:42 +0900190 // TODO(hamaji): Probably we could use a faster string-specific sort
191 // algorithm.
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900192 vector<StringPiece> toks;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900193 WordScanner(list).Split(&toks);
Shinichiro Hamaji14436892016-02-12 16:32:42 +0900194 stable_sort(toks.begin(), toks.end());
Shinichiro Hamajid87e59e2015-06-17 18:18:34 +0900195 WordWriter ww(s);
196 StringPiece prev;
197 for (StringPiece tok : toks) {
198 if (prev != tok) {
199 ww.Write(tok);
200 prev = tok;
201 }
202 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900203}
204
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900205static 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;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900213}
214
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900215void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900216 const string&& n_str = args[0]->Eval(ev);
217 int n = GetNumericValueForFunc(n_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900218 if (n < 0) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700219 ev->Error(
220 StringPrintf("*** non-numeric first argument to `word' function: '%s'.",
221 n_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900222 }
223 if (n == 0) {
224 ev->Error("*** first argument to `word' function must be greater than 0.");
225 }
226
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900227 const string&& text = args[1]->Eval(ev);
228 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900229 n--;
230 if (n == 0) {
231 AppendString(tok, s);
232 break;
233 }
234 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900235}
236
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900237void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900238 const string&& s_str = args[0]->Eval(ev);
239 int si = GetNumericValueForFunc(s_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900240 if (si < 0) {
241 ev->Error(StringPrintf(
242 "*** non-numeric first argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900243 s_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900244 }
245 if (si == 0) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700246 ev->Error(
247 StringPrintf("*** invalid first argument to `wordlist' function: %s`",
248 s_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900249 }
250
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900251 const string&& e_str = args[1]->Eval(ev);
252 int ei = GetNumericValueForFunc(e_str);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900253 if (ei < 0) {
254 ev->Error(StringPrintf(
255 "*** non-numeric second argument to `wordlist' function: '%s'.",
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900256 e_str.c_str()));
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900257 }
258
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900259 const string&& text = args[2]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900260 int i = 0;
261 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900262 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900263 i++;
264 if (si <= i && i <= ei) {
265 ww.Write(tok);
266 }
267 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900268}
269
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900270void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900271 const string&& text = args[0]->Eval(ev);
272 WordScanner ws(text);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900273 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;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900279}
280
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900281void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900282 const string&& text = args[0]->Eval(ev);
283 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900284 AppendString(tok, s);
285 return;
286 }
287}
288
289void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900290 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900291 StringPiece last;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900292 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamajid5271452015-06-17 18:50:03 +0900293 last = tok;
294 }
295 AppendString(last, s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900296}
297
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900298void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900299 const string&& list1 = args[0]->Eval(ev);
300 const string&& list2 = args[1]->Eval(ev);
301 WordScanner ws1(list1);
302 WordScanner ws2(list2);
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900303 WordWriter ww(s);
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900304 WordScanner::Iterator iter1, iter2;
305 for (iter1 = ws1.begin(), iter2 = ws2.begin();
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700306 iter1 != ws1.end() && iter2 != ws2.end(); ++iter1, ++iter2) {
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900307 ww.Write(*iter1);
308 // Use |AppendString| not to append extra ' '.
309 AppendString(*iter2, s);
310 }
Shinichiro Hamaji71e79342016-06-07 14:05:48 +0900311 for (; iter1 != ws1.end(); ++iter1)
312 ww.Write(*iter1);
313 for (; iter2 != ws2.end(); ++iter2)
314 ww.Write(*iter2);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900315}
316
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900317void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900318 const string&& pat = args[0]->Eval(ev);
Shinichiro Hamajib67a2992015-11-07 14:11:09 +0900319 COLLECT_STATS("func wildcard time");
Shinichiro Hamaji7409aee2015-07-28 14:52:37 +0900320 // Note GNU make does not delay the execution of $(wildcard) so we
321 // do not need to check avoid_io here.
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900322 WordWriter ww(s);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900323 vector<string>* files;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900324 for (StringPiece tok : WordScanner(pat)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900325 ScopedTerminator st(tok);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900326 Glob(tok.data(), &files);
Shinichiro Hamaji0e3873a2015-07-05 15:48:28 +0900327 for (const string& file : *files) {
Shinichiro Hamajife97c412015-06-29 16:57:57 +0900328 ww.Write(file);
329 }
Shinichiro Hamaji284f3d12015-06-17 19:29:01 +0900330 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900331}
332
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900333void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900334 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900335 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900336 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900337 ww.Write(Dirname(tok));
Shinichiro Hamaji55906852015-06-29 16:40:33 +0900338 s->push_back('/');
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900339 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900340}
341
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900342void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900343 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900344 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900345 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900346 if (tok == "/") {
Shinichiro Hamaji388e8582015-07-03 16:51:46 +0900347 ww.Write(StringPiece(""));
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900348 } else {
349 ww.Write(Basename(tok));
350 }
351 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900352}
353
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900354void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900355 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900356 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900357 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900358 StringPiece suf = GetExt(tok);
359 if (!suf.empty())
360 ww.Write(suf);
361 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900362}
363
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900364void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900365 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900366 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900367 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji67f9a702015-06-18 06:00:57 +0900368 ww.Write(StripExt(tok));
369 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900370}
371
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900372void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900373 const string&& suf = args[0]->Eval(ev);
374 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900375 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900376 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900377 ww.Write(tok);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900378 *s += suf;
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900379 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900380}
381
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900382void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900383 const string&& pre = args[0]->Eval(ev);
384 const string&& text = args[1]->Eval(ev);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900385 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900386 for (StringPiece tok : WordScanner(text)) {
387 ww.Write(pre);
Shinichiro Hamaji5d694f02015-06-18 06:05:36 +0900388 AppendString(tok, s);
389 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900390}
391
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900392void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900393 const string&& text = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900394 if (ev->avoid_io()) {
Shinichiro Hamaji71cf60b2015-10-08 18:00:07 +0900395 *s += "$(";
396 string kati_binary;
397 GetExecutablePath(&kati_binary);
398 *s += kati_binary;
399 *s += " --realpath ";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900400 *s += text;
Shinichiro Hamaji65dce542015-07-28 15:39:03 +0900401 *s += " 2> /dev/null)";
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900402 return;
403 }
404
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900405 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900406 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8f68bd32015-06-18 11:01:51 +0900407 ScopedTerminator st(tok);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900408 char buf[PATH_MAX];
409 if (realpath(tok.data(), buf))
Shinichiro Hamajicb4724e2015-10-08 17:52:49 +0900410 ww.Write(buf);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900411 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900412}
413
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900414void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900415 const string&& text = args[0]->Eval(ev);
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900416 WordWriter ww(s);
417 string buf;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900418 for (StringPiece tok : WordScanner(text)) {
Shinichiro Hamaji8a963582015-06-18 07:05:58 +0900419 AbsPath(tok, &buf);
420 ww.Write(buf);
421 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900422}
423
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900424void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900425 const string&& cond = args[0]->Eval(ev);
426 if (cond.empty()) {
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900427 if (args.size() > 2)
428 args[2]->Eval(ev, s);
429 } else {
430 args[1]->Eval(ev, s);
431 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900432}
433
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900434void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900435 string cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900436 for (Value* a : args) {
437 cond = a->Eval(ev);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900438 if (cond.empty())
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900439 return;
440 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900441 if (!cond.empty()) {
442 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900443 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900444}
445
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900446void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
447 for (Value* a : args) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900448 const string&& cond = a->Eval(ev);
449 if (!cond.empty()) {
450 *s += cond;
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900451 return;
452 }
453 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900454}
455
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900456void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900457 const string&& var_name = args[0]->Eval(ev);
458 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamaji81699be2015-06-22 18:07:38 +0900459 AppendString(var->String().as_string(), s);
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900460}
461
Shinichiro Hamajifead3b72015-06-18 15:31:15 +0900462void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900463 // TODO: eval leaks everything... for now.
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700464 // const string text = args[0]->Eval(ev);
Dan Willemsen36e57292017-10-09 11:23:32 -0700465 ev->CheckStack();
Shinichiro Hamaji76ff9832015-06-18 17:11:22 +0900466 string* text = new string;
467 args[0]->Eval(ev, text);
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900468 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700469 KATI_WARN_LOC(ev->loc(),
470 "*warning*: $(eval) in a recipe is not recommended: %s",
Dan Willemsene41c7552017-02-22 14:31:16 -0800471 text->c_str());
Shinichiro Hamaji644d6b92015-11-17 14:47:56 +0900472 }
Shinichiro Hamaji645cca72015-09-24 17:04:21 +0900473 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);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700478 // delete stmt;
Shinichiro Hamaji80456fb2015-06-18 14:56:10 +0900479 }
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900480}
481
Shinichiro Hamaji5f57a992015-06-30 19:39:39 +0900482//#define TEST_FIND_EMULATOR
483
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900484// 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.
489static bool HasNoIoInShellScript(const string& cmd) {
490 if (cmd.empty())
491 return true;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700492 if (HasPrefix(cmd, "echo $((") && cmd[cmd.size() - 1] == ')')
Shinichiro Hamaji68e712b2015-07-17 06:11:08 +0900493 return true;
494 return false;
495}
496
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700497static void ShellFuncImpl(const string& shell,
498 const string& shellflag,
499 const string& cmd,
500 const Loc& loc,
501 string* s,
Dan Willemsen692e64e2017-02-22 15:38:33 -0800502 FindCommand** fc) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900503 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
Dan Willemsen692e64e2017-02-22 15:38:33 -0800513 if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, &out2)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900514 need_check = true;
515 }
516#else
Dan Willemsen692e64e2017-02-22 15:38:33 -0800517 if (FindEmulator::Get()->HandleFind(cmd, **fc, loc, s)) {
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900518 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());
Dan Willemsen064be222016-09-30 20:17:14 -0700527 RunCommand(shell, shellflag, cmd, RedirectStderr::NONE, s);
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700528 FormatForCommandSubstitution(s);
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900529
530#ifdef TEST_FIND_EMULATOR
531 if (need_check) {
Dan Willemsen48d6e8c2015-08-05 14:38:34 -0700532 if (*s != out2) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700533 ERROR("FindEmulator is broken: %s\n%s\nvs\n%s", cmd.c_str(), s->c_str(),
534 out2.c_str());
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900535 }
536 }
537#endif
538}
539
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900540static vector<CommandResult*> g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900541
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900542bool ShouldStoreCommandResult(StringPiece cmd) {
Dan Willemsen40e5a3d2016-09-16 19:35:32 -0700543 // We really just want to ignore this one, or remove BUILD_DATETIME from
544 // Android completely
545 if (cmd == "date +%s")
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900546 return false;
Colin Crossf23ae8c2015-11-12 17:05:32 -0800547
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;
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900553 }
554 }
Colin Crossf23ae8c2015-11-12 17:05:32 -0800555
Shinichiro Hamaji180b4092015-08-13 17:11:18 +0900556 return true;
557}
558
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900559void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900560 string cmd = args[0]->Eval(ev);
561 if (ev->avoid_io() && !HasNoIoInShellScript(cmd)) {
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900562 if (ev->eval_depth() > 1) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700563 ERROR_LOC(ev->loc(),
564 "kati doesn't support passing results of $(shell) "
Dan Willemsene41c7552017-02-22 14:31:16 -0800565 "to other make constructs: %s",
566 cmd.c_str());
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900567 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900568 StripShellComment(&cmd);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900569 *s += "$(";
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900570 *s += cmd;
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900571 *s += ")";
572 return;
573 }
574
Dan Willemsen064be222016-09-30 20:17:14 -0700575 const string&& shell = ev->GetShell();
576 const string&& shellflag = ev->GetShellFlag();
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900577
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900578 string out;
579 FindCommand* fc = NULL;
Dan Willemsen692e64e2017-02-22 15:38:33 -0800580 ShellFuncImpl(shell, shellflag, cmd, ev->loc(), &out, &fc);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900581 if (ShouldStoreCommandResult(cmd)) {
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900582 CommandResult* cr = new CommandResult();
Dan Willemsenf06d8012016-10-03 00:16:07 -0700583 cr->op = (fc == NULL) ? CommandOp::SHELL : CommandOp::FIND,
Stefan Beckerd4f28712016-04-07 13:29:36 +0300584 cr->shell = shell;
Dan Willemsen064be222016-09-30 20:17:14 -0700585 cr->shellflag = shellflag;
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900586 cr->cmd = cmd;
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +0900587 cr->find.reset(fc);
588 cr->result = out;
589 g_command_results.push_back(cr);
Shinichiro Hamajifcf1b762015-06-18 03:43:54 +0900590 }
591 *s += out;
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900592}
593
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900594void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900595 static const Symbol tmpvar_names[] = {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700596 Intern("0"), Intern("1"), Intern("2"), Intern("3"), Intern("4"),
597 Intern("5"), Intern("6"), Intern("7"), Intern("8"), Intern("9")};
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900598
Dan Willemsen36e57292017-10-09 11:23:32 -0700599 ev->CheckStack();
Shinichiro Hamajid8d43ea2016-04-27 16:10:47 +0900600 const string&& func_name_buf = args[0]->Eval(ev);
601 const StringPiece func_name = TrimSpace(func_name_buf);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900602 Var* func = ev->LookupVar(Intern(func_name));
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900603 if (!func->IsDefined()) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800604 KATI_WARN_LOC(ev->loc(), "*warning*: undefined user function: %s",
605 func_name.as_string().c_str());
Shinichiro Hamaji433ad992015-11-17 15:43:07 +0900606 }
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900607 vector<unique_ptr<SimpleVar>> av;
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900608 for (size_t i = 1; i < args.size(); i++) {
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900609 unique_ptr<SimpleVar> s(
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900610 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900611 av.push_back(move(s));
612 }
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900613 vector<unique_ptr<ScopedGlobalVar>> sv;
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700614 for (size_t i = 1;; i++) {
Colin Cross580cc1f2015-07-27 13:18:18 -0700615 string s;
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900616 Symbol tmpvar_name_sym(Symbol::IsUninitialized{});
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700617 if (i < sizeof(tmpvar_names) / sizeof(tmpvar_names[0])) {
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900618 tmpvar_name_sym = tmpvar_names[i];
Colin Cross580cc1f2015-07-27 13:18:18 -0700619 } else {
620 s = StringPrintf("%d", i);
Shinichiro Hamajif3c9bbc2016-02-08 18:47:26 +0900621 tmpvar_name_sym = Intern(s);
Colin Cross580cc1f2015-07-27 13:18:18 -0700622 }
Dan Willemsenb4467962015-08-06 23:59:22 -0700623 if (i < args.size()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700624 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700625 } else {
626 // We need to blank further automatic vars
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700627 Var* v = ev->LookupVar(tmpvar_name_sym);
628 if (!v->IsDefined())
629 break;
630 if (v->Origin() != VarOrigin::AUTOMATIC)
631 break;
Dan Willemsenb4467962015-08-06 23:59:22 -0700632
Shinichiro Hamajie978a892015-08-17 16:53:40 +0900633 av.emplace_back(new SimpleVar("", VarOrigin::AUTOMATIC));
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700634 sv.emplace_back(new ScopedGlobalVar(tmpvar_name_sym, av[i - 1].get()));
Dan Willemsenb4467962015-08-06 23:59:22 -0700635 }
Shinichiro Hamaji5d53bc72015-06-26 08:31:54 +0900636 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900637
638 ev->DecrementEvalDepth();
Shinichiro Hamaji3064f1f2015-06-18 16:32:09 +0900639 func->Eval(ev, s);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900640 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900641}
642
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900643void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900644 const string&& varname = args[0]->Eval(ev);
645 const string&& list = args[1]->Eval(ev);
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900646 ev->DecrementEvalDepth();
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900647 WordWriter ww(s);
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900648 for (StringPiece tok : WordScanner(list)) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700649 unique_ptr<SimpleVar> v(
650 new SimpleVar(tok.as_string(), VarOrigin::AUTOMATIC));
Shinichiro Hamajic9b9e5e2016-02-18 18:18:54 +0900651 ScopedGlobalVar sv(Intern(varname), v.get());
Shinichiro Hamajicf0cd682015-06-18 16:18:13 +0900652 ww.MaybeAddWhitespace();
653 args[2]->Eval(ev, s);
654 }
Shinichiro Hamaji28da2372015-11-30 19:03:53 +0900655 ev->IncrementEvalDepth();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900656}
657
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900658void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900659 const string&& var_name = args[0]->Eval(ev);
660 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajif62e9a72015-06-26 04:18:21 +0900661 *s += GetOriginStr(var->Origin());
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900662}
663
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900664void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900665 const string&& var_name = args[0]->Eval(ev);
666 Var* var = ev->LookupVar(Intern(var_name));
Shinichiro Hamajic22fdb42015-06-22 18:10:40 +0900667 *s += var->Flavor();
Shinichiro Hamaji4f22f5c2015-06-16 16:28:25 +0900668}
669
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900670void InfoFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900671 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900672 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700673 ev->add_delayed_output_command(
674 StringPrintf("echo -e \"%s\"", EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900675 return;
676 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900677 printf("%s\n", a.c_str());
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900678 fflush(stdout);
679}
680
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900681void WarningFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900682 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900683 if (ev->avoid_io()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700684 ev->add_delayed_output_command(StringPrintf(
685 "echo -e \"%s:%d: %s\" 2>&1", LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900686 return;
687 }
Dan Willemsene41c7552017-02-22 14:31:16 -0800688 WARN_LOC(ev->loc(), "%s", a.c_str());
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900689}
690
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900691void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900692 const string&& a = args[0]->Eval(ev);
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900693 if (ev->avoid_io()) {
Shinichiro Hamaji86e11332015-07-28 15:24:17 +0900694 ev->add_delayed_output_command(
Dan Willemsene6f68582015-08-21 11:13:28 -0700695 StringPrintf("echo -e \"%s:%d: *** %s.\" 2>&1 && false",
696 LOCF(ev->loc()), EchoEscape(a).c_str()));
Shinichiro Hamajidf1fc8b2015-06-29 15:45:21 +0900697 return;
698 }
Shinichiro Hamajifb415ad2015-08-14 17:19:34 +0900699 ev->Error(StringPrintf("*** %s.", a.c_str()));
Shinichiro Hamaji9619b362015-06-16 16:13:25 +0900700}
701
Dan Willemsenf06d8012016-10-03 00:16:07 -0700702static 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
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700748static void FileWriteFunc(Evaluator* ev,
749 const string& filename,
750 bool append,
751 string text) {
Dan Willemsenf06d8012016-10-03 00:16:07 -0700752 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
774void 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 {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700819 ev->Error(StringPrintf("*** Invalid file operation: %s. Stop.",
820 filename.as_string().c_str()));
Dan Willemsenf06d8012016-10-03 00:16:07 -0700821 }
822}
823
Dan Willemsen276e96a2017-10-03 14:24:48 -0700824void 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);
Dan Willemsen74197412017-12-27 16:50:09 -0800838 Var* v = ev->PeekVar(sym);
Dan Willemsen276e96a2017-10-03 14:24:48 -0700839 if (!v->IsDefined()) {
840 v = new SimpleVar(VarOrigin::FILE);
841 sym.SetGlobalVar(v, false, nullptr);
842 }
843
844 if (v->Deprecated()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700845 ev->Error(
846 StringPrintf("*** Cannot call KATI_deprecated_var on already "
847 "deprecated variable: %s.",
848 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700849 } else if (v->Obsolete()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700850 ev->Error(
851 StringPrintf("*** Cannot call KATI_deprecated_var on already "
852 "obsolete variable: %s.",
853 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700854 }
855
856 v->SetDeprecated(msg);
857 }
858}
859
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700860void ObsoleteVarFunc(const vector<Value*>& args, Evaluator* ev, string*) {
Dan Willemsen276e96a2017-10-03 14:24:48 -0700861 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);
Dan Willemsen74197412017-12-27 16:50:09 -0800874 Var* v = ev->PeekVar(sym);
Dan Willemsen276e96a2017-10-03 14:24:48 -0700875 if (!v->IsDefined()) {
876 v = new SimpleVar(VarOrigin::FILE);
877 sym.SetGlobalVar(v, false, nullptr);
878 }
879
880 if (v->Deprecated()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700881 ev->Error(
882 StringPrintf("*** Cannot call KATI_obsolete_var on already "
883 "deprecated variable: %s.",
884 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700885 } else if (v->Obsolete()) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700886 ev->Error(StringPrintf(
887 "*** Cannot call KATI_obsolete_var on already obsolete variable: %s.",
888 sym.c_str()));
Dan Willemsen276e96a2017-10-03 14:24:48 -0700889 }
890
891 v->SetObsolete(msg);
892 }
893}
894
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800895void 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
911void 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
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900925FuncInfo g_func_infos[] = {
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700926 {"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},
Shinichiro Hamaji2e6cbfc2015-06-16 18:46:50 +0900938
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700939 {"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},
Shinichiro Hamaji30b8e602015-06-17 19:28:54 +0900949
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700950 {"if", &IfFunc, 3, 2, false, true},
951 {"and", &AndFunc, 0, 0, true, false},
952 {"or", &OrFunc, 0, 0, true, false},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900953
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700954 {"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},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900959
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700960 {"origin", &OriginFunc, 1, 1, false, false},
961 {"flavor", &FlavorFunc, 1, 1, false, false},
Shinichiro Hamajie22fe8e2015-06-18 07:11:54 +0900962
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700963 {"info", &InfoFunc, 1, 1, false, false},
964 {"warning", &WarningFunc, 1, 1, false, false},
965 {"error", &ErrorFunc, 1, 1, false, false},
Dan Willemsenf06d8012016-10-03 00:16:07 -0700966
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700967 {"file", &FileFunc, 2, 1, false, false},
Dan Willemsen276e96a2017-10-03 14:24:48 -0700968
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700969 /* Kati custom extension functions */
970 {"KATI_deprecated_var", &DeprecatedVarFunc, 2, 1, false, false},
971 {"KATI_obsolete_var", &ObsoleteVarFunc, 2, 1, false, false},
Dan Willemsenc3f6a972018-02-27 00:25:01 -0800972 {"KATI_deprecate_export", &DeprecateExportFunc, 1, 1, false, false},
973 {"KATI_obsolete_export", &ObsoleteExportFunc, 1, 1, false, false},
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900974};
975
976unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
977
978} // namespace
979
980void 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];
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900984 bool ok = g_func_info_map->emplace(fi->name, fi).second;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900985 CHECK(ok);
986 }
987}
988
989void QuitFuncTable() {
990 delete g_func_info_map;
991}
992
993FuncInfo* 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}
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +0900999
Shinichiro Hamaji4db9edc2015-08-13 16:43:02 +09001000const vector<CommandResult*>& GetShellCommandResults() {
1001 return g_command_results;
Shinichiro Hamajic9b0aca2015-07-31 16:47:56 +09001002}