testing new non-autotools build system
[chaz/yoink] / src / moof / resource.cc
1
2 /*] Copyright (c) 2009-2010, Charles McGarvey [**************************
3 **] All rights reserved.
4 *
5 * vi:ts=4 sw=4 tw=75
6 *
7 * Distributable under the terms and conditions of the 2-clause BSD license;
8 * see the file COPYING for a complete text of the license.
9 *
10 **************************************************************************/
11
12 #include <queue>
13
14 #include <boost/algorithm/string.hpp>
15 #include <boost/weak_ptr.hpp>
16
17 #include <stlplus/portability/file_system.hpp>
18
19 #include "hash.hh"
20 #include "resource.hh"
21
22 #if HAVE_CONFIG_H
23 #include "../config.h"
24 #endif
25
26 #if USE_HOTLOADING
27 #include <sys/inotify.h>
28 #include <sys/ioctl.h>
29 #endif
30
31 #ifndef BUF_SIZE
32 #define BUF_SIZE 4096
33 #endif
34
35
36 namespace moof {
37
38
39 static std::vector<std::string> search_paths_;
40
41 typedef boost::weak_ptr<resource> resource_weakptr;
42 static hash<std::string,resource_weakptr,hash_function> resource_table_;
43
44 // static member
45 resource::type_lookup_ptr resource::type_lookup_;
46
47
48 #if USE_HOTLOADING
49 static hash<int,std::string,hash_function> monitor_lookup_;
50 static int monitor_fd_ = inotify_init1(IN_NONBLOCK);
51 #endif
52
53 int resource::reload_as_needed()
54 {
55 int num_resources = 0;
56
57 #if USE_HOTLOADING
58 log_info("hotloading?");
59 char bytes[BUF_SIZE];
60 int num_bytes;
61 if (0 < (num_bytes = read(monitor_fd_, bytes, num_bytes)))
62 {
63 char* end = bytes + num_bytes;
64 char* byte = bytes;
65
66 log_warning("num_bytes:", num_bytes);
67 log_error("1");
68
69 while (byte < end)
70 {
71 struct inotify_event* event = (struct inotify_event*)byte;
72
73 if (event->mask & IN_IGNORED)
74 {
75 log_warning("watch", event->wd, "removed");
76 }
77
78 log_error("2");
79 hash<int,std::string,hash_function>::iterator it;
80 it = monitor_lookup_.find(event->wd);
81 if (it != monitor_lookup_.end())
82 {
83 log_error("3");
84 std::string path = (*it).second;
85 monitor_lookup_.erase(it);
86 resource::reload(path);
87 }
88
89 byte += sizeof(*event) + event->len;
90
91 ++num_resources;
92 }
93 }
94 #endif
95
96 return num_resources;
97 }
98
99
100 resource::~resource()
101 {
102 #if USE_HOTLOADING
103 inotify_rm_watch(monitor_fd_, wd_);
104 #endif
105 }
106
107
108 resource_ptr resource::load(const std::string& path)
109 {
110 std::string extension = stlplus::extension_part(path);
111
112 if (!find(path)) return resource_ptr();
113
114 hash<std::string,resource_weakptr,hash_function>::iterator it;
115 it = resource_table_.find(path);
116 if (it != resource_table_.end())
117 {
118 resource_weakptr rsrc = (*it).second;
119 resource_ptr locked = rsrc.lock();
120 if (locked) return locked;
121 }
122
123 std::map<std::string,loader_ptr>::iterator jt;
124 jt = type_lookup_->find(extension);
125 if (jt != type_lookup_->end())
126 {
127 resource_ptr rsrc((*jt).second->load(path));
128 rsrc->set_loader(path, (*jt).second);
129 resource_table_[path] = rsrc;
130
131 #if USE_HOTLOADING
132 int wd = inotify_add_watch(monitor_fd_,
133 path.c_str(), IN_MODIFY);
134 rsrc->set_watch_descriptor(wd);
135 monitor_lookup_[wd] = path;
136 #endif
137
138 log_info("loaded", rsrc.get());
139 return rsrc;
140 }
141
142 return resource_ptr();
143 }
144
145
146 resource_ptr resource::reload(std::string& path)
147 {
148 log_info("reloading...", path);
149 hash<std::string,resource_weakptr,hash_function>::iterator it;
150 it = resource_table_.find(path);
151 if (it != resource_table_.end())
152 {
153 resource_weakptr rsrc = (*it).second;
154 resource_ptr locked = rsrc.lock();
155 if (locked)
156 {
157 locked->reload();
158 return locked;
159 }
160 }
161
162 return load(path);
163 }
164
165 void resource::reload()
166 {
167 log_info("reloaded", path_);
168
169 resource* resource = loader_->load(path_);
170 //*this = *resource;
171 resource_ = resource->resource_;
172 typeinfo_ = resource->typeinfo_;
173 unloader_ = resource->unloader_;
174
175 #if USE_HOTLOADING
176 int wd = inotify_add_watch(monitor_fd_,
177 path_.c_str(), IN_MODIFY);
178 set_watch_descriptor(wd);
179 monitor_lookup_[wd] = path_;
180 #endif
181
182 delete resource;
183 }
184
185
186 void resource::add_search_paths(const std::string& paths)
187 {
188 std::vector<std::string> pathList;
189 boost::split(pathList, paths, boost::is_any_of(":"));
190
191 add_search_paths(pathList);
192 }
193
194 void resource::add_search_paths(const std::vector<std::string>& pathList)
195 {
196 std::vector<std::string>::const_iterator it;
197 for (it = pathList.begin(); it != pathList.end(); ++it)
198 {
199 std::string path(*it);
200
201 ASSERT(!path.empty() && "empty search path string");
202
203 // add a slash if there isn't one already
204 if (*path.rbegin() != '/') path += '/';
205
206 #if defined(_WIN32)
207 //boost::replace_all(path, "/", "\\");
208 #endif
209
210 search_paths_.push_back(path);
211 log_info << "added search path " << path << std::endl;
212 }
213 }
214
215
216 bool resource::find(const std::string& path)
217 {
218 FILE* file = open_file(path);
219 if (file)
220 {
221 fclose(file);
222 return true;
223 }
224
225 return false;
226 }
227
228 FILE* resource::open_file(const std::string& path, const std::string& mode)
229 {
230 #if defined(_WIN32)
231 // windows always has to be a little different
232 //boost::replace_all(path, "/", "\\");
233 #endif
234
235 std::vector<std::string>::iterator it;
236 for (it = search_paths_.begin(); it != search_paths_.end(); ++it)
237 {
238 // check path relative to search path
239 std::string complete_path(*it);
240 complete_path += path;
241
242 FILE* file = fopen(complete_path.c_str(), mode.c_str());
243 if (file) return file;
244 }
245
246 // last ditch effort; maybe it's already a path to a valid resource
247 return fopen(path.c_str(), mode.c_str());
248 }
249
250
251 } // namespace moof
252
This page took 0.042306 seconds and 5 git commands to generate.