aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--eval.cc44
-rw-r--r--eval.h2
-rw-r--r--fileutil.cc43
-rw-r--r--fileutil.h4
-rw-r--r--func.cc20
5 files changed, 72 insertions, 41 deletions
diff --git a/eval.cc b/eval.cc
index 9504f51..1708488 100644
--- a/eval.cc
+++ b/eval.cc
@@ -17,12 +17,12 @@
#include "eval.h"
#include <errno.h>
-#include <glob.h>
#include <string.h>
#include "ast.h"
#include "file.h"
#include "file_cache.h"
+#include "fileutil.h"
#include "parser.h"
#include "rule.h"
#include "strutil.h"
@@ -217,22 +217,9 @@ void Evaluator::EvalIf(const IfAST* ast) {
}
}
-void Evaluator::DoInclude(const char* fname, bool should_exist) {
- if (!should_exist && g_ignore_optional_include_pattern &&
- Pattern(g_ignore_optional_include_pattern).Match(fname)) {
- return;
- }
-
+void Evaluator::DoInclude(const string& fname) {
Makefile* mk = MakefileCacheManager::Get()->ReadMakefile(fname);
- if (!mk->Exists()) {
- if (should_exist) {
- Error(StringPrintf(
- "%s: %s\n"
- "NOTE: kati does not support generating missing makefiles",
- fname, strerror(errno)));
- }
- return;
- }
+ CHECK(mk->Exists());
Var* var_list = LookupVar(Intern("MAKEFILE_LIST"));
var_list->AppendVar(this, NewLiteral(Intern(TrimLeadingCurdir(fname)).str()));
@@ -249,15 +236,24 @@ void Evaluator::EvalInclude(const IncludeAST* ast) {
shared_ptr<string> pats = ast->expr->Eval(this);
for (StringPiece pat : WordScanner(*pats)) {
ScopedTerminator st(pat);
- if (pat.find_first_of("?*[") != string::npos) {
- glob_t gl;
- glob(pat.data(), GLOB_NOSORT, NULL, &gl);
- for (size_t i = 0; i < gl.gl_pathc; i++) {
- DoInclude(gl.gl_pathv[i], ast->should_exist);
+ vector<string>* files;
+ Glob(pat.data(), &files);
+
+ if (ast->should_exist) {
+ if (files->empty()) {
+ Error(StringPrintf(
+ "%s: %s\n"
+ "NOTE: kati does not support generating missing makefiles",
+ pat.data(), strerror(errno)));
}
- globfree(&gl);
- } else {
- DoInclude(pat.data(), ast->should_exist);
+ }
+
+ for (const string& fname : *files) {
+ if (!ast->should_exist && g_ignore_optional_include_pattern &&
+ Pattern(g_ignore_optional_include_pattern).Match(fname)) {
+ return;
+ }
+ DoInclude(fname);
}
}
}
diff --git a/eval.h b/eval.h
index 6287e67..558df3c 100644
--- a/eval.h
+++ b/eval.h
@@ -79,7 +79,7 @@ class Evaluator {
private:
Var* EvalRHS(Symbol lhs, Value* rhs, StringPiece orig_rhs, AssignOp op,
bool is_override = false);
- void DoInclude(const char* fname, bool should_exist);
+ void DoInclude(const string& fname);
const Vars* in_vars_;
Vars* vars_;
diff --git a/fileutil.cc b/fileutil.cc
index 9a686e5..eb4fc22 100644
--- a/fileutil.cc
+++ b/fileutil.cc
@@ -17,12 +17,15 @@
#include "fileutil.h"
#include <errno.h>
+#include <glob.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
+#include <unordered_map>
+
#include "log.h"
bool Exists(StringPiece filename) {
@@ -91,3 +94,43 @@ int RunCommand(const string& shell, const string& cmd, bool redirect_stderr,
}
abort();
}
+
+namespace {
+
+class GlobCache {
+ public:
+ ~GlobCache() {
+ for (auto& p : cache_) {
+ delete p.second;
+ }
+ }
+
+ void Get(const char* pat, vector<string>** files) {
+ auto p = cache_.emplace(pat, nullptr);
+ if (p.second) {
+ vector<string>* files = p.first->second = new vector<string>;
+ if (strcspn(pat, "?*[\\") != strlen(pat)) {
+ glob_t gl;
+ glob(pat, GLOB_NOSORT, NULL, &gl);
+ for (size_t i = 0; i < gl.gl_pathc; i++) {
+ files->push_back(gl.gl_pathv[i]);
+ }
+ globfree(&gl);
+ } else {
+ if (Exists(pat))
+ files->push_back(pat);
+ }
+ }
+ *files = p.first->second;
+ }
+
+ private:
+ unordered_map<string, vector<string>*> cache_;
+};
+
+} // namespace
+
+void Glob(const char* pat, vector<string>** files) {
+ static GlobCache gc;
+ gc.Get(pat, files);
+}
diff --git a/fileutil.h b/fileutil.h
index df84dda..26b8e5e 100644
--- a/fileutil.h
+++ b/fileutil.h
@@ -15,7 +15,9 @@
#ifndef FILEUTIL_H_
#define FILEUTIL_H_
+#include <memory>
#include <string>
+#include <vector>
#include "string_piece.h"
@@ -27,4 +29,6 @@ double GetTimestamp(StringPiece f);
int RunCommand(const string& shell, const string& cmd, bool redirect_stderr,
string* out);
+void Glob(const char* pat, vector<string>** files);
+
#endif // FILEUTIL_H_
diff --git a/func.cc b/func.cc
index 6988b28..a33dd8e 100644
--- a/func.cc
+++ b/func.cc
@@ -17,7 +17,6 @@
#include "func.h"
#include <errno.h>
-#include <glob.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
@@ -257,25 +256,14 @@ void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) {
}
WordWriter ww(s);
- vector<const char*> files;
+ vector<string>* files;
for (StringPiece tok : WordScanner(*pat)) {
ScopedTerminator st(tok);
- // TODO: Make this faster by not always using glob.
- files.clear();
- glob_t gl;
- glob(tok.data(), GLOB_NOSORT, NULL, &gl);
- for (size_t i = 0; i < gl.gl_pathc; i++) {
- files.push_back(gl.gl_pathv[i]);
- }
- sort(files.begin(), files.end(),
- [](const char* a, const char* b) {
- return strcmp(a, b) < 0;
- });
- for (const char* file : files) {
+ Glob(tok.data(), &files);
+ sort(files->begin(), files->end());
+ for (const string& file : *files) {
ww.Write(file);
}
-
- globfree(&gl);
}
}