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