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