aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-07-04 17:11:58 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2024-07-04 17:11:58 -0300
commit366c85564874d560b3608349f752e9e490f9002d (patch)
tree77426f1c700cf4c7aa15b0742cf6669c9166af7a
parent781219dbe16fc327f5b828e1ff6fa45ec3265cba (diff)
downloadlua-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.c88
-rw-r--r--luaconf.h11
-rw-r--r--makefile4
-rw-r--r--testes/main.lua16
4 files changed, 90 insertions, 29 deletions
diff --git a/lua.c b/lua.c
index 88fb8793..51979a8b 100644
--- a/lua.c
+++ b/lua.c
@@ -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) */
456typedef char *(*l_readline_t) (const char *prompt);
457static l_readline_t l_readline = NULL;
458
459static 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) */
471typedef void (*l_addhist_t) (const char *string);
472static l_addhist_t l_addhist = NULL;
473
474static 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
481static 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
497static 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*/
506static int pushline (lua_State *L, int firstline) { 559static 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... */
diff --git a/luaconf.h b/luaconf.h
index fe98d9a9..65715c8b 100644
--- a/luaconf.h
+++ b/luaconf.h
@@ -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
diff --git a/makefile b/makefile
index 74801eef..58b12f8e 100644
--- a/makefile
+++ b/makefile
@@ -70,9 +70,9 @@ LOCAL = $(TESTS) $(CWARNS)
70 70
71 71
72# enable Linux goodies 72# enable Linux goodies
73MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX -DLUA_USE_READLINE 73MYCFLAGS= $(LOCAL) -std=c99 -DLUA_USE_LINUX
74MYLDFLAGS= $(LOCAL) -Wl,-E 74MYLDFLAGS= $(LOCAL) -Wl,-E
75MYLIBS= -ldl -lreadline 75MYLIBS= -ldl
76 76
77 77
78CC= gcc 78CC= 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
371prompt = 371prompt = [[
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]]
375prepfile[[ -- 376prepfile[[ --
376a = 2 377a = 2
377]] 378]]
378RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out) 379RUN([[lua -e "%s" -i < %s > %s]], prompt, prog, out)
379local t = getoutput() 380local t = getoutput()
380assert(string.find(t, [[ 381-- skip version line and then check the presence of the three prompts
3811 -- 382assert(string.find(t, "^.-\nXX[^\nX]*\n?XXX[^\nX]*\n?XXXX\n?$"))
3822a = 2
3833
384]], 1, true))
385 383
386 384
387-- test for error objects 385-- test for error objects