diff options
| -rw-r--r-- | loadlib.c | 154 |
1 files changed, 89 insertions, 65 deletions
| @@ -1,5 +1,5 @@ | |||
| 1 | /* | 1 | /* |
| 2 | ** $Id: loadlib.c,v 1.33 2005/07/12 21:17:46 roberto Exp roberto $ | 2 | ** $Id: loadlib.c,v 1.34 2005/07/13 19:02:42 roberto Exp roberto $ |
| 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 | ** |
| @@ -38,6 +38,10 @@ | |||
| 38 | #define LIB_FAIL "open" | 38 | #define LIB_FAIL "open" |
| 39 | 39 | ||
| 40 | 40 | ||
| 41 | /* error codes for ll_loadfunc */ | ||
| 42 | #define ERRLIB 1 | ||
| 43 | #define ERRFUNC 2 | ||
| 44 | |||
| 41 | #define setprogdir(L) ((void)0) | 45 | #define setprogdir(L) ((void)0) |
| 42 | 46 | ||
| 43 | 47 | ||
| @@ -294,43 +298,45 @@ static int gctm (lua_State *L) { | |||
| 294 | 298 | ||
| 295 | 299 | ||
| 296 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { | 300 | static int ll_loadfunc (lua_State *L, const char *path, const char *sym) { |
| 297 | const char *reason; | ||
| 298 | void **reg = ll_register(L, path); | 301 | void **reg = ll_register(L, path); |
| 299 | if (*reg == NULL) *reg = ll_load(L, path); | 302 | if (*reg == NULL) *reg = ll_load(L, path); |
| 300 | if (*reg == NULL) | 303 | if (*reg == NULL) |
| 301 | reason = LIB_FAIL; | 304 | return ERRLIB; /* unable to load library */ |
| 302 | else { | 305 | else { |
| 303 | lua_CFunction f = ll_sym(L, *reg, sym); | 306 | lua_CFunction f = ll_sym(L, *reg, sym); |
| 304 | if (f) { | 307 | if (f == NULL) |
| 305 | lua_pushcfunction(L, f); | 308 | return ERRFUNC; /* unable to find function */ |
| 306 | return 1; /* return function */ | 309 | lua_pushcfunction(L, f); |
| 307 | } | 310 | return 0; /* return function */ |
| 308 | reason = "init"; | ||
| 309 | } | 311 | } |
| 310 | lua_pushnil(L); | ||
| 311 | lua_insert(L, -2); | ||
| 312 | lua_pushstring(L, reason); | ||
| 313 | return 3; /* return nil, ll_error, reason */ | ||
| 314 | } | 312 | } |
| 315 | 313 | ||
| 316 | 314 | ||
| 317 | static int ll_loadlib (lua_State *L) { | 315 | static int ll_loadlib (lua_State *L) { |
| 318 | const char *path = luaL_checkstring(L, 1); | 316 | const char *path = luaL_checkstring(L, 1); |
| 319 | const char *init = luaL_checkstring(L, 2); | 317 | const char *init = luaL_checkstring(L, 2); |
| 320 | return ll_loadfunc(L, path, init); | 318 | int stat = ll_loadfunc(L, path, init); |
| 319 | if (stat == 0) /* no errors? */ | ||
| 320 | return 1; /* return the loaded function */ | ||
| 321 | else { /* error; error message is on stack top */ | ||
| 322 | lua_pushnil(L); | ||
| 323 | lua_insert(L, -2); | ||
| 324 | lua_pushstring(L, (stat == ERRLIB) ? LIB_FAIL : "init"); | ||
| 325 | return 3; /* return nil, error message, and where */ | ||
| 326 | } | ||
| 321 | } | 327 | } |
| 322 | 328 | ||
| 323 | 329 | ||
| 324 | 330 | ||
| 325 | /* | 331 | /* |
| 326 | ** {====================================================== | 332 | ** {====================================================== |
| 327 | ** `require' and `module' functions | 333 | ** 'require' function |
| 328 | ** ======================================================= | 334 | ** ======================================================= |
| 329 | */ | 335 | */ |
| 330 | 336 | ||
| 331 | 337 | ||
| 332 | static int readable (const char *fname) { | 338 | static int readable (const char *filename) { |
| 333 | FILE *f = fopen(fname, "r"); /* try to open file */ | 339 | FILE *f = fopen(filename, "r"); /* try to open file */ |
| 334 | if (f == NULL) return 0; /* open failed */ | 340 | if (f == NULL) return 0; /* open failed */ |
| 335 | fclose(f); | 341 | fclose(f); |
| 336 | return 1; | 342 | return 1; |
| @@ -348,53 +354,85 @@ static const char *pushnexttemplate (lua_State *L, const char *path) { | |||
| 348 | } | 354 | } |
| 349 | 355 | ||
| 350 | 356 | ||
| 351 | static const char *findfile (lua_State *L, const char *pname) { | 357 | static const char *findfile (lua_State *L, const char *name, |
| 358 | const char *pname) { | ||
| 352 | const char *path; | 359 | const char *path; |
| 353 | const char *name = luaL_checkstring(L, 1); | ||
| 354 | name = luaL_gsub(L, name, ".", LUA_DIRSEP); | 360 | name = luaL_gsub(L, name, ".", LUA_DIRSEP); |
| 355 | lua_getfield(L, LUA_ENVIRONINDEX, pname); | 361 | lua_getfield(L, LUA_ENVIRONINDEX, pname); |
| 356 | path = lua_tostring(L, -1); | 362 | path = lua_tostring(L, -1); |
| 357 | if (path == NULL) | 363 | if (path == NULL) |
| 358 | luaL_error(L, LUA_QL("package.%s") " must be a string", pname); | 364 | luaL_error(L, LUA_QL("package.%s") " must be a string", pname); |
| 359 | while ((path = pushnexttemplate(L, path)) != NULL) { | 365 | while ((path = pushnexttemplate(L, path)) != NULL) { |
| 360 | const char *fname; | 366 | const char *filename; |
| 361 | fname = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); | 367 | filename = luaL_gsub(L, lua_tostring(L, -1), LUA_PATH_MARK, name); |
| 362 | if (readable(fname)) /* does file exist and is readable? */ | 368 | if (readable(filename)) /* does file exist and is readable? */ |
| 363 | return fname; /* return that file name */ | 369 | return filename; /* return that file name */ |
| 364 | lua_pop(L, 2); /* remove path template and file name */ | 370 | lua_pop(L, 2); /* remove path template and file name */ |
| 365 | } | 371 | } |
| 366 | return NULL; /* not found */ | 372 | return NULL; /* not found */ |
| 367 | } | 373 | } |
| 368 | 374 | ||
| 369 | 375 | ||
| 370 | static void loaderror (lua_State *L, const char *msg) { | 376 | static void loaderror (lua_State *L) { |
| 371 | luaL_error(L, "error loading package " LUA_QS " (%s)", | 377 | luaL_error(L, "error loading package " LUA_QS " (%s)", |
| 372 | lua_tostring(L, 1), msg); | 378 | lua_tostring(L, 1), lua_tostring(L, -1)); |
| 373 | } | 379 | } |
| 374 | 380 | ||
| 375 | 381 | ||
| 376 | static int loader_Lua (lua_State *L) { | 382 | static int loader_Lua (lua_State *L) { |
| 377 | const char *fname; | 383 | const char *filename; |
| 378 | fname = findfile(L, "path"); | 384 | const char *name = luaL_checkstring(L, 1); |
| 379 | if (fname == NULL) return 0; /* library not found in this path */ | 385 | filename = findfile(L, name, "path"); |
| 380 | if (luaL_loadfile(L, fname) != 0) | 386 | if (filename == NULL) return 0; /* library not found in this path */ |
| 381 | loaderror(L, lua_tostring(L, -1)); | 387 | if (luaL_loadfile(L, filename) != 0) |
| 388 | loaderror(L); | ||
| 382 | return 1; /* library loaded successfully */ | 389 | return 1; /* library loaded successfully */ |
| 383 | } | 390 | } |
| 384 | 391 | ||
| 385 | 392 | ||
| 386 | static int loader_C (lua_State *L) { | 393 | static const char *mkfuncname (lua_State *L, const char *modname) { |
| 387 | const char *funcname; | 394 | const char *funcname; |
| 388 | const char *fname = findfile(L, "cpath"); | 395 | const char *mark = strchr(modname, *LUA_IGMARK); |
| 389 | if (fname == NULL) return 0; /* library not found in this path */ | 396 | if (mark) modname = mark + 1; |
| 390 | funcname = luaL_gsub(L, lua_tostring(L, 1), ".", LUA_OFSEP); | 397 | funcname = luaL_gsub(L, modname, ".", LUA_OFSEP); |
| 391 | funcname = lua_pushfstring(L, POF"%s", funcname); | 398 | funcname = lua_pushfstring(L, POF"%s", funcname); |
| 392 | if (ll_loadfunc(L, fname, funcname) != 1) | 399 | lua_remove(L, -2); /* remove 'gsub' result */ |
| 393 | loaderror(L, lua_tostring(L, -2)); | 400 | return funcname; |
| 401 | } | ||
| 402 | |||
| 403 | |||
| 404 | static int loader_C (lua_State *L) { | ||
| 405 | const char *funcname; | ||
| 406 | const char *name = luaL_checkstring(L, 1); | ||
| 407 | const char *filename = findfile(L, name, "cpath"); | ||
| 408 | if (filename == NULL) return 0; /* library not found in this path */ | ||
| 409 | funcname = mkfuncname(L, name); | ||
| 410 | if (ll_loadfunc(L, filename, funcname) != 0) | ||
| 411 | loaderror(L); | ||
| 394 | return 1; /* library loaded successfully */ | 412 | return 1; /* library loaded successfully */ |
| 395 | } | 413 | } |
| 396 | 414 | ||
| 397 | 415 | ||
| 416 | static int loader_Croot (lua_State *L) { | ||
| 417 | const char *funcname; | ||
| 418 | const char *filename; | ||
| 419 | const char *name = luaL_checkstring(L, 1); | ||
| 420 | const char *p = strchr(name, '.'); | ||
| 421 | int stat; | ||
| 422 | if (p == NULL) return 0; /* is root */ | ||
| 423 | lua_pushlstring(L, name, p - name); | ||
| 424 | filename = findfile(L, lua_tostring(L, -1), "cpath"); | ||
| 425 | if (filename == NULL) return 0; /* root not found */ | ||
| 426 | funcname = mkfuncname(L, name); | ||
| 427 | if ((stat = ll_loadfunc(L, filename, funcname)) != 0) { | ||
| 428 | if (stat == ERRFUNC) return 0; /* function not found */ | ||
| 429 | else | ||
| 430 | loaderror(L); /* real error */ | ||
| 431 | } | ||
| 432 | return 1; | ||
| 433 | } | ||
| 434 | |||
| 435 | |||
| 398 | static int loader_preload (lua_State *L) { | 436 | static int loader_preload (lua_State *L) { |
| 399 | lua_getfield(L, LUA_ENVIRONINDEX, "preload"); | 437 | lua_getfield(L, LUA_ENVIRONINDEX, "preload"); |
| 400 | if (!lua_istable(L, -1)) | 438 | if (!lua_istable(L, -1)) |
| @@ -440,36 +478,22 @@ static int require_aux (lua_State *L, const char *name) { | |||
| 440 | } | 478 | } |
| 441 | 479 | ||
| 442 | 480 | ||
| 443 | static void require_check (lua_State *L, const char *name) { | ||
| 444 | if (!require_aux(L, name)) { /* error? */ | ||
| 445 | /* build and show error message */ | ||
| 446 | const char *msg; | ||
| 447 | lua_settop(L, 1); | ||
| 448 | lua_getfield(L, LUA_ENVIRONINDEX, "path"); | ||
| 449 | lua_getfield(L, LUA_ENVIRONINDEX, "cpath"); | ||
| 450 | msg = lua_pushfstring(L, | ||
| 451 | "package " LUA_QS " not found in following paths:\n" | ||
| 452 | " Lua path: %s\n" | ||
| 453 | " C path: %s\n", name, | ||
| 454 | lua_tostring(L, -2), lua_tostring(L, -1)); | ||
| 455 | msg = luaL_gsub(L, msg, LUA_PATHSEP, "\n "); | ||
| 456 | luaL_error(L, msg); | ||
| 457 | } | ||
| 458 | } | ||
| 459 | |||
| 460 | |||
| 461 | static int ll_require (lua_State *L) { | 481 | static int ll_require (lua_State *L) { |
| 462 | const char *name = luaL_checkstring(L, 1); | 482 | const char *name = luaL_checkstring(L, 1); |
| 463 | const char *pt; | 483 | if (!require_aux(L, name)) /* error? */ |
| 464 | /* load all parent modules */ | 484 | luaL_error(L, "package " LUA_QS " not found", name); |
| 465 | for (pt = name; (pt = strchr(pt, '.')) != NULL; pt++) { | ||
| 466 | lua_settop(L, 1); | ||
| 467 | lua_pushlstring(L, name, pt - name); | ||
| 468 | require_aux(L, lua_tostring(L, -1)); | ||
| 469 | } | ||
| 470 | require_check(L, name); /* load module itself */ | ||
| 471 | return 1; | 485 | return 1; |
| 472 | } | 486 | } |
| 487 | |||
| 488 | /* }====================================================== */ | ||
| 489 | |||
| 490 | |||
| 491 | |||
| 492 | /* | ||
| 493 | ** {====================================================== | ||
| 494 | ** 'module' function | ||
| 495 | ** ======================================================= | ||
| 496 | */ | ||
| 473 | 497 | ||
| 474 | 498 | ||
| 475 | static void setfenv (lua_State *L) { | 499 | static void setfenv (lua_State *L) { |
| @@ -524,14 +548,14 @@ static int ll_module (lua_State *L) { | |||
| 524 | return 0; | 548 | return 0; |
| 525 | } | 549 | } |
| 526 | 550 | ||
| 527 | |||
| 528 | /* }====================================================== */ | 551 | /* }====================================================== */ |
| 529 | 552 | ||
| 530 | 553 | ||
| 554 | |||
| 531 | /* auxiliary mark (for internal use) */ | 555 | /* auxiliary mark (for internal use) */ |
| 532 | #define AUXMARK "\1" | 556 | #define AUXMARK "\1" |
| 533 | 557 | ||
| 534 | static void setpath (lua_State *L, const char *fname, const char *envname, | 558 | static void setpath (lua_State *L, const char *fieldname, const char *envname, |
| 535 | const char *def) { | 559 | const char *def) { |
| 536 | const char *path = getenv(envname); | 560 | const char *path = getenv(envname); |
| 537 | if (path == NULL) /* no environment variable? */ | 561 | if (path == NULL) /* no environment variable? */ |
| @@ -544,7 +568,7 @@ static void setpath (lua_State *L, const char *fname, const char *envname, | |||
| 544 | lua_remove(L, -2); | 568 | lua_remove(L, -2); |
| 545 | } | 569 | } |
| 546 | setprogdir(L); | 570 | setprogdir(L); |
| 547 | lua_setfield(L, -2, fname); | 571 | lua_setfield(L, -2, fieldname); |
| 548 | } | 572 | } |
| 549 | 573 | ||
| 550 | 574 | ||
| @@ -556,7 +580,7 @@ static const luaL_reg ll_funcs[] = { | |||
| 556 | 580 | ||
| 557 | 581 | ||
| 558 | static const lua_CFunction loaders[] = | 582 | static const lua_CFunction loaders[] = |
| 559 | {loader_preload, loader_Lua, loader_C, NULL}; | 583 | {loader_preload, loader_Lua, loader_C, loader_Croot, NULL}; |
| 560 | 584 | ||
| 561 | 585 | ||
| 562 | LUALIB_API int luaopen_loadlib (lua_State *L) { | 586 | LUALIB_API int luaopen_loadlib (lua_State *L) { |
