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