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 | |
| parent | 62dd4cbe91617741a9f8e594201ad510d073b12d (diff) | |
| download | lua-391c5459cbfb2a01a66b318f42cf780d952704b7.tar.gz lua-391c5459cbfb2a01a66b318f42cf780d952704b7.tar.bz2 lua-391c5459cbfb2a01a66b318f42cf780d952704b7.zip | |
new implementation for `require' (with templates)
| -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 | ||
