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 |