func.cc revision df1fc8b2ead00bad8c23065affb9576a4b03cff5
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  for (StringPiece tok : WordScanner(*pat)) {
254    ScopedTerminator st(tok);
255    // TODO: Make this faster by not always using glob.
256    glob_t gl;
257    glob(tok.data(), GLOB_NOSORT, NULL, &gl);
258    for (size_t i = 0; i < gl.gl_pathc; i++) {
259      ww.Write(gl.gl_pathv[i]);
260    }
261    globfree(&gl);
262  }
263}
264
265void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
266  shared_ptr<string> text = args[0]->Eval(ev);
267  WordWriter ww(s);
268  for (StringPiece tok : WordScanner(*text)) {
269    ww.Write(Dirname(tok));
270    if (tok != "/")
271      s->push_back('/');
272  }
273}
274
275void NotdirFunc(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    if (tok == "/") {
280      ww.Write(STRING_PIECE(""));
281    } else {
282      ww.Write(Basename(tok));
283    }
284  }
285}
286
287void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
288  shared_ptr<string> text = args[0]->Eval(ev);
289  WordWriter ww(s);
290  for (StringPiece tok : WordScanner(*text)) {
291    StringPiece suf = GetExt(tok);
292    if (!suf.empty())
293      ww.Write(suf);
294  }
295}
296
297void BasenameFunc(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    ww.Write(StripExt(tok));
302  }
303}
304
305void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
306  shared_ptr<string> suf = args[0]->Eval(ev);
307  shared_ptr<string> text = args[1]->Eval(ev);
308  WordWriter ww(s);
309  for (StringPiece tok : WordScanner(*text)) {
310    ww.Write(tok);
311    *s += *suf;
312  }
313}
314
315void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
316  shared_ptr<string> pre = args[0]->Eval(ev);
317  shared_ptr<string> text = args[1]->Eval(ev);
318  WordWriter ww(s);
319  for (StringPiece tok : WordScanner(*text)) {
320    ww.Write(*pre);
321    AppendString(tok, s);
322  }
323}
324
325void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
326  shared_ptr<string> text = args[0]->Eval(ev);
327  if (ev->avoid_io()) {
328    *s += "KATI_TODO(realpath)";
329    return;
330  }
331
332  WordWriter ww(s);
333  for (StringPiece tok : WordScanner(*text)) {
334    ScopedTerminator st(tok);
335    char buf[PATH_MAX];
336    if (realpath(tok.data(), buf))
337      *s += buf;
338  }
339}
340
341void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
342  shared_ptr<string> text = args[0]->Eval(ev);
343  WordWriter ww(s);
344  string buf;
345  for (StringPiece tok : WordScanner(*text)) {
346    AbsPath(tok, &buf);
347    ww.Write(buf);
348  }
349}
350
351void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
352  shared_ptr<string> cond = args[0]->Eval(ev);
353  if (cond->empty()) {
354    if (args.size() > 2)
355      args[2]->Eval(ev, s);
356  } else {
357    args[1]->Eval(ev, s);
358  }
359}
360
361void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
362  shared_ptr<string> cond;
363  for (Value* a : args) {
364    cond = a->Eval(ev);
365    if (cond->empty())
366      return;
367  }
368  if (cond.get()) {
369    *s += *cond;
370  }
371}
372
373void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
374  for (Value* a : args) {
375    shared_ptr<string> cond = a->Eval(ev);
376    if (!cond->empty()) {
377      *s += *cond;
378      return;
379    }
380  }
381}
382
383void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
384  shared_ptr<string> var_name = args[0]->Eval(ev);
385  Var* var = ev->LookupVar(*var_name);
386  AppendString(var->String().as_string(), s);
387}
388
389void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) {
390  // TODO: eval leaks everything... for now.
391  //shared_ptr<string> text = args[0]->Eval(ev);
392  string* text = new string;
393  args[0]->Eval(ev, text);
394  vector<AST*> asts;
395  Parse(*text, ev->loc(), &asts);
396  for (AST* ast : asts) {
397    LOG("%s", ast->DebugString().c_str());
398    ast->Eval(ev);
399    //delete ast;
400  }
401}
402
403void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
404  shared_ptr<string> cmd = args[0]->Eval(ev);
405  if (ev->avoid_io()) {
406    *s += "$(";
407    *s += *cmd;
408    *s += ")";
409    return;
410  }
411
412  LOG("ShellFunc: %s", cmd->c_str());
413  string out;
414  // TODO: Handle $(SHELL).
415  FILE* fp = popen(cmd->c_str(), "r");
416  while (true) {
417    char buf[4096];
418    size_t r = fread(buf, 1, 4096, fp);
419    out.append(buf, buf+r);
420    if (r == 0) {
421      fclose(fp);
422      break;
423    }
424  }
425
426  while (out[out.size()-1] == '\n')
427    out.pop_back();
428  for (size_t i = 0; i < out.size(); i++) {
429    if (out[i] == '\n')
430      out[i] = ' ';
431  }
432  *s += out;
433}
434
435void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
436  static const char* tmpvar_names[] = {
437    "0", "1",  "2",  "3",  "4",  "5",  "6",  "7",  "8",  "9"
438  };
439
440  shared_ptr<string> func_name = args[0]->Eval(ev);
441  Var* func = ev->LookupVar(*func_name);
442  vector<unique_ptr<SimpleVar>> av;
443  for (size_t i = 1; i < args.size(); i++) {
444    unique_ptr<SimpleVar> s(
445        new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC));
446    av.push_back(move(s));
447  }
448  vector<unique_ptr<ScopedVar>> sv;
449  for (size_t i = 1; i < args.size(); i++) {
450    sv.push_back(move(unique_ptr<ScopedVar>(
451        new ScopedVar(ev->mutable_vars(), tmpvar_names[i], av[i-1].get()))));
452  }
453  func->Eval(ev, s);
454}
455
456void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
457  shared_ptr<string> varname = args[0]->Eval(ev);
458  shared_ptr<string> list = args[1]->Eval(ev);
459  WordWriter ww(s);
460  for (StringPiece tok : WordScanner(*list)) {
461    unique_ptr<SimpleVar> v(new SimpleVar(
462        make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC));
463    ScopedVar sv(ev->mutable_vars(), *varname, v.get());
464    ww.MaybeAddWhitespace();
465    args[2]->Eval(ev, s);
466  }
467}
468
469void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
470  shared_ptr<string> var_name = args[0]->Eval(ev);
471  Var* var = ev->LookupVar(*var_name);
472  *s += GetOriginStr(var->Origin());
473}
474
475void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
476  shared_ptr<string> var_name = args[0]->Eval(ev);
477  Var* var = ev->LookupVar(*var_name);
478  *s += var->Flavor();
479}
480
481void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
482  shared_ptr<string> a = args[0]->Eval(ev);
483  if (ev->avoid_io()) {
484    *s += "KATI_TODO(info)";
485    return;
486  }
487  printf("%s\n", a->c_str());
488  fflush(stdout);
489}
490
491void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
492  shared_ptr<string> a = args[0]->Eval(ev);
493  if (ev->avoid_io()) {
494    *s += "KATI_TODO(warning)";
495    return;
496  }
497  printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str());
498  fflush(stdout);
499}
500
501void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
502  shared_ptr<string> a = args[0]->Eval(ev);
503  if (ev->avoid_io()) {
504    *s += "KATI_TODO(error)";
505    return;
506  }
507  ev->Error(StringPrintf("*** %s.", a->c_str()));
508}
509
510FuncInfo g_func_infos[] = {
511  { "patsubst", &PatsubstFunc, 3, 3, false, false },
512  { "strip", &StripFunc, 1, 1, false, false },
513  { "subst", &SubstFunc, 3, 3, false, false },
514  { "findstring", &FindstringFunc, 2, 2, false, false },
515  { "filter", &FilterFunc, 2, 2, false, false },
516  { "filter-out", &FilterOutFunc, 2, 2, false, false },
517  { "sort", &SortFunc, 1, 1, false, false },
518  { "word", &WordFunc, 2, 2, false, false },
519  { "wordlist", &WordlistFunc, 3, 3, false, false },
520  { "words", &WordsFunc, 1, 1, false, false },
521  { "firstword", &FirstwordFunc, 1, 1, false, false },
522  { "lastword", &LastwordFunc, 1, 1, false, false },
523
524  { "join", &JoinFunc, 2, 2, false, false },
525  { "wildcard", &WildcardFunc, 1, 1, false, false },
526  { "dir", &DirFunc, 1, 1, false, false },
527  { "notdir", &NotdirFunc, 1, 1, false, false },
528  { "suffix", &SuffixFunc, 1, 1, false, false },
529  { "basename", &BasenameFunc, 1, 1, false, false },
530  { "addsuffix", &AddsuffixFunc, 2, 2, false, false },
531  { "addprefix", &AddprefixFunc, 2, 2, false, false },
532  { "realpath", &RealpathFunc, 1, 1, false, false },
533  { "abspath", &AbspathFunc, 1, 1, false, false },
534
535  { "if", &IfFunc, 3, 2, false, true },
536  { "and", &AndFunc, 0, 0, true, false },
537  { "or", &OrFunc, 0, 0, true, false },
538
539  { "value", &ValueFunc, 1, 1, false, false },
540  { "eval", &EvalFunc, 1, 1, false, false },
541  { "shell", &ShellFunc, 1, 1, false, false },
542  { "call", &CallFunc, 0, 0, false, false },
543  { "foreach", &ForeachFunc, 3, 3, false, false },
544
545  { "origin", &OriginFunc, 1, 1, false, false },
546  { "flavor", &FlavorFunc, 1, 1, false, false },
547
548  { "info", &InfoFunc, 1, 1, false, false },
549  { "warning", &WarningFunc, 1, 1, false, false },
550  { "error", &ErrorFunc, 1, 1, false, false },
551};
552
553unordered_map<StringPiece, FuncInfo*>* g_func_info_map;
554
555}  // namespace
556
557void InitFuncTable() {
558  g_func_info_map = new unordered_map<StringPiece, FuncInfo*>;
559  for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) {
560    FuncInfo* fi = &g_func_infos[i];
561    bool ok = g_func_info_map->insert(make_pair(Intern(fi->name), fi)).second;
562    CHECK(ok);
563  }
564}
565
566void QuitFuncTable() {
567  delete g_func_info_map;
568}
569
570FuncInfo* GetFuncInfo(StringPiece name) {
571  auto found = g_func_info_map->find(name);
572  if (found == g_func_info_map->end())
573    return NULL;
574  return found->second;
575}
576