1 /* $NetBSD: loadlib.c,v 1.1.1.2 2012/03/15 00:08:12 alnsn Exp $ */
4 ** $Id: loadlib.c,v 1.1.1.2 2012/03/15 00:08:12 alnsn Exp $
5 ** Dynamic library loader for Lua
6 ** See Copyright Notice in lua.h
8 ** This module contains an implementation of loadlib for Unix systems
9 ** that have dlfcn, an implementation for Darwin (Mac OS X), an
10 ** implementation for Windows, and a stub for other systems.
27 /* prefix for open functions in C libraries */
28 #define LUA_POF "luaopen_"
30 /* separator for open functions in C libraries */
34 #define LIBPREFIX "LOADLIB: "
37 #define LIB_FAIL "open"
40 /* error codes for ll_loadfunc */
44 #define setprogdir(L) ((void)0)
47 static void ll_unloadlib (void *lib
);
48 static void *ll_load (lua_State
*L
, const char *path
);
49 static lua_CFunction
ll_sym (lua_State
*L
, void *lib
, const char *sym
);
53 #if defined(LUA_DL_DLOPEN)
55 ** {========================================================================
56 ** This is an implementation of loadlib based on the dlfcn interface.
57 ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD,
58 ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least
59 ** as an emulation layer on top of native functions.
60 ** =========================================================================
65 static void ll_unloadlib (void *lib
) {
70 static void *ll_load (lua_State
*L
, const char *path
) {
71 void *lib
= dlopen(path
, RTLD_NOW
);
72 if (lib
== NULL
) lua_pushstring(L
, dlerror());
77 static lua_CFunction
ll_sym (lua_State
*L
, void *lib
, const char *sym
) {
78 lua_CFunction f
= (lua_CFunction
)dlsym(lib
, sym
);
79 if (f
== NULL
) lua_pushstring(L
, dlerror());
83 /* }====================================================== */
87 #elif defined(LUA_DL_DLL)
89 ** {======================================================================
90 ** This is an implementation of loadlib for Windows using native functions.
91 ** =======================================================================
99 static void setprogdir (lua_State
*L
) {
100 char buff
[MAX_PATH
+ 1];
102 DWORD nsize
= sizeof(buff
)/sizeof(char);
103 DWORD n
= GetModuleFileNameA(NULL
, buff
, nsize
);
104 if (n
== 0 || n
== nsize
|| (lb
= strrchr(buff
, '\\')) == NULL
)
105 luaL_error(L
, "unable to get ModuleFileName");
108 luaL_gsub(L
, lua_tostring(L
, -1), LUA_EXECDIR
, buff
);
109 lua_remove(L
, -2); /* remove original string */
114 static void pusherror (lua_State
*L
) {
115 int error
= GetLastError();
117 if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS
| FORMAT_MESSAGE_FROM_SYSTEM
,
118 NULL
, error
, 0, buffer
, sizeof(buffer
), NULL
))
119 lua_pushstring(L
, buffer
);
121 lua_pushfstring(L
, "system error %d\n", error
);
124 static void ll_unloadlib (void *lib
) {
125 FreeLibrary((HINSTANCE
)lib
);
129 static void *ll_load (lua_State
*L
, const char *path
) {
130 HINSTANCE lib
= LoadLibraryA(path
);
131 if (lib
== NULL
) pusherror(L
);
136 static lua_CFunction
ll_sym (lua_State
*L
, void *lib
, const char *sym
) {
137 lua_CFunction f
= (lua_CFunction
)GetProcAddress((HINSTANCE
)lib
, sym
);
138 if (f
== NULL
) pusherror(L
);
142 /* }====================================================== */
146 #elif defined(LUA_DL_DYLD)
148 ** {======================================================================
149 ** Native Mac OS X / Darwin Implementation
150 ** =======================================================================
153 #include <mach-o/dyld.h>
156 /* Mac appends a `_' before C function names */
158 #define POF "_" LUA_POF
161 static void pusherror (lua_State
*L
) {
163 const char *err_file
;
164 NSLinkEditErrors err
;
166 NSLinkEditError(&err
, &err_num
, &err_file
, &err_str
);
167 lua_pushstring(L
, err_str
);
171 static const char *errorfromcode (NSObjectFileImageReturnCode ret
) {
173 case NSObjectFileImageInappropriateFile
:
174 return "file is not a bundle";
175 case NSObjectFileImageArch
:
176 return "library is for wrong CPU type";
177 case NSObjectFileImageFormat
:
179 case NSObjectFileImageAccess
:
180 return "cannot access file";
181 case NSObjectFileImageFailure
:
183 return "unable to load library";
188 static void ll_unloadlib (void *lib
) {
189 NSUnLinkModule((NSModule
)lib
, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES
);
193 static void *ll_load (lua_State
*L
, const char *path
) {
194 NSObjectFileImage img
;
195 NSObjectFileImageReturnCode ret
;
196 /* this would be a rare case, but prevents crashing if it happens */
197 if(!_dyld_present()) {
198 lua_pushliteral(L
, "dyld not present");
201 ret
= NSCreateObjectFileImageFromFile(path
, &img
);
202 if (ret
== NSObjectFileImageSuccess
) {
203 NSModule mod
= NSLinkModule(img
, path
, NSLINKMODULE_OPTION_PRIVATE
|
204 NSLINKMODULE_OPTION_RETURN_ON_ERROR
);
205 NSDestroyObjectFileImage(img
);
206 if (mod
== NULL
) pusherror(L
);
209 lua_pushstring(L
, errorfromcode(ret
));
214 static lua_CFunction
ll_sym (lua_State
*L
, void *lib
, const char *sym
) {
215 NSSymbol nss
= NSLookupSymbolInModule((NSModule
)lib
, sym
);
217 lua_pushfstring(L
, "symbol " LUA_QS
" not found", sym
);
220 return (lua_CFunction
)NSAddressOfSymbol(nss
);
223 /* }====================================================== */
229 ** {======================================================
230 ** Fallback for other systems
231 ** =======================================================
235 #define LIB_FAIL "absent"
238 #define DLMSG "dynamic libraries not enabled; check your Lua installation"
241 static void ll_unloadlib (void *lib
) {
242 (void)lib
; /* to avoid warnings */
246 static void *ll_load (lua_State
*L
, const char *path
) {
247 (void)path
; /* to avoid warnings */
248 lua_pushliteral(L
, DLMSG
);
253 static lua_CFunction
ll_sym (lua_State
*L
, void *lib
, const char *sym
) {
254 (void)lib
; (void)sym
; /* to avoid warnings */
255 lua_pushliteral(L
, DLMSG
);
259 /* }====================================================== */
264 static void **ll_register (lua_State
*L
, const char *path
) {
266 lua_pushfstring(L
, "%s%s", LIBPREFIX
, path
);
267 lua_gettable(L
, LUA_REGISTRYINDEX
); /* check library in registry? */
268 if (!lua_isnil(L
, -1)) /* is there an entry? */
269 plib
= (void **)lua_touserdata(L
, -1);
270 else { /* no entry yet; create one */
272 plib
= (void **)lua_newuserdata(L
, sizeof(const void *));
274 luaL_getmetatable(L
, "_LOADLIB");
275 lua_setmetatable(L
, -2);
276 lua_pushfstring(L
, "%s%s", LIBPREFIX
, path
);
277 lua_pushvalue(L
, -2);
278 lua_settable(L
, LUA_REGISTRYINDEX
);
285 ** __gc tag method: calls library's `ll_unloadlib' function with the lib
288 static int gctm (lua_State
*L
) {
289 void **lib
= (void **)luaL_checkudata(L
, 1, "_LOADLIB");
290 if (*lib
) ll_unloadlib(*lib
);
291 *lib
= NULL
; /* mark library as closed */
296 static int ll_loadfunc (lua_State
*L
, const char *path
, const char *sym
) {
297 void **reg
= ll_register(L
, path
);
298 if (*reg
== NULL
) *reg
= ll_load(L
, path
);
300 return ERRLIB
; /* unable to load library */
302 lua_CFunction f
= ll_sym(L
, *reg
, sym
);
304 return ERRFUNC
; /* unable to find function */
305 lua_pushcfunction(L
, f
);
306 return 0; /* return function */
311 static int ll_loadlib (lua_State
*L
) {
312 const char *path
= luaL_checkstring(L
, 1);
313 const char *init
= luaL_checkstring(L
, 2);
314 int stat
= ll_loadfunc(L
, path
, init
);
315 if (stat
== 0) /* no errors? */
316 return 1; /* return the loaded function */
317 else { /* error; error message is on stack top */
320 lua_pushstring(L
, (stat
== ERRLIB
) ? LIB_FAIL
: "init");
321 return 3; /* return nil, error message, and where */
328 ** {======================================================
329 ** 'require' function
330 ** =======================================================
334 static int readable (const char *filename
) {
335 FILE *f
= fopen(filename
, "r"); /* try to open file */
336 if (f
== NULL
) return 0; /* open failed */
342 static const char *pushnexttemplate (lua_State
*L
, const char *path
) {
344 while (*path
== *LUA_PATHSEP
) path
++; /* skip separators */
345 if (*path
== '\0') return NULL
; /* no more templates */
346 l
= strchr(path
, *LUA_PATHSEP
); /* find next separator */
347 if (l
== NULL
) l
= path
+ strlen(path
);
348 lua_pushlstring(L
, path
, l
- path
); /* template */
353 static const char *findfile (lua_State
*L
, const char *name
,
356 name
= luaL_gsub(L
, name
, ".", LUA_DIRSEP
);
357 lua_getfield(L
, LUA_ENVIRONINDEX
, pname
);
358 path
= lua_tostring(L
, -1);
360 luaL_error(L
, LUA_QL("package.%s") " must be a string", pname
);
361 lua_pushliteral(L
, ""); /* error accumulator */
362 while ((path
= pushnexttemplate(L
, path
)) != NULL
) {
363 const char *filename
;
364 filename
= luaL_gsub(L
, lua_tostring(L
, -1), LUA_PATH_MARK
, name
);
365 lua_remove(L
, -2); /* remove path template */
366 if (readable(filename
)) /* does file exist and is readable? */
367 return filename
; /* return that file name */
368 lua_pushfstring(L
, "\n\tno file " LUA_QS
, filename
);
369 lua_remove(L
, -2); /* remove file name */
370 lua_concat(L
, 2); /* add entry to possible error message */
372 return NULL
; /* not found */
376 static void loaderror (lua_State
*L
, const char *filename
) {
377 luaL_error(L
, "error loading module " LUA_QS
" from file " LUA_QS
":\n\t%s",
378 lua_tostring(L
, 1), filename
, lua_tostring(L
, -1));
382 static int loader_Lua (lua_State
*L
) {
383 const char *filename
;
384 const char *name
= luaL_checkstring(L
, 1);
385 filename
= findfile(L
, name
, "path");
386 if (filename
== NULL
) return 1; /* library not found in this path */
387 if (luaL_loadfile(L
, filename
) != 0)
388 loaderror(L
, filename
);
389 return 1; /* library loaded successfully */
393 static const char *mkfuncname (lua_State
*L
, const char *modname
) {
394 const char *funcname
;
395 const char *mark
= strchr(modname
, *LUA_IGMARK
);
396 if (mark
) modname
= mark
+ 1;
397 funcname
= luaL_gsub(L
, modname
, ".", LUA_OFSEP
);
398 funcname
= lua_pushfstring(L
, POF
"%s", funcname
);
399 lua_remove(L
, -2); /* remove 'gsub' result */
404 static int loader_C (lua_State
*L
) {
405 const char *funcname
;
406 const char *name
= luaL_checkstring(L
, 1);
407 const char *filename
= findfile(L
, name
, "cpath");
408 if (filename
== NULL
) return 1; /* library not found in this path */
409 funcname
= mkfuncname(L
, name
);
410 if (ll_loadfunc(L
, filename
, funcname
) != 0)
411 loaderror(L
, filename
);
412 return 1; /* library loaded successfully */
416 static int loader_Croot (lua_State
*L
) {
417 const char *funcname
;
418 const char *filename
;
419 const char *name
= luaL_checkstring(L
, 1);
420 const char *p
= strchr(name
, '.');
422 if (p
== NULL
) return 0; /* is root */
423 lua_pushlstring(L
, name
, p
- name
);
424 filename
= findfile(L
, lua_tostring(L
, -1), "cpath");
425 if (filename
== NULL
) return 1; /* root not found */
426 funcname
= mkfuncname(L
, name
);
427 if ((stat
= ll_loadfunc(L
, filename
, funcname
)) != 0) {
428 if (stat
!= ERRFUNC
) loaderror(L
, filename
); /* real error */
429 lua_pushfstring(L
, "\n\tno module " LUA_QS
" in file " LUA_QS
,
431 return 1; /* function not found */
437 static int loader_preload (lua_State
*L
) {
438 const char *name
= luaL_checkstring(L
, 1);
439 lua_getfield(L
, LUA_ENVIRONINDEX
, "preload");
440 if (!lua_istable(L
, -1))
441 luaL_error(L
, LUA_QL("package.preload") " must be a table");
442 lua_getfield(L
, -1, name
);
443 if (lua_isnil(L
, -1)) /* not found? */
444 lua_pushfstring(L
, "\n\tno field package.preload['%s']", name
);
449 static const int sentinel_
= 0;
450 #define sentinel ((void *)&sentinel_)
453 static int ll_require (lua_State
*L
) {
454 const char *name
= luaL_checkstring(L
, 1);
456 lua_settop(L
, 1); /* _LOADED table will be at index 2 */
457 lua_getfield(L
, LUA_REGISTRYINDEX
, "_LOADED");
458 lua_getfield(L
, 2, name
);
459 if (lua_toboolean(L
, -1)) { /* is it there? */
460 if (lua_touserdata(L
, -1) == sentinel
) /* check loops */
461 luaL_error(L
, "loop or previous error loading module " LUA_QS
, name
);
462 return 1; /* package is already loaded */
464 /* else must load it; iterate over available loaders */
465 lua_getfield(L
, LUA_ENVIRONINDEX
, "loaders");
466 if (!lua_istable(L
, -1))
467 luaL_error(L
, LUA_QL("package.loaders") " must be a table");
468 lua_pushliteral(L
, ""); /* error message accumulator */
470 lua_rawgeti(L
, -2, i
); /* get a loader */
471 if (lua_isnil(L
, -1))
472 luaL_error(L
, "module " LUA_QS
" not found:%s",
473 name
, lua_tostring(L
, -2));
474 lua_pushstring(L
, name
);
475 lua_call(L
, 1, 1); /* call it */
476 if (lua_isfunction(L
, -1)) /* did it find module? */
477 break; /* module loaded successfully */
478 else if (lua_isstring(L
, -1)) /* loader returned error message? */
479 lua_concat(L
, 2); /* accumulate it */
483 lua_pushlightuserdata(L
, sentinel
);
484 lua_setfield(L
, 2, name
); /* _LOADED[name] = sentinel */
485 lua_pushstring(L
, name
); /* pass name as argument to module */
486 lua_call(L
, 1, 1); /* run loaded module */
487 if (!lua_isnil(L
, -1)) /* non-nil return? */
488 lua_setfield(L
, 2, name
); /* _LOADED[name] = returned value */
489 lua_getfield(L
, 2, name
);
490 if (lua_touserdata(L
, -1) == sentinel
) { /* module did not set a value? */
491 lua_pushboolean(L
, 1); /* use true as result */
492 lua_pushvalue(L
, -1); /* extra copy to be returned */
493 lua_setfield(L
, 2, name
); /* _LOADED[name] = true */
498 /* }====================================================== */
503 ** {======================================================
505 ** =======================================================
509 static void setfenv (lua_State
*L
) {
511 if (lua_getstack(L
, 1, &ar
) == 0 ||
512 lua_getinfo(L
, "f", &ar
) == 0 || /* get calling function */
513 lua_iscfunction(L
, -1))
514 luaL_error(L
, LUA_QL("module") " not called from a Lua function");
515 lua_pushvalue(L
, -2);
521 static void dooptions (lua_State
*L
, int n
) {
523 for (i
= 2; i
<= n
; i
++) {
524 lua_pushvalue(L
, i
); /* get option (a function) */
525 lua_pushvalue(L
, -2); /* module */
531 static void modinit (lua_State
*L
, const char *modname
) {
533 lua_pushvalue(L
, -1);
534 lua_setfield(L
, -2, "_M"); /* module._M = module */
535 lua_pushstring(L
, modname
);
536 lua_setfield(L
, -2, "_NAME");
537 dot
= strrchr(modname
, '.'); /* look for last dot in module name */
538 if (dot
== NULL
) dot
= modname
;
540 /* set _PACKAGE as package name (full module name minus last part) */
541 lua_pushlstring(L
, modname
, dot
- modname
);
542 lua_setfield(L
, -2, "_PACKAGE");
546 static int ll_module (lua_State
*L
) {
547 const char *modname
= luaL_checkstring(L
, 1);
548 int loaded
= lua_gettop(L
) + 1; /* index of _LOADED table */
549 lua_getfield(L
, LUA_REGISTRYINDEX
, "_LOADED");
550 lua_getfield(L
, loaded
, modname
); /* get _LOADED[modname] */
551 if (!lua_istable(L
, -1)) { /* not found? */
552 lua_pop(L
, 1); /* remove previous result */
553 /* try global variable (and create one if it does not exist) */
554 if (luaL_findtable(L
, LUA_GLOBALSINDEX
, modname
, 1) != NULL
)
555 return luaL_error(L
, "name conflict for module " LUA_QS
, modname
);
556 lua_pushvalue(L
, -1);
557 lua_setfield(L
, loaded
, modname
); /* _LOADED[modname] = new table */
559 /* check whether table already has a _NAME field */
560 lua_getfield(L
, -1, "_NAME");
561 if (!lua_isnil(L
, -1)) /* is table an initialized module? */
563 else { /* no; initialize it */
567 lua_pushvalue(L
, -1);
569 dooptions(L
, loaded
- 1);
574 static int ll_seeall (lua_State
*L
) {
575 luaL_checktype(L
, 1, LUA_TTABLE
);
576 if (!lua_getmetatable(L
, 1)) {
577 lua_createtable(L
, 0, 1); /* create new metatable */
578 lua_pushvalue(L
, -1);
579 lua_setmetatable(L
, 1);
581 lua_pushvalue(L
, LUA_GLOBALSINDEX
);
582 lua_setfield(L
, -2, "__index"); /* mt.__index = _G */
587 /* }====================================================== */
591 /* auxiliary mark (for internal use) */
594 static void setpath (lua_State
*L
, const char *fieldname
, const char *envname
,
596 const char *path
= getenv(envname
);
597 if (path
== NULL
) /* no environment variable? */
598 lua_pushstring(L
, def
); /* use default */
600 /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
601 path
= luaL_gsub(L
, path
, LUA_PATHSEP LUA_PATHSEP
,
602 LUA_PATHSEP AUXMARK LUA_PATHSEP
);
603 luaL_gsub(L
, path
, AUXMARK
, def
);
607 lua_setfield(L
, -2, fieldname
);
611 static const luaL_Reg pk_funcs
[] = {
612 {"loadlib", ll_loadlib
},
613 {"seeall", ll_seeall
},
618 static const luaL_Reg ll_funcs
[] = {
619 {"module", ll_module
},
620 {"require", ll_require
},
625 static const lua_CFunction loaders
[] =
626 {loader_preload
, loader_Lua
, loader_C
, loader_Croot
, NULL
};
629 LUALIB_API
int luaopen_package (lua_State
*L
) {
631 /* create new type _LOADLIB */
632 luaL_newmetatable(L
, "_LOADLIB");
633 lua_pushcfunction(L
, gctm
);
634 lua_setfield(L
, -2, "__gc");
635 /* create `package' table */
636 luaL_register(L
, LUA_LOADLIBNAME
, pk_funcs
);
637 #if defined(LUA_COMPAT_LOADLIB)
638 lua_getfield(L
, -1, "loadlib");
639 lua_setfield(L
, LUA_GLOBALSINDEX
, "loadlib");
641 lua_pushvalue(L
, -1);
642 lua_replace(L
, LUA_ENVIRONINDEX
);
643 /* create `loaders' table */
644 lua_createtable(L
, sizeof(loaders
)/sizeof(loaders
[0]) - 1, 0);
645 /* fill it with pre-defined loaders */
646 for (i
=0; loaders
[i
] != NULL
; i
++) {
647 lua_pushcfunction(L
, loaders
[i
]);
648 lua_rawseti(L
, -2, i
+1);
650 lua_setfield(L
, -2, "loaders"); /* put it in field `loaders' */
651 setpath(L
, "path", LUA_PATH
, LUA_PATH_DEFAULT
); /* set field `path' */
652 setpath(L
, "cpath", LUA_CPATH
, LUA_CPATH_DEFAULT
); /* set field `cpath' */
653 /* store config information */
654 lua_pushliteral(L
, LUA_DIRSEP
"\n" LUA_PATHSEP
"\n" LUA_PATH_MARK
"\n"
655 LUA_EXECDIR
"\n" LUA_IGMARK
);
656 lua_setfield(L
, -2, "config");
657 /* set field `loaded' */
658 luaL_findtable(L
, LUA_REGISTRYINDEX
, "_LOADED", 2);
659 lua_setfield(L
, -2, "loaded");
660 /* set field `preload' */
662 lua_setfield(L
, -2, "preload");
663 lua_pushvalue(L
, LUA_GLOBALSINDEX
);
664 luaL_register(L
, NULL
, ll_funcs
); /* open lib into global table */
666 return 1; /* return 'package' table */