func.cc revision fe97c4154b6c56487fd7260dc45e71feff7eab2b
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 <glob.h> 20#include <limits.h> 21#include <stdio.h> 22#include <stdlib.h> 23 24#include <algorithm> 25#include <iterator> 26#include <memory> 27#include <unordered_map> 28 29#include "ast.h" 30#include "eval.h" 31#include "log.h" 32#include "parser.h" 33#include "strutil.h" 34#include "var.h" 35 36namespace { 37 38void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 39 shared_ptr<string> pat_str = args[0]->Eval(ev); 40 shared_ptr<string> repl = args[1]->Eval(ev); 41 shared_ptr<string> str = args[2]->Eval(ev); 42 WordWriter ww(s); 43 Pattern pat(*pat_str); 44 for (StringPiece tok : WordScanner(*str)) { 45 ww.MaybeAddWhitespace(); 46 pat.AppendSubst(tok, *repl, s); 47 } 48} 49 50void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 51 shared_ptr<string> str = args[0]->Eval(ev); 52 WordWriter ww(s); 53 for (StringPiece tok : WordScanner(*str)) { 54 ww.Write(tok); 55 } 56} 57 58void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 59 shared_ptr<string> pat = args[0]->Eval(ev); 60 shared_ptr<string> repl = args[1]->Eval(ev); 61 shared_ptr<string> str = args[2]->Eval(ev); 62 size_t index = 0; 63 while (index < str->size()) { 64 size_t found = str->find(*pat, index); 65 if (found == string::npos) 66 break; 67 AppendString(StringPiece(*str).substr(index, found - index), s); 68 AppendString(*repl, s); 69 index = found + pat->size(); 70 } 71 AppendString(StringPiece(*str).substr(index), s); 72} 73 74void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 75 shared_ptr<string> find = args[0]->Eval(ev); 76 shared_ptr<string> in = args[1]->Eval(ev); 77 if (in->find(*find) != string::npos) 78 AppendString(*find, s); 79} 80 81void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 82 shared_ptr<string> pat_buf = args[0]->Eval(ev); 83 shared_ptr<string> text = args[1]->Eval(ev); 84 vector<Pattern> pats; 85 for (StringPiece pat : WordScanner(*pat_buf)) { 86 pats.push_back(Pattern(pat)); 87 } 88 WordWriter ww(s); 89 for (StringPiece tok : WordScanner(*text)) { 90 for (const Pattern& pat : pats) { 91 if (pat.Match(tok)) { 92 ww.Write(tok); 93 break; 94 } 95 } 96 } 97} 98 99void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 100 shared_ptr<string> pat_buf = args[0]->Eval(ev); 101 shared_ptr<string> text = args[1]->Eval(ev); 102 vector<Pattern> pats; 103 for (StringPiece pat : WordScanner(*pat_buf)) { 104 pats.push_back(Pattern(pat)); 105 } 106 WordWriter ww(s); 107 for (StringPiece tok : WordScanner(*text)) { 108 bool matched = false; 109 for (const Pattern& pat : pats) { 110 if (pat.Match(tok)) { 111 matched = true; 112 break; 113 } 114 } 115 if (!matched) 116 ww.Write(tok); 117 } 118} 119 120void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 121 shared_ptr<string> list = args[0]->Eval(ev); 122 vector<StringPiece> toks; 123 WordScanner(*list).Split(&toks); 124 sort(toks.begin(), toks.end()); 125 WordWriter ww(s); 126 StringPiece prev; 127 for (StringPiece tok : toks) { 128 if (prev != tok) { 129 ww.Write(tok); 130 prev = tok; 131 } 132 } 133} 134 135static int GetNumericValueForFunc(const string& buf) { 136 StringPiece s = TrimLeftSpace(buf); 137 char* end; 138 long n = strtol(s.data(), &end, 10); 139 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) { 140 return -1; 141 } 142 return n; 143} 144 145void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 146 shared_ptr<string> n_str = args[0]->Eval(ev); 147 int n = GetNumericValueForFunc(*n_str); 148 if (n < 0) { 149 ev->Error(StringPrintf( 150 "*** non-numeric first argument to `word' function: '%s'.", 151 n_str->c_str())); 152 } 153 if (n == 0) { 154 ev->Error("*** first argument to `word' function must be greater than 0."); 155 } 156 157 shared_ptr<string> text = args[1]->Eval(ev); 158 for (StringPiece tok : WordScanner(*text)) { 159 n--; 160 if (n == 0) { 161 AppendString(tok, s); 162 break; 163 } 164 } 165} 166 167void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 168 shared_ptr<string> s_str = args[0]->Eval(ev); 169 int si = GetNumericValueForFunc(*s_str); 170 if (si < 0) { 171 ev->Error(StringPrintf( 172 "*** non-numeric first argument to `wordlist' function: '%s'.", 173 s_str->c_str())); 174 } 175 if (si == 0) { 176 ev->Error(StringPrintf( 177 "*** invalid first argument to `wordlist' function: %s`", 178 s_str->c_str())); 179 } 180 181 shared_ptr<string> e_str = args[1]->Eval(ev); 182 int ei = GetNumericValueForFunc(*e_str); 183 if (ei < 0) { 184 ev->Error(StringPrintf( 185 "*** non-numeric second argument to `wordlist' function: '%s'.", 186 e_str->c_str())); 187 } 188 189 shared_ptr<string> text = args[2]->Eval(ev); 190 int i = 0; 191 WordWriter ww(s); 192 for (StringPiece tok : WordScanner(*text)) { 193 i++; 194 if (si <= i && i <= ei) { 195 ww.Write(tok); 196 } 197 } 198} 199 200void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 201 shared_ptr<string> text = args[0]->Eval(ev); 202 WordScanner ws(*text); 203 int n = 0; 204 for (auto iter = ws.begin(); iter != ws.end(); ++iter) 205 n++; 206 char buf[32]; 207 sprintf(buf, "%d", n); 208 *s += buf; 209} 210 211void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 212 shared_ptr<string> text = args[0]->Eval(ev); 213 for (StringPiece tok : WordScanner(*text)) { 214 AppendString(tok, s); 215 return; 216 } 217} 218 219void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 220 shared_ptr<string> text = args[0]->Eval(ev); 221 StringPiece last; 222 for (StringPiece tok : WordScanner(*text)) { 223 last = tok; 224 } 225 AppendString(last, s); 226} 227 228void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 229 shared_ptr<string> list1 = args[0]->Eval(ev); 230 shared_ptr<string> list2 = args[1]->Eval(ev); 231 WordScanner ws1(*list1); 232 WordScanner ws2(*list2); 233 WordWriter ww(s); 234 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin(); 235 iter1 != ws1.end() && iter2 != ws2.end(); 236 ++iter1, ++iter2) { 237 ww.Write(*iter1); 238 // Use |AppendString| not to append extra ' '. 239 AppendString(*iter2, s); 240 } 241} 242 243void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 244 shared_ptr<string> pat = args[0]->Eval(ev); 245 if (ev->avoid_io()) { 246 *s += "$(/bin/ls -d "; 247 *s += *pat; 248 *s += " 2> /dev/null)"; 249 return; 250 } 251 252 WordWriter ww(s); 253 vector<const char*> files; 254 for (StringPiece tok : WordScanner(*pat)) { 255 ScopedTerminator st(tok); 256 // TODO: Make this faster by not always using glob. 257 files.clear(); 258 glob_t gl; 259 glob(tok.data(), GLOB_NOSORT, NULL, &gl); 260 for (size_t i = 0; i < gl.gl_pathc; i++) { 261 files.push_back(gl.gl_pathv[i]); 262 } 263 sort(files.begin(), files.end(), 264 [](const char* a, const char* b) { 265 return strcmp(a, b) < 0; 266 }); 267 for (const char* file : files) { 268 ww.Write(file); 269 } 270 271 globfree(&gl); 272 } 273} 274 275void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 276 shared_ptr<string> text = args[0]->Eval(ev); 277 WordWriter ww(s); 278 for (StringPiece tok : WordScanner(*text)) { 279 ww.Write(Dirname(tok)); 280 s->push_back('/'); 281 } 282} 283 284void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 285 shared_ptr<string> text = args[0]->Eval(ev); 286 WordWriter ww(s); 287 for (StringPiece tok : WordScanner(*text)) { 288 if (tok == "/") { 289 ww.Write(STRING_PIECE("")); 290 } else { 291 ww.Write(Basename(tok)); 292 } 293 } 294} 295 296void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 297 shared_ptr<string> text = args[0]->Eval(ev); 298 WordWriter ww(s); 299 for (StringPiece tok : WordScanner(*text)) { 300 StringPiece suf = GetExt(tok); 301 if (!suf.empty()) 302 ww.Write(suf); 303 } 304} 305 306void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 307 shared_ptr<string> text = args[0]->Eval(ev); 308 WordWriter ww(s); 309 for (StringPiece tok : WordScanner(*text)) { 310 ww.Write(StripExt(tok)); 311 } 312} 313 314void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 315 shared_ptr<string> suf = args[0]->Eval(ev); 316 shared_ptr<string> text = args[1]->Eval(ev); 317 WordWriter ww(s); 318 for (StringPiece tok : WordScanner(*text)) { 319 ww.Write(tok); 320 *s += *suf; 321 } 322} 323 324void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 325 shared_ptr<string> pre = args[0]->Eval(ev); 326 shared_ptr<string> text = args[1]->Eval(ev); 327 WordWriter ww(s); 328 for (StringPiece tok : WordScanner(*text)) { 329 ww.Write(*pre); 330 AppendString(tok, s); 331 } 332} 333 334void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 335 shared_ptr<string> text = args[0]->Eval(ev); 336 if (ev->avoid_io()) { 337 *s += "KATI_TODO(realpath)"; 338 return; 339 } 340 341 WordWriter ww(s); 342 for (StringPiece tok : WordScanner(*text)) { 343 ScopedTerminator st(tok); 344 char buf[PATH_MAX]; 345 if (realpath(tok.data(), buf)) 346 *s += buf; 347 } 348} 349 350void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 351 shared_ptr<string> text = args[0]->Eval(ev); 352 WordWriter ww(s); 353 string buf; 354 for (StringPiece tok : WordScanner(*text)) { 355 AbsPath(tok, &buf); 356 ww.Write(buf); 357 } 358} 359 360void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 361 shared_ptr<string> cond = args[0]->Eval(ev); 362 if (cond->empty()) { 363 if (args.size() > 2) 364 args[2]->Eval(ev, s); 365 } else { 366 args[1]->Eval(ev, s); 367 } 368} 369 370void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 371 shared_ptr<string> cond; 372 for (Value* a : args) { 373 cond = a->Eval(ev); 374 if (cond->empty()) 375 return; 376 } 377 if (cond.get()) { 378 *s += *cond; 379 } 380} 381 382void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 383 for (Value* a : args) { 384 shared_ptr<string> cond = a->Eval(ev); 385 if (!cond->empty()) { 386 *s += *cond; 387 return; 388 } 389 } 390} 391 392void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 393 shared_ptr<string> var_name = args[0]->Eval(ev); 394 Var* var = ev->LookupVar(*var_name); 395 AppendString(var->String().as_string(), s); 396} 397 398void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) { 399 // TODO: eval leaks everything... for now. 400 //shared_ptr<string> text = args[0]->Eval(ev); 401 string* text = new string; 402 args[0]->Eval(ev, text); 403 vector<AST*> asts; 404 Parse(*text, ev->loc(), &asts); 405 for (AST* ast : asts) { 406 LOG("%s", ast->DebugString().c_str()); 407 ast->Eval(ev); 408 //delete ast; 409 } 410} 411 412void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 413 shared_ptr<string> cmd = args[0]->Eval(ev); 414 if (ev->avoid_io()) { 415 *s += "$("; 416 *s += *cmd; 417 *s += ")"; 418 return; 419 } 420 421 LOG("ShellFunc: %s", cmd->c_str()); 422 string out; 423 // TODO: Handle $(SHELL). 424 FILE* fp = popen(cmd->c_str(), "r"); 425 while (true) { 426 char buf[4096]; 427 size_t r = fread(buf, 1, 4096, fp); 428 out.append(buf, buf+r); 429 if (r == 0) { 430 fclose(fp); 431 break; 432 } 433 } 434 435 while (out[out.size()-1] == '\n') 436 out.pop_back(); 437 for (size_t i = 0; i < out.size(); i++) { 438 if (out[i] == '\n') 439 out[i] = ' '; 440 } 441 *s += out; 442} 443 444void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 445 static const char* tmpvar_names[] = { 446 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" 447 }; 448 449 shared_ptr<string> func_name = args[0]->Eval(ev); 450 Var* func = ev->LookupVar(*func_name); 451 vector<unique_ptr<SimpleVar>> av; 452 for (size_t i = 1; i < args.size(); i++) { 453 unique_ptr<SimpleVar> s( 454 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC)); 455 av.push_back(move(s)); 456 } 457 vector<unique_ptr<ScopedVar>> sv; 458 for (size_t i = 1; i < args.size(); i++) { 459 sv.push_back(move(unique_ptr<ScopedVar>( 460 new ScopedVar(ev->mutable_vars(), tmpvar_names[i], av[i-1].get())))); 461 } 462 func->Eval(ev, s); 463} 464 465void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 466 shared_ptr<string> varname = args[0]->Eval(ev); 467 shared_ptr<string> list = args[1]->Eval(ev); 468 WordWriter ww(s); 469 for (StringPiece tok : WordScanner(*list)) { 470 unique_ptr<SimpleVar> v(new SimpleVar( 471 make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC)); 472 ScopedVar sv(ev->mutable_vars(), *varname, v.get()); 473 ww.MaybeAddWhitespace(); 474 args[2]->Eval(ev, s); 475 } 476} 477 478void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 479 shared_ptr<string> var_name = args[0]->Eval(ev); 480 Var* var = ev->LookupVar(*var_name); 481 *s += GetOriginStr(var->Origin()); 482} 483 484void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 485 shared_ptr<string> var_name = args[0]->Eval(ev); 486 Var* var = ev->LookupVar(*var_name); 487 *s += var->Flavor(); 488} 489 490void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 491 shared_ptr<string> a = args[0]->Eval(ev); 492 if (ev->avoid_io()) { 493 *s += "KATI_TODO(info)"; 494 return; 495 } 496 printf("%s\n", a->c_str()); 497 fflush(stdout); 498} 499 500void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 501 shared_ptr<string> a = args[0]->Eval(ev); 502 if (ev->avoid_io()) { 503 *s += "KATI_TODO(warning)"; 504 return; 505 } 506 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str()); 507 fflush(stdout); 508} 509 510void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 511 shared_ptr<string> a = args[0]->Eval(ev); 512 if (ev->avoid_io()) { 513 *s += "KATI_TODO(error)"; 514 return; 515 } 516 ev->Error(StringPrintf("*** %s.", a->c_str())); 517} 518 519FuncInfo g_func_infos[] = { 520 { "patsubst", &PatsubstFunc, 3, 3, false, false }, 521 { "strip", &StripFunc, 1, 1, false, false }, 522 { "subst", &SubstFunc, 3, 3, false, false }, 523 { "findstring", &FindstringFunc, 2, 2, false, false }, 524 { "filter", &FilterFunc, 2, 2, false, false }, 525 { "filter-out", &FilterOutFunc, 2, 2, false, false }, 526 { "sort", &SortFunc, 1, 1, false, false }, 527 { "word", &WordFunc, 2, 2, false, false }, 528 { "wordlist", &WordlistFunc, 3, 3, false, false }, 529 { "words", &WordsFunc, 1, 1, false, false }, 530 { "firstword", &FirstwordFunc, 1, 1, false, false }, 531 { "lastword", &LastwordFunc, 1, 1, false, false }, 532 533 { "join", &JoinFunc, 2, 2, false, false }, 534 { "wildcard", &WildcardFunc, 1, 1, false, false }, 535 { "dir", &DirFunc, 1, 1, false, false }, 536 { "notdir", &NotdirFunc, 1, 1, false, false }, 537 { "suffix", &SuffixFunc, 1, 1, false, false }, 538 { "basename", &BasenameFunc, 1, 1, false, false }, 539 { "addsuffix", &AddsuffixFunc, 2, 2, false, false }, 540 { "addprefix", &AddprefixFunc, 2, 2, false, false }, 541 { "realpath", &RealpathFunc, 1, 1, false, false }, 542 { "abspath", &AbspathFunc, 1, 1, false, false }, 543 544 { "if", &IfFunc, 3, 2, false, true }, 545 { "and", &AndFunc, 0, 0, true, false }, 546 { "or", &OrFunc, 0, 0, true, false }, 547 548 { "value", &ValueFunc, 1, 1, false, false }, 549 { "eval", &EvalFunc, 1, 1, false, false }, 550 { "shell", &ShellFunc, 1, 1, false, false }, 551 { "call", &CallFunc, 0, 0, false, false }, 552 { "foreach", &ForeachFunc, 3, 3, false, false }, 553 554 { "origin", &OriginFunc, 1, 1, false, false }, 555 { "flavor", &FlavorFunc, 1, 1, false, false }, 556 557 { "info", &InfoFunc, 1, 1, false, false }, 558 { "warning", &WarningFunc, 1, 1, false, false }, 559 { "error", &ErrorFunc, 1, 1, false, false }, 560}; 561 562unordered_map<StringPiece, FuncInfo*>* g_func_info_map; 563 564} // namespace 565 566void InitFuncTable() { 567 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>; 568 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) { 569 FuncInfo* fi = &g_func_infos[i]; 570 bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second; 571 CHECK(ok); 572 } 573} 574 575void QuitFuncTable() { 576 delete g_func_info_map; 577} 578 579FuncInfo* GetFuncInfo(StringPiece name) { 580 auto found = g_func_info_map->find(name); 581 if (found == g_func_info_map->end()) 582 return NULL; 583 return found->second; 584} 585