1 /* Lua interface (scripting engine) */
21 #include "bfu/dialog.h"
22 #include "cache/cache.h"
23 #include "config/home.h"
24 #include "config/kbdbind.h"
25 #include "config/options.h"
26 #include "config/opttypes.h"
27 #include "document/document.h"
28 #include "document/renderer.h"
29 #include "document/view.h"
30 #include "intl/charsets.h"
31 #include "intl/gettext/libintl.h"
32 #include "main/event.h"
33 #include "main/module.h"
34 #include "osdep/osdep.h"
35 #include "osdep/signals.h"
36 #include "protocol/uri.h"
37 #include "scripting/lua/core.h"
38 #include "session/location.h"
39 #include "session/session.h"
40 #include "session/task.h"
41 #include "terminal/terminal.h"
42 #include "util/color.h"
43 #include "util/conv.h"
44 #include "util/file.h"
45 #include "util/memory.h"
46 #include "util/string.h"
47 #include "viewer/dump/dump.h"
48 #include "viewer/text/view.h"
49 #include "viewer/text/vs.h"
51 #define LUA_HOOKS_FILENAME "hooks.lua"
56 static struct session
*lua_ses
;
57 static struct terminal
*errterm
;
58 static sigjmp_buf errjmp
;
61 #define LS lua_State *S
63 static void handle_standard_lua_returns(unsigned char *from
);
64 static void handle_ref(LS
, struct session
*ses
, int func_ref
,
65 unsigned char *from
, int num_args
, int unref
);
69 * Functions exported to the lua_State.
75 unsigned char *msg
= (unsigned char *) lua_tostring(S
, 1);
77 /* Don't crash if a script calls e.g. error(nil) or error(error). */
79 msg
= "(cannot convert the error message to a string)";
88 if (lua_ses
&& have_location(lua_ses
)) {
89 struct view_state
*vs
= &cur_loc(lua_ses
)->vs
;
90 unsigned char *url
= get_uri_string(vs
->uri
, URI_ORIGINAL
);
93 lua_pushstring(S
, url
);
106 struct link
*link
= get_current_session_link(lua_ses
);
109 lua_pushstring(S
, link
->where
);
120 struct document_view
*doc_view
= current_frame(lua_ses
);
122 if (doc_view
&& doc_view
->document
->title
) {
123 unsigned char *clean_title
= stracpy(doc_view
->document
->title
);
126 sanitize_title(clean_title
);
128 lua_pushstring(S
, clean_title
);
129 mem_free(clean_title
);
139 l_current_document(LS
)
141 if (lua_ses
&& lua_ses
->doc_view
&& lua_ses
->doc_view
->document
) {
142 struct cache_entry
*cached
= lua_ses
->doc_view
->document
->cached
;
143 struct fragment
*f
= cached
? cached
->frag
.next
: NULL
;
145 if (f
&& f
->length
) {
146 lua_pushlstring(S
, f
->data
, f
->length
);
155 /* XXX: This function is mostly copied from `dump_to_file'. */
157 l_current_document_formatted(LS
)
159 struct document_view
*doc_view
;
160 struct string buffer
;
161 int width
, old_width
= 0;
163 if (lua_gettop(S
) == 0) width
= -1;
164 else if (!lua_isnumber(S
, 1)) goto lua_error
;
165 else if ((width
= lua_tonumber(S
, 1)) <= 0) goto lua_error
;
167 if (!lua_ses
|| !(doc_view
= current_frame(lua_ses
))) goto lua_error
;
169 old_width
= lua_ses
->tab
->term
->width
;
170 lua_ses
->tab
->term
->width
= width
;
171 render_document_frames(lua_ses
, 0);
174 if (init_string(&buffer
)) {
175 add_document_to_string(&buffer
, doc_view
->document
);
176 lua_pushlstring(S
, buffer
.source
, buffer
.length
);
177 done_string(&buffer
);
181 lua_ses
->tab
->term
->width
= old_width
;
182 render_document_frames(lua_ses
, 0);
195 unsigned char *s
= NULL
;
198 if (!lua_isstring(S
, 1)) goto lua_error
;
200 fp
= popen(lua_tostring(S
, 1), "r");
201 if (!fp
) goto lua_error
;
204 unsigned char buf
[1024];
205 size_t l
= fread(buf
, 1, sizeof(buf
), fp
);
208 unsigned char *news
= mem_realloc(s
, len
+ l
);
210 if (!news
) goto lua_error
;
212 memcpy(s
+ len
, buf
, l
);
221 lua_pushlstring(S
, s
, len
);
234 if (lua_isstring(S
, 1)) {
235 exec_on_terminal(lua_ses
->tab
->term
, (unsigned char *) lua_tostring(S
, 1), "",
237 lua_pushnumber(S
, 0);
248 unsigned char *fn
= tempnam(NULL
, "elinks");
251 lua_pushstring(S
, fn
);
256 alert_lua_error("Error generating temporary file name");
262 * Helper to run Lua functions bound to keystrokes.
265 static enum evhook_status
266 run_lua_func(va_list ap
, void *data
)
268 struct session
*ses
= va_arg(ap
, struct session
*);
269 int func_ref
= (long) data
;
271 if (func_ref
== LUA_NOREF
) {
272 alert_lua_error("key bound to nothing (internal error)");
273 return EVENT_HOOK_STATUS_NEXT
;
276 handle_ref(L
, ses
, func_ref
, "keyboard function", 0, 0);
278 return EVENT_HOOK_STATUS_NEXT
;
281 /* bind_key (keymap, keystroke, function) */
287 unsigned char *err
= NULL
;
288 struct string event_name
= NULL_STRING
;
290 if (!lua_isstring(S
, 1) || !lua_isstring(S
, 2)
291 || !lua_isfunction(S
, 3)) {
292 alert_lua_error("bad arguments to bind_key");
296 if (!init_string(&event_name
)) goto lua_error
;
298 /* ELinks will need to call the Lua function when the user
299 * presses the key. However, ELinks cannot store a pointer
300 * to the function, because the C API of Lua does not provide
301 * one. Instead, ask the "reference system" of Lua to
302 * generate an integer key that ELinks can store.
304 * TODO: If l_bind_key() succeeds, then the function will
305 * never be removed from the reference system again, because
306 * the rest of ELinks does not tell this module if the
307 * keybinding is removed. This is part of bug 810. */
309 ref
= luaL_ref(S
, LUA_REGISTRYINDEX
);
310 add_format_to_string(&event_name
, "lua-run-func %i", ref
);
312 event_id
= bind_key_to_event_name((unsigned char *) lua_tostring(S
, 1),
313 (const unsigned char *) lua_tostring(S
, 2),
314 event_name
.source
, &err
);
315 done_string(&event_name
);
318 event_id
= register_event_hook(event_id
, run_lua_func
, 0,
319 (void *) (long) ref
);
321 if (event_id
== EVENT_NONE
)
322 err
= gettext("Error registering event hook");
326 luaL_unref(S
, LUA_REGISTRYINDEX
, ref
);
327 alert_lua_error2("error in bind_key: ", err
);
331 lua_pushnumber(S
, 1);
340 /* Begin very hackish bit for bookmark editing dialog. */
341 /* XXX: Add history and generalise. */
343 struct lua_dlg_data
{
345 unsigned char cat
[MAX_STR_LEN
];
346 unsigned char name
[MAX_STR_LEN
];
347 unsigned char url
[MAX_STR_LEN
];
352 dialog_run_lua(void *data_
)
354 struct lua_dlg_data
*data
= data_
;
355 lua_State
*s
= data
->state
;
357 lua_pushstring(s
, data
->cat
);
358 lua_pushstring(s
, data
->name
);
359 lua_pushstring(s
, data
->url
);
360 handle_ref(s
, lua_ses
, data
->func_ref
, "post dialog function", 3, 1);
364 l_edit_bookmark_dialog(LS
)
366 /* [gettext_accelerator_context(.l_edit_bookmark_dialog)] */
367 struct terminal
*term
= lua_ses
->tab
->term
;
369 struct lua_dlg_data
*data
;
371 if (!lua_isstring(S
, 1) || !lua_isstring(S
, 2)
372 || !lua_isstring(S
, 3) || !lua_isfunction(S
, 4)) {
373 alert_lua_error("bad arguments to edit_bookmark_dialog");
378 #define L_EDIT_BMK_WIDGETS_COUNT 5
379 dlg
= calloc_dialog(L_EDIT_BMK_WIDGETS_COUNT
, sizeof(*data
));
382 data
= (struct lua_dlg_data
*) get_dialog_offset(dlg
, L_EDIT_BMK_WIDGETS_COUNT
);
384 safe_strncpy(data
->cat
, (unsigned char *) lua_tostring(S
, 1),
386 safe_strncpy(data
->name
, (unsigned char *) lua_tostring(S
, 2),
388 safe_strncpy(data
->url
, (unsigned char *) lua_tostring(S
, 3),
391 data
->func_ref
= luaL_ref(S
, LUA_REGISTRYINDEX
);
393 dlg
->title
= _("Edit bookmark", term
);
394 dlg
->layouter
= generic_dialog_layouter
;
395 dlg
->layout
.maximize_width
= 1;
397 add_dlg_field(dlg
, _("Name", term
), 0, 0, NULL
, MAX_STR_LEN
, data
->cat
, NULL
);
398 add_dlg_field(dlg
, _("Name", term
), 0, 0, NULL
, MAX_STR_LEN
, data
->name
, NULL
);
399 add_dlg_field(dlg
, _("URL", term
), 0, 0, NULL
, MAX_STR_LEN
, data
->url
, NULL
);
401 add_dlg_ok_button(dlg
, _("~OK", term
), B_ENTER
, dialog_run_lua
, data
);
402 add_dlg_button(dlg
, _("~Cancel", term
), B_ESC
, cancel_dialog
, NULL
);
404 add_dlg_end(dlg
, L_EDIT_BMK_WIDGETS_COUNT
);
406 do_dialog(term
, dlg
, getml(dlg
, (void *) NULL
));
408 lua_pushnumber(S
, 1);
412 /* End very hackish bit. */
415 /* Begin hackish bit for half-generalised dialog. */
416 /* XXX: Add history and custom labels. */
418 #define XDIALOG_MAX_FIELDS 5
420 struct lua_xdialog_data
{
424 unsigned char fields
[XDIALOG_MAX_FIELDS
][MAX_STR_LEN
];
428 xdialog_run_lua(void *data_
)
430 struct lua_xdialog_data
*data
= data_
;
431 lua_State
*s
= data
->state
;
434 for (i
= 0; i
< data
->nfields
; i
++) lua_pushstring(s
, data
->fields
[i
]);
435 handle_ref(s
, lua_ses
, data
->func_ref
, "post xdialog function",
442 /* [gettext_accelerator_context(.l_xdialog)] */
443 struct terminal
*term
;
445 struct lua_xdialog_data
*data
;
446 int nargs
, nfields
, nitems
;
449 if (!lua_ses
) return 0;
451 term
= lua_ses
->tab
->term
;
453 nargs
= lua_gettop(S
);
455 nitems
= nfields
+ 2;
457 if ((nfields
< 1) || (nfields
> XDIALOG_MAX_FIELDS
)) goto lua_error
;
458 for (i
= 1; i
< nargs
; i
++) if (!lua_isstring(S
, i
)) goto lua_error
;
459 if (!lua_isfunction(S
, nargs
)) goto lua_error
;
461 dlg
= calloc_dialog(nitems
, sizeof(*data
));
464 data
= (struct lua_xdialog_data
*) get_dialog_offset(dlg
, nitems
);
466 data
->nfields
= nfields
;
467 for (i
= 0; i
< nfields
; i
++)
468 safe_strncpy(data
->fields
[i
],
469 (unsigned char *) lua_tostring(S
, i
+1),
471 lua_pushvalue(S
, nargs
);
472 data
->func_ref
= luaL_ref(S
, LUA_REGISTRYINDEX
);
474 dlg
->title
= _("User dialog", term
);
475 dlg
->layouter
= generic_dialog_layouter
;
476 dlg
->layout
.maximize_width
= 1;
478 for (i
= 0; i
< nfields
; i
++)
479 add_dlg_field(dlg
, _("Name", term
), 0, 0, NULL
, MAX_STR_LEN
,
480 data
->fields
[i
], NULL
);
482 add_dlg_ok_button(dlg
, _("~OK", term
), B_ENTER
, xdialog_run_lua
, data
);
483 add_dlg_button(dlg
, _("~Cancel", term
), B_ESC
, cancel_dialog
, NULL
);
485 add_dlg_end(dlg
, nitems
);
487 do_dialog(term
, dlg
, getml(dlg
, (void *) NULL
));
489 lua_pushnumber(S
, 1);
497 /* End xdialog bit. */
508 nargs
= lua_gettop(S
);
512 /* Get option record */
513 name
= lua_tostring(S
, 1);
514 opt
= get_opt_rec(config_options
, (unsigned char *) name
);
522 /* option_types[OPT_BOOL].set expects a long even though it
523 * saves the value to opt->value.number, which is an int. */
524 long value
= lua_toboolean(S
, 2);
526 option_types
[opt
->type
].set(opt
, (unsigned char *) (&value
));
532 /* option_types[OPT_INT].set expects a long even though it
533 * saves the value to opt->value.number, which is an int.
534 * option_types[OPT_LONG].set of course wants a long too. */
535 long value
= lua_tonumber(S
, 2);
537 option_types
[opt
->type
].set(opt
, (unsigned char *) (&value
));
544 option_types
[opt
->type
].set(opt
, (unsigned char *) lua_tostring(S
, 2));
551 option_changed(lua_ses
, opt
);
566 /* Get option record */
567 nargs
= lua_gettop(S
);
570 name
= lua_tostring(S
, 1);
571 opt
= get_opt_rec(config_options
, (unsigned char *) name
);
575 /* Convert to an appropriate Lua type */
578 lua_pushboolean(S
, opt
->value
.number
);
581 lua_pushnumber(S
, opt
->value
.number
);
584 lua_pushnumber(S
, opt
->value
.big_number
);
587 lua_pushstring(S
, opt
->value
.string
);
591 unsigned char *cp_name
;
593 cp_name
= get_cp_config_name(opt
->value
.number
);
594 lua_pushstring(S
, cp_name
);
602 lang
= language_to_name(current_language
);
606 lua_pushstring(S
, lang
);
612 unsigned char hexcolor
[8];
613 const unsigned char *strcolor
;
615 color
= opt
->value
.color
;
616 strcolor
= get_color_string(color
, hexcolor
);
617 lua_pushstring(S
, strcolor
);
632 /* End of set/get option */
635 eval_function(LS
, int num_args
, int num_results
)
639 err
= lua_pcall(S
, num_args
, num_results
, 0);
641 alert_lua_error((unsigned char *) lua_tostring(L
, -1));
651 do_hooks_file(LS
, unsigned char *prefix
, unsigned char *filename
)
653 unsigned char *file
= straconcat(prefix
, STRING_DIR_SEP
, filename
,
654 (unsigned char *) NULL
);
658 /* Test file existence to avoid Lua error reporting (under version 5.x)
659 * Fixes debian bug #231760 ('dbug 231760' using URI rewrite) */
660 if (file_can_read(file
)) {
661 int oldtop
= lua_gettop(S
);
663 if (luaL_dofile(S
, file
) != 0)
664 sleep(3); /* Let some time to see error messages. */
665 lua_settop(S
, oldtop
);
672 init_lua(struct module
*module
)
678 lua_register(L
, LUA_ALERT
, l_alert
);
679 lua_register(L
, "current_url", l_current_url
);
680 lua_register(L
, "current_link", l_current_link
);
681 lua_register(L
, "current_title", l_current_title
);
682 lua_register(L
, "current_document", l_current_document
);
683 lua_register(L
, "current_document_formatted", l_current_document_formatted
);
684 lua_register(L
, "pipe_read", l_pipe_read
);
685 lua_register(L
, "execute", l_execute
);
686 lua_register(L
, "tmpname", l_tmpname
);
687 lua_register(L
, "bind_key", l_bind_key
);
688 lua_register(L
, "edit_bookmark_dialog", l_edit_bookmark_dialog
);
689 lua_register(L
, "xdialog", l_xdialog
);
690 lua_register(L
, "set_option", l_set_option
);
691 lua_register(L
, "get_option", l_get_option
);
693 lua_pushstring(L
, elinks_home
? elinks_home
694 : (unsigned char *) CONFDIR
);
695 lua_setglobal(L
, "elinks_home");
697 do_hooks_file(L
, CONFDIR
, LUA_HOOKS_FILENAME
);
698 if (elinks_home
) do_hooks_file(L
, elinks_home
, LUA_HOOKS_FILENAME
);
701 static void free_lua_console_history_entries(void);
704 cleanup_lua(struct module
*module
)
706 free_lua_console_history_entries();
710 /* Attempt to handle infinite loops by trapping SIGINT. If we get a
711 * SIGINT, we longjump to where prepare_lua was called. finish_lua()
712 * disables the trapping. */
715 handle_sigint(void *data
)
718 siglongjmp(errjmp
, -1);
722 prepare_lua(struct session
*ses
)
725 errterm
= lua_ses
? lua_ses
->tab
->term
: NULL
;
726 /* XXX this uses the wrong term, I think */
727 install_signal_handler(SIGINT
, (void (*)(void *)) handle_sigint
, NULL
, 1);
729 return sigsetjmp(errjmp
, 1);
735 /* XXX should save previous handler instead of assuming this one */
736 install_signal_handler(SIGINT
, (void (*)(void *)) sig_ctrl_c
, errterm
, 0);
740 /* Error reporting. */
743 alert_lua_error(unsigned char *msg
)
746 info_box(errterm
, MSGBOX_NO_TEXT_INTL
| MSGBOX_FREE_TEXT
,
747 N_("Lua Error"), ALIGN_LEFT
,
752 usrerror("Lua: %s", msg
);
757 alert_lua_error2(unsigned char *msg
, unsigned char *msg2
)
759 unsigned char *tmp
= stracpy(msg
);
762 add_to_strn(&tmp
, msg2
);
763 alert_lua_error(tmp
);
768 /* The following stuff is to handle the return values of
769 * lua_console_hook and keystroke functions, and also the xdialog
770 * function. It expects two values on top of the stack. */
773 handle_ret_eval(struct session
*ses
)
775 const unsigned char *expr
= lua_tostring(L
, -1);
778 int oldtop
= lua_gettop(L
);
780 if (prepare_lua(ses
) == 0) {
781 (void)luaL_dostring(L
, expr
);
782 lua_settop(L
, oldtop
);
788 alert_lua_error("bad argument for eval");
792 handle_ret_run(struct session
*ses
)
794 unsigned char *cmd
= (unsigned char *) lua_tostring(L
, -1);
797 exec_on_terminal(ses
->tab
->term
, cmd
, "", TERM_EXEC_FG
);
801 alert_lua_error("bad argument for run");
805 handle_ret_goto_url(struct session
*ses
)
807 unsigned char *url
= (unsigned char *) lua_tostring(L
, -1);
810 goto_url_with_hook(ses
, url
);
814 alert_lua_error("bad argument for goto_url");
818 handle_standard_lua_returns(unsigned char *from
)
820 const unsigned char *act
= lua_tostring(L
, -2);
823 if (!strcmp(act
, "eval"))
824 handle_ret_eval(lua_ses
);
825 else if (!strcmp(act
, "run"))
826 handle_ret_run(lua_ses
);
827 else if (!strcmp(act
, "goto_url"))
828 handle_ret_goto_url(lua_ses
);
830 alert_lua_error2("unrecognised return value from ", from
);
832 else if (!lua_isnil(L
, -2))
833 alert_lua_error2("bad return type from ", from
);
839 handle_ref_on_stack(LS
, struct session
*ses
, unsigned char *from
, int num_args
)
843 if (prepare_lua(ses
)) return;
844 err
= eval_function(S
, num_args
, 2);
847 if (!err
) handle_standard_lua_returns(from
);
851 handle_ref(LS
, struct session
*ses
, int func_ref
, unsigned char *from
,
852 int num_args
, int unref
)
854 lua_rawgeti(S
, LUA_REGISTRYINDEX
, func_ref
);
856 /* The function must be below the arguments on the stack. */
857 if (num_args
!= 0) lua_insert(S
, -(num_args
+ 1));
859 handle_ref_on_stack(S
, ses
, from
, num_args
);
862 luaL_unref(S
, LUA_REGISTRYINDEX
, func_ref
);
868 static INIT_INPUT_HISTORY(lua_console_history
);
871 lua_console(struct session
*ses
, unsigned char *expr
)
873 lua_getglobal(L
, "lua_console_hook");
874 if (lua_isnil(L
, -1)) {
876 handle_ret_eval(ses
);
880 lua_pushstring(L
, expr
);
881 handle_ref_on_stack(L
, ses
, "lua_console_hook", 1);
884 /* TODO: Make this a "Scripting console" instead, with a radiobutton below the
885 * inputbox selecting the appropriate scripting backend to use to evaluate the
886 * expression. --pasky */
889 dialog_lua_console(va_list ap
, void *data
)
891 struct session
*ses
= va_arg(ap
, struct session
*);
893 if (get_cmd_opt_bool("anonymous"))
894 return EVENT_HOOK_STATUS_NEXT
;
896 input_dialog(ses
->tab
->term
, NULL
,
897 N_("Lua Console"), N_("Enter expression"),
898 ses
, &lua_console_history
,
899 MAX_STR_LEN
, "", 0, 0, NULL
,
900 (void (*)(void *, unsigned char *)) lua_console
, NULL
);
901 return EVENT_HOOK_STATUS_NEXT
;
905 free_lua_console_history_entries(void)
907 free_list(lua_console_history
.entries
);
911 free_lua_console_history(va_list ap
, void *data
)
913 free_lua_console_history_entries();
914 return EVENT_HOOK_STATUS_NEXT
;