diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-04-15 17:54:41 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2002-04-15 17:54:41 -0300 |
commit | 391c5459cbfb2a01a66b318f42cf780d952704b7 (patch) | |
tree | 1b2251c3b7cd7da0580ea29b75d93241e77af7c0 /lbaselib.c | |
parent | 62dd4cbe91617741a9f8e594201ad510d073b12d (diff) | |
download | lua-391c5459cbfb2a01a66b318f42cf780d952704b7.tar.gz lua-391c5459cbfb2a01a66b318f42cf780d952704b7.tar.bz2 lua-391c5459cbfb2a01a66b318f42cf780d952704b7.zip |
new implementation for `require' (with templates)
Diffstat (limited to 'lbaselib.c')
-rw-r--r-- | lbaselib.c | 175 |
1 files changed, 119 insertions, 56 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lbaselib.c,v 1.66 2002/04/09 20:19:06 roberto Exp roberto $ | 2 | ** $Id: lbaselib.c,v 1.67 2002/04/12 19:57:29 roberto Exp roberto $ |
3 | ** Basic library | 3 | ** Basic library |
4 | ** See Copyright Notice in lua.h | 4 | ** See Copyright Notice in lua.h |
5 | */ | 5 | */ |
@@ -200,6 +200,23 @@ static int luaB_next (lua_State *L) { | |||
200 | } | 200 | } |
201 | 201 | ||
202 | 202 | ||
203 | static int luaB_nexti (lua_State *L) { | ||
204 | lua_Number i = lua_tonumber(L, 2); | ||
205 | luaL_check_type(L, 1, LUA_TTABLE); | ||
206 | if (i == 0) { /* `for' start? */ | ||
207 | lua_getglobal(L, "nexti"); /* return generator, */ | ||
208 | lua_pushvalue(L, 1); /* state, */ | ||
209 | lua_pushnumber(L, 1); /* and initial value */ | ||
210 | return 3; | ||
211 | } | ||
212 | else { /* `for' step */ | ||
213 | lua_pushnumber(L, i+1); /* next value */ | ||
214 | lua_rawgeti(L, 1, i); | ||
215 | return (lua_isnil(L, -1)) ? 0 : 2; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | |||
203 | static int passresults (lua_State *L, int status, int oldtop) { | 220 | static int passresults (lua_State *L, int status, int oldtop) { |
204 | if (status == 0) { | 221 | if (status == 0) { |
205 | int nresults = lua_gettop(L) - oldtop; | 222 | int nresults = lua_gettop(L) - oldtop; |
@@ -259,58 +276,6 @@ static int luaB_assert (lua_State *L) { | |||
259 | } | 276 | } |
260 | 277 | ||
261 | 278 | ||
262 | #define LUA_PATH "LUA_PATH" | ||
263 | |||
264 | #define LUA_PATH_SEP ";" | ||
265 | |||
266 | #ifndef LUA_PATH_DEFAULT | ||
267 | #define LUA_PATH_DEFAULT "./" | ||
268 | #endif | ||
269 | |||
270 | static int luaB_require (lua_State *L) { | ||
271 | const char *path; | ||
272 | luaL_check_string(L, 1); | ||
273 | lua_settop(L, 1); | ||
274 | lua_getglobal(L, LUA_PATH); /* get path */ | ||
275 | if (lua_isstring(L, 2)) /* is LUA_PATH defined? */ | ||
276 | path = lua_tostring(L, 2); | ||
277 | else { /* LUA_PATH not defined */ | ||
278 | lua_pop(L, 1); /* pop old global value */ | ||
279 | path = getenv(LUA_PATH); /* try environment variable */ | ||
280 | if (path == NULL) path = LUA_PATH_DEFAULT; /* else use default */ | ||
281 | lua_pushstring(L, path); | ||
282 | lua_pushvalue(L, -1); /* duplicate to leave a copy on stack */ | ||
283 | lua_setglobal(L, LUA_PATH); | ||
284 | } | ||
285 | lua_pushvalue(L, 1); /* check package's name in book-keeping table */ | ||
286 | lua_gettable(L, lua_upvalueindex(1)); | ||
287 | if (!lua_isnil(L, -1)) /* is it there? */ | ||
288 | return 0; /* package is already loaded */ | ||
289 | else { /* must load it */ | ||
290 | for (;;) { /* traverse path */ | ||
291 | int res; | ||
292 | int l = strcspn(path, LUA_PATH_SEP); /* find separator */ | ||
293 | lua_pushlstring(L, path, l); /* directory name */ | ||
294 | lua_pushvalue(L, 1); /* package name */ | ||
295 | lua_concat(L, 2); /* concat directory with package name */ | ||
296 | res = lua_dofile(L, lua_tostring(L, -1)); /* try to load it */ | ||
297 | lua_settop(L, 2); /* pop string and eventual results from dofile */ | ||
298 | if (res == 0) break; /* ok; file done */ | ||
299 | else if (res != LUA_ERRFILE) | ||
300 | lua_error(L, NULL); /* error running package; propagate it */ | ||
301 | if (*(path+l) == '\0') /* no more directories? */ | ||
302 | luaL_verror(L, "could not load package `%.20s' from path `%.200s'", | ||
303 | lua_tostring(L, 1), lua_tostring(L, 2)); | ||
304 | path += l+1; /* try next directory */ | ||
305 | } | ||
306 | } | ||
307 | lua_pushvalue(L, 1); | ||
308 | lua_pushnumber(L, 1); | ||
309 | lua_settable(L, lua_upvalueindex(1)); /* mark it as loaded */ | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | |||
314 | static int aux_unpack (lua_State *L, int arg) { | 279 | static int aux_unpack (lua_State *L, int arg) { |
315 | int n, i; | 280 | int n, i; |
316 | luaL_check_type(L, arg, LUA_TTABLE); | 281 | luaL_check_type(L, arg, LUA_TTABLE); |
@@ -395,6 +360,104 @@ static int luaB_tostring (lua_State *L) { | |||
395 | } | 360 | } |
396 | 361 | ||
397 | 362 | ||
363 | |||
364 | /* | ||
365 | ** {====================================================== | ||
366 | ** `require' function | ||
367 | ** ======================================================= | ||
368 | */ | ||
369 | |||
370 | |||
371 | /* name of global that holds table with loaded packages */ | ||
372 | #define REQTAB "_LOADED" | ||
373 | |||
374 | /* name of global that holds the search path for packages */ | ||
375 | #define LUA_PATH "LUA_PATH" | ||
376 | |||
377 | #ifndef LUA_PATH_SEP | ||
378 | #define LUA_PATH_SEP ';' | ||
379 | #endif | ||
380 | |||
381 | #ifndef LUA_PATH_DEFAULT | ||
382 | #define LUA_PATH_DEFAULT "?.lua" | ||
383 | #endif | ||
384 | |||
385 | |||
386 | static const char *getpath (lua_State *L) { | ||
387 | const char *path; | ||
388 | lua_getglobal(L, LUA_PATH); /* try global variable */ | ||
389 | path = lua_tostring(L, -1); | ||
390 | if (path) return path; | ||
391 | path = getenv(LUA_PATH); /* else try environment variable */ | ||
392 | if (path) return path; | ||
393 | return LUA_PATH_DEFAULT; /* else use default */ | ||
394 | } | ||
395 | |||
396 | |||
397 | static const char *nextpath (lua_State *L, const char *path) { | ||
398 | const char *l; | ||
399 | if (*path == '\0') return NULL; /* no more pathes */ | ||
400 | if (*path == LUA_PATH_SEP) path++; /* skip separator */ | ||
401 | l = strchr(path, LUA_PATH_SEP); /* find next separator */ | ||
402 | if (l == NULL) l = path+strlen(path); | ||
403 | lua_pushlstring(L, path, l - path); /* directory name */ | ||
404 | return l; | ||
405 | } | ||
406 | |||
407 | |||
408 | static void composename (lua_State *L) { | ||
409 | const char *path = lua_tostring(L, -1); | ||
410 | const char *wild = strchr(path, '?'); | ||
411 | if (wild == NULL) return; /* no wild char; path is the file name */ | ||
412 | lua_pushlstring(L, path, wild - path); | ||
413 | lua_pushvalue(L, 1); /* package name */ | ||
414 | lua_pushstring(L, wild + 1); | ||
415 | lua_concat(L, 3); | ||
416 | } | ||
417 | |||
418 | |||
419 | static int luaB_require (lua_State *L) { | ||
420 | const char *path; | ||
421 | int status = LUA_ERRFILE; /* not found (yet) */ | ||
422 | luaL_check_string(L, 1); | ||
423 | lua_settop(L, 1); | ||
424 | lua_pushvalue(L, 1); | ||
425 | lua_setglobal(L, "_REQUIREDNAME"); | ||
426 | lua_getglobal(L, REQTAB); | ||
427 | if (!lua_istable(L, 2)) lua_error(L, REQTAB " is not a table"); | ||
428 | path = getpath(L); | ||
429 | lua_pushvalue(L, 1); /* check package's name in book-keeping table */ | ||
430 | lua_gettable(L, 2); | ||
431 | if (!lua_isnil(L, -1)) /* is it there? */ | ||
432 | return 0; /* package is already loaded */ | ||
433 | else { /* must load it */ | ||
434 | while (status == LUA_ERRFILE && (path = nextpath(L, path)) != NULL) { | ||
435 | composename(L); | ||
436 | status = lua_dofile(L, lua_tostring(L, -1)); /* try to load it */ | ||
437 | lua_settop(L, 3); /* pop string and eventual results from dofile */ | ||
438 | } | ||
439 | } | ||
440 | switch (status) { | ||
441 | case 0: { | ||
442 | lua_pushvalue(L, 1); | ||
443 | lua_pushboolean(L, 1); | ||
444 | lua_settable(L, 2); /* mark it as loaded */ | ||
445 | return 0; | ||
446 | } | ||
447 | case LUA_ERRFILE: { /* file not found */ | ||
448 | luaL_verror(L, "could not load package `%.20s' from path `%.200s'", | ||
449 | lua_tostring(L, 1), lua_tostring(L, 3)); | ||
450 | } | ||
451 | default: { /* error loading package */ | ||
452 | lua_error(L, NULL); | ||
453 | return 0; /* to avoid warnings */ | ||
454 | } | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* }====================================================== */ | ||
459 | |||
460 | |||
398 | static const luaL_reg base_funcs[] = { | 461 | static const luaL_reg base_funcs[] = { |
399 | {LUA_ALERT, luaB__ALERT}, | 462 | {LUA_ALERT, luaB__ALERT}, |
400 | {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, | 463 | {LUA_ERRORMESSAGE, luaB__ERRORMESSAGE}, |
@@ -402,6 +465,7 @@ static const luaL_reg base_funcs[] = { | |||
402 | {"metatable", luaB_metatable}, | 465 | {"metatable", luaB_metatable}, |
403 | {"globals", luaB_globals}, | 466 | {"globals", luaB_globals}, |
404 | {"next", luaB_next}, | 467 | {"next", luaB_next}, |
468 | {"nexti", luaB_nexti}, | ||
405 | {"print", luaB_print}, | 469 | {"print", luaB_print}, |
406 | {"tonumber", luaB_tonumber}, | 470 | {"tonumber", luaB_tonumber}, |
407 | {"tostring", luaB_tostring}, | 471 | {"tostring", luaB_tostring}, |
@@ -417,6 +481,7 @@ static const luaL_reg base_funcs[] = { | |||
417 | {"loadstring", luaB_loadstring}, | 481 | {"loadstring", luaB_loadstring}, |
418 | {"dofile", luaB_dofile}, | 482 | {"dofile", luaB_dofile}, |
419 | {"dostring", luaB_dostring}, | 483 | {"dostring", luaB_dostring}, |
484 | {"require", luaB_require}, | ||
420 | {NULL, NULL} | 485 | {NULL, NULL} |
421 | }; | 486 | }; |
422 | 487 | ||
@@ -511,10 +576,8 @@ static void base_open (lua_State *L) { | |||
511 | LUALIB_API int lua_baselibopen (lua_State *L) { | 576 | LUALIB_API int lua_baselibopen (lua_State *L) { |
512 | base_open(L); | 577 | base_open(L); |
513 | co_open(L); | 578 | co_open(L); |
514 | /* `require' needs an empty table as upvalue */ | ||
515 | lua_newtable(L); | 579 | lua_newtable(L); |
516 | lua_pushcclosure(L, luaB_require, 1); | 580 | lua_setglobal(L, REQTAB); |
517 | lua_setglobal(L, "require"); | ||
518 | return 0; | 581 | return 0; |
519 | } | 582 | } |
520 | 583 | ||