source: project/lua/loadlib.c @ 4980

Last change on this file since 4980 was 4980, checked in by felix winkelmann, 12 years ago

updated xmi, added lua

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