serious bugfix in Raise_IdxError (number got formatted as string, causing a segmentat...
[vox.git] / src / stdlib / importlib.cpp
bloba4009e39731281b9a16110204944e21c44e2db14
2 #include <ctime>
3 #include <cstdlib>
4 #include <cstdio>
5 #include <boost/filesystem.hpp>
6 #include "helper.hpp"
7 #include "vxlibrary.hpp"
9 #define IMPORTHOOK_NAME "importhook"
12 #define IMPORT_GET_SELF(__vm__, __var__) \
13 VXObject o; \
14 if(!__vm__->GetRegistryTable()->Get(v->NewString(IMPORTHOOK_NAME), o)) \
15 { \
16 return v->ThrowError("importhook wasn't installed correctly!"); \
17 } \
18 __var__ = (VXImportHook*)o.UserPointer();
20 namespace fslib = boost::filesystem;
21 typedef fslib::filesystem_error fslib_error;
24 //DSO_EXT = kernel.getproperty("DSO_EXT")
25 //const char* DSO_EXT = "." VOX_PLATFORM_NAME ".vxd";
26 const char* DSO_EXT = ".vxd";
27 //VOX_EXT = kernel.getproperty("VOX_EXT")
28 const char* VOX_EXT = ".vx";
30 const char* VOX_PLUGIN_FUNCTION_OPEN = "vox_module_open";
32 void get_err(VXState* v, const char** err)
35 vox_pushlasterror(v);
36 if(VX_FAILED(vox_getstring(v, -1, err, NULL)))
38 *err = "<unknown error>";
41 (*err) = v->LastError();
45 struct VXImportError
47 std::string path;
48 std::string message;
49 bool is_dll;
50 bool dll_failed_to_load;
53 struct VXLibWrap
55 VXSharedLibrary handle;
58 struct VXImportHook
60 VXState* v;
61 VXVector<std::string> searchpaths;
62 VXVector<VXImportError> errvalues;
63 bool foundmodule;
64 VXInteger status;
66 void fill_searchpaths()
68 const char* env = getenv("VOX_PATH");
69 if(env != NULL)
71 searchpaths.push_back(env);
73 searchpaths.push_back("./");
74 // add installdir before srcdir, so it has higher priority
75 #if defined(VOX_MODULEPATH_INSTALLDIR)
76 searchpaths.push_back(VOX_MODULEPATH_INSTALLDIR);
77 #endif
78 #if defined(VOX_MODULEPATH_SRCDIR)
79 searchpaths.push_back(VOX_MODULEPATH_SRCDIR);
80 #endif
83 VXImportHook(VXState* _v): v(_v)
85 fill_searchpaths();
88 void pusherror(const std::string& path,
89 const std::string& message,
90 bool is_dll = false,
91 bool dll_failed_to_load = false)
93 VXImportError err;
94 err.path = path;
95 err.message = message;
96 err.is_dll = is_dll;
97 err.dll_failed_to_load = dll_failed_to_load;
98 errvalues.push_back(err);
101 void do_import(const std::string& expr)
103 int i;
104 char dir_sep = '/';
105 char dot = '.';
106 std::string relpath;
107 std::string abspath;
108 std::string searchpath;
109 VXImportError pair;
110 this->status = 1;
111 this->foundmodule = false;
112 for(i=0; i<searchpaths.size(); i++)
114 searchpath = searchpaths.at(i);
115 relpath = expr;
116 fslib::path p(searchpath);
117 if(p.is_absolute())
119 abspath = searchpath + relpath;
121 else
123 abspath = abspath + searchpath + relpath;
125 this->checkmodule(abspath);
126 if(foundmodule == true)
128 return;
131 if(foundmodule == false)
133 // create a little errormessage, explaining what went wrong,
134 // and what files we have searched
135 // yes, the errormessage is inspired by Lua
136 std::string msg;
137 msg = "import: Module '"+expr+"' not found:\n";
138 for(i=0; i<errvalues.size(); i++)
140 pair = errvalues.at(i);
141 std::string epath = pair.path;
142 std::string eerr = pair.message;
143 // might happen in some rare cases
144 if(eerr.length() == 0)
146 eerr = "<unknown>";
148 //if(pair.is_dll && pair.dll_failed_to_load)
150 // msg += " No file '"+epath+"' ("+eerr+")\n";
152 //else
154 msg += " No file '"+epath+"'\n";
157 status = v->ThrowError(msg.c_str());
162 void checkmodule(const std::string& abspath)
164 std::string dso_path;
165 std::string vox_path;
166 std::string err;
167 dso_path = abspath + DSO_EXT;
168 vox_path = abspath + VOX_EXT;
169 this->check_voxfile(vox_path);
170 // only continue searching DSO files when
171 // no voxfile could be found, to
172 // prevent race conditions
173 if(!foundmodule)
175 this->check_dsofile(dso_path);
179 void check_voxfile(const std::string& path)
181 bool retval = true;
182 bool ofail;
183 const char* err;
184 std::string ret_err;
185 VXObject closure;
186 if(VX_SUCCEEDED(v->LoadFile(path.c_str(), true, &ofail, &closure)))
188 v->PushRoot();
189 if(VX_SUCCEEDED(v->CallSimple(closure, 1, retval, true)))
191 foundmodule = true;
192 return;
194 else
196 get_err(v, &err);
197 ret_err = err;
198 pusherror(path, ret_err);
199 v->Pop(1);
200 return;
203 else
205 get_err(v, &err);
206 ret_err = err;
207 pusherror(path, ret_err);
208 return;
212 void check_dsofile(const std::string& path)
214 VXFunction func;
215 VXLibWrap lib;
218 lib.handle.open(path);
219 func = lib.handle.resolve<VXFunction>(VOX_PLUGIN_FUNCTION_OPEN);
220 func(v);
221 foundmodule = true;
222 return;
224 catch(VXSharedLibrary::LoadError& err)
226 lib.handle.close();
227 pusherror(path, err.what(), true, true);
229 catch(std::runtime_error& err)
231 lib.handle.destroy();
232 pusherror(path, err.what(), true, true);
236 VXInteger finalize()
238 this->errvalues.clear();
239 return this->status;
245 VXInteger importreg_release(VXState* v)
247 VXImportHook* self;
248 IMPORT_GET_SELF(v, self)
249 delete self;
250 return 1;
254 VXInteger importlib_import(VXState* v)
256 std::string expr;
257 VXImportHook* self;
258 IMPORT_GET_SELF(v, self)
259 v->GetString(2, &expr);
260 self->do_import(expr);
261 return self->finalize();
264 VXInteger package_searchpaths(VXState* v)
266 std::string path;
267 VXInteger i;
268 VXImportHook* self;
269 IMPORT_GET_SELF(v, self)
270 VXArrayObj* arr = v->NewArray();
271 for(i=0; i<self->searchpaths.size(); i++)
273 path = self->searchpaths.at(i);
274 arr->Append(v->NewString(path.c_str(), path.length()));
276 v->Push(arr);
277 return 1;
280 VXInteger package_addpath(VXState* v)
282 std::string path;
283 VXImportHook* self;
284 IMPORT_GET_SELF(v, self)
285 v->GetString(2, &path);
286 self->searchpaths.push_back(path);
287 return VX_OK;
290 static VXRegFunction package_funcs[] =
292 {"searchpaths", package_searchpaths, 1, NULL},
293 {"addpath", package_addpath, 2, ".s"},
294 {0, 0, 0, 0},
297 static VXRegFunction importlib_funcs[]=
299 {"import", importlib_import, 2, ".s"},
300 {0, 0, 0, 0}
304 VXInteger voxstd_register_importlib(VXState* v)
306 VXImportHook* self = new VXImportHook(v);
307 v->GetRegistryTable()->NewSlot(v->NewString(IMPORTHOOK_NAME), (VXUserPointer)self);
308 //vox_pushatexitfunc_native(v, importreg_release);
309 v->AtExit(v->NewClosure(importreg_release, 0));
310 //vox_registerlib(v, "package", package_funcs, true, true);
311 v->RegisterLib("package", package_funcs, true);
312 //vox_registerlib(v, NULL, importlib_funcs, true, true);
313 v->RegisterLib(NULL, importlib_funcs, true);
314 return 0;