Line |
Branch |
Decision |
Exec |
Source |
1 |
|
|
|
/* |
2 |
|
|
|
** $Id: loadlib.c $ |
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 Windows, and a stub for other |
8 |
|
|
|
** systems. |
9 |
|
|
|
*/ |
10 |
|
|
|
|
11 |
|
|
|
#define loadlib_c |
12 |
|
|
|
#define LUA_LIB |
13 |
|
|
|
|
14 |
|
|
|
#include "lprefix.h" |
15 |
|
|
|
|
16 |
|
|
|
|
17 |
|
|
|
#include <stdio.h> |
18 |
|
|
|
#include <stdlib.h> |
19 |
|
|
|
#include <string.h> |
20 |
|
|
|
|
21 |
|
|
|
#include "lua.h" |
22 |
|
|
|
|
23 |
|
|
|
#include "lauxlib.h" |
24 |
|
|
|
#include "lualib.h" |
25 |
|
|
|
|
26 |
|
|
|
|
27 |
|
|
|
/* |
28 |
|
|
|
** LUA_IGMARK is a mark to ignore all before it when building the |
29 |
|
|
|
** luaopen_ function name. |
30 |
|
|
|
*/ |
31 |
|
|
|
#if !defined (LUA_IGMARK) |
32 |
|
|
|
#define LUA_IGMARK "-" |
33 |
|
|
|
#endif |
34 |
|
|
|
|
35 |
|
|
|
|
36 |
|
|
|
/* |
37 |
|
|
|
** LUA_CSUBSEP is the character that replaces dots in submodule names |
38 |
|
|
|
** when searching for a C loader. |
39 |
|
|
|
** LUA_LSUBSEP is the character that replaces dots in submodule names |
40 |
|
|
|
** when searching for a Lua loader. |
41 |
|
|
|
*/ |
42 |
|
|
|
#if !defined(LUA_CSUBSEP) |
43 |
|
|
|
#define LUA_CSUBSEP LUA_DIRSEP |
44 |
|
|
|
#endif |
45 |
|
|
|
|
46 |
|
|
|
#if !defined(LUA_LSUBSEP) |
47 |
|
|
|
#define LUA_LSUBSEP LUA_DIRSEP |
48 |
|
|
|
#endif |
49 |
|
|
|
|
50 |
|
|
|
|
51 |
|
|
|
/* prefix for open functions in C libraries */ |
52 |
|
|
|
#define LUA_POF "luaopen_" |
53 |
|
|
|
|
54 |
|
|
|
/* separator for open functions in C libraries */ |
55 |
|
|
|
#define LUA_OFSEP "_" |
56 |
|
|
|
|
57 |
|
|
|
|
58 |
|
|
|
/* |
59 |
|
|
|
** key for table in the registry that keeps handles |
60 |
|
|
|
** for all loaded C libraries |
61 |
|
|
|
*/ |
62 |
|
|
|
static const char *const CLIBS = "_CLIBS"; |
63 |
|
|
|
|
64 |
|
|
|
#define LIB_FAIL "open" |
65 |
|
|
|
|
66 |
|
|
|
|
67 |
|
|
|
#define setprogdir(L) ((void)0) |
68 |
|
|
|
|
69 |
|
|
|
|
70 |
|
|
|
/* |
71 |
|
|
|
** Special type equivalent to '(void*)' for functions in gcc |
72 |
|
|
|
** (to suppress warnings when converting function pointers) |
73 |
|
|
|
*/ |
74 |
|
|
|
typedef void (*voidf)(void); |
75 |
|
|
|
|
76 |
|
|
|
|
77 |
|
|
|
/* |
78 |
|
|
|
** system-dependent functions |
79 |
|
|
|
*/ |
80 |
|
|
|
|
81 |
|
|
|
/* |
82 |
|
|
|
** unload library 'lib' |
83 |
|
|
|
*/ |
84 |
|
|
|
static void lsys_unloadlib (void *lib); |
85 |
|
|
|
|
86 |
|
|
|
/* |
87 |
|
|
|
** load C library in file 'path'. If 'seeglb', load with all names in |
88 |
|
|
|
** the library global. |
89 |
|
|
|
** Returns the library; in case of error, returns NULL plus an |
90 |
|
|
|
** error string in the stack. |
91 |
|
|
|
*/ |
92 |
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb); |
93 |
|
|
|
|
94 |
|
|
|
/* |
95 |
|
|
|
** Try to find a function named 'sym' in library 'lib'. |
96 |
|
|
|
** Returns the function; in case of error, returns NULL plus an |
97 |
|
|
|
** error string in the stack. |
98 |
|
|
|
*/ |
99 |
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym); |
100 |
|
|
|
|
101 |
|
|
|
|
102 |
|
|
|
|
103 |
|
|
|
|
104 |
|
|
|
#if defined(LUA_USE_DLOPEN) /* { */ |
105 |
|
|
|
/* |
106 |
|
|
|
** {======================================================================== |
107 |
|
|
|
** This is an implementation of loadlib based on the dlfcn interface. |
108 |
|
|
|
** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, |
109 |
|
|
|
** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least |
110 |
|
|
|
** as an emulation layer on top of native functions. |
111 |
|
|
|
** ========================================================================= |
112 |
|
|
|
*/ |
113 |
|
|
|
|
114 |
|
|
|
#include <dlfcn.h> |
115 |
|
|
|
|
116 |
|
|
|
/* |
117 |
|
|
|
** Macro to convert pointer-to-void* to pointer-to-function. This cast |
118 |
|
|
|
** is undefined according to ISO C, but POSIX assumes that it works. |
119 |
|
|
|
** (The '__extension__' in gnu compilers is only to avoid warnings.) |
120 |
|
|
|
*/ |
121 |
|
|
|
#if defined(__GNUC__) |
122 |
|
|
|
#define cast_func(p) (__extension__ (lua_CFunction)(p)) |
123 |
|
|
|
#else |
124 |
|
|
|
#define cast_func(p) ((lua_CFunction)(p)) |
125 |
|
|
|
#endif |
126 |
|
|
|
|
127 |
|
|
|
|
128 |
|
|
|
static void lsys_unloadlib (void *lib) { |
129 |
|
|
|
dlclose(lib); |
130 |
|
|
|
} |
131 |
|
|
|
|
132 |
|
|
|
|
133 |
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb) { |
134 |
|
|
|
void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); |
135 |
|
|
|
if (l_unlikely(lib == NULL)) |
136 |
|
|
|
lua_pushstring(L, dlerror()); |
137 |
|
|
|
return lib; |
138 |
|
|
|
} |
139 |
|
|
|
|
140 |
|
|
|
|
141 |
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { |
142 |
|
|
|
lua_CFunction f = cast_func(dlsym(lib, sym)); |
143 |
|
|
|
if (l_unlikely(f == NULL)) |
144 |
|
|
|
lua_pushstring(L, dlerror()); |
145 |
|
|
|
return f; |
146 |
|
|
|
} |
147 |
|
|
|
|
148 |
|
|
|
/* }====================================================== */ |
149 |
|
|
|
|
150 |
|
|
|
|
151 |
|
|
|
|
152 |
|
|
|
#elif defined(LUA_DL_DLL) /* }{ */ |
153 |
|
|
|
/* |
154 |
|
|
|
** {====================================================================== |
155 |
|
|
|
** This is an implementation of loadlib for Windows using native functions. |
156 |
|
|
|
** ======================================================================= |
157 |
|
|
|
*/ |
158 |
|
|
|
|
159 |
|
|
|
#include <windows.h> |
160 |
|
|
|
|
161 |
|
|
|
|
162 |
|
|
|
/* |
163 |
|
|
|
** optional flags for LoadLibraryEx |
164 |
|
|
|
*/ |
165 |
|
|
|
#if !defined(LUA_LLE_FLAGS) |
166 |
|
|
|
#define LUA_LLE_FLAGS 0 |
167 |
|
|
|
#endif |
168 |
|
|
|
|
169 |
|
|
|
|
170 |
|
|
|
#undef setprogdir |
171 |
|
|
|
|
172 |
|
|
|
|
173 |
|
|
|
/* |
174 |
|
|
|
** Replace in the path (on the top of the stack) any occurrence |
175 |
|
|
|
** of LUA_EXEC_DIR with the executable's path. |
176 |
|
|
|
*/ |
177 |
|
|
|
static void setprogdir (lua_State *L) { |
178 |
|
|
|
char buff[MAX_PATH + 1]; |
179 |
|
|
|
char *lb; |
180 |
|
|
|
DWORD nsize = sizeof(buff)/sizeof(char); |
181 |
|
|
|
DWORD n = GetModuleFileNameA(NULL, buff, nsize); /* get exec. name */ |
182 |
|
|
|
if (n == 0 || n == nsize || (lb = strrchr(buff, '\\')) == NULL) |
183 |
|
|
|
luaL_error(L, "unable to get ModuleFileName"); |
184 |
|
|
|
else { |
185 |
|
|
|
*lb = '\0'; /* cut name on the last '\\' to get the path */ |
186 |
|
|
|
luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); |
187 |
|
|
|
lua_remove(L, -2); /* remove original string */ |
188 |
|
|
|
} |
189 |
|
|
|
} |
190 |
|
|
|
|
191 |
|
|
|
|
192 |
|
|
|
|
193 |
|
|
|
|
194 |
|
|
|
static void pusherror (lua_State *L) { |
195 |
|
|
|
int error = GetLastError(); |
196 |
|
|
|
char buffer[128]; |
197 |
|
|
|
if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, |
198 |
|
|
|
NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) |
199 |
|
|
|
lua_pushstring(L, buffer); |
200 |
|
|
|
else |
201 |
|
|
|
lua_pushfstring(L, "system error %d\n", error); |
202 |
|
|
|
} |
203 |
|
|
|
|
204 |
|
|
|
static void lsys_unloadlib (void *lib) { |
205 |
|
|
|
FreeLibrary((HMODULE)lib); |
206 |
|
|
|
} |
207 |
|
|
|
|
208 |
|
|
|
|
209 |
|
|
|
static void *lsys_load (lua_State *L, const char *path, int seeglb) { |
210 |
|
|
|
HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); |
211 |
|
|
|
(void)(seeglb); /* not used: symbols are 'global' by default */ |
212 |
|
|
|
if (lib == NULL) pusherror(L); |
213 |
|
|
|
return lib; |
214 |
|
|
|
} |
215 |
|
|
|
|
216 |
|
|
|
|
217 |
|
|
|
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { |
218 |
|
|
|
lua_CFunction f = (lua_CFunction)(voidf)GetProcAddress((HMODULE)lib, sym); |
219 |
|
|
|
if (f == NULL) pusherror(L); |
220 |
|
|
|
return f; |
221 |
|
|
|
} |
222 |
|
|
|
|
223 |
|
|
|
/* }====================================================== */ |
224 |
|
|
|
|
225 |
|
|
|
|
226 |
|
|
|
#else /* }{ */ |
227 |
|
|
|
/* |
228 |
|
|
|
** {====================================================== |
229 |
|
|
|
** Fallback for other systems |
230 |
|
|
|
** ======================================================= |
231 |
|
|
|
*/ |
232 |
|
|
|
|
233 |
|
|
|
#undef LIB_FAIL |
234 |
|
|
|
#define LIB_FAIL "absent" |
235 |
|
|
|
|
236 |
|
|
|
|
237 |
|
|
|
#define DLMSG "dynamic libraries not enabled; check your Lua installation" |
238 |
|
|
|
|
239 |
|
|
|
|
240 |
|
|
✗ |
static void lsys_unloadlib (void *lib) { |
241 |
|
|
|
(void)(lib); /* not used */ |
242 |
|
|
✗ |
} |
243 |
|
|
|
|
244 |
|
|
|
|
245 |
|
|
✗ |
static void *lsys_load (lua_State *L, const char *path, int seeglb) { |
246 |
|
|
|
(void)(path); (void)(seeglb); /* not used */ |
247 |
|
|
✗ |
lua_pushliteral(L, DLMSG); |
248 |
|
|
✗ |
return NULL; |
249 |
|
|
|
} |
250 |
|
|
|
|
251 |
|
|
|
|
252 |
|
|
✗ |
static lua_CFunction lsys_sym (lua_State *L, void *lib, const char *sym) { |
253 |
|
|
|
(void)(lib); (void)(sym); /* not used */ |
254 |
|
|
✗ |
lua_pushliteral(L, DLMSG); |
255 |
|
|
✗ |
return NULL; |
256 |
|
|
|
} |
257 |
|
|
|
|
258 |
|
|
|
/* }====================================================== */ |
259 |
|
|
|
#endif /* } */ |
260 |
|
|
|
|
261 |
|
|
|
|
262 |
|
|
|
/* |
263 |
|
|
|
** {================================================================== |
264 |
|
|
|
** Set Paths |
265 |
|
|
|
** =================================================================== |
266 |
|
|
|
*/ |
267 |
|
|
|
|
268 |
|
|
|
/* |
269 |
|
|
|
** LUA_PATH_VAR and LUA_CPATH_VAR are the names of the environment |
270 |
|
|
|
** variables that Lua check to set its paths. |
271 |
|
|
|
*/ |
272 |
|
|
|
#if !defined(LUA_PATH_VAR) |
273 |
|
|
|
#define LUA_PATH_VAR "LUA_PATH" |
274 |
|
|
|
#endif |
275 |
|
|
|
|
276 |
|
|
|
#if !defined(LUA_CPATH_VAR) |
277 |
|
|
|
#define LUA_CPATH_VAR "LUA_CPATH" |
278 |
|
|
|
#endif |
279 |
|
|
|
|
280 |
|
|
|
|
281 |
|
|
|
|
282 |
|
|
|
/* |
283 |
|
|
|
** return registry.LUA_NOENV as a boolean |
284 |
|
|
|
*/ |
285 |
|
|
✗ |
static int noenv (lua_State *L) { |
286 |
|
|
|
int b; |
287 |
|
|
✗ |
lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); |
288 |
|
|
✗ |
b = lua_toboolean(L, -1); |
289 |
|
|
✗ |
lua_pop(L, 1); /* remove value */ |
290 |
|
|
✗ |
return b; |
291 |
|
|
|
} |
292 |
|
|
|
|
293 |
|
|
|
|
294 |
|
|
|
/* |
295 |
|
|
|
** Set a path |
296 |
|
|
|
*/ |
297 |
|
|
✗ |
static void setpath (lua_State *L, const char *fieldname, |
298 |
|
|
|
const char *envname, |
299 |
|
|
|
const char *dft) { |
300 |
|
|
|
const char *dftmark; |
301 |
|
|
✗ |
const char *nver = lua_pushfstring(L, "%s%s", envname, LUA_VERSUFFIX); |
302 |
|
|
✗ |
const char *path = getenv(nver); /* try versioned name */ |
303 |
|
|
✗ |
if (path == NULL) /* no versioned environment variable? */ |
304 |
|
|
✗ |
path = getenv(envname); /* try unversioned name */ |
305 |
|
|
✗ |
if (path == NULL || noenv(L)) /* no environment variable? */ |
306 |
|
|
✗ |
lua_pushstring(L, dft); /* use default */ |
307 |
|
|
✗ |
else if ((dftmark = strstr(path, LUA_PATH_SEP LUA_PATH_SEP)) == NULL) |
308 |
|
|
✗ |
lua_pushstring(L, path); /* nothing to change */ |
309 |
|
|
|
else { /* path contains a ";;": insert default path in its place */ |
310 |
|
|
✗ |
size_t len = strlen(path); |
311 |
|
|
|
luaL_Buffer b; |
312 |
|
|
✗ |
luaL_buffinit(L, &b); |
313 |
|
|
✗ |
if (path < dftmark) { /* is there a prefix before ';;'? */ |
314 |
|
|
✗ |
luaL_addlstring(&b, path, dftmark - path); /* add it */ |
315 |
|
|
✗ |
luaL_addchar(&b, *LUA_PATH_SEP); |
316 |
|
|
|
} |
317 |
|
|
✗ |
luaL_addstring(&b, dft); /* add default */ |
318 |
|
|
✗ |
if (dftmark < path + len - 2) { /* is there a suffix after ';;'? */ |
319 |
|
|
✗ |
luaL_addchar(&b, *LUA_PATH_SEP); |
320 |
|
|
✗ |
luaL_addlstring(&b, dftmark + 2, (path + len - 2) - dftmark); |
321 |
|
|
|
} |
322 |
|
|
✗ |
luaL_pushresult(&b); |
323 |
|
|
|
} |
324 |
|
|
|
setprogdir(L); |
325 |
|
|
✗ |
lua_setfield(L, -3, fieldname); /* package[fieldname] = path value */ |
326 |
|
|
✗ |
lua_pop(L, 1); /* pop versioned variable name ('nver') */ |
327 |
|
|
✗ |
} |
328 |
|
|
|
|
329 |
|
|
|
/* }================================================================== */ |
330 |
|
|
|
|
331 |
|
|
|
|
332 |
|
|
|
/* |
333 |
|
|
|
** return registry.CLIBS[path] |
334 |
|
|
|
*/ |
335 |
|
|
✗ |
static void *checkclib (lua_State *L, const char *path) { |
336 |
|
|
|
void *plib; |
337 |
|
|
✗ |
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); |
338 |
|
|
✗ |
lua_getfield(L, -1, path); |
339 |
|
|
✗ |
plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ |
340 |
|
|
✗ |
lua_pop(L, 2); /* pop CLIBS table and 'plib' */ |
341 |
|
|
✗ |
return plib; |
342 |
|
|
|
} |
343 |
|
|
|
|
344 |
|
|
|
|
345 |
|
|
|
/* |
346 |
|
|
|
** registry.CLIBS[path] = plib -- for queries |
347 |
|
|
|
** registry.CLIBS[#CLIBS + 1] = plib -- also keep a list of all libraries |
348 |
|
|
|
*/ |
349 |
|
|
✗ |
static void addtoclib (lua_State *L, const char *path, void *plib) { |
350 |
|
|
✗ |
lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); |
351 |
|
|
✗ |
lua_pushlightuserdata(L, plib); |
352 |
|
|
✗ |
lua_pushvalue(L, -1); |
353 |
|
|
✗ |
lua_setfield(L, -3, path); /* CLIBS[path] = plib */ |
354 |
|
|
✗ |
lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ |
355 |
|
|
✗ |
lua_pop(L, 1); /* pop CLIBS table */ |
356 |
|
|
✗ |
} |
357 |
|
|
|
|
358 |
|
|
|
|
359 |
|
|
|
/* |
360 |
|
|
|
** __gc tag method for CLIBS table: calls 'lsys_unloadlib' for all lib |
361 |
|
|
|
** handles in list CLIBS |
362 |
|
|
|
*/ |
363 |
|
|
✗ |
static int gctm (lua_State *L) { |
364 |
|
|
✗ |
lua_Integer n = luaL_len(L, 1); |
365 |
|
|
✗ |
for (; n >= 1; n--) { /* for each handle, in reverse order */ |
366 |
|
|
✗ |
lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ |
367 |
|
|
✗ |
lsys_unloadlib(lua_touserdata(L, -1)); |
368 |
|
|
✗ |
lua_pop(L, 1); /* pop handle */ |
369 |
|
|
|
} |
370 |
|
|
✗ |
return 0; |
371 |
|
|
|
} |
372 |
|
|
|
|
373 |
|
|
|
|
374 |
|
|
|
|
375 |
|
|
|
/* error codes for 'lookforfunc' */ |
376 |
|
|
|
#define ERRLIB 1 |
377 |
|
|
|
#define ERRFUNC 2 |
378 |
|
|
|
|
379 |
|
|
|
/* |
380 |
|
|
|
** Look for a C function named 'sym' in a dynamically loaded library |
381 |
|
|
|
** 'path'. |
382 |
|
|
|
** First, check whether the library is already loaded; if not, try |
383 |
|
|
|
** to load it. |
384 |
|
|
|
** Then, if 'sym' is '*', return true (as library has been loaded). |
385 |
|
|
|
** Otherwise, look for symbol 'sym' in the library and push a |
386 |
|
|
|
** C function with that symbol. |
387 |
|
|
|
** Return 0 and 'true' or a function in the stack; in case of |
388 |
|
|
|
** errors, return an error code and an error message in the stack. |
389 |
|
|
|
*/ |
390 |
|
|
✗ |
static int lookforfunc (lua_State *L, const char *path, const char *sym) { |
391 |
|
|
✗ |
void *reg = checkclib(L, path); /* check loaded C libraries */ |
392 |
|
|
✗ |
if (reg == NULL) { /* must load library? */ |
393 |
|
|
✗ |
reg = lsys_load(L, path, *sym == '*'); /* global symbols if 'sym'=='*' */ |
394 |
|
|
✗ |
if (reg == NULL) return ERRLIB; /* unable to load library */ |
395 |
|
|
✗ |
addtoclib(L, path, reg); |
396 |
|
|
|
} |
397 |
|
|
✗ |
if (*sym == '*') { /* loading only library (no function)? */ |
398 |
|
|
✗ |
lua_pushboolean(L, 1); /* return 'true' */ |
399 |
|
|
✗ |
return 0; /* no errors */ |
400 |
|
|
|
} |
401 |
|
|
|
else { |
402 |
|
|
✗ |
lua_CFunction f = lsys_sym(L, reg, sym); |
403 |
|
|
✗ |
if (f == NULL) |
404 |
|
|
✗ |
return ERRFUNC; /* unable to find function */ |
405 |
|
|
✗ |
lua_pushcfunction(L, f); /* else create new function */ |
406 |
|
|
✗ |
return 0; /* no errors */ |
407 |
|
|
|
} |
408 |
|
|
|
} |
409 |
|
|
|
|
410 |
|
|
|
|
411 |
|
|
✗ |
static int ll_loadlib (lua_State *L) { |
412 |
|
|
✗ |
const char *path = luaL_checkstring(L, 1); |
413 |
|
|
✗ |
const char *init = luaL_checkstring(L, 2); |
414 |
|
|
✗ |
int stat = lookforfunc(L, path, init); |
415 |
|
|
✗ |
if (l_likely(stat == 0)) /* no errors? */ |
416 |
|
|
✗ |
return 1; /* return the loaded function */ |
417 |
|
|
|
else { /* error; error message is on stack top */ |
418 |
|
|
✗ |
luaL_pushfail(L); |
419 |
|
|
✗ |
lua_insert(L, -2); |
420 |
|
|
✗ |
lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); |
421 |
|
|
✗ |
return 3; /* return fail, error message, and where */ |
422 |
|
|
|
} |
423 |
|
|
|
} |
424 |
|
|
|
|
425 |
|
|
|
|
426 |
|
|
|
|
427 |
|
|
|
/* |
428 |
|
|
|
** {====================================================== |
429 |
|
|
|
** 'require' function |
430 |
|
|
|
** ======================================================= |
431 |
|
|
|
*/ |
432 |
|
|
|
|
433 |
|
|
|
|
434 |
|
|
✗ |
static int readable (const char *filename) { |
435 |
|
|
✗ |
FILE *f = fopen(filename, "r"); /* try to open file */ |
436 |
|
|
✗ |
if (f == NULL) return 0; /* open failed */ |
437 |
|
|
✗ |
fclose(f); |
438 |
|
|
✗ |
return 1; |
439 |
|
|
|
} |
440 |
|
|
|
|
441 |
|
|
|
|
442 |
|
|
|
/* |
443 |
|
|
|
** Get the next name in '*path' = 'name1;name2;name3;...', changing |
444 |
|
|
|
** the ending ';' to '\0' to create a zero-terminated string. Return |
445 |
|
|
|
** NULL when list ends. |
446 |
|
|
|
*/ |
447 |
|
|
✗ |
static const char *getnextfilename (char **path, char *end) { |
448 |
|
|
|
char *sep; |
449 |
|
|
✗ |
char *name = *path; |
450 |
|
|
✗ |
if (name == end) |
451 |
|
|
✗ |
return NULL; /* no more names */ |
452 |
|
|
✗ |
else if (*name == '\0') { /* from previous iteration? */ |
453 |
|
|
✗ |
*name = *LUA_PATH_SEP; /* restore separator */ |
454 |
|
|
✗ |
name++; /* skip it */ |
455 |
|
|
|
} |
456 |
|
|
✗ |
sep = strchr(name, *LUA_PATH_SEP); /* find next separator */ |
457 |
|
|
✗ |
if (sep == NULL) /* separator not found? */ |
458 |
|
|
✗ |
sep = end; /* name goes until the end */ |
459 |
|
|
✗ |
*sep = '\0'; /* finish file name */ |
460 |
|
|
✗ |
*path = sep; /* will start next search from here */ |
461 |
|
|
✗ |
return name; |
462 |
|
|
|
} |
463 |
|
|
|
|
464 |
|
|
|
|
465 |
|
|
|
/* |
466 |
|
|
|
** Given a path such as ";blabla.so;blublu.so", pushes the string |
467 |
|
|
|
** |
468 |
|
|
|
** no file 'blabla.so' |
469 |
|
|
|
** no file 'blublu.so' |
470 |
|
|
|
*/ |
471 |
|
|
✗ |
static void pusherrornotfound (lua_State *L, const char *path) { |
472 |
|
|
|
luaL_Buffer b; |
473 |
|
|
✗ |
luaL_buffinit(L, &b); |
474 |
|
|
✗ |
luaL_addstring(&b, "no file '"); |
475 |
|
|
✗ |
luaL_addgsub(&b, path, LUA_PATH_SEP, "'\n\tno file '"); |
476 |
|
|
✗ |
luaL_addstring(&b, "'"); |
477 |
|
|
✗ |
luaL_pushresult(&b); |
478 |
|
|
✗ |
} |
479 |
|
|
|
|
480 |
|
|
|
|
481 |
|
|
✗ |
static const char *searchpath (lua_State *L, const char *name, |
482 |
|
|
|
const char *path, |
483 |
|
|
|
const char *sep, |
484 |
|
|
|
const char *dirsep) { |
485 |
|
|
|
luaL_Buffer buff; |
486 |
|
|
|
char *pathname; /* path with name inserted */ |
487 |
|
|
|
char *endpathname; /* its end */ |
488 |
|
|
|
const char *filename; |
489 |
|
|
|
/* separator is non-empty and appears in 'name'? */ |
490 |
|
|
✗ |
if (*sep != '\0' && strchr(name, *sep) != NULL) |
491 |
|
|
✗ |
name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ |
492 |
|
|
✗ |
luaL_buffinit(L, &buff); |
493 |
|
|
|
/* add path to the buffer, replacing marks ('?') with the file name */ |
494 |
|
|
✗ |
luaL_addgsub(&buff, path, LUA_PATH_MARK, name); |
495 |
|
|
✗ |
luaL_addchar(&buff, '\0'); |
496 |
|
|
✗ |
pathname = luaL_buffaddr(&buff); /* writable list of file names */ |
497 |
|
|
✗ |
endpathname = pathname + luaL_bufflen(&buff) - 1; |
498 |
|
|
✗ |
while ((filename = getnextfilename(&pathname, endpathname)) != NULL) { |
499 |
|
|
✗ |
if (readable(filename)) /* does file exist and is readable? */ |
500 |
|
|
✗ |
return lua_pushstring(L, filename); /* save and return name */ |
501 |
|
|
|
} |
502 |
|
|
✗ |
luaL_pushresult(&buff); /* push path to create error message */ |
503 |
|
|
✗ |
pusherrornotfound(L, lua_tostring(L, -1)); /* create error message */ |
504 |
|
|
✗ |
return NULL; /* not found */ |
505 |
|
|
|
} |
506 |
|
|
|
|
507 |
|
|
|
|
508 |
|
|
✗ |
static int ll_searchpath (lua_State *L) { |
509 |
|
|
✗ |
const char *f = searchpath(L, luaL_checkstring(L, 1), |
510 |
|
|
|
luaL_checkstring(L, 2), |
511 |
|
|
|
luaL_optstring(L, 3, "."), |
512 |
|
|
|
luaL_optstring(L, 4, LUA_DIRSEP)); |
513 |
|
|
✗ |
if (f != NULL) return 1; |
514 |
|
|
|
else { /* error message is on top of the stack */ |
515 |
|
|
✗ |
luaL_pushfail(L); |
516 |
|
|
✗ |
lua_insert(L, -2); |
517 |
|
|
✗ |
return 2; /* return fail + error message */ |
518 |
|
|
|
} |
519 |
|
|
|
} |
520 |
|
|
|
|
521 |
|
|
|
|
522 |
|
|
✗ |
static const char *findfile (lua_State *L, const char *name, |
523 |
|
|
|
const char *pname, |
524 |
|
|
|
const char *dirsep) { |
525 |
|
|
|
const char *path; |
526 |
|
|
✗ |
lua_getfield(L, lua_upvalueindex(1), pname); |
527 |
|
|
✗ |
path = lua_tostring(L, -1); |
528 |
|
|
✗ |
if (l_unlikely(path == NULL)) |
529 |
|
|
✗ |
luaL_error(L, "'package.%s' must be a string", pname); |
530 |
|
|
✗ |
return searchpath(L, name, path, ".", dirsep); |
531 |
|
|
|
} |
532 |
|
|
|
|
533 |
|
|
|
|
534 |
|
|
✗ |
static int checkload (lua_State *L, int stat, const char *filename) { |
535 |
|
|
✗ |
if (l_likely(stat)) { /* module loaded successfully? */ |
536 |
|
|
✗ |
lua_pushstring(L, filename); /* will be 2nd argument to module */ |
537 |
|
|
✗ |
return 2; /* return open function and file name */ |
538 |
|
|
|
} |
539 |
|
|
|
else |
540 |
|
|
✗ |
return luaL_error(L, "error loading module '%s' from file '%s':\n\t%s", |
541 |
|
|
|
lua_tostring(L, 1), filename, lua_tostring(L, -1)); |
542 |
|
|
|
} |
543 |
|
|
|
|
544 |
|
|
|
|
545 |
|
|
✗ |
static int searcher_Lua (lua_State *L) { |
546 |
|
|
|
const char *filename; |
547 |
|
|
✗ |
const char *name = luaL_checkstring(L, 1); |
548 |
|
|
✗ |
filename = findfile(L, name, "path", LUA_LSUBSEP); |
549 |
|
|
✗ |
if (filename == NULL) return 1; /* module not found in this path */ |
550 |
|
|
✗ |
return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); |
551 |
|
|
|
} |
552 |
|
|
|
|
553 |
|
|
|
|
554 |
|
|
|
/* |
555 |
|
|
|
** Try to find a load function for module 'modname' at file 'filename'. |
556 |
|
|
|
** First, change '.' to '_' in 'modname'; then, if 'modname' has |
557 |
|
|
|
** the form X-Y (that is, it has an "ignore mark"), build a function |
558 |
|
|
|
** name "luaopen_X" and look for it. (For compatibility, if that |
559 |
|
|
|
** fails, it also tries "luaopen_Y".) If there is no ignore mark, |
560 |
|
|
|
** look for a function named "luaopen_modname". |
561 |
|
|
|
*/ |
562 |
|
|
✗ |
static int loadfunc (lua_State *L, const char *filename, const char *modname) { |
563 |
|
|
|
const char *openfunc; |
564 |
|
|
|
const char *mark; |
565 |
|
|
✗ |
modname = luaL_gsub(L, modname, ".", LUA_OFSEP); |
566 |
|
|
✗ |
mark = strchr(modname, *LUA_IGMARK); |
567 |
|
|
✗ |
if (mark) { |
568 |
|
|
|
int stat; |
569 |
|
|
✗ |
openfunc = lua_pushlstring(L, modname, mark - modname); |
570 |
|
|
✗ |
openfunc = lua_pushfstring(L, LUA_POF"%s", openfunc); |
571 |
|
|
✗ |
stat = lookforfunc(L, filename, openfunc); |
572 |
|
|
✗ |
if (stat != ERRFUNC) return stat; |
573 |
|
|
✗ |
modname = mark + 1; /* else go ahead and try old-style name */ |
574 |
|
|
|
} |
575 |
|
|
✗ |
openfunc = lua_pushfstring(L, LUA_POF"%s", modname); |
576 |
|
|
✗ |
return lookforfunc(L, filename, openfunc); |
577 |
|
|
|
} |
578 |
|
|
|
|
579 |
|
|
|
|
580 |
|
|
✗ |
static int searcher_C (lua_State *L) { |
581 |
|
|
✗ |
const char *name = luaL_checkstring(L, 1); |
582 |
|
|
✗ |
const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); |
583 |
|
|
✗ |
if (filename == NULL) return 1; /* module not found in this path */ |
584 |
|
|
✗ |
return checkload(L, (loadfunc(L, filename, name) == 0), filename); |
585 |
|
|
|
} |
586 |
|
|
|
|
587 |
|
|
|
|
588 |
|
|
✗ |
static int searcher_Croot (lua_State *L) { |
589 |
|
|
|
const char *filename; |
590 |
|
|
✗ |
const char *name = luaL_checkstring(L, 1); |
591 |
|
|
✗ |
const char *p = strchr(name, '.'); |
592 |
|
|
|
int stat; |
593 |
|
|
✗ |
if (p == NULL) return 0; /* is root */ |
594 |
|
|
✗ |
lua_pushlstring(L, name, p - name); |
595 |
|
|
✗ |
filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); |
596 |
|
|
✗ |
if (filename == NULL) return 1; /* root not found */ |
597 |
|
|
✗ |
if ((stat = loadfunc(L, filename, name)) != 0) { |
598 |
|
|
✗ |
if (stat != ERRFUNC) |
599 |
|
|
✗ |
return checkload(L, 0, filename); /* real error */ |
600 |
|
|
|
else { /* open function not found */ |
601 |
|
|
✗ |
lua_pushfstring(L, "no module '%s' in file '%s'", name, filename); |
602 |
|
|
✗ |
return 1; |
603 |
|
|
|
} |
604 |
|
|
|
} |
605 |
|
|
✗ |
lua_pushstring(L, filename); /* will be 2nd argument to module */ |
606 |
|
|
✗ |
return 2; |
607 |
|
|
|
} |
608 |
|
|
|
|
609 |
|
|
|
|
610 |
|
|
✗ |
static int searcher_preload (lua_State *L) { |
611 |
|
|
✗ |
const char *name = luaL_checkstring(L, 1); |
612 |
|
|
✗ |
lua_getfield(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); |
613 |
|
|
✗ |
if (lua_getfield(L, -1, name) == LUA_TNIL) { /* not found? */ |
614 |
|
|
✗ |
lua_pushfstring(L, "no field package.preload['%s']", name); |
615 |
|
|
✗ |
return 1; |
616 |
|
|
|
} |
617 |
|
|
|
else { |
618 |
|
|
✗ |
lua_pushliteral(L, ":preload:"); |
619 |
|
|
✗ |
return 2; |
620 |
|
|
|
} |
621 |
|
|
|
} |
622 |
|
|
|
|
623 |
|
|
|
|
624 |
|
|
✗ |
static void findloader (lua_State *L, const char *name) { |
625 |
|
|
|
int i; |
626 |
|
|
|
luaL_Buffer msg; /* to build error message */ |
627 |
|
|
|
/* push 'package.searchers' to index 3 in the stack */ |
628 |
|
|
✗ |
if (l_unlikely(lua_getfield(L, lua_upvalueindex(1), "searchers") |
629 |
|
|
|
!= LUA_TTABLE)) |
630 |
|
|
✗ |
luaL_error(L, "'package.searchers' must be a table"); |
631 |
|
|
✗ |
luaL_buffinit(L, &msg); |
632 |
|
|
|
/* iterate over available searchers to find a loader */ |
633 |
|
|
✗ |
for (i = 1; ; i++) { |
634 |
|
|
✗ |
luaL_addstring(&msg, "\n\t"); /* error-message prefix */ |
635 |
|
|
✗ |
if (l_unlikely(lua_rawgeti(L, 3, i) == LUA_TNIL)) { /* no more searchers? */ |
636 |
|
|
✗ |
lua_pop(L, 1); /* remove nil */ |
637 |
|
|
✗ |
luaL_buffsub(&msg, 2); /* remove prefix */ |
638 |
|
|
✗ |
luaL_pushresult(&msg); /* create error message */ |
639 |
|
|
✗ |
luaL_error(L, "module '%s' not found:%s", name, lua_tostring(L, -1)); |
640 |
|
|
|
} |
641 |
|
|
✗ |
lua_pushstring(L, name); |
642 |
|
|
✗ |
lua_call(L, 1, 2); /* call it */ |
643 |
|
|
✗ |
if (lua_isfunction(L, -2)) /* did it find a loader? */ |
644 |
|
|
✗ |
return; /* module loader found */ |
645 |
|
|
✗ |
else if (lua_isstring(L, -2)) { /* searcher returned error message? */ |
646 |
|
|
✗ |
lua_pop(L, 1); /* remove extra return */ |
647 |
|
|
✗ |
luaL_addvalue(&msg); /* concatenate error message */ |
648 |
|
|
|
} |
649 |
|
|
|
else { /* no error message */ |
650 |
|
|
✗ |
lua_pop(L, 2); /* remove both returns */ |
651 |
|
|
✗ |
luaL_buffsub(&msg, 2); /* remove prefix */ |
652 |
|
|
|
} |
653 |
|
|
|
} |
654 |
|
|
|
} |
655 |
|
|
|
|
656 |
|
|
|
|
657 |
|
|
✗ |
static int ll_require (lua_State *L) { |
658 |
|
|
✗ |
const char *name = luaL_checkstring(L, 1); |
659 |
|
|
✗ |
lua_settop(L, 1); /* LOADED table will be at index 2 */ |
660 |
|
|
✗ |
lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); |
661 |
|
|
✗ |
lua_getfield(L, 2, name); /* LOADED[name] */ |
662 |
|
|
✗ |
if (lua_toboolean(L, -1)) /* is it there? */ |
663 |
|
|
✗ |
return 1; /* package is already loaded */ |
664 |
|
|
|
/* else must load package */ |
665 |
|
|
✗ |
lua_pop(L, 1); /* remove 'getfield' result */ |
666 |
|
|
✗ |
findloader(L, name); |
667 |
|
|
✗ |
lua_rotate(L, -2, 1); /* function <-> loader data */ |
668 |
|
|
✗ |
lua_pushvalue(L, 1); /* name is 1st argument to module loader */ |
669 |
|
|
✗ |
lua_pushvalue(L, -3); /* loader data is 2nd argument */ |
670 |
|
|
|
/* stack: ...; loader data; loader function; mod. name; loader data */ |
671 |
|
|
✗ |
lua_call(L, 2, 1); /* run loader to load module */ |
672 |
|
|
|
/* stack: ...; loader data; result from loader */ |
673 |
|
|
✗ |
if (!lua_isnil(L, -1)) /* non-nil return? */ |
674 |
|
|
✗ |
lua_setfield(L, 2, name); /* LOADED[name] = returned value */ |
675 |
|
|
|
else |
676 |
|
|
✗ |
lua_pop(L, 1); /* pop nil */ |
677 |
|
|
✗ |
if (lua_getfield(L, 2, name) == LUA_TNIL) { /* module set no value? */ |
678 |
|
|
✗ |
lua_pushboolean(L, 1); /* use true as result */ |
679 |
|
|
✗ |
lua_copy(L, -1, -2); /* replace loader result */ |
680 |
|
|
✗ |
lua_setfield(L, 2, name); /* LOADED[name] = true */ |
681 |
|
|
|
} |
682 |
|
|
✗ |
lua_rotate(L, -2, 1); /* loader data <-> module result */ |
683 |
|
|
✗ |
return 2; /* return module result and loader data */ |
684 |
|
|
|
} |
685 |
|
|
|
|
686 |
|
|
|
/* }====================================================== */ |
687 |
|
|
|
|
688 |
|
|
|
|
689 |
|
|
|
|
690 |
|
|
|
|
691 |
|
|
|
static const luaL_Reg pk_funcs[] = { |
692 |
|
|
|
{"loadlib", ll_loadlib}, |
693 |
|
|
|
{"searchpath", ll_searchpath}, |
694 |
|
|
|
/* placeholders */ |
695 |
|
|
|
{"preload", NULL}, |
696 |
|
|
|
{"cpath", NULL}, |
697 |
|
|
|
{"path", NULL}, |
698 |
|
|
|
{"searchers", NULL}, |
699 |
|
|
|
{"loaded", NULL}, |
700 |
|
|
|
{NULL, NULL} |
701 |
|
|
|
}; |
702 |
|
|
|
|
703 |
|
|
|
|
704 |
|
|
|
static const luaL_Reg ll_funcs[] = { |
705 |
|
|
|
{"require", ll_require}, |
706 |
|
|
|
{NULL, NULL} |
707 |
|
|
|
}; |
708 |
|
|
|
|
709 |
|
|
|
|
710 |
|
|
✗ |
static void createsearcherstable (lua_State *L) { |
711 |
|
|
|
static const lua_CFunction searchers[] = { |
712 |
|
|
|
searcher_preload, |
713 |
|
|
|
searcher_Lua, |
714 |
|
|
|
searcher_C, |
715 |
|
|
|
searcher_Croot, |
716 |
|
|
|
NULL |
717 |
|
|
|
}; |
718 |
|
|
|
int i; |
719 |
|
|
|
/* create 'searchers' table */ |
720 |
|
|
✗ |
lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); |
721 |
|
|
|
/* fill it with predefined searchers */ |
722 |
|
|
✗ |
for (i=0; searchers[i] != NULL; i++) { |
723 |
|
|
✗ |
lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ |
724 |
|
|
✗ |
lua_pushcclosure(L, searchers[i], 1); |
725 |
|
|
✗ |
lua_rawseti(L, -2, i+1); |
726 |
|
|
|
} |
727 |
|
|
✗ |
lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ |
728 |
|
|
✗ |
} |
729 |
|
|
|
|
730 |
|
|
|
|
731 |
|
|
|
/* |
732 |
|
|
|
** create table CLIBS to keep track of loaded C libraries, |
733 |
|
|
|
** setting a finalizer to close all libraries when closing state. |
734 |
|
|
|
*/ |
735 |
|
|
✗ |
static void createclibstable (lua_State *L) { |
736 |
|
|
✗ |
luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); /* create CLIBS table */ |
737 |
|
|
✗ |
lua_createtable(L, 0, 1); /* create metatable for CLIBS */ |
738 |
|
|
✗ |
lua_pushcfunction(L, gctm); |
739 |
|
|
✗ |
lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ |
740 |
|
|
✗ |
lua_setmetatable(L, -2); |
741 |
|
|
✗ |
} |
742 |
|
|
|
|
743 |
|
|
|
|
744 |
|
|
✗ |
LUAMOD_API int luaopen_package (lua_State *L) { |
745 |
|
|
✗ |
createclibstable(L); |
746 |
|
|
✗ |
luaL_newlib(L, pk_funcs); /* create 'package' table */ |
747 |
|
|
✗ |
createsearcherstable(L); |
748 |
|
|
|
/* set paths */ |
749 |
|
|
✗ |
setpath(L, "path", LUA_PATH_VAR, LUA_PATH_DEFAULT); |
750 |
|
|
✗ |
setpath(L, "cpath", LUA_CPATH_VAR, LUA_CPATH_DEFAULT); |
751 |
|
|
|
/* store config information */ |
752 |
|
|
✗ |
lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" |
753 |
|
|
|
LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); |
754 |
|
|
✗ |
lua_setfield(L, -2, "config"); |
755 |
|
|
|
/* set field 'loaded' */ |
756 |
|
|
✗ |
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); |
757 |
|
|
✗ |
lua_setfield(L, -2, "loaded"); |
758 |
|
|
|
/* set field 'preload' */ |
759 |
|
|
✗ |
luaL_getsubtable(L, LUA_REGISTRYINDEX, LUA_PRELOAD_TABLE); |
760 |
|
|
✗ |
lua_setfield(L, -2, "preload"); |
761 |
|
|
✗ |
lua_pushglobaltable(L); |
762 |
|
|
✗ |
lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ |
763 |
|
|
✗ |
luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ |
764 |
|
|
✗ |
lua_pop(L, 1); /* pop global table */ |
765 |
|
|
✗ |
return 1; /* return 'package' table */ |
766 |
|
|
|
} |
767 |
|
|
|
|
768 |
|
|
|
|