diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-12-27 11:02:25 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2007-12-27 11:02:25 -0200 |
commit | f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23 (patch) | |
tree | b4c761dac7648caea2cc20f8ebc2dd5b27a3fa1e /loadlib.c | |
parent | 98194db4295726069137d13b8d24fca8cbf892b6 (diff) | |
download | lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.tar.gz lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.tar.bz2 lua-f5ae26ec6c2eb69f03f316e59c1e1977c52c7c23.zip |
official branch for Lua 5.1
Diffstat (limited to 'loadlib.c')
-rw-r--r-- | loadlib.c | 663 |
1 files changed, 0 insertions, 663 deletions
diff --git a/loadlib.c b/loadlib.c deleted file mode 100644 index b9ac3761..00000000 --- a/loadlib.c +++ /dev/null | |||
@@ -1,663 +0,0 @@ | |||
1 | /* | ||
2 | ** $Id: loadlib.c,v 1.51 2005/12/29 15:32:11 roberto Exp roberto $ | ||
3 | ** Dynamic library loader for Lua | ||
4 | ** See Copyright Notice in lua.h | ||
5 | ** | ||
6 | ** This module contains an implementation of loadlib for Unix systems | ||
7 | ** that have dlfcn, an implementation for Darwin (Mac OS X), an | ||
8 | ** implementation for Windows, and a stub for other systems. | ||
9 | */ | ||
10 | |||
11 | |||
12 | #include <stdlib.h> | ||
13 | #include <string.h> | ||
14 | |||
15 | |||
16 | #define loadlib_c | ||
17 | #define LUA_LIB | ||
18 | |||
19 | #include "lauxlib.h" | ||
20 | #include "lobject.h" | ||
21 | #include "lua.h" | ||
22 | #include "lualib.h" | ||
23 | |||
24 | |||
25 | /* prefix for open functions in C libraries */ | ||
26 | #define LUA_POF "luaopen_" | ||
27 | |||
28 | /* separator for open functions in C libraries */ | ||
29 | #define LUA_OFSEP "_" | ||
30 | |||
31 | |||
32 | #define LIBPREFIX "LOADLIB: " | ||
33 | |||
34 | #define POF LUA_POF | ||
35 | #define LIB_FAIL "open" | ||
36 | |||
37 | |||
38 | /* error codes for ll_loadfunc */ | ||
39 | #define ERRLIB 1 | ||
40 | #define ERRFUNC 2 | ||
41 | |||
42 | #define setprogdir(L) ((void)0) | ||
43 | |||
44 | |||
45 | static void ll_unloadlib (void *lib); | ||
46 | static void *ll_load (lua_State *L, const char *path); | ||
47 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); | ||
48 | |||
49 | |||
50 | |||
51 | #if defined(LUA_DL_DLOPEN) | ||
52 | /* | ||
53 | ** {======================================================================== | ||
54 | ** This is an implementation of loadlib based on the dlfcn interface. | ||
55 | ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, | ||
56 | ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least | ||
57 | ** as an emulation layer on top of native functions. | ||
58 | ** ========================================================================= | ||
59 | */ | ||
60 | |||
61 | #include <dlfcn.h> | ||
62 | |||
63 | static void ll_unloadlib (void *lib) { | ||
64 | dlclose(lib); | ||
65 | } | ||
66 | |||
67 | |||
68 | static void *ll_load (lua_State *L, const char *path) { | ||
69 | void *lib = dlopen(path, RTLD_NOW); | ||
70 | if (lib == NULL) lua_pushstring(L, dlerror()); | ||
71 | return lib; | ||
72 | } | ||
73 | |||
74 | |||
75 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
76 | lua_CFunction f = (lua_CFunction)dlsym(lib, sym); | ||
77 | if (f == NULL) lua_pushstring(L, dlerror()); | ||
78 | return f; | ||
79 | } | ||
80 | |||
81 | /* }====================================================== */ | ||
82 | |||
83 | |||
84 | |||
85 | #elif defined(LUA_DL_DLL) | ||
86 | /* | ||
87 | ** {====================================================================== | ||
88 | ** This is an implementation of loadlib for Windows using native functions. | ||
89 | ** ======================================================================= | ||
90 | */ | ||
91 | |||
92 | #include <windows.h> | ||
93 | |||
94 | |||
95 | #undef setprogdir | ||
96 | |||
97 | static void setprogdir (lua_State *L) { | ||
98 | char buff[MAX_PATH + 1]; | ||
99 | char *lb; | ||
100 | DWORD nsize = sizeof(buff)/sizeof(char); | ||
101 | DWORD n = GetModuleFileName(NULL, buff, nsize); | ||
102 | if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) | ||
103 | luaL_error(L, "unable to get ModuleFileName"); | ||
104 | else { | ||
105 | *lb = '\0'; | ||
106 | luaL_gsub(L, lua_tostring(L, -1), LUA_EXECDIR, buff); | ||
107 | lua_remove(L, -2); /* remove original string */ | ||
108 | } | ||
109 | } | ||
110 | |||
111 | |||
112 | static void pusherror (lua_State *L) { | ||
113 | int error = GetLastError(); | ||
114 | char buffer[128]; | ||
115 | if (FormatMessage(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, | ||
116 | NULL, error, 0, buffer, sizeof(buffer), NULL)) | ||
117 | lua_pushstring(L, buffer); | ||
118 | else | ||
119 | lua_pushfstring(L, "system error %d\n", error); | ||
120 | } | ||
121 | |||
122 | static void ll_unloadlib (void *lib) { | ||
123 | FreeLibrary((HINSTANCE)lib); | ||
124 | } | ||
125 | |||
126 | |||
127 | static void *ll_load (lua_State *L, const char *path) { | ||
128 | HINSTANCE lib = LoadLibrary(path); | ||
129 | if (lib == NULL) pusherror(L); | ||
130 | return lib; | ||
131 | } | ||
132 | |||
133 | |||
134 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
135 | lua_CFunction f = (lua_CFunction)GetProcAddress((HINSTANCE)lib, sym); | ||
136 | if (f == NULL) pusherror(L); | ||
137 | return f; | ||
138 | } | ||
139 | |||
140 | /* }====================================================== */ | ||
141 | |||
142 | |||
143 | |||
144 | #elif defined(LUA_DL_DYLD) | ||
145 | /* | ||
146 | ** {====================================================================== | ||
147 | ** Native Mac OS X / Darwin Implementation | ||
148 | ** ======================================================================= | ||
149 | */ | ||
150 | |||
151 | #include <mach-o/dyld.h> | ||
152 | |||
153 | |||
154 | /* Mac appends a `_' before C function names */ | ||
155 | #undef POF | ||
156 | #define POF "_" LUA_POF | ||
157 | |||
158 | |||
159 | static void pusherror (lua_State *L) { | ||
160 | const char *err_str; | ||
161 | const char *err_file; | ||
162 | NSLinkEditErrors err; | ||
163 | int err_num; | ||
164 | NSLinkEditError(&err, &err_num, &err_file, &err_str); | ||
165 | lua_pushstring(L, err_str); | ||
166 | } | ||
167 | |||
168 | |||
169 | static const char *errorfromcode (NSObjectFileImageReturnCode ret) { | ||
170 | switch (ret) { | ||
171 | case NSObjectFileImageInappropriateFile: | ||
172 | return "file is not a bundle"; | ||
173 | case NSObjectFileImageArch: | ||
174 | return "library is for wrong CPU type"; | ||
175 | case NSObjectFileImageFormat: | ||
176 | return "bad format"; | ||
177 | case NSObjectFileImageAccess: | ||
178 | return "cannot access file"; | ||
179 | case NSObjectFileImageFailure: | ||
180 | default: | ||
181 | return "unable to load library"; | ||
182 | } | ||
183 | } | ||
184 | |||
185 | |||
186 | static void ll_unloadlib (void *lib) { | ||
187 | NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES); | ||
188 | } | ||
189 | |||
190 | |||
191 | static void *ll_load (lua_State *L, const char *path) { | ||
192 | NSObjectFileImage img; | ||
193 | NSObjectFileImageReturnCode ret; | ||
194 | /* this would be a rare case, but prevents crashing if it happens */ | ||
195 | if(!_dyld_present()) { | ||
196 | lua_pushliteral(L, "dyld not present"); | ||
197 | return NULL; | ||
198 | } | ||
199 | ret = NSCreateObjectFileImageFromFile(path, &img); | ||
200 | if (ret == NSObjectFileImageSuccess) { | ||
201 | NSModule mod = NSLinkModule(img, path, NSLINKMODULE_OPTION_PRIVATE | | ||
202 | NSLINKMODULE_OPTION_RETURN_ON_ERROR); | ||
203 | NSDestroyObjectFileImage(img); | ||
204 | if (mod == NULL) pusherror(L); | ||
205 | return mod; | ||
206 | } | ||
207 | lua_pushstring(L, errorfromcode(ret)); | ||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | |||
212 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
213 | NSSymbol nss = NSLookupSymbolInModule((NSModule)lib, sym); | ||
214 | if (nss == NULL) { | ||
215 | lua_pushfstring(L, "symbol " LUA_QS " not found", sym); | ||
216 | return NULL; | ||
217 | } | ||
218 | return (lua_CFunction)NSAddressOfSymbol(nss); | ||
219 | } | ||
220 | |||
221 | /* }====================================================== */ | ||
222 | |||
223 | |||
224 | |||
225 | #else | ||
226 | /* | ||
227 | ** {====================================================== | ||
228 | ** Fallback for other systems | ||
229 | ** ======================================================= | ||
230 | */ | ||
231 | |||
232 | #undef LIB_FAIL | ||
233 | #define LIB_FAIL "absent" | ||
234 | |||
235 | |||
236 | #define DLMSG "dynamic libraries not enabled; check your Lua installation" | ||
237 | |||
238 | |||
239 | static void ll_unloadlib (void *lib) { | ||
240 | (void)lib; /* to avoid warnings */ | ||
241 | } | ||
242 | |||
243 | |||
244 | static void *ll_load (lua_State *L, const char *path) { | ||
245 | (void)path; /* to avoid warnings */ | ||
246 | lua_pushliteral(L, DLMSG); | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | |||
251 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
252 | (void)lib; (void)sym; /* to avoid warnings */ | ||
253 | lua_pushliteral(L, DLMSG); | ||
254 | return NULL; | ||
255 | } | ||
256 | |||
257 | /* }====================================================== */ | ||
258 | #endif | ||
259 | |||
260 | |||
261 | |||
262 | static void **ll_register (lua_State *L, const char *path) { | ||
263 | void **plib; | ||
264 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
265 | lua_gettable(L, LUA_REGISTRYINDEX); /* check library in registry? */ | ||
266 | if (!lua_isnil(L, -1)) /* is there an entry? */ | ||
267 | plib = (void **)lua_touserdata(L, -1); | ||
268 | else { /* no entry yet; create one */ | ||
269 | lua_pop(L, 1); | ||
270 | plib = (void **)lua_newuserdata(L, sizeof(const void *)); | ||
271 | *plib = NULL; | ||
272 | luaL_getmetatable(L, "_LOADLIB"); | ||
273 | lua_setmetatable(L, -2); | ||
274 | lua_pushfstring(L, "%s%s", LIBPREFIX, path); | ||
275 | lua_pushvalue(L, -2); | ||
276 | lua_settable(L, LUA_REGISTRYINDEX); | ||
277 | } | ||
278 | return plib; | ||
279 | } | ||
280 | |||
281 | |||
282 | /* | ||
283 | ** __gc tag method: calls library's `ll_unloadlib' function with the lib | ||
284 | ** handle | ||
285 | */ | ||
286 | static int gctm (lua_State *L) { | ||
287 | void **lib = (void **)luaL_checkudata(L, 1, "_LOADLIB"); | ||
288 | if (*lib) ll_unloadlib(*lib); | ||
289 | *lib = NULL; /* mark library as closed */ | ||
290 | return 0; | ||
291 | } | ||
292 | |||
293 | |||
294 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | ||
295 | void **reg = ll_register(L, path); | ||
296 | if (*reg == NULL) *reg = ll_load(L, path); | ||
297 | if (*reg == NULL) | ||
298 | return ERRLIB; /* unable to load library */ | ||
299 | else { | ||
300 | lua_CFunction f = ll_sym(L, *reg, sym); | ||
301 | if (f == NULL) | ||
302 | return ERRFUNC; /* unable to find function */ | ||
303 | lua_pushcfunction(L, f); | ||
304 | return 0; /* return function */ | ||
305 | } | ||
306 | } | ||
307 | |||
308 | |||
309 | static int ll_loadlib (lua_State *L) { | ||
310 | const char *path = luaL_checkstring(L, 1); | ||
311 | const char *init = luaL_checkstring(L, 2); | ||
312 | int stat = ll_loadfunc(L, path, init); | ||
313 | if (stat == 0) /* no errors? */ | ||
314 | return 1; /* return the loaded function */ | ||
315 | else { /* error; error message is on stack top */ | ||
316 | lua_pushnil(L); | ||
317 | lua_insert(L, -2); | ||
318 | lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); | ||
319 | return 3; /* return nil, error message, and where */ | ||
320 | } | ||
321 | } | ||
322 | |||
323 | |||
324 | |||
325 | /* | ||
326 | ** {====================================================== | ||
327 | ** 'require' function | ||
328 | ** ======================================================= | ||
329 | */ | ||
330 | |||
331 | |||
332 | static int readable (const char *filename) { | ||
333 | FILE *f = fopen(filename, "r"); /* try to open file */ | ||
334 | if (f == NULL) return 0; /* open failed */ | ||
335 | fclose(f); | ||
336 | return 1; | ||
337 | } | ||
338 | |||
339 | |||
340 | static const char *pushnexttemplate (lua_State *L, const char *path) { | ||
341 | const char *l; | ||
342 | while (*path == *LUA_PATHSEP) path++; /* skip separators */ | ||
343 | if (*path == '\0') return NULL; /* no more templates */ | ||
344 | l = strchr(path, *LUA_PATHSEP); /* find next separator */ | ||
345 | if (l == NULL) l = path + strlen(path); | ||
346 | lua_pushlstring(L, path, l - path); /* template */ | ||
347 | return l; | ||
348 | } | ||
349 | |||
350 | |||
351 | static const char *findfile (lua_State *L, const char *name, | ||
352 | const char *pname) { | ||
353 | const char *path; | ||
354 | name = luaL_gsub(L, name, ".", LUA_DIRSEP); | ||
355 | lua_getfield(L, LUA_ENVIRONINDEX, pname); | ||
356 | path = lua_tostring(L, -1); | ||
357 | if (path == NULL) | ||
358 | luaL_error(L, LUA_QL("package.%s") " must be a string", pname); | ||
359 | lua_pushstring(L, ""); /* error accumulator */ | ||
360 | while ((path = pushnexttemplate(L, path)) != NULL) { | ||
361 | const char *filename; | ||
362 | filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); | ||
363 | if (readable(filename)) /* does file exist and is readable? */ | ||
364 | return filename; /* return that file name */ | ||
365 | lua_pop(L, 2); /* remove path template and file name */ | ||
366 | luaO_pushfstring(L, "\n\tno file " LUA_QS, filename); | ||
367 | lua_concat(L, 2); | ||
368 | } | ||
369 | return NULL; /* not found */ | ||
370 | } | ||
371 | |||
372 | |||
373 | static void loaderror (lua_State *L, const char *filename) { | ||
374 | luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", | ||
375 | lua_tostring(L, 1), filename, lua_tostring(L, -1)); | ||
376 | } | ||
377 | |||
378 | |||
379 | static int loader_Lua (lua_State *L) { | ||
380 | const char *filename; | ||
381 | const char *name = luaL_checkstring(L, 1); | ||
382 | filename = findfile(L, name, "path"); | ||
383 | if (filename == NULL) return 1; /* library not found in this path */ | ||
384 | if (luaL_loadfile(L, filename) != 0) | ||
385 | loaderror(L, filename); | ||
386 | return 1; /* library loaded successfully */ | ||
387 | } | ||
388 | |||
389 | |||
390 | static const char *mkfuncname (lua_State *L, const char *modname) { | ||
391 | const char *funcname; | ||
392 | const char *mark = strchr(modname, *LUA_IGMARK); | ||
393 | if (mark) modname = mark + 1; | ||
394 | funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); | ||
395 | funcname = lua_pushfstring(L, POF"%s", funcname); | ||
396 | lua_remove(L, -2); /* remove 'gsub' result */ | ||
397 | return funcname; | ||
398 | } | ||
399 | |||
400 | |||
401 | static int loader_C (lua_State *L) { | ||
402 | const char *funcname; | ||
403 | const char *name = luaL_checkstring(L, 1); | ||
404 | const char *filename = findfile(L, name, "cpath"); | ||
405 | if (filename == NULL) return 1; /* library not found in this path */ | ||
406 | funcname = mkfuncname(L, name); | ||
407 | if (ll_loadfunc(L, filename, funcname) != 0) | ||
408 | loaderror(L, filename); | ||
409 | return 1; /* library loaded successfully */ | ||
410 | } | ||
411 | |||
412 | |||
413 | static int loader_Croot (lua_State *L) { | ||
414 | const char *funcname; | ||
415 | const char *filename; | ||
416 | const char *name = luaL_checkstring(L, 1); | ||
417 | const char *p = strchr(name, '.'); | ||
418 | int stat; | ||
419 | if (p == NULL) return 0; /* is root */ | ||
420 | lua_pushlstring(L, name, p - name); | ||
421 | filename = findfile(L, lua_tostring(L, -1), "cpath"); | ||
422 | if (filename == NULL) return 1; /* root not found */ | ||
423 | funcname = mkfuncname(L, name); | ||
424 | if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { | ||
425 | if (stat != ERRFUNC) loaderror(L, filename); /* real error */ | ||
426 | luaO_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, | ||
427 | name, filename); | ||
428 | return 1; /* function not found */ | ||
429 | } | ||
430 | return 1; | ||
431 | } | ||
432 | |||
433 | |||
434 | static int loader_preload (lua_State *L) { | ||
435 | const char *name = luaL_checkstring(L, 1); | ||
436 | lua_getfield(L, LUA_ENVIRONINDEX, "preload"); | ||
437 | if (!lua_istable(L, -1)) | ||
438 | luaL_error(L, LUA_QL("package.preload") " must be a table"); | ||
439 | lua_getfield(L, -1, name); | ||
440 | if (lua_isnil(L, -1)) /* not found? */ | ||
441 | luaO_pushfstring(L, "\n\tno field package.preload['%s']", name); | ||
442 | return 1; | ||
443 | } | ||
444 | |||
445 | |||
446 | static const int sentinel_ = 0; | ||
447 | #define sentinel ((void *)&sentinel_) | ||
448 | |||
449 | |||
450 | static int ll_require (lua_State *L) { | ||
451 | const char *name = luaL_checkstring(L, 1); | ||
452 | int i; | ||
453 | lua_settop(L, 1); /* _LOADED table will be at index 2 */ | ||
454 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | ||
455 | lua_getfield(L, 2, name); | ||
456 | if (lua_toboolean(L, -1)) { /* is it there? */ | ||
457 | if (lua_touserdata(L, -1) == sentinel) /* check loops */ | ||
458 | luaL_error(L, "loop or previous error loading module " LUA_QS, name); | ||
459 | return 1; /* package is already loaded */ | ||
460 | } | ||
461 | /* else must load it; iterate over available loaders */ | ||
462 | lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); | ||
463 | if (!lua_istable(L, -1)) | ||
464 | luaL_error(L, LUA_QL("package.loaders") " must be a table"); | ||
465 | lua_pushstring(L, ""); /* error message accumulator */ | ||
466 | for (i=1; ; i++) { | ||
467 | lua_rawgeti(L, -2, i); /* get a loader */ | ||
468 | if (lua_isnil(L, -1)) | ||
469 | luaL_error(L, "module " LUA_QS " not found:%s", | ||
470 | name, lua_tostring(L, -2)); | ||
471 | lua_pushstring(L, name); | ||
472 | lua_call(L, 1, 1); /* call it */ | ||
473 | if (lua_isfunction(L, -1)) /* did it find module? */ | ||
474 | break; /* module loaded successfully */ | ||
475 | else if (lua_isstring(L, -1)) /* loader returned error message? */ | ||
476 | lua_concat(L, 2); /* accumulate it */ | ||
477 | else | ||
478 | lua_pop(L, 1); | ||
479 | } | ||
480 | lua_pushlightuserdata(L, sentinel); | ||
481 | lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ | ||
482 | lua_pushstring(L, name); /* pass name as argument to module */ | ||
483 | lua_call(L, 1, 1); /* run loaded module */ | ||
484 | if (!lua_isnil(L, -1)) /* non-nil return? */ | ||
485 | lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ | ||
486 | lua_getfield(L, 2, name); | ||
487 | if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ | ||
488 | lua_pushboolean(L, 1); /* use true as result */ | ||
489 | lua_pushvalue(L, -1); /* extra copy to be returned */ | ||
490 | lua_setfield(L, 2, name); /* _LOADED[name] = true */ | ||
491 | } | ||
492 | return 1; | ||
493 | } | ||
494 | |||
495 | /* }====================================================== */ | ||
496 | |||
497 | |||
498 | |||
499 | /* | ||
500 | ** {====================================================== | ||
501 | ** 'module' function | ||
502 | ** ======================================================= | ||
503 | */ | ||
504 | |||
505 | |||
506 | static void setfenv (lua_State *L) { | ||
507 | lua_Debug ar; | ||
508 | lua_getstack(L, 1, &ar); | ||
509 | lua_getinfo(L, "f", &ar); | ||
510 | lua_pushvalue(L, -2); | ||
511 | lua_setfenv(L, -2); | ||
512 | lua_pop(L, 1); | ||
513 | } | ||
514 | |||
515 | |||
516 | static void dooptions (lua_State *L, int n) { | ||
517 | int i; | ||
518 | for (i = 2; i <= n; i++) { | ||
519 | lua_pushvalue(L, i); /* get option (a function) */ | ||
520 | lua_pushvalue(L, -2); /* module */ | ||
521 | lua_call(L, 1, 0); | ||
522 | } | ||
523 | } | ||
524 | |||
525 | |||
526 | static void modinit (lua_State *L, const char *modname) { | ||
527 | const char *dot; | ||
528 | lua_pushvalue(L, -1); | ||
529 | lua_setfield(L, -2, "_M"); /* module._M = module */ | ||
530 | lua_pushstring(L, modname); | ||
531 | lua_setfield(L, -2, "_NAME"); | ||
532 | dot = strrchr(modname, '.'); /* look for last dot in module name */ | ||
533 | if (dot == NULL) dot = modname; | ||
534 | else dot++; | ||
535 | /* set _PACKAGE as package name (full module name minus last part) */ | ||
536 | lua_pushlstring(L, modname, dot - modname); | ||
537 | lua_setfield(L, -2, "_PACKAGE"); | ||
538 | } | ||
539 | |||
540 | |||
541 | static int ll_module (lua_State *L) { | ||
542 | const char *modname = luaL_checkstring(L, 1); | ||
543 | int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ | ||
544 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | ||
545 | lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ | ||
546 | if (!lua_istable(L, -1)) { /* not found? */ | ||
547 | lua_pop(L, 1); /* remove previous result */ | ||
548 | /* try global variable (and create one if it does not exist) */ | ||
549 | if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) | ||
550 | return luaL_error(L, "name conflict for module " LUA_QS, modname); | ||
551 | lua_pushvalue(L, -1); | ||
552 | lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ | ||
553 | } | ||
554 | /* check whether table already has a _NAME field */ | ||
555 | lua_getfield(L, -1, "_NAME"); | ||
556 | if (!lua_isnil(L, -1)) /* is table an initialized module? */ | ||
557 | lua_pop(L, 1); | ||
558 | else { /* no; initialize it */ | ||
559 | lua_pop(L, 1); | ||
560 | modinit(L, modname); | ||
561 | } | ||
562 | lua_pushvalue(L, -1); | ||
563 | setfenv(L); | ||
564 | dooptions(L, loaded - 1); | ||
565 | return 0; | ||
566 | } | ||
567 | |||
568 | |||
569 | static int ll_seeall (lua_State *L) { | ||
570 | luaL_checktype(L, 1, LUA_TTABLE); | ||
571 | if (!lua_getmetatable(L, 1)) { | ||
572 | lua_createtable(L, 0, 1); /* create new metatable */ | ||
573 | lua_pushvalue(L, -1); | ||
574 | lua_setmetatable(L, 1); | ||
575 | } | ||
576 | lua_pushvalue(L, LUA_GLOBALSINDEX); | ||
577 | lua_setfield(L, -2, "__index"); /* mt.__index = _G */ | ||
578 | return 0; | ||
579 | } | ||
580 | |||
581 | |||
582 | /* }====================================================== */ | ||
583 | |||
584 | |||
585 | |||
586 | /* auxiliary mark (for internal use) */ | ||
587 | #define AUXMARK "\1" | ||
588 | |||
589 | static void setpath (lua_State *L, const char *fieldname, const char *envname, | ||
590 | const char *def) { | ||
591 | const char *path = getenv(envname); | ||
592 | if (path == NULL) /* no environment variable? */ | ||
593 | lua_pushstring(L, def); /* use default */ | ||
594 | else { | ||
595 | /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */ | ||
596 | path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP, | ||
597 | LUA_PATHSEP AUXMARK LUA_PATHSEP); | ||
598 | luaL_gsub(L, path, AUXMARK, def); | ||
599 | lua_remove(L, -2); | ||
600 | } | ||
601 | setprogdir(L); | ||
602 | lua_setfield(L, -2, fieldname); | ||
603 | } | ||
604 | |||
605 | |||
606 | static const luaL_Reg pk_funcs[] = { | ||
607 | {"loadlib", ll_loadlib}, | ||
608 | {"seeall", ll_seeall}, | ||
609 | {NULL, NULL} | ||
610 | }; | ||
611 | |||
612 | |||
613 | static const luaL_Reg ll_funcs[] = { | ||
614 | {"module", ll_module}, | ||
615 | {"require", ll_require}, | ||
616 | {NULL, NULL} | ||
617 | }; | ||
618 | |||
619 | |||
620 | static const lua_CFunction loaders[] = | ||
621 | {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; | ||
622 | |||
623 | |||
624 | LUALIB_API int luaopen_package (lua_State *L) { | ||
625 | int i; | ||
626 | /* create new type _LOADLIB */ | ||
627 | luaL_newmetatable(L, "_LOADLIB"); | ||
628 | lua_pushcfunction(L, gctm); | ||
629 | lua_setfield(L, -2, "__gc"); | ||
630 | /* create `package' table */ | ||
631 | luaL_register(L, LUA_LOADLIBNAME, pk_funcs); | ||
632 | #if defined(LUA_COMPAT_LOADLIB) | ||
633 | lua_getfield(L, -1, "loadlib"); | ||
634 | lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); | ||
635 | #endif | ||
636 | lua_pushvalue(L, -1); | ||
637 | lua_replace(L, LUA_ENVIRONINDEX); | ||
638 | /* create `loaders' table */ | ||
639 | lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); | ||
640 | /* fill it with pre-defined loaders */ | ||
641 | for (i=0; loaders[i] != NULL; i++) { | ||
642 | lua_pushcfunction(L, loaders[i]); | ||
643 | lua_rawseti(L, -2, i+1); | ||
644 | } | ||
645 | lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ | ||
646 | setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ | ||
647 | setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */ | ||
648 | /* store config information */ | ||
649 | lua_pushstring(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" | ||
650 | LUA_EXECDIR "\n" LUA_IGMARK); | ||
651 | lua_setfield(L, -2, "config"); | ||
652 | /* set field `loaded' */ | ||
653 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); | ||
654 | lua_setfield(L, -2, "loaded"); | ||
655 | /* set field `preload' */ | ||
656 | lua_newtable(L); | ||
657 | lua_setfield(L, -2, "preload"); | ||
658 | lua_pushvalue(L, LUA_GLOBALSINDEX); | ||
659 | luaL_register(L, NULL, ll_funcs); /* open lib into global table */ | ||
660 | lua_pop(L, 1); | ||
661 | return 1; /* return 'package' table */ | ||
662 | } | ||
663 | |||