Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/ceguilua/src/lua/loadlib.c @ 1835

Last change on this file since 1835 was 1806, checked in by rgrieder, 16 years ago

added single 5.1.3 directory for lua since CEGUILua 0.5 can also build against lua 5.1

  • Property svn:eol-style set to native
File size: 18.6 KB
RevLine 
[1806]1/*
2** $Id: loadlib.c,v 1.52.1.2 2007/12/28 14:58:43 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 "lua.h"
20
21#include "lauxlib.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
45static void ll_unloadlib (void *lib);
46static void *ll_load (lua_State *L, const char *path);
47static 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
63static void ll_unloadlib (void *lib) {
64  dlclose(lib);
65}
66
67
68static 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
75static 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
97static void setprogdir (lua_State *L) {
98  char buff[MAX_PATH + 1];
99  char *lb;
100  DWORD nsize = sizeof(buff)/sizeof(char);
101  DWORD n = GetModuleFileNameA(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
112static void pusherror (lua_State *L) {
113  int error = GetLastError();
114  char buffer[128];
115  if (FormatMessageA(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
122static void ll_unloadlib (void *lib) {
123  FreeLibrary((HINSTANCE)lib);
124}
125
126
127static void *ll_load (lua_State *L, const char *path) {
128  HINSTANCE lib = LoadLibraryA(path);
129  if (lib == NULL) pusherror(L);
130  return lib;
131}
132
133
134static 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
159static 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
169static 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
186static void ll_unloadlib (void *lib) {
187  NSUnLinkModule((NSModule)lib, NSUNLINKMODULE_OPTION_RESET_LAZY_REFERENCES);
188}
189
190
191static 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
212static 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
239static void ll_unloadlib (void *lib) {
240  (void)lib;  /* to avoid warnings */
241}
242
243
244static 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
251static 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
262static 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*/
286static 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
294static 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
309static 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
332static 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
340static 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
351static 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_pushliteral(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    lua_remove(L, -2);  /* remove path template */
364    if (readable(filename))  /* does file exist and is readable? */
365      return filename;  /* return that file name */
366    lua_pushfstring(L, "\n\tno file " LUA_QS, filename);
367    lua_remove(L, -2);  /* remove file name */
368    lua_concat(L, 2);  /* add entry to possible error message */
369  }
370  return NULL;  /* not found */
371}
372
373
374static void loaderror (lua_State *L, const char *filename) {
375  luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s",
376                lua_tostring(L, 1), filename, lua_tostring(L, -1));
377}
378
379
380static int loader_Lua (lua_State *L) {
381  const char *filename;
382  const char *name = luaL_checkstring(L, 1);
383  filename = findfile(L, name, "path");
384  if (filename == NULL) return 1;  /* library not found in this path */
385  if (luaL_loadfile(L, filename) != 0)
386    loaderror(L, filename);
387  return 1;  /* library loaded successfully */
388}
389
390
391static const char *mkfuncname (lua_State *L, const char *modname) {
392  const char *funcname;
393  const char *mark = strchr(modname, *LUA_IGMARK);
394  if (mark) modname = mark + 1;
395  funcname = luaL_gsub(L, modname, ".", LUA_OFSEP);
396  funcname = lua_pushfstring(L, POF"%s", funcname);
397  lua_remove(L, -2);  /* remove 'gsub' result */
398  return funcname;
399}
400
401
402static int loader_C (lua_State *L) {
403  const char *funcname;
404  const char *name = luaL_checkstring(L, 1);
405  const char *filename = findfile(L, name, "cpath");
406  if (filename == NULL) return 1;  /* library not found in this path */
407  funcname = mkfuncname(L, name);
408  if (ll_loadfunc(L, filename, funcname) != 0)
409    loaderror(L, filename);
410  return 1;  /* library loaded successfully */
411}
412
413
414static int loader_Croot (lua_State *L) {
415  const char *funcname;
416  const char *filename;
417  const char *name = luaL_checkstring(L, 1);
418  const char *p = strchr(name, '.');
419  int stat;
420  if (p == NULL) return 0;  /* is root */
421  lua_pushlstring(L, name, p - name);
422  filename = findfile(L, lua_tostring(L, -1), "cpath");
423  if (filename == NULL) return 1;  /* root not found */
424  funcname = mkfuncname(L, name);
425  if ((stat = ll_loadfunc(L, filename, funcname)) != 0) {
426    if (stat != ERRFUNC) loaderror(L, filename);  /* real error */
427    lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS,
428                       name, filename);
429    return 1;  /* function not found */
430  }
431  return 1;
432}
433
434
435static int loader_preload (lua_State *L) {
436  const char *name = luaL_checkstring(L, 1);
437  lua_getfield(L, LUA_ENVIRONINDEX, "preload");
438  if (!lua_istable(L, -1))
439    luaL_error(L, LUA_QL("package.preload") " must be a table");
440  lua_getfield(L, -1, name);
441  if (lua_isnil(L, -1))  /* not found? */
442    lua_pushfstring(L, "\n\tno field package.preload['%s']", name);
443  return 1;
444}
445
446
447static const int sentinel_ = 0;
448#define sentinel        ((void *)&sentinel_)
449
450
451static int ll_require (lua_State *L) {
452  const char *name = luaL_checkstring(L, 1);
453  int i;
454  lua_settop(L, 1);  /* _LOADED table will be at index 2 */
455  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
456  lua_getfield(L, 2, name);
457  if (lua_toboolean(L, -1)) {  /* is it there? */
458    if (lua_touserdata(L, -1) == sentinel)  /* check loops */
459      luaL_error(L, "loop or previous error loading module " LUA_QS, name);
460    return 1;  /* package is already loaded */
461  }
462  /* else must load it; iterate over available loaders */
463  lua_getfield(L, LUA_ENVIRONINDEX, "loaders");
464  if (!lua_istable(L, -1))
465    luaL_error(L, LUA_QL("package.loaders") " must be a table");
466  lua_pushliteral(L, "");  /* error message accumulator */
467  for (i=1; ; i++) {
468    lua_rawgeti(L, -2, i);  /* get a loader */
469    if (lua_isnil(L, -1))
470      luaL_error(L, "module " LUA_QS " not found:%s",
471                    name, lua_tostring(L, -2));
472    lua_pushstring(L, name);
473    lua_call(L, 1, 1);  /* call it */
474    if (lua_isfunction(L, -1))  /* did it find module? */
475      break;  /* module loaded successfully */
476    else if (lua_isstring(L, -1))  /* loader returned error message? */
477      lua_concat(L, 2);  /* accumulate it */
478    else
479      lua_pop(L, 1);
480  }
481  lua_pushlightuserdata(L, sentinel);
482  lua_setfield(L, 2, name);  /* _LOADED[name] = sentinel */
483  lua_pushstring(L, name);  /* pass name as argument to module */
484  lua_call(L, 1, 1);  /* run loaded module */
485  if (!lua_isnil(L, -1))  /* non-nil return? */
486    lua_setfield(L, 2, name);  /* _LOADED[name] = returned value */
487  lua_getfield(L, 2, name);
488  if (lua_touserdata(L, -1) == sentinel) {   /* module did not set a value? */
489    lua_pushboolean(L, 1);  /* use true as result */
490    lua_pushvalue(L, -1);  /* extra copy to be returned */
491    lua_setfield(L, 2, name);  /* _LOADED[name] = true */
492  }
493  return 1;
494}
495
496/* }====================================================== */
497
498
499
500/*
501** {======================================================
502** 'module' function
503** =======================================================
504*/
505 
506
507static void setfenv (lua_State *L) {
508  lua_Debug ar;
509  lua_getstack(L, 1, &ar);
510  lua_getinfo(L, "f", &ar);
511  lua_pushvalue(L, -2);
512  lua_setfenv(L, -2);
513  lua_pop(L, 1);
514}
515
516
517static void dooptions (lua_State *L, int n) {
518  int i;
519  for (i = 2; i <= n; i++) {
520    lua_pushvalue(L, i);  /* get option (a function) */
521    lua_pushvalue(L, -2);  /* module */
522    lua_call(L, 1, 0);
523  }
524}
525
526
527static void modinit (lua_State *L, const char *modname) {
528  const char *dot;
529  lua_pushvalue(L, -1);
530  lua_setfield(L, -2, "_M");  /* module._M = module */
531  lua_pushstring(L, modname);
532  lua_setfield(L, -2, "_NAME");
533  dot = strrchr(modname, '.');  /* look for last dot in module name */
534  if (dot == NULL) dot = modname;
535  else dot++;
536  /* set _PACKAGE as package name (full module name minus last part) */
537  lua_pushlstring(L, modname, dot - modname);
538  lua_setfield(L, -2, "_PACKAGE");
539}
540
541
542static int ll_module (lua_State *L) {
543  const char *modname = luaL_checkstring(L, 1);
544  int loaded = lua_gettop(L) + 1;  /* index of _LOADED table */
545  lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED");
546  lua_getfield(L, loaded, modname);  /* get _LOADED[modname] */
547  if (!lua_istable(L, -1)) {  /* not found? */
548    lua_pop(L, 1);  /* remove previous result */
549    /* try global variable (and create one if it does not exist) */
550    if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL)
551      return luaL_error(L, "name conflict for module " LUA_QS, modname);
552    lua_pushvalue(L, -1);
553    lua_setfield(L, loaded, modname);  /* _LOADED[modname] = new table */
554  }
555  /* check whether table already has a _NAME field */
556  lua_getfield(L, -1, "_NAME");
557  if (!lua_isnil(L, -1))  /* is table an initialized module? */
558    lua_pop(L, 1);
559  else {  /* no; initialize it */
560    lua_pop(L, 1);
561    modinit(L, modname);
562  }
563  lua_pushvalue(L, -1);
564  setfenv(L);
565  dooptions(L, loaded - 1);
566  return 0;
567}
568
569
570static int ll_seeall (lua_State *L) {
571  luaL_checktype(L, 1, LUA_TTABLE);
572  if (!lua_getmetatable(L, 1)) {
573    lua_createtable(L, 0, 1); /* create new metatable */
574    lua_pushvalue(L, -1);
575    lua_setmetatable(L, 1);
576  }
577  lua_pushvalue(L, LUA_GLOBALSINDEX);
578  lua_setfield(L, -2, "__index");  /* mt.__index = _G */
579  return 0;
580}
581
582
583/* }====================================================== */
584
585
586
587/* auxiliary mark (for internal use) */
588#define AUXMARK         "\1"
589
590static void setpath (lua_State *L, const char *fieldname, const char *envname,
591                                   const char *def) {
592  const char *path = getenv(envname);
593  if (path == NULL)  /* no environment variable? */
594    lua_pushstring(L, def);  /* use default */
595  else {
596    /* replace ";;" by ";AUXMARK;" and then AUXMARK by default path */
597    path = luaL_gsub(L, path, LUA_PATHSEP LUA_PATHSEP,
598                              LUA_PATHSEP AUXMARK LUA_PATHSEP);
599    luaL_gsub(L, path, AUXMARK, def);
600    lua_remove(L, -2);
601  }
602  setprogdir(L);
603  lua_setfield(L, -2, fieldname);
604}
605
606
607static const luaL_Reg pk_funcs[] = {
608  {"loadlib", ll_loadlib},
609  {"seeall", ll_seeall},
610  {NULL, NULL}
611};
612
613
614static const luaL_Reg ll_funcs[] = {
615  {"module", ll_module},
616  {"require", ll_require},
617  {NULL, NULL}
618};
619
620
621static const lua_CFunction loaders[] =
622  {loader_preload, loader_Lua, loader_C, loader_Croot, NULL};
623
624
625LUALIB_API int luaopen_package (lua_State *L) {
626  int i;
627  /* create new type _LOADLIB */
628  luaL_newmetatable(L, "_LOADLIB");
629  lua_pushcfunction(L, gctm);
630  lua_setfield(L, -2, "__gc");
631  /* create `package' table */
632  luaL_register(L, LUA_LOADLIBNAME, pk_funcs);
633#if defined(LUA_COMPAT_LOADLIB)
634  lua_getfield(L, -1, "loadlib");
635  lua_setfield(L, LUA_GLOBALSINDEX, "loadlib");
636#endif
637  lua_pushvalue(L, -1);
638  lua_replace(L, LUA_ENVIRONINDEX);
639  /* create `loaders' table */
640  lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1);
641  /* fill it with pre-defined loaders */
642  for (i=0; loaders[i] != NULL; i++) {
643    lua_pushcfunction(L, loaders[i]);
644    lua_rawseti(L, -2, i+1);
645  }
646  lua_setfield(L, -2, "loaders");  /* put it in field `loaders' */
647  setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT);  /* set field `path' */
648  setpath(L, "cpath", LUA_CPATH, LUA_CPATH_DEFAULT); /* set field `cpath' */
649  /* store config information */
650  lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n"
651                     LUA_EXECDIR "\n" LUA_IGMARK);
652  lua_setfield(L, -2, "config");
653  /* set field `loaded' */
654  luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2);
655  lua_setfield(L, -2, "loaded");
656  /* set field `preload' */
657  lua_newtable(L);
658  lua_setfield(L, -2, "preload");
659  lua_pushvalue(L, LUA_GLOBALSINDEX);
660  luaL_register(L, NULL, ll_funcs);  /* open lib into global table */
661  lua_pop(L, 1);
662  return 1;  /* return 'package' table */
663}
664
Note: See TracBrowser for help on using the repository browser.