diff options
author | Richard Quirk <richard.quirk@gmail.com> | 2014-03-19 19:31:31 +0100 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2014-04-02 20:31:54 +0200 |
commit | 36378988ad4059982742f05f5eb50580b456840a (patch) | |
tree | ee70be810d894566c5e351f21a1ebb79be742a85 /apps/plugins/lua/loadlib.c | |
parent | 020f16a1c7d5bc9a302671cef03f56ac735e20c5 (diff) | |
download | rockbox-36378988ad4059982742f05f5eb50580b456840a.tar.gz rockbox-36378988ad4059982742f05f5eb50580b456840a.zip |
Update lua plugin to 5.2.3
Prior to this patch the Lua plugin used version 5.1.4. This change
reduces the number of modifications in the Lua source using some new
defines and because the upstream source is now more flexible.
Unless otherwise stated, l*.[ch] files are taken unmodified from the
upstream lua-5.2.3.
fscanf.c:
file descriptors in rockbox are just ints, they are hidden behind a
void* now so liolib requires less modifications. fscanf is updated to
use void* too.
getc.c: this is a new file required for getc implementation in lauxlib.c
lauxlib.c: LoadF replaced FILE* with int, the rockbox file
descriptor int are cast to FILE* (actually void* due to typedef).
getc uses the PREFIX version. stdin is not used, as per 5.1.4.
lbaselib.c: now uses strspn in the number parsing. print uses DEBUGF now
rather than being commented out.
lbitlib.c: use the built-in version from 5.2.3 rather than Reuben
Thomas's external library. Backwards compatible and adds some new bit
operations.
ldo.c: the LUAI_THROW/TRY defines are now in the core lua code, so have
been removed from rockconf.h
liolib.c: here the implementation has changed to use the LStream from
the original source, and cast the FILE* pointers to int. This has
reduced the number of modifications from the upstream version.
llex.c: the only change from upstream is to remove the locale include.
lmathlib.c: updated from the 5.2.3 version and re-applied the changes
that were made vs 5.1.4 for random numbers and to remove unsupported
float functions.
loadlib.c: upstream version, with the 5.1.4 changes for missing
functions.
lobject.c: upstream version, with ctype.h added and sprintf changed to
snprintf.
loslib.c: upstream version with locale.h removed and 5.1.4 changes for
unsupportable functions.
lstrlib.c: sprintf changed to snprintf.
ltable.c: upstream with the hashnum function from 5.1.4 to avoid frexp
in luai_hashnum.
luaconf.h: updated to 5.2.3 version, restored relevant parts from the
original 5.1.4 configuration. The COMPAT defines that are no longer
available are not included.
lundump.c: VERSION macro conflicts with the core Rockbox equivalent.
rocklib.c: luaL_reg is no longer available, replaced by luaL_Reg
equivalent. Moved checkboolean/optboolean functions to this file and out
of core lua files. luaL_getn is no longer available, replaced by
luaL_rawlen. luaL_register is deprecated, use the newlib/setfuncs
replacements. rli_init has to be called before setting up the newlib to
avoid overwriting the rb table.
rocklib_aux.pl: use rli_checkboolean from rocklib.c.
rocklua.c: new default bits library used, update the library loading
code with idiomatic 5.2 code.
strcspn.c: no longer needed, but strspn.c is required for strspn in
lbaselib.c
Change-Id: I0c7945c755f79083afe98ec117e1e8cf13de2651
Reviewed-on: http://gerrit.rockbox.org/774
Tested: Richard Quirk <richard.quirk@gmail.com>
Reviewed-by: Marcin Bukat <marcin.bukat@gmail.com>
Diffstat (limited to 'apps/plugins/lua/loadlib.c')
-rw-r--r-- | apps/plugins/lua/loadlib.c | 650 |
1 files changed, 525 insertions, 125 deletions
diff --git a/apps/plugins/lua/loadlib.c b/apps/plugins/lua/loadlib.c index 1cc7ebd7db..f5a63386b5 100644 --- a/apps/plugins/lua/loadlib.c +++ b/apps/plugins/lua/loadlib.c | |||
@@ -1,14 +1,22 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: loadlib.c,v 1.52.1.3 2008/08/06 13:29:28 roberto Exp $ | 2 | ** $Id: loadlib.c,v 1.111.1.1 2013/04/12 18:48:47 roberto Exp $ |
3 | ** Dynamic library loader for Lua | 3 | ** Dynamic library loader for Lua |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | ** | 5 | ** |
6 | ** This module contains an implementation of loadlib for Unix systems | 6 | ** This module contains an implementation of loadlib for Unix systems |
7 | ** that have dlfcn, an implementation for Darwin (Mac OS X), an | 7 | ** that have dlfcn, an implementation for Windows, and a stub for other |
8 | ** implementation for Windows, and a stub for other systems. | 8 | ** systems. |
9 | */ | 9 | */ |
10 | 10 | ||
11 | 11 | ||
12 | /* | ||
13 | ** if needed, includes windows header before everything else | ||
14 | */ | ||
15 | #if defined(_WIN32) | ||
16 | #include <windows.h> | ||
17 | #endif | ||
18 | |||
19 | |||
12 | #include <stdlib.h> | 20 | #include <stdlib.h> |
13 | #include <string.h> | 21 | #include <string.h> |
14 | 22 | ||
@@ -20,10 +28,296 @@ | |||
20 | 28 | ||
21 | #include "lauxlib.h" | 29 | #include "lauxlib.h" |
22 | #include "lualib.h" | 30 | #include "lualib.h" |
23 | #include "rocklib.h" | ||
24 | 31 | ||
25 | 32 | ||
26 | #define setprogdir(L) ((void)0) | 33 | /* |
34 | ** LUA_PATH and LUA_CPATH are the names of the environment | ||
35 | ** variables that Lua check to set its paths. | ||
36 | */ | ||
37 | #if !defined(LUA_PATH) | ||
38 | #define LUA_PATH "LUA_PATH" | ||
39 | #endif | ||
40 | |||
41 | #if !defined(LUA_CPATH) | ||
42 | #define LUA_CPATH "LUA_CPATH" | ||
43 | #endif | ||
44 | |||
45 | #define LUA_PATHSUFFIX "_" LUA_VERSION_MAJOR "_" LUA_VERSION_MINOR | ||
46 | |||
47 | #define LUA_PATHVERSION LUA_PATH LUA_PATHSUFFIX | ||
48 | #define LUA_CPATHVERSION LUA_CPATH LUA_PATHSUFFIX | ||
49 | |||
50 | /* | ||
51 | ** LUA_PATH_SEP is the character that separates templates in a path. | ||
52 | ** LUA_PATH_MARK is the string that marks the substitution points in a | ||
53 | ** template. | ||
54 | ** LUA_EXEC_DIR in a Windows path is replaced by the executable's | ||
55 | ** directory. | ||
56 | ** LUA_IGMARK is a mark to ignore all before it when building the | ||
57 | ** luaopen_ function name. | ||
58 | */ | ||
59 | #if !defined (LUA_PATH_SEP) | ||
60 | #define LUA_PATH_SEP ";" | ||
61 | #endif | ||
62 | #if !defined (LUA_PATH_MARK) | ||
63 | #define LUA_PATH_MARK "?" | ||
64 | #endif | ||
65 | #if !defined (LUA_EXEC_DIR) | ||
66 | #define LUA_EXEC_DIR "!" | ||
67 | #endif | ||
68 | #if !defined (LUA_IGMARK) | ||
69 | #define LUA_IGMARK "-" | ||
70 | #endif | ||
71 | |||
72 | |||
73 | /* | ||
74 | ** LUA_CSUBSEP is the character that replaces dots in submodule names | ||
75 | ** when searching for a C loader. | ||
76 | ** LUA_LSUBSEP is the character that replaces dots in submodule names | ||
77 | ** when searching for a Lua loader. | ||
78 | */ | ||
79 | #if !defined(LUA_CSUBSEP) | ||
80 | #define LUA_CSUBSEP LUA_DIRSEP | ||
81 | #endif | ||
82 | |||
83 | #if !defined(LUA_LSUBSEP) | ||
84 | #define LUA_LSUBSEP LUA_DIRSEP | ||
85 | #endif | ||
86 | |||
87 | |||
88 | /* prefix for open functions in C libraries */ | ||
89 | #define LUA_POF "luaopen_" | ||
90 | |||
91 | /* separator for open functions in C libraries */ | ||
92 | #define LUA_OFSEP "_" | ||
93 | |||
94 | |||
95 | /* table (in the registry) that keeps handles for all loaded C libraries */ | ||
96 | #define CLIBS "_CLIBS" | ||
97 | |||
98 | #define LIB_FAIL "open" | ||
99 | |||
100 | |||
101 | /* error codes for ll_loadfunc */ | ||
102 | #define ERRLIB 1 | ||
103 | #define ERRFUNC 2 | ||
104 | |||
105 | #define setprogdir(L) ((void)0) | ||
106 | |||
107 | |||
108 | /* | ||
109 | ** system-dependent functions | ||
110 | */ | ||
111 | static void ll_unloadlib (void *lib); | ||
112 | static void *ll_load (lua_State *L, const char *path, int seeglb); | ||
113 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym); | ||
114 | |||
115 | |||
116 | |||
117 | #if defined(LUA_USE_DLOPEN) | ||
118 | /* | ||
119 | ** {======================================================================== | ||
120 | ** This is an implementation of loadlib based on the dlfcn interface. | ||
121 | ** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, | ||
122 | ** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least | ||
123 | ** as an emulation layer on top of native functions. | ||
124 | ** ========================================================================= | ||
125 | */ | ||
126 | |||
127 | #include <dlfcn.h> | ||
128 | |||
129 | static void ll_unloadlib (void *lib) { | ||
130 | dlclose(lib); | ||
131 | } | ||
132 | |||
133 | |||
134 | static void *ll_load (lua_State *L, const char *path, int seeglb) { | ||
135 | void *lib = dlopen(path, RTLD_NOW | (seeglb ? RTLD_GLOBAL : RTLD_LOCAL)); | ||
136 | if (lib == NULL) lua_pushstring(L, dlerror()); | ||
137 | return lib; | ||
138 | } | ||
139 | |||
140 | |||
141 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
142 | lua_CFunction f = (lua_CFunction)dlsym(lib, sym); | ||
143 | if (f == NULL) lua_pushstring(L, dlerror()); | ||
144 | return f; | ||
145 | } | ||
146 | |||
147 | /* }====================================================== */ | ||
148 | |||
149 | |||
150 | |||
151 | #elif defined(LUA_DL_DLL) | ||
152 | /* | ||
153 | ** {====================================================================== | ||
154 | ** This is an implementation of loadlib for Windows using native functions. | ||
155 | ** ======================================================================= | ||
156 | */ | ||
157 | |||
158 | #undef setprogdir | ||
159 | |||
160 | /* | ||
161 | ** optional flags for LoadLibraryEx | ||
162 | */ | ||
163 | #if !defined(LUA_LLE_FLAGS) | ||
164 | #define LUA_LLE_FLAGS 0 | ||
165 | #endif | ||
166 | |||
167 | |||
168 | static void setprogdir (lua_State *L) { | ||
169 | char buff[MAX_PATH + 1]; | ||
170 | char *lb; | ||
171 | DWORD nsize = sizeof(buff)/sizeof(char); | ||
172 | DWORD n = GetModuleFileNameA(NULL, buff, nsize); | ||
173 | if (n == 0 || n == nsize || (lb = rb->strrchr(buff, '\\')) == NULL) | ||
174 | luaL_error(L, "unable to get ModuleFileName"); | ||
175 | else { | ||
176 | *lb = '\0'; | ||
177 | luaL_gsub(L, lua_tostring(L, -1), LUA_EXEC_DIR, buff); | ||
178 | lua_remove(L, -2); /* remove original string */ | ||
179 | } | ||
180 | } | ||
181 | |||
182 | |||
183 | static void pusherror (lua_State *L) { | ||
184 | int error = GetLastError(); | ||
185 | char buffer[128]; | ||
186 | if (FormatMessageA(FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, | ||
187 | NULL, error, 0, buffer, sizeof(buffer)/sizeof(char), NULL)) | ||
188 | lua_pushstring(L, buffer); | ||
189 | else | ||
190 | lua_pushfstring(L, "system error %d\n", error); | ||
191 | } | ||
192 | |||
193 | static void ll_unloadlib (void *lib) { | ||
194 | FreeLibrary((HMODULE)lib); | ||
195 | } | ||
196 | |||
197 | |||
198 | static void *ll_load (lua_State *L, const char *path, int seeglb) { | ||
199 | HMODULE lib = LoadLibraryExA(path, NULL, LUA_LLE_FLAGS); | ||
200 | (void)(seeglb); /* not used: symbols are 'global' by default */ | ||
201 | if (lib == NULL) pusherror(L); | ||
202 | return lib; | ||
203 | } | ||
204 | |||
205 | |||
206 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
207 | lua_CFunction f = (lua_CFunction)GetProcAddress((HMODULE)lib, sym); | ||
208 | if (f == NULL) pusherror(L); | ||
209 | return f; | ||
210 | } | ||
211 | |||
212 | /* }====================================================== */ | ||
213 | |||
214 | |||
215 | #else | ||
216 | /* | ||
217 | ** {====================================================== | ||
218 | ** Fallback for other systems | ||
219 | ** ======================================================= | ||
220 | */ | ||
221 | |||
222 | #undef LIB_FAIL | ||
223 | #define LIB_FAIL "absent" | ||
224 | |||
225 | |||
226 | #define DLMSG "dynamic libraries not enabled; check your Lua installation" | ||
227 | |||
228 | |||
229 | static void ll_unloadlib (void *lib) { | ||
230 | (void)(lib); /* not used */ | ||
231 | } | ||
232 | |||
233 | |||
234 | static void *ll_load (lua_State *L, const char *path, int seeglb) { | ||
235 | (void)(path); (void)(seeglb); /* not used */ | ||
236 | lua_pushliteral(L, DLMSG); | ||
237 | return NULL; | ||
238 | } | ||
239 | |||
240 | |||
241 | static lua_CFunction ll_sym (lua_State *L, void *lib, const char *sym) { | ||
242 | (void)(lib); (void)(sym); /* not used */ | ||
243 | lua_pushliteral(L, DLMSG); | ||
244 | return NULL; | ||
245 | } | ||
246 | |||
247 | /* }====================================================== */ | ||
248 | #endif | ||
249 | |||
250 | |||
251 | static void *ll_checkclib (lua_State *L, const char *path) { | ||
252 | void *plib; | ||
253 | lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); | ||
254 | lua_getfield(L, -1, path); | ||
255 | plib = lua_touserdata(L, -1); /* plib = CLIBS[path] */ | ||
256 | lua_pop(L, 2); /* pop CLIBS table and 'plib' */ | ||
257 | return plib; | ||
258 | } | ||
259 | |||
260 | |||
261 | static void ll_addtoclib (lua_State *L, const char *path, void *plib) { | ||
262 | lua_getfield(L, LUA_REGISTRYINDEX, CLIBS); | ||
263 | lua_pushlightuserdata(L, plib); | ||
264 | lua_pushvalue(L, -1); | ||
265 | lua_setfield(L, -3, path); /* CLIBS[path] = plib */ | ||
266 | lua_rawseti(L, -2, luaL_len(L, -2) + 1); /* CLIBS[#CLIBS + 1] = plib */ | ||
267 | lua_pop(L, 1); /* pop CLIBS table */ | ||
268 | } | ||
269 | |||
270 | |||
271 | /* | ||
272 | ** __gc tag method for CLIBS table: calls 'll_unloadlib' for all lib | ||
273 | ** handles in list CLIBS | ||
274 | */ | ||
275 | static int gctm (lua_State *L) { | ||
276 | int n = luaL_len(L, 1); | ||
277 | for (; n >= 1; n--) { /* for each handle, in reverse order */ | ||
278 | lua_rawgeti(L, 1, n); /* get handle CLIBS[n] */ | ||
279 | ll_unloadlib(lua_touserdata(L, -1)); | ||
280 | lua_pop(L, 1); /* pop handle */ | ||
281 | } | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | |||
286 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | ||
287 | void *reg = ll_checkclib(L, path); /* check loaded C libraries */ | ||
288 | if (reg == NULL) { /* must load library? */ | ||
289 | reg = ll_load(L, path, *sym == '*'); | ||
290 | if (reg == NULL) return ERRLIB; /* unable to load library */ | ||
291 | ll_addtoclib(L, path, reg); | ||
292 | } | ||
293 | if (*sym == '*') { /* loading only library (no function)? */ | ||
294 | lua_pushboolean(L, 1); /* return 'true' */ | ||
295 | return 0; /* no errors */ | ||
296 | } | ||
297 | else { | ||
298 | lua_CFunction f = ll_sym(L, reg, sym); | ||
299 | if (f == NULL) | ||
300 | return ERRFUNC; /* unable to find function */ | ||
301 | lua_pushcfunction(L, f); /* else create new function */ | ||
302 | return 0; /* no errors */ | ||
303 | } | ||
304 | } | ||
305 | |||
306 | |||
307 | static int ll_loadlib (lua_State *L) { | ||
308 | const char *path = luaL_checkstring(L, 1); | ||
309 | const char *init = luaL_checkstring(L, 2); | ||
310 | int stat = ll_loadfunc(L, path, init); | ||
311 | if (stat == 0) /* no errors? */ | ||
312 | return 1; /* return the loaded function */ | ||
313 | else { /* error; error message is on stack top */ | ||
314 | lua_pushnil(L); | ||
315 | lua_insert(L, -2); | ||
316 | lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); | ||
317 | return 3; /* return nil, error message, and where */ | ||
318 | } | ||
319 | } | ||
320 | |||
27 | 321 | ||
28 | 322 | ||
29 | /* | 323 | /* |
@@ -34,70 +328,143 @@ | |||
34 | 328 | ||
35 | 329 | ||
36 | static int readable (const char *filename) { | 330 | static int readable (const char *filename) { |
37 | int f = rb->open(filename, O_RDONLY); /* try to open file */ | 331 | return rb->file_exists(filename); |
38 | if (f < 0) return 0; /* open failed */ | ||
39 | rb->close(f); | ||
40 | return 1; | ||
41 | } | 332 | } |
42 | 333 | ||
43 | 334 | ||
44 | static const char *pushnexttemplate (lua_State *L, const char *path) { | 335 | static const char *pushnexttemplate (lua_State *L, const char *path) { |
45 | const char *l; | 336 | const char *l; |
46 | while (*path == *LUA_PATHSEP) path++; /* skip separators */ | 337 | while (*path == *LUA_PATH_SEP) path++; /* skip separators */ |
47 | if (*path == '\0') return NULL; /* no more templates */ | 338 | if (*path == '\0') return NULL; /* no more templates */ |
48 | l = strchr(path, *LUA_PATHSEP); /* find next separator */ | 339 | l = strchr(path, *LUA_PATH_SEP); /* find next separator */ |
49 | if (l == NULL) l = path + strlen(path); | 340 | if (l == NULL) l = path + strlen(path); |
50 | lua_pushlstring(L, path, l - path); /* template */ | 341 | lua_pushlstring(L, path, l - path); /* template */ |
51 | return l; | 342 | return l; |
52 | } | 343 | } |
53 | 344 | ||
54 | 345 | ||
55 | static const char *findfile (lua_State *L, const char *name, | 346 | static const char *searchpath (lua_State *L, const char *name, |
56 | const char *pname) { | 347 | const char *path, |
57 | const char *path, *current_path = get_current_path(L, 2); | 348 | const char *sep, |
58 | name = luaL_gsub(L, name, ".", LUA_DIRSEP); | 349 | const char *dirsep) { |
59 | lua_getfield(L, LUA_ENVIRONINDEX, pname); | 350 | luaL_Buffer msg; /* to build error message */ |
60 | path = lua_tostring(L, -1); | 351 | luaL_buffinit(L, &msg); |
61 | if (path == NULL) | 352 | if (*sep != '\0') /* non-empty separator? */ |
62 | luaL_error(L, LUA_QL("package.%s") " must be a string", pname); | 353 | name = luaL_gsub(L, name, sep, dirsep); /* replace it by 'dirsep' */ |
63 | lua_pushliteral(L, ""); /* error accumulator */ | ||
64 | while ((path = pushnexttemplate(L, path)) != NULL) { | 354 | while ((path = pushnexttemplate(L, path)) != NULL) { |
65 | const char *filename; | 355 | const char *filename = luaL_gsub(L, lua_tostring(L, -1), |
66 | filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); | 356 | LUA_PATH_MARK, name); |
67 | if(current_path != NULL) filename = luaL_gsub(L, filename, "$", current_path); | ||
68 | lua_remove(L, -2); /* remove path template */ | 357 | lua_remove(L, -2); /* remove path template */ |
69 | if (readable(filename)) /* does file exist and is readable? */ | 358 | if (readable(filename)) /* does file exist and is readable? */ |
70 | return filename; /* return that file name */ | 359 | return filename; /* return that file name */ |
71 | lua_pushfstring(L, "\n\tno file " LUA_QS, filename); | 360 | lua_pushfstring(L, "\n\tno file " LUA_QS, filename); |
72 | lua_remove(L, -2); /* remove file name */ | 361 | lua_remove(L, -2); /* remove file name */ |
73 | lua_concat(L, 2); /* add entry to possible error message */ | 362 | luaL_addvalue(&msg); /* concatenate error msg. entry */ |
74 | } | 363 | } |
364 | luaL_pushresult(&msg); /* create error message */ | ||
75 | return NULL; /* not found */ | 365 | return NULL; /* not found */ |
76 | } | 366 | } |
77 | 367 | ||
78 | 368 | ||
79 | static void loaderror (lua_State *L, const char *filename) { | 369 | static int ll_searchpath (lua_State *L) { |
80 | luaL_error(L, "error loading module " LUA_QS " from file " LUA_QS ":\n\t%s", | 370 | const char *f = searchpath(L, luaL_checkstring(L, 1), |
81 | lua_tostring(L, 1), filename, lua_tostring(L, -1)); | 371 | luaL_checkstring(L, 2), |
372 | luaL_optstring(L, 3, "."), | ||
373 | luaL_optstring(L, 4, LUA_DIRSEP)); | ||
374 | if (f != NULL) return 1; | ||
375 | else { /* error message is on top of the stack */ | ||
376 | lua_pushnil(L); | ||
377 | lua_insert(L, -2); | ||
378 | return 2; /* return nil + error message */ | ||
379 | } | ||
82 | } | 380 | } |
83 | 381 | ||
84 | 382 | ||
85 | static int loader_Lua (lua_State *L) { | 383 | static const char *findfile (lua_State *L, const char *name, |
384 | const char *pname, | ||
385 | const char *dirsep) { | ||
386 | const char *path; | ||
387 | lua_getfield(L, lua_upvalueindex(1), pname); | ||
388 | path = lua_tostring(L, -1); | ||
389 | if (path == NULL) | ||
390 | luaL_error(L, LUA_QL("package.%s") " must be a string", pname); | ||
391 | return searchpath(L, name, path, ".", dirsep); | ||
392 | } | ||
393 | |||
394 | |||
395 | static int checkload (lua_State *L, int stat, const char *filename) { | ||
396 | if (stat) { /* module loaded successfully? */ | ||
397 | lua_pushstring(L, filename); /* will be 2nd argument to module */ | ||
398 | return 2; /* return open function and file name */ | ||
399 | } | ||
400 | else | ||
401 | return luaL_error(L, "error loading module " LUA_QS | ||
402 | " from file " LUA_QS ":\n\t%s", | ||
403 | lua_tostring(L, 1), filename, lua_tostring(L, -1)); | ||
404 | } | ||
405 | |||
406 | |||
407 | static int searcher_Lua (lua_State *L) { | ||
86 | const char *filename; | 408 | const char *filename; |
87 | const char *name = luaL_checkstring(L, 1); | 409 | const char *name = luaL_checkstring(L, 1); |
88 | filename = findfile(L, name, "path"); | 410 | filename = findfile(L, name, "path", LUA_LSUBSEP); |
89 | if (filename == NULL) return 1; /* library not found in this path */ | 411 | if (filename == NULL) return 1; /* module not found in this path */ |
90 | if (luaL_loadfile(L, filename) != 0) | 412 | return checkload(L, (luaL_loadfile(L, filename) == LUA_OK), filename); |
91 | loaderror(L, filename); | 413 | } |
92 | return 1; /* library loaded successfully */ | 414 | |
415 | |||
416 | static int loadfunc (lua_State *L, const char *filename, const char *modname) { | ||
417 | const char *funcname; | ||
418 | const char *mark; | ||
419 | modname = luaL_gsub(L, modname, ".", LUA_OFSEP); | ||
420 | mark = strchr(modname, *LUA_IGMARK); | ||
421 | if (mark) { | ||
422 | int stat; | ||
423 | funcname = lua_pushlstring(L, modname, mark - modname); | ||
424 | funcname = lua_pushfstring(L, LUA_POF"%s", funcname); | ||
425 | stat = ll_loadfunc(L, filename, funcname); | ||
426 | if (stat != ERRFUNC) return stat; | ||
427 | modname = mark + 1; /* else go ahead and try old-style name */ | ||
428 | } | ||
429 | funcname = lua_pushfstring(L, LUA_POF"%s", modname); | ||
430 | return ll_loadfunc(L, filename, funcname); | ||
93 | } | 431 | } |
94 | 432 | ||
95 | 433 | ||
96 | static int loader_preload (lua_State *L) { | 434 | static int searcher_C (lua_State *L) { |
97 | const char *name = luaL_checkstring(L, 1); | 435 | const char *name = luaL_checkstring(L, 1); |
98 | lua_getfield(L, LUA_ENVIRONINDEX, "preload"); | 436 | const char *filename = findfile(L, name, "cpath", LUA_CSUBSEP); |
99 | if (!lua_istable(L, -1)) | 437 | if (filename == NULL) return 1; /* module not found in this path */ |
100 | luaL_error(L, LUA_QL("package.preload") " must be a table"); | 438 | return checkload(L, (loadfunc(L, filename, name) == 0), filename); |
439 | } | ||
440 | |||
441 | |||
442 | static int searcher_Croot (lua_State *L) { | ||
443 | const char *filename; | ||
444 | const char *name = luaL_checkstring(L, 1); | ||
445 | const char *p = strchr(name, '.'); | ||
446 | int stat; | ||
447 | if (p == NULL) return 0; /* is root */ | ||
448 | lua_pushlstring(L, name, p - name); | ||
449 | filename = findfile(L, lua_tostring(L, -1), "cpath", LUA_CSUBSEP); | ||
450 | if (filename == NULL) return 1; /* root not found */ | ||
451 | if ((stat = loadfunc(L, filename, name)) != 0) { | ||
452 | if (stat != ERRFUNC) | ||
453 | return checkload(L, 0, filename); /* real error */ | ||
454 | else { /* open function not found */ | ||
455 | lua_pushfstring(L, "\n\tno module " LUA_QS " in file " LUA_QS, | ||
456 | name, filename); | ||
457 | return 1; | ||
458 | } | ||
459 | } | ||
460 | lua_pushstring(L, filename); /* will be 2nd argument to module */ | ||
461 | return 2; | ||
462 | } | ||
463 | |||
464 | |||
465 | static int searcher_preload (lua_State *L) { | ||
466 | const char *name = luaL_checkstring(L, 1); | ||
467 | lua_getfield(L, LUA_REGISTRYINDEX, "_PRELOAD"); | ||
101 | lua_getfield(L, -1, name); | 468 | lua_getfield(L, -1, name); |
102 | if (lua_isnil(L, -1)) /* not found? */ | 469 | if (lua_isnil(L, -1)) /* not found? */ |
103 | lua_pushfstring(L, "\n\tno field package.preload['%s']", name); | 470 | lua_pushfstring(L, "\n\tno field package.preload['%s']", name); |
@@ -105,48 +472,53 @@ static int loader_preload (lua_State *L) { | |||
105 | } | 472 | } |
106 | 473 | ||
107 | 474 | ||
108 | static const int sentinel_ = 0; | 475 | static void findloader (lua_State *L, const char *name) { |
109 | #define sentinel ((void *)&sentinel_) | 476 | int i; |
477 | luaL_Buffer msg; /* to build error message */ | ||
478 | luaL_buffinit(L, &msg); | ||
479 | lua_getfield(L, lua_upvalueindex(1), "searchers"); /* will be at index 3 */ | ||
480 | if (!lua_istable(L, 3)) | ||
481 | luaL_error(L, LUA_QL("package.searchers") " must be a table"); | ||
482 | /* iterate over available searchers to find a loader */ | ||
483 | for (i = 1; ; i++) { | ||
484 | lua_rawgeti(L, 3, i); /* get a searcher */ | ||
485 | if (lua_isnil(L, -1)) { /* no more searchers? */ | ||
486 | lua_pop(L, 1); /* remove nil */ | ||
487 | luaL_pushresult(&msg); /* create error message */ | ||
488 | luaL_error(L, "module " LUA_QS " not found:%s", | ||
489 | name, lua_tostring(L, -1)); | ||
490 | } | ||
491 | lua_pushstring(L, name); | ||
492 | lua_call(L, 1, 2); /* call it */ | ||
493 | if (lua_isfunction(L, -2)) /* did it find a loader? */ | ||
494 | return; /* module loader found */ | ||
495 | else if (lua_isstring(L, -2)) { /* searcher returned error message? */ | ||
496 | lua_pop(L, 1); /* remove extra return */ | ||
497 | luaL_addvalue(&msg); /* concatenate error message */ | ||
498 | } | ||
499 | else | ||
500 | lua_pop(L, 2); /* remove both returns */ | ||
501 | } | ||
502 | } | ||
110 | 503 | ||
111 | 504 | ||
112 | static int ll_require (lua_State *L) { | 505 | static int ll_require (lua_State *L) { |
113 | const char *name = luaL_checkstring(L, 1); | 506 | const char *name = luaL_checkstring(L, 1); |
114 | int i; | ||
115 | lua_settop(L, 1); /* _LOADED table will be at index 2 */ | 507 | lua_settop(L, 1); /* _LOADED table will be at index 2 */ |
116 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | 508 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); |
117 | lua_getfield(L, 2, name); | 509 | lua_getfield(L, 2, name); /* _LOADED[name] */ |
118 | if (lua_toboolean(L, -1)) { /* is it there? */ | 510 | if (lua_toboolean(L, -1)) /* is it there? */ |
119 | if (lua_touserdata(L, -1) == sentinel) /* check loops */ | ||
120 | luaL_error(L, "loop or previous error loading module " LUA_QS, name); | ||
121 | return 1; /* package is already loaded */ | 511 | return 1; /* package is already loaded */ |
122 | } | 512 | /* else must load package */ |
123 | /* else must load it; iterate over available loaders */ | 513 | lua_pop(L, 1); /* remove 'getfield' result */ |
124 | lua_getfield(L, LUA_ENVIRONINDEX, "loaders"); | 514 | findloader(L, name); |
125 | if (!lua_istable(L, -1)) | 515 | lua_pushstring(L, name); /* pass name as argument to module loader */ |
126 | luaL_error(L, LUA_QL("package.loaders") " must be a table"); | 516 | lua_insert(L, -2); /* name is 1st argument (before search data) */ |
127 | lua_pushliteral(L, ""); /* error message accumulator */ | 517 | lua_call(L, 2, 1); /* run loader to load module */ |
128 | for (i=1; ; i++) { | ||
129 | lua_rawgeti(L, -2, i); /* get a loader */ | ||
130 | if (lua_isnil(L, -1)) | ||
131 | luaL_error(L, "module " LUA_QS " not found:%s", | ||
132 | name, lua_tostring(L, -2)); | ||
133 | lua_pushstring(L, name); | ||
134 | lua_call(L, 1, 1); /* call it */ | ||
135 | if (lua_isfunction(L, -1)) /* did it find module? */ | ||
136 | break; /* module loaded successfully */ | ||
137 | else if (lua_isstring(L, -1)) /* loader returned error message? */ | ||
138 | lua_concat(L, 2); /* accumulate it */ | ||
139 | else | ||
140 | lua_pop(L, 1); | ||
141 | } | ||
142 | lua_pushlightuserdata(L, sentinel); | ||
143 | lua_setfield(L, 2, name); /* _LOADED[name] = sentinel */ | ||
144 | lua_pushstring(L, name); /* pass name as argument to module */ | ||
145 | lua_call(L, 1, 1); /* run loaded module */ | ||
146 | if (!lua_isnil(L, -1)) /* non-nil return? */ | 518 | if (!lua_isnil(L, -1)) /* non-nil return? */ |
147 | lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ | 519 | lua_setfield(L, 2, name); /* _LOADED[name] = returned value */ |
148 | lua_getfield(L, 2, name); | 520 | lua_getfield(L, 2, name); |
149 | if (lua_touserdata(L, -1) == sentinel) { /* module did not set a value? */ | 521 | if (lua_isnil(L, -1)) { /* module did not set a value? */ |
150 | lua_pushboolean(L, 1); /* use true as result */ | 522 | lua_pushboolean(L, 1); /* use true as result */ |
151 | lua_pushvalue(L, -1); /* extra copy to be returned */ | 523 | lua_pushvalue(L, -1); /* extra copy to be returned */ |
152 | lua_setfield(L, 2, name); /* _LOADED[name] = true */ | 524 | lua_setfield(L, 2, name); /* _LOADED[name] = true */ |
@@ -163,26 +535,31 @@ static int ll_require (lua_State *L) { | |||
163 | ** 'module' function | 535 | ** 'module' function |
164 | ** ======================================================= | 536 | ** ======================================================= |
165 | */ | 537 | */ |
166 | 538 | #if defined(LUA_COMPAT_MODULE) | |
167 | 539 | ||
168 | static void setfenv (lua_State *L) { | 540 | /* |
541 | ** changes the environment variable of calling function | ||
542 | */ | ||
543 | static void set_env (lua_State *L) { | ||
169 | lua_Debug ar; | 544 | lua_Debug ar; |
170 | if (lua_getstack(L, 1, &ar) == 0 || | 545 | if (lua_getstack(L, 1, &ar) == 0 || |
171 | lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ | 546 | lua_getinfo(L, "f", &ar) == 0 || /* get calling function */ |
172 | lua_iscfunction(L, -1)) | 547 | lua_iscfunction(L, -1)) |
173 | luaL_error(L, LUA_QL("module") " not called from a Lua function"); | 548 | luaL_error(L, LUA_QL("module") " not called from a Lua function"); |
174 | lua_pushvalue(L, -2); | 549 | lua_pushvalue(L, -2); /* copy new environment table to top */ |
175 | lua_setfenv(L, -2); | 550 | lua_setupvalue(L, -2, 1); |
176 | lua_pop(L, 1); | 551 | lua_pop(L, 1); /* remove function */ |
177 | } | 552 | } |
178 | 553 | ||
179 | 554 | ||
180 | static void dooptions (lua_State *L, int n) { | 555 | static void dooptions (lua_State *L, int n) { |
181 | int i; | 556 | int i; |
182 | for (i = 2; i <= n; i++) { | 557 | for (i = 2; i <= n; i++) { |
183 | lua_pushvalue(L, i); /* get option (a function) */ | 558 | if (lua_isfunction(L, i)) { /* avoid 'calling' extra info. */ |
184 | lua_pushvalue(L, -2); /* module */ | 559 | lua_pushvalue(L, i); /* get option (a function) */ |
185 | lua_call(L, 1, 0); | 560 | lua_pushvalue(L, -2); /* module */ |
561 | lua_call(L, 1, 0); | ||
562 | } | ||
186 | } | 563 | } |
187 | } | 564 | } |
188 | 565 | ||
@@ -204,17 +581,8 @@ static void modinit (lua_State *L, const char *modname) { | |||
204 | 581 | ||
205 | static int ll_module (lua_State *L) { | 582 | static int ll_module (lua_State *L) { |
206 | const char *modname = luaL_checkstring(L, 1); | 583 | const char *modname = luaL_checkstring(L, 1); |
207 | int loaded = lua_gettop(L) + 1; /* index of _LOADED table */ | 584 | int lastarg = lua_gettop(L); /* last parameter */ |
208 | lua_getfield(L, LUA_REGISTRYINDEX, "_LOADED"); | 585 | luaL_pushmodule(L, modname, 1); /* get/create module table */ |
209 | lua_getfield(L, loaded, modname); /* get _LOADED[modname] */ | ||
210 | if (!lua_istable(L, -1)) { /* not found? */ | ||
211 | lua_pop(L, 1); /* remove previous result */ | ||
212 | /* try global variable (and create one if it does not exist) */ | ||
213 | if (luaL_findtable(L, LUA_GLOBALSINDEX, modname, 1) != NULL) | ||
214 | return luaL_error(L, "name conflict for module " LUA_QS, modname); | ||
215 | lua_pushvalue(L, -1); | ||
216 | lua_setfield(L, loaded, modname); /* _LOADED[modname] = new table */ | ||
217 | } | ||
218 | /* check whether table already has a _NAME field */ | 586 | /* check whether table already has a _NAME field */ |
219 | lua_getfield(L, -1, "_NAME"); | 587 | lua_getfield(L, -1, "_NAME"); |
220 | if (!lua_isnil(L, -1)) /* is table an initialized module? */ | 588 | if (!lua_isnil(L, -1)) /* is table an initialized module? */ |
@@ -224,9 +592,9 @@ static int ll_module (lua_State *L) { | |||
224 | modinit(L, modname); | 592 | modinit(L, modname); |
225 | } | 593 | } |
226 | lua_pushvalue(L, -1); | 594 | lua_pushvalue(L, -1); |
227 | setfenv(L); | 595 | set_env(L); |
228 | dooptions(L, loaded - 1); | 596 | dooptions(L, lastarg); |
229 | return 0; | 597 | return 1; |
230 | } | 598 | } |
231 | 599 | ||
232 | 600 | ||
@@ -237,22 +605,38 @@ static int ll_seeall (lua_State *L) { | |||
237 | lua_pushvalue(L, -1); | 605 | lua_pushvalue(L, -1); |
238 | lua_setmetatable(L, 1); | 606 | lua_setmetatable(L, 1); |
239 | } | 607 | } |
240 | lua_pushvalue(L, LUA_GLOBALSINDEX); | 608 | lua_pushglobaltable(L); |
241 | lua_setfield(L, -2, "__index"); /* mt.__index = _G */ | 609 | lua_setfield(L, -2, "__index"); /* mt.__index = _G */ |
242 | return 0; | 610 | return 0; |
243 | } | 611 | } |
244 | 612 | ||
245 | 613 | #endif | |
246 | /* }====================================================== */ | 614 | /* }====================================================== */ |
247 | 615 | ||
248 | 616 | ||
249 | 617 | ||
250 | /* auxiliary mark (for internal use) */ | 618 | /* auxiliary mark (for internal use) */ |
251 | #define AUXMARK "\1" | 619 | #define AUXMARK "\1" |
620 | |||
621 | |||
622 | /* | ||
623 | ** return registry.LUA_NOENV as a boolean | ||
624 | */ | ||
625 | #if 0 | ||
626 | static int noenv (lua_State *L) { | ||
627 | int b; | ||
628 | lua_getfield(L, LUA_REGISTRYINDEX, "LUA_NOENV"); | ||
629 | b = lua_toboolean(L, -1); | ||
630 | lua_pop(L, 1); /* remove value */ | ||
631 | return b; | ||
632 | } | ||
633 | #endif | ||
634 | |||
252 | 635 | ||
253 | static void setpath (lua_State *L, const char *fieldname, const char *envname, | 636 | static void setpath (lua_State *L, const char *fieldname, const char *envname1, |
254 | const char *def) { | 637 | const char *envname2, const char *def) { |
255 | (void)envname; | 638 | (void)envname1; |
639 | (void)envname2; | ||
256 | lua_pushstring(L, def); /* use default */ | 640 | lua_pushstring(L, def); /* use default */ |
257 | setprogdir(L); | 641 | setprogdir(L); |
258 | lua_setfield(L, -2, fieldname); | 642 | lua_setfield(L, -2, fieldname); |
@@ -260,56 +644,72 @@ static void setpath (lua_State *L, const char *fieldname, const char *envname, | |||
260 | 644 | ||
261 | 645 | ||
262 | static const luaL_Reg pk_funcs[] = { | 646 | static const luaL_Reg pk_funcs[] = { |
647 | {"loadlib", ll_loadlib}, | ||
648 | {"searchpath", ll_searchpath}, | ||
649 | #if defined(LUA_COMPAT_MODULE) | ||
263 | {"seeall", ll_seeall}, | 650 | {"seeall", ll_seeall}, |
651 | #endif | ||
264 | {NULL, NULL} | 652 | {NULL, NULL} |
265 | }; | 653 | }; |
266 | 654 | ||
267 | 655 | ||
268 | static const luaL_Reg ll_funcs[] = { | 656 | static const luaL_Reg ll_funcs[] = { |
657 | #if defined(LUA_COMPAT_MODULE) | ||
269 | {"module", ll_module}, | 658 | {"module", ll_module}, |
659 | #endif | ||
270 | {"require", ll_require}, | 660 | {"require", ll_require}, |
271 | {NULL, NULL} | 661 | {NULL, NULL} |
272 | }; | 662 | }; |
273 | 663 | ||
274 | 664 | ||
275 | static const lua_CFunction loaders[] = | 665 | static void createsearcherstable (lua_State *L) { |
276 | {loader_preload, loader_Lua, NULL}; | 666 | static const lua_CFunction searchers[] = |
667 | {searcher_preload, searcher_Lua, searcher_C, searcher_Croot, NULL}; | ||
668 | int i; | ||
669 | /* create 'searchers' table */ | ||
670 | lua_createtable(L, sizeof(searchers)/sizeof(searchers[0]) - 1, 0); | ||
671 | /* fill it with pre-defined searchers */ | ||
672 | for (i=0; searchers[i] != NULL; i++) { | ||
673 | lua_pushvalue(L, -2); /* set 'package' as upvalue for all searchers */ | ||
674 | lua_pushcclosure(L, searchers[i], 1); | ||
675 | lua_rawseti(L, -2, i+1); | ||
676 | } | ||
677 | } | ||
277 | 678 | ||
278 | 679 | ||
279 | LUALIB_API int luaopen_package (lua_State *L) { | 680 | LUAMOD_API int luaopen_package (lua_State *L) { |
280 | int i; | 681 | /* create table CLIBS to keep track of loaded C libraries */ |
281 | /* create new type _LOADLIB */ | 682 | luaL_getsubtable(L, LUA_REGISTRYINDEX, CLIBS); |
282 | luaL_newmetatable(L, "_LOADLIB"); | 683 | lua_createtable(L, 0, 1); /* metatable for CLIBS */ |
684 | lua_pushcfunction(L, gctm); | ||
685 | lua_setfield(L, -2, "__gc"); /* set finalizer for CLIBS table */ | ||
686 | lua_setmetatable(L, -2); | ||
283 | /* create `package' table */ | 687 | /* create `package' table */ |
284 | luaL_register(L, LUA_LOADLIBNAME, pk_funcs); | 688 | luaL_newlib(L, pk_funcs); |
285 | #if defined(LUA_COMPAT_LOADLIB) | 689 | createsearcherstable(L); |
286 | lua_getfield(L, -1, "loadlib"); | 690 | #if defined(LUA_COMPAT_LOADERS) |
287 | lua_setfield(L, LUA_GLOBALSINDEX, "loadlib"); | 691 | lua_pushvalue(L, -1); /* make a copy of 'searchers' table */ |
692 | lua_setfield(L, -3, "loaders"); /* put it in field `loaders' */ | ||
288 | #endif | 693 | #endif |
289 | lua_pushvalue(L, -1); | 694 | lua_setfield(L, -2, "searchers"); /* put it in field 'searchers' */ |
290 | lua_replace(L, LUA_ENVIRONINDEX); | 695 | /* set field 'path' */ |
291 | /* create `loaders' table */ | 696 | setpath(L, "path", LUA_PATHVERSION, LUA_PATH, LUA_PATH_DEFAULT); |
292 | lua_createtable(L, 0, sizeof(loaders)/sizeof(loaders[0]) - 1); | 697 | /* set field 'cpath' */ |
293 | /* fill it with pre-defined loaders */ | 698 | setpath(L, "cpath", LUA_CPATHVERSION, LUA_CPATH, LUA_CPATH_DEFAULT); |
294 | for (i=0; loaders[i] != NULL; i++) { | ||
295 | lua_pushcfunction(L, loaders[i]); | ||
296 | lua_rawseti(L, -2, i+1); | ||
297 | } | ||
298 | lua_setfield(L, -2, "loaders"); /* put it in field `loaders' */ | ||
299 | setpath(L, "path", LUA_PATH, LUA_PATH_DEFAULT); /* set field `path' */ | ||
300 | /* store config information */ | 699 | /* store config information */ |
301 | lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATHSEP "\n" LUA_PATH_MARK "\n" | 700 | lua_pushliteral(L, LUA_DIRSEP "\n" LUA_PATH_SEP "\n" LUA_PATH_MARK "\n" |
302 | LUA_EXECDIR "\n" LUA_IGMARK); | 701 | LUA_EXEC_DIR "\n" LUA_IGMARK "\n"); |
303 | lua_setfield(L, -2, "config"); | 702 | lua_setfield(L, -2, "config"); |
304 | /* set field `loaded' */ | 703 | /* set field `loaded' */ |
305 | luaL_findtable(L, LUA_REGISTRYINDEX, "_LOADED", 2); | 704 | luaL_getsubtable(L, LUA_REGISTRYINDEX, "_LOADED"); |
306 | lua_setfield(L, -2, "loaded"); | 705 | lua_setfield(L, -2, "loaded"); |
307 | /* set field `preload' */ | 706 | /* set field `preload' */ |
308 | lua_newtable(L); | 707 | luaL_getsubtable(L, LUA_REGISTRYINDEX, "_PRELOAD"); |
309 | lua_setfield(L, -2, "preload"); | 708 | lua_setfield(L, -2, "preload"); |
310 | lua_pushvalue(L, LUA_GLOBALSINDEX); | 709 | lua_pushglobaltable(L); |
311 | luaL_register(L, NULL, ll_funcs); /* open lib into global table */ | 710 | lua_pushvalue(L, -2); /* set 'package' as upvalue for next lib */ |
312 | lua_pop(L, 1); | 711 | luaL_setfuncs(L, ll_funcs, 1); /* open lib into global table */ |
712 | lua_pop(L, 1); /* pop global table */ | ||
313 | return 1; /* return 'package' table */ | 713 | return 1; /* return 'package' table */ |
314 | } | 714 | } |
315 | 715 | ||