diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-08-01 01:21:17 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2005-08-01 01:21:17 -0300 |
commit | e82bdb24f3727fbecb3d0596c1a8abc0af4cc687 (patch) | |
tree | a4b4c81eb6a8da06bcd418643b6aafa565db4884 | |
parent | 1a343814d8da9f9c2067d6ca3d82d57c84f91f10 (diff) | |
download | lua-e82bdb24f3727fbecb3d0596c1a8abc0af4cc687.tar.gz lua-e82bdb24f3727fbecb3d0596c1a8abc0af4cc687.tar.bz2 lua-e82bdb24f3727fbecb3d0596c1a8abc0af4cc687.zip |
new loader for "all-in-one" C packages
-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) { |