diff options
| author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-04 17:11:58 -0300 |
|---|---|---|
| committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2024-07-04 17:11:58 -0300 |
| commit | 366c85564874d560b3608349f752e9e490f9002d (patch) | |
| tree | 77426f1c700cf4c7aa15b0742cf6669c9166af7a | |
| parent | 781219dbe16fc327f5b828e1ff6fa45ec3265cba (diff) | |
| download | lua-366c85564874d560b3608349f752e9e490f9002d.tar.gz lua-366c85564874d560b3608349f752e9e490f9002d.tar.bz2 lua-366c85564874d560b3608349f752e9e490f9002d.zip | |
lua.c loads 'readline' dynamically
(See comments in luaconf.h.) This change allows easier compilation,
as Lua compiles and works even if the package 'readline' is absent
from the system. Moreover, non-interactive uses don't load the library,
making the stand-alone slightly faster for small loads.
| -rw-r--r-- | lua.c | 88 | ||||
| -rw-r--r-- | luaconf.h | 11 | ||||
| -rw-r--r-- | makefile | 4 | ||||
| -rw-r--r-- | testes/main.lua | 16 |
4 files changed, 90 insertions, 29 deletions
| @@ -437,27 +437,80 @@ static int handle_luainit (lua_State *L) { | |||
| 437 | ** lua_saveline defines how to "save" a read line in a "history". | 437 | ** lua_saveline defines how to "save" a read line in a "history". |
| 438 | ** lua_freeline defines how to free a line read by lua_readline. | 438 | ** lua_freeline defines how to free a line read by lua_readline. |
| 439 | */ | 439 | */ |
| 440 | #if !defined(lua_readline) /* { */ | ||
| 441 | 440 | ||
| 442 | #if defined(LUA_USE_READLINE) /* { */ | 441 | #if defined(LUA_USE_READLINE) |
| 443 | 442 | ||
| 444 | #include <readline/readline.h> | 443 | #include <readline/readline.h> |
| 445 | #include <readline/history.h> | 444 | #include <readline/history.h> |
| 446 | #define lua_initreadline(L) ((void)L, rl_readline_name="lua") | 445 | #define lua_initreadline(L) ((void)L, rl_readline_name="lua") |
| 447 | #define lua_readline(L,b,p) ((void)L, ((b)=readline(p)) != NULL) | 446 | #define lua_readline(b,p) ((void)b, readline(p)) |
| 448 | #define lua_saveline(L,line) ((void)L, add_history(line)) | 447 | #define lua_saveline(line) add_history(line) |
| 449 | #define lua_freeline(L,b) ((void)L, free(b)) | 448 | #define lua_freeline(b) free(b) |
| 449 | |||
| 450 | #endif | ||
| 451 | |||
| 452 | |||
| 453 | #if !defined(lua_readline) /* { */ | ||
| 454 | |||
| 455 | /* pointer to dynamically loaded 'readline' function (if any) */ | ||
| 456 | typedef char *(*l_readline_t) (const char *prompt); | ||
| 457 | static l_readline_t l_readline = NULL; | ||
| 458 | |||
| 459 | static char *lua_readline (char *buff, const char *prompt) { | ||
| 460 | if (l_readline != NULL) /* is there a dynamic 'readline'? */ | ||
| 461 | return (*l_readline)(prompt); /* use it */ | ||
| 462 | else { /* emulate 'readline' over 'buff' */ | ||
| 463 | fputs(prompt, stdout); | ||
| 464 | fflush(stdout); /* show prompt */ | ||
| 465 | return fgets(buff, LUA_MAXINPUT, stdin); /* read line */ | ||
| 466 | } | ||
| 467 | } | ||
| 468 | |||
| 469 | |||
| 470 | /* pointer to dynamically loaded 'add_history' function (if any) */ | ||
| 471 | typedef void (*l_addhist_t) (const char *string); | ||
| 472 | static l_addhist_t l_addhist = NULL; | ||
| 473 | |||
| 474 | static void lua_saveline (const char *line) { | ||
| 475 | if (l_addhist != NULL) /* is there a dynamic 'add_history'? */ | ||
| 476 | (*l_addhist)(line); /* use it */ | ||
| 477 | /* else nothing to be done */ | ||
| 478 | } | ||
| 450 | 479 | ||
| 451 | #else /* }{ */ | 480 | |
| 481 | static void lua_freeline (char *line) { | ||
| 482 | if (l_readline != NULL) /* is there a dynamic 'readline'? */ | ||
| 483 | free(line); /* free line created by it */ | ||
| 484 | /* else 'lua_readline' used an automatic buffer; nothing to free */ | ||
| 485 | } | ||
| 486 | |||
| 487 | |||
| 488 | #if !defined(LUA_USE_DLOPEN) || !defined(LUA_READLINELIB) | ||
| 452 | 489 | ||
| 453 | #define lua_initreadline(L) ((void)L) | 490 | #define lua_initreadline(L) ((void)L) |
| 454 | #define lua_readline(L,b,p) \ | ||
| 455 | ((void)L, fputs(p, stdout), fflush(stdout), /* show prompt */ \ | ||
| 456 | fgets(b, LUA_MAXINPUT, stdin) != NULL) /* get line */ | ||
| 457 | #define lua_saveline(L,line) { (void)L; (void)line; } | ||
| 458 | #define lua_freeline(L,b) { (void)L; (void)b; } | ||
| 459 | 491 | ||
| 460 | #endif /* } */ | 492 | #else /* { */ |
| 493 | |||
| 494 | #include <dlfcn.h> | ||
| 495 | |||
| 496 | |||
| 497 | static void lua_initreadline (lua_State *L) { | ||
| 498 | void *lib = dlopen(LUA_READLINELIB, RTLD_NOW | RTLD_LOCAL); | ||
| 499 | if (lib == NULL) | ||
| 500 | lua_warning(L, "library '" LUA_READLINELIB "'not found", 0); | ||
| 501 | else { | ||
| 502 | const char **name = cast(const char**, dlsym(lib, "rl_readline_name")); | ||
| 503 | if (name != NULL) | ||
| 504 | *name = "Lua"; | ||
| 505 | l_readline = cast(l_readline_t, cast_func(dlsym(lib, "readline"))); | ||
| 506 | if (l_readline == NULL) | ||
| 507 | lua_warning(L, "unable to load 'readline'", 0); | ||
| 508 | else | ||
| 509 | l_addhist = cast(l_addhist_t, cast_func(dlsym(lib, "add_history"))); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | #endif /* } */ | ||
| 461 | 514 | ||
| 462 | #endif /* } */ | 515 | #endif /* } */ |
| 463 | 516 | ||
| @@ -505,11 +558,10 @@ static int incomplete (lua_State *L, int status) { | |||
| 505 | */ | 558 | */ |
| 506 | static int pushline (lua_State *L, int firstline) { | 559 | static int pushline (lua_State *L, int firstline) { |
| 507 | char buffer[LUA_MAXINPUT]; | 560 | char buffer[LUA_MAXINPUT]; |
| 508 | char *b = buffer; | ||
| 509 | size_t l; | 561 | size_t l; |
| 510 | const char *prmt = get_prompt(L, firstline); | 562 | const char *prmt = get_prompt(L, firstline); |
| 511 | int readstatus = lua_readline(L, b, prmt); | 563 | char *b = lua_readline(buffer, prmt); |
| 512 | if (readstatus == 0) | 564 | if (b == NULL) |
| 513 | return 0; /* no input (prompt will be popped by caller) */ | 565 | return 0; /* no input (prompt will be popped by caller) */ |
| 514 | lua_pop(L, 1); /* remove prompt */ | 566 | lua_pop(L, 1); /* remove prompt */ |
| 515 | l = strlen(b); | 567 | l = strlen(b); |
| @@ -519,7 +571,7 @@ static int pushline (lua_State *L, int firstline) { | |||
| 519 | lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ | 571 | lua_pushfstring(L, "return %s", b + 1); /* change '=' to 'return' */ |
| 520 | else | 572 | else |
| 521 | lua_pushlstring(L, b, l); | 573 | lua_pushlstring(L, b, l); |
| 522 | lua_freeline(L, b); | 574 | lua_freeline(b); |
| 523 | return 1; | 575 | return 1; |
| 524 | } | 576 | } |
| 525 | 577 | ||
| @@ -535,7 +587,7 @@ static int addreturn (lua_State *L) { | |||
| 535 | if (status == LUA_OK) { | 587 | if (status == LUA_OK) { |
| 536 | lua_remove(L, -2); /* remove modified line */ | 588 | lua_remove(L, -2); /* remove modified line */ |
| 537 | if (line[0] != '\0') /* non empty? */ | 589 | if (line[0] != '\0') /* non empty? */ |
| 538 | lua_saveline(L, line); /* keep history */ | 590 | lua_saveline(line); /* keep history */ |
| 539 | } | 591 | } |
| 540 | else | 592 | else |
| 541 | lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ | 593 | lua_pop(L, 2); /* pop result from 'luaL_loadbuffer' and modified line */ |
| @@ -552,7 +604,7 @@ static int multiline (lua_State *L) { | |||
| 552 | const char *line = lua_tolstring(L, 1, &len); /* get what it has */ | 604 | const char *line = lua_tolstring(L, 1, &len); /* get what it has */ |
| 553 | int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ | 605 | int status = luaL_loadbuffer(L, line, len, "=stdin"); /* try it */ |
| 554 | if (!incomplete(L, status) || !pushline(L, 0)) { | 606 | if (!incomplete(L, status) || !pushline(L, 0)) { |
| 555 | lua_saveline(L, line); /* keep history */ | 607 | lua_saveline(line); /* keep history */ |
| 556 | return status; /* cannot or should not try to add continuation line */ | 608 | return status; /* cannot or should not try to add continuation line */ |
| 557 | } | 609 | } |
| 558 | lua_pushliteral(L, "\n"); /* add newline... */ | 610 | lua_pushliteral(L, "\n"); /* add newline... */ |
| @@ -58,15 +58,26 @@ | |||
| 58 | #endif | 58 | #endif |
| 59 | 59 | ||
| 60 | 60 | ||
| 61 | /* | ||
| 62 | ** When Posix DLL ('LUA_USE_DLOPEN') is enabled, the Lua stand-alone | ||
| 63 | ** application will try to dynamically link a 'readline' facility | ||
| 64 | ** for its REPL. In that case, LUA_READLINELIB is the name of the | ||
| 65 | ** library it will look for those facilities. If lua.c cannot open | ||
| 66 | ** the specified library, it will generate a warning and then run | ||
| 67 | ** without 'readline'. If that macro is not defined, lua.c will not | ||
| 68 | ** use 'readline'. | ||
| 69 | */ | ||
| 61 | #if defined(LUA_USE_LINUX) | 70 | #if defined(LUA_USE_LINUX) |
| 62 | #define LUA_USE_POSIX | 71 | #define LUA_USE_POSIX |
| 63 | #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ | 72 | #define LUA_USE_DLOPEN /* needs an extra library: -ldl */ |
| 73 | #define LUA_READLINELIB "libreadline.so" | ||
| 64 | #endif | 74 | #endif |
| 65 | 75 | ||
| 66 | 76 | ||
| 67 | #if defined(LUA_USE_MACOSX) | 77 | #if defined(LUA_USE_MACOSX) |
| 68 | #define LUA_USE_POSIX | 78 | #define LUA_USE_POSIX |
| 69 | #define LUA_USE_DLOPEN /* MacOS does not need -ldl */ | 79 | #define LUA_USE_DLOPEN /* MacOS does not need -ldl */ |
| 80 | #define LUA_READLINELIB "libedit.dylib" | ||
| 70 | #endif | 81 | #endif |
| 71 | 82 | ||
| 72 | 83 | ||
| @@ -70,9 +70,9 @@ LOCAL = $(TESTS) $(CWARNS) | |||
| 70 | 70 | ||
| 71 | 71 | ||
| 72 | # enable Linux goodies | 72 | # enable Linux goodies |
| 73 | MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE | 73 | MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX |
| 74 | MYLDFLAGS= $(LOCAL) -Wl,-E | 74 | MYLDFLAGS= $(LOCAL) -Wl,-E |
| 75 | MYLIBS= -ldl -lreadline | 75 | MYLIBS= -ldl |
| 76 | 76 | ||
| 77 | 77 | ||
| 78 | CC= gcc | 78 | CC= gcc |
diff --git a/testes/main.lua b/testes/main.lua index 5c7d0a10..9a86fb5a 100644 --- a/testes/main.lua +++ b/testes/main.lua | |||
| @@ -368,20 +368,18 @@ assert(string.find(t, prompt .. ".*" .. prompt .. ".*" .. prompt)) | |||
| 368 | 368 | ||
| 369 | 369 | ||
| 370 | -- non-string prompt | 370 | -- non-string prompt |
| 371 | prompt = | 371 | prompt = [[ |
| 372 | "local C = 0;\z | 372 | local C = 'X'; |
| 373 | _PROMPT=setmetatable({},{__tostring = function () \z | 373 | _PROMPT=setmetatable({},{__tostring = function () |
| 374 | C = C + 1; return C end})" | 374 | C = C .. 'X'; return C end}) |
| 375 | ]] | ||
| 375 | prepfile[[ -- | 376 | prepfile[[ -- |
| 376 | a = 2 | 377 | a = 2 |
| 377 | ]] | 378 | ]] |
| 378 | RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out) | 379 | RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out) |
| 379 | local t = getoutput() | 380 | local t = getoutput() |
| 380 | assert(string.find(t, [[ | 381 | -- skip version line and then check the presence of the three prompts |
| 381 | 1 -- | 382 | assert(string.find(t, "^.-\nXX[^\nX]*\n?XXX[^\nX]*\n?XXXX\n?$")) |
| 382 | 2a = 2 | ||
| 383 | 3 | ||
| 384 | ]], 1, true)) | ||
| 385 | 383 | ||
| 386 | 384 | ||
| 387 | -- test for error objects | 385 | -- test for error objects |
