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