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