1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#include "ModuleCache.h"
#include "module.h"
#include "printutils.h"
#include "openscad.h"
#include "boosty.h"
#include <boost/format.hpp>
#include <boost/filesystem.hpp>
#include <boost/foreach.hpp>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <time.h>
#include <sys/stat.h>
/*!
FIXME: Implement an LRU scheme to avoid having an ever-growing module cache
*/
ModuleCache *ModuleCache::inst = NULL;
static bool is_modified(const std::string &filename, const time_t &mtime)
{
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(filename.c_str(), &st);
return (st.st_mtime > mtime);
}
Module *ModuleCache::evaluate(const std::string &filename)
{
Module *lib_mod = NULL;
// Create cache ID
struct stat st;
memset(&st, 0, sizeof(struct stat));
stat(filename.c_str(), &st);
std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size);
// Lookup in cache
if (this->entries.find(filename) != this->entries.end() &&
this->entries[filename].cache_id == cache_id) {
#ifdef DEBUG
// Causes too much debug output
// PRINTB("Using cached library: %s (%s)", filename % cache_id);
#endif
lib_mod = &(*this->entries[filename].module);
BOOST_FOREACH(const Module::IncludeContainer::value_type &item, lib_mod->includes) {
if (is_modified(item.first, item.second)) {
lib_mod = NULL;
break;
}
}
}
// If cache lookup failed (non-existing or old timestamp), compile module
if (!lib_mod) {
#ifdef DEBUG
if (this->entries.find(filename) != this->entries.end()) {
PRINTB("Recompiling cached library: %s (%s)", filename % cache_id);
}
else {
PRINTB("Compiling library '%s'.", filename);
}
#endif
std::ifstream ifs(filename.c_str());
if (!ifs.is_open()) {
PRINTB("WARNING: Can't open library file '%s'\n", filename);
return NULL;
}
std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
print_messages_push();
cache_entry e = { NULL, cache_id };
if (this->entries.find(filename) != this->entries.end()) {
delete this->entries[filename].module;
}
this->entries[filename] = e;
std::string pathname = boosty::stringy(fs::path(filename).parent_path());
lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), 0));
if (lib_mod) {
this->entries[filename].module = lib_mod;
} else {
this->entries.erase(filename);
}
print_messages_pop();
}
if (lib_mod) lib_mod->handleDependencies();
return lib_mod;
}
void ModuleCache::clear()
{
this->entries.clear();
}
|