diff options
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/guile/weechat-guile.c | 359 | ||||
-rw-r--r-- | src/plugins/javascript/weechat-js.cpp | 146 | ||||
-rw-r--r-- | src/plugins/lua/weechat-lua.c | 147 | ||||
-rw-r--r-- | src/plugins/perl/weechat-perl-api.c | 4 | ||||
-rw-r--r-- | src/plugins/perl/weechat-perl.c | 355 | ||||
-rw-r--r-- | src/plugins/perl/weechat-perl.h | 1 | ||||
-rw-r--r-- | src/plugins/php/weechat-php.c | 142 | ||||
-rw-r--r-- | src/plugins/plugin-script.c | 137 | ||||
-rw-r--r-- | src/plugins/plugin-script.h | 31 | ||||
-rw-r--r-- | src/plugins/python/weechat-python.c | 552 | ||||
-rw-r--r-- | src/plugins/ruby/weechat-ruby.c | 410 | ||||
-rw-r--r-- | src/plugins/tcl/weechat-tcl.c | 152 |
12 files changed, 1933 insertions, 503 deletions
diff --git a/src/plugins/guile/weechat-guile.c b/src/plugins/guile/weechat-guile.c index 6eb563840..0f7251c90 100644 --- a/src/plugins/guile/weechat-guile.c +++ b/src/plugins/guile/weechat-guile.c @@ -46,7 +46,23 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_guile_plugin = NULL; -int guile_quiet; +int guile_quiet = 0; + +struct t_plugin_script *guile_script_eval = NULL; +int guile_eval_mode = 0; +int guile_eval_send_input = 0; +int guile_eval_exec_commands = 0; +struct t_gui_buffer *guile_eval_buffer = NULL; +char *guile_eval_output = NULL; +#define GUILE_EVAL_SCRIPT \ + "(weechat:register \"" WEECHAT_SCRIPT_EVAL_NAME "\" \"\" \"1.0\" " \ + "\"" WEECHAT_LICENSE "\" \"Evaluation of script code\" " \ + "\"\" \"\")\n" \ + "\n" \ + "(define (script_guile_eval code)\n" \ + " (eval-string code)\n" \ + ")\n" + struct t_plugin_script *guile_scripts = NULL; struct t_plugin_script *last_guile_script = NULL; struct t_plugin_script *guile_current_script = NULL; @@ -54,7 +70,7 @@ struct t_plugin_script *guile_registered_script = NULL; const char *guile_current_script_filename = NULL; SCM guile_module_weechat; SCM guile_port; -char *guile_stdout = NULL; +char **guile_buffer_output = NULL; struct t_guile_function { @@ -89,20 +105,63 @@ char *guile_action_autoload_list = NULL; /* - * Flushes stdout. + * Flushes output. */ void -weechat_guile_stdout_flush () +weechat_guile_output_flush () { - if (guile_stdout) + const char *ptr_command; + char *command; + int length; + + if (!*guile_buffer_output[0]) + return; + + if (guile_eval_mode) { + /* if there's no buffer, we catch the output, so there's no flush */ + if (!guile_eval_buffer) + return; + + if (guile_eval_send_input) + { + if (guile_eval_exec_commands) + ptr_command = *guile_buffer_output; + else + ptr_command = weechat_string_input_for_buffer (*guile_buffer_output); + if (ptr_command) + { + weechat_command (guile_eval_buffer, *guile_buffer_output); + } + else + { + length = 1 + strlen (*guile_buffer_output) + 1; + command = malloc (length); + if (command) + { + snprintf (command, length, "%c%s", + *guile_buffer_output[0], *guile_buffer_output); + weechat_command (guile_eval_buffer, + (command[0]) ? command : " "); + free (command); + } + } + } + else + { + weechat_printf (guile_eval_buffer, "%s", *guile_buffer_output); + } + } + else + { + /* script (no eval mode) */ weechat_printf (NULL, - weechat_gettext ("%s: stdout/stderr: %s%s"), - GUILE_PLUGIN_NAME, guile_stdout, ""); - free (guile_stdout); - guile_stdout = NULL; + weechat_gettext ("%s: stdout/stderr: %s"), + GUILE_PLUGIN_NAME, *guile_buffer_output); } + + weechat_string_dyn_copy (guile_buffer_output, NULL); } /* @@ -272,6 +331,8 @@ weechat_guile_exec (struct t_plugin_script *script, void *argv2[17], *ret_value; int i, argc, *ret_int; + ret_value = NULL; + old_guile_current_script = guile_current_script; old_current_module = NULL; if (script->interpreter) @@ -310,7 +371,7 @@ weechat_guile_exec (struct t_plugin_script *script, rc = weechat_guile_exec_function (function, NULL, 0); } - ret_value = NULL; + weechat_guile_output_flush (); if ((ret_type == WEECHAT_SCRIPT_EXEC_STRING) && (scm_is_string (rc))) { @@ -332,13 +393,17 @@ weechat_guile_exec (struct t_plugin_script *script, } else { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must return " - "a valid value"), - weechat_prefix ("error"), GUILE_PLUGIN_NAME, function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), GUILE_PLUGIN_NAME, + function); + } } - if (ret_value == NULL) + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) { weechat_printf (NULL, weechat_gettext ("%s%s: error in function \"%s\""), @@ -354,16 +419,43 @@ weechat_guile_exec (struct t_plugin_script *script, } /* - * Initializes guile module for script. + * Initializes guile module for a script file. */ void -weechat_guile_module_init_script (void *data) +weechat_guile_module_init_file (void *filename) { SCM rc; weechat_guile_catch (scm_c_eval_string, "(use-modules (weechat))"); - rc = weechat_guile_catch (scm_c_primitive_load, data); + rc = weechat_guile_catch (scm_c_primitive_load, filename); + + /* error loading script? */ + if (rc == SCM_BOOL_F) + { + /* if script was registered, remove it from list */ + if (guile_current_script) + { + plugin_script_remove (weechat_guile_plugin, + &guile_scripts, &last_guile_script, + guile_current_script); + } + guile_current_script = NULL; + guile_registered_script = NULL; + } +} + +/* + * Initializes guile module for a string with guile code. + */ + +void +weechat_guile_module_init_code (void *code) +{ + SCM rc; + + weechat_guile_catch (scm_c_eval_string, "(use-modules (weechat))"); + rc = weechat_guile_catch (scm_c_eval_string, code); /* error loading script? */ if (rc == SCM_BOOL_F) @@ -383,16 +475,30 @@ weechat_guile_module_init_script (void *data) /* * Loads a guile script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_guile_load (const char *filename) +struct t_plugin_script * +weechat_guile_load (const char *filename, const char *code) { char *filename2, *ptr_base_name, *base_name; SCM module; + struct stat buf; + + if (!code) + { + if (stat (filename, &buf) != 0) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: script \"%s\" not found"), + weechat_prefix ("error"), GUILE_PLUGIN_NAME, + filename); + return NULL; + } + } if ((weechat_guile_plugin->debug >= 2) || !guile_quiet) { @@ -405,15 +511,24 @@ weechat_guile_load (const char *filename) guile_registered_script = NULL; guile_current_script_filename = filename; - filename2 = strdup (filename); - if (!filename2) - return 0; - - ptr_base_name = basename (filename2); - base_name = strdup (ptr_base_name); - module = scm_c_define_module (base_name, - &weechat_guile_module_init_script, filename2); - free (filename2); + if (code) + { + module = scm_c_define_module (filename, + &weechat_guile_module_init_code, + (char *)code); + } + else + { + filename2 = strdup (filename); + if (!filename2) + return NULL; + ptr_base_name = basename (filename2); + base_name = strdup (ptr_base_name); + module = scm_c_define_module (base_name, + &weechat_guile_module_init_file, + filename2); + free (filename2); + } if (!guile_registered_script) { @@ -421,7 +536,7 @@ weechat_guile_load (const char *filename) weechat_gettext ("%s%s: function \"register\" not " "found (or failed) in file \"%s\""), weechat_prefix ("error"), GUILE_PLUGIN_NAME, filename); - return 0; + return NULL; } weechat_guile_catch (scm_gc_protect_object, (void *)module); @@ -442,7 +557,7 @@ weechat_guile_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, guile_current_script->filename); - return 1; + return guile_current_script; } /* @@ -455,7 +570,7 @@ weechat_guile_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_guile_load (filename); + weechat_guile_load (filename, NULL); } /* @@ -570,7 +685,7 @@ weechat_guile_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), GUILE_PLUGIN_NAME, name); } - weechat_guile_load (filename); + weechat_guile_load (filename, NULL); free (filename); } } @@ -583,6 +698,56 @@ weechat_guile_reload_name (const char *name) } /* + * Evaluates guile code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_guile_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + void *func_argv[1], *result; + + if (!guile_script_eval) + { + guile_quiet = 1; + guile_script_eval = weechat_guile_load (WEECHAT_SCRIPT_EVAL_NAME, + GUILE_EVAL_SCRIPT); + guile_quiet = 0; + if (!guile_script_eval) + return 0; + } + + weechat_guile_output_flush (); + + guile_eval_mode = 1; + guile_eval_send_input = send_to_buffer_as_input; + guile_eval_exec_commands = exec_commands; + guile_eval_buffer = buffer; + + func_argv[0] = (char *)code; + result = weechat_guile_exec (guile_script_eval, + WEECHAT_SCRIPT_EXEC_IGNORE, + "script_guile_eval", + "s", func_argv); + /* result is ignored */ + if (result) + free (result); + + weechat_guile_output_flush (); + + guile_eval_mode = 0; + guile_eval_send_input = 0; + guile_eval_exec_commands = 0; + guile_eval_buffer = NULL; + + return 1; +} + +/* * Callback for command "/guile". */ @@ -591,13 +756,12 @@ weechat_guile_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; - SCM value; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -667,7 +831,8 @@ weechat_guile_command_cb (const void *pointer, void *data, /* load guile script */ path_script = plugin_script_search_path (weechat_guile_plugin, ptr_name); - weechat_guile_load ((path_script) ? path_script : ptr_name); + weechat_guile_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -685,14 +850,36 @@ weechat_guile_command_cb (const void *pointer, void *data, } else if (weechat_strcasecmp (argv[1], "eval") == 0) { - /* eval guile code */ - value = weechat_guile_catch (scm_c_eval_string, argv_eol[2]); - if (!SCM_EQ_P (value, SCM_UNDEFINED) - && !SCM_EQ_P (value, SCM_UNSPECIFIED)) + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) { - scm_display (value, guile_port); + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; } - weechat_guile_stdout_flush (); + if (!weechat_guile_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; } else WEECHAT_COMMAND_ERROR; @@ -740,6 +927,29 @@ weechat_guile_hdata_cb (const void *pointer, void *data, } /* + * Returns guile info "guile_eval". + */ + +const char * +weechat_guile_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + weechat_guile_eval (NULL, 0, 0, (arguments) ? arguments : ""); + if (guile_eval_output) + free (guile_eval_output); + guile_eval_output = strdup (*guile_buffer_output); + weechat_string_dyn_copy (guile_buffer_output, NULL); + + return guile_eval_output; +} + +/* * Returns infolist with guile scripts. */ @@ -896,39 +1106,28 @@ weechat_guile_port_fill_input (SCM port) void weechat_guile_port_write (SCM port, const void *data, size_t size) { - char *new_stdout; - int length_stdout; + char *data2, *ptr_data, *ptr_newline; /* make C compiler happy */ (void) port; - /* concatenate str to guile_stdout */ - if (guile_stdout) - { - length_stdout = strlen (guile_stdout); - new_stdout = realloc (guile_stdout, length_stdout + size + 1); - if (!new_stdout) - { - free (guile_stdout); - return; - } - guile_stdout = new_stdout; - memcpy (guile_stdout + length_stdout, data, size); - guile_stdout[length_stdout + size] = '\0'; - } - else + data2 = malloc (size + 1); + if (!data2) + return; + + memcpy (data2, data, size); + data2[size] = '\0'; + + ptr_data = data2; + while ((ptr_newline = strchr (ptr_data, '\n')) != NULL) { - guile_stdout = malloc (size + 1); - if (guile_stdout) - { - memcpy (guile_stdout, data, size); - guile_stdout[size] = '\0'; - } + ptr_newline[0] = '\0'; + weechat_string_dyn_concat (guile_buffer_output, ptr_data); + weechat_guile_output_flush (); + ptr_newline[0] = '\n'; + ptr_data = ++ptr_newline; } - - /* flush stdout if at least "\n" is in string */ - if (guile_stdout && (strchr (guile_stdout, '\n'))) - weechat_guile_stdout_flush (); + weechat_string_dyn_concat (guile_buffer_output, ptr_data); } /* @@ -960,7 +1159,10 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) ""); #endif /* defined(SCM_MAJOR_VERSION) && defined(SCM_MINOR_VERSION) && defined(SCM_MICRO_VERSION) */ - guile_stdout = NULL; + /* init stdout/stderr buffer */ + guile_buffer_output = weechat_string_dyn_alloc (256); + if (!guile_buffer_output) + return WEECHAT_RC_ERROR; #ifdef HAVE_GUILE_GMP_MEMORY_FUNCTIONS /* @@ -982,6 +1184,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_guile_command_cb; init.callback_completion = &weechat_guile_completion_cb; init.callback_hdata = &weechat_guile_hdata_cb; + init.callback_info_eval = &weechat_guile_info_eval_cb; init.callback_infolist = &weechat_guile_infolist_cb; init.callback_signal_debug_dump = &weechat_guile_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_guile_signal_script_action_cb; @@ -1008,6 +1211,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ guile_quiet = 1; plugin_script_end (plugin, &guile_scripts, &weechat_guile_unload_all); + if (guile_script_eval) + { + weechat_guile_unload (guile_script_eval); + guile_script_eval = NULL; + } guile_quiet = 0; /* unprotect module */ @@ -1020,6 +1228,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (guile_action_remove_list); if (guile_action_autoload_list) free (guile_action_autoload_list); + weechat_string_dyn_free (guile_buffer_output, 1); + if (guile_eval_output) + free (guile_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/javascript/weechat-js.cpp b/src/plugins/javascript/weechat-js.cpp index 3a04c3425..ffffba072 100644 --- a/src/plugins/javascript/weechat-js.cpp +++ b/src/plugins/javascript/weechat-js.cpp @@ -44,6 +44,14 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_js_plugin; int js_quiet = 0; + +struct t_plugin_script *js_script_eval = NULL; +int js_eval_mode = 0; +int js_eval_send_input = 0; +int js_eval_exec_commands = 0; +struct t_gui_buffer *js_eval_buffer = NULL; +char *js_eval_output = NULL; + struct t_plugin_script *js_scripts = NULL; struct t_plugin_script *last_js_script = NULL; struct t_plugin_script *js_current_script = NULL; @@ -235,15 +243,18 @@ weechat_js_exec (struct t_plugin_script *script, } else { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must " - "return a valid value"), - weechat_prefix ("error"), JS_PLUGIN_NAME, - function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), JS_PLUGIN_NAME, + function); + } } } - if (!ret_value) + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) { weechat_printf (NULL, weechat_gettext ("%s%s: error in function \"%s\""), @@ -259,13 +270,14 @@ end: /* * Loads a javascript script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_js_load (const char *filename) +struct t_plugin_script * +weechat_js_load (const char *filename, const char *code) { char *source; @@ -275,7 +287,7 @@ weechat_js_load (const char *filename) weechat_printf (NULL, weechat_gettext ("%s%s: script \"%s\" not found"), weechat_prefix ("error"), JS_PLUGIN_NAME, filename); - return 0; + return NULL; } if ((weechat_js_plugin->debug >= 2) || !js_quiet) @@ -297,7 +309,7 @@ weechat_js_load (const char *filename) "sub-interpreter"), weechat_prefix ("error"), JS_PLUGIN_NAME); free (source); - return 0; + return NULL; } /* load libs */ @@ -322,7 +334,7 @@ weechat_js_load (const char *filename) js_current_script = NULL; } - return 0; + return NULL; } free (source); @@ -343,7 +355,7 @@ weechat_js_load (const char *filename) js_current_script); js_current_script = NULL; } - return 0; + return NULL; } if (!js_registered_script) @@ -353,7 +365,7 @@ weechat_js_load (const char *filename) "found (or failed) in file \"%s\""), weechat_prefix ("error"), JS_PLUGIN_NAME, filename); delete js_current_interpreter; - return 0; + return NULL; } js_current_script = js_registered_script; @@ -372,7 +384,7 @@ weechat_js_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, js_current_script->filename); - return 1; + return js_current_script; } /* @@ -385,7 +397,7 @@ weechat_js_load_cb (void *data, const char *filename) /* make C++ compiler happy */ (void) data; - weechat_js_load (filename); + weechat_js_load (filename, NULL); } /* @@ -499,7 +511,7 @@ weechat_js_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), JS_PLUGIN_NAME, name); } - weechat_js_load (filename); + weechat_js_load (filename, NULL); free (filename); } } @@ -512,6 +524,27 @@ weechat_js_reload_name (const char *name) } /* + * Evaluates javascript code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_js_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + /* TODO: implement javascript eval */ + (void) buffer; + (void) send_to_buffer_as_input; + (void) exec_commands; + (void) code; + + return 1; +} + +/* * Callback for command "/javascript". */ @@ -520,12 +553,12 @@ weechat_js_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C++ compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -595,7 +628,8 @@ weechat_js_command_cb (const void *pointer, void *data, /* load javascript script */ path_script = plugin_script_search_path (weechat_js_plugin, ptr_name); - weechat_js_load ((path_script) ? path_script : ptr_name); + weechat_js_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -611,6 +645,43 @@ weechat_js_command_cb (const void *pointer, void *data, } js_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_js_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + /* TODO: implement /javascript eval */ + weechat_printf (NULL, + "%sCommand \"/javascript eval\" is not yet implemented", + weechat_prefix ("error")); + } else WEECHAT_COMMAND_ERROR; } @@ -657,6 +728,28 @@ weechat_js_hdata_cb (const void *pointer, void *data, } /* + * Returns javascript info "javascript_eval". + */ + +const char * +weechat_js_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + static const char *not_implemented = "not yet implemented"; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + (void) arguments; + return not_implemented; + + return NULL; +} + +/* * Returns infolist with javascript scripts. */ @@ -817,6 +910,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_js_command_cb; init.callback_completion = &weechat_js_completion_cb; init.callback_hdata = &weechat_js_hdata_cb; + init.callback_info_eval = &weechat_js_info_eval_cb; init.callback_infolist = &weechat_js_infolist_cb; init.callback_signal_debug_dump = &weechat_js_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_js_signal_script_action_cb; @@ -840,6 +934,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) { js_quiet = 1; plugin_script_end (plugin, &js_scripts, &weechat_js_unload_all); + if (js_script_eval) + { + weechat_js_unload (js_script_eval); + js_script_eval = NULL; + } js_quiet = 0; /* free some data */ @@ -849,6 +948,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (js_action_remove_list); if (js_action_autoload_list) free (js_action_autoload_list); + /* weechat_string_dyn_free (js_buffer_output, 1); */ + if (js_eval_output) + free (js_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/lua/weechat-lua.c b/src/plugins/lua/weechat-lua.c index 48da8668d..e211ba3ad 100644 --- a/src/plugins/lua/weechat-lua.c +++ b/src/plugins/lua/weechat-lua.c @@ -45,6 +45,14 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_lua_plugin; int lua_quiet = 0; + +struct t_plugin_script *lua_script_eval = NULL; +int lua_eval_mode = 0; +int lua_eval_send_input = 0; +int lua_eval_exec_commands = 0; +struct t_gui_buffer *lua_eval_buffer = NULL; +char *lua_eval_output = NULL; + struct t_plugin_script *lua_scripts = NULL; struct t_plugin_script *last_lua_script = NULL; struct t_plugin_script *lua_current_script = NULL; @@ -239,7 +247,14 @@ weechat_lua_exec (struct t_plugin_script *script, int ret_type, } else { - WEECHAT_SCRIPT_MSG_WRONG_ARGS(LUA_CURRENT_SCRIPT_NAME, function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), LUA_PLUGIN_NAME, + function); + } } } else @@ -253,6 +268,13 @@ weechat_lua_exec (struct t_plugin_script *script, int ret_type, lua_tostring (lua_current_interpreter, -1)); } + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: error in function \"%s\""), + weechat_prefix ("error"), LUA_PLUGIN_NAME, function); + } + lua_pop (lua_current_interpreter, 1); lua_current_script = old_lua_current_script; @@ -338,13 +360,14 @@ weechat_lua_register_lib (lua_State *L, const char *libname, /* * Loads a lua script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_lua_load (const char *filename) +struct t_plugin_script * +weechat_lua_load (const char *filename, const char *code) { FILE *fp; char *weechat_lua_code = { @@ -362,7 +385,7 @@ weechat_lua_load (const char *filename) weechat_printf (NULL, weechat_gettext ("%s%s: script \"%s\" not found"), weechat_prefix ("error"), LUA_PLUGIN_NAME, filename); - return 0; + return NULL; } if ((weechat_lua_plugin->debug >= 2) || !lua_quiet) @@ -384,7 +407,7 @@ weechat_lua_load (const char *filename) "sub-interpreter"), weechat_prefix ("error"), LUA_PLUGIN_NAME); fclose (fp); - return 0; + return NULL; } #ifdef LUA_VERSION_NUM /* LUA_VERSION_NUM is defined only in lua >= 5.1.0 */ @@ -427,7 +450,7 @@ weechat_lua_load (const char *filename) lua_tostring (lua_current_interpreter, -1)); lua_close (lua_current_interpreter); fclose (fp); - return 0; + return NULL; } if (lua_pcall (lua_current_interpreter, 0, 0, 0) != 0) @@ -452,7 +475,7 @@ weechat_lua_load (const char *filename) lua_current_script = NULL; } - return 0; + return NULL; } fclose (fp); @@ -463,7 +486,7 @@ weechat_lua_load (const char *filename) "found (or failed) in file \"%s\""), weechat_prefix ("error"), LUA_PLUGIN_NAME, filename); lua_close (lua_current_interpreter); - return 0; + return NULL; } lua_current_script = lua_registered_script; @@ -481,7 +504,7 @@ weechat_lua_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, lua_current_script->filename); - return 1; + return lua_current_script; } /* @@ -494,7 +517,7 @@ weechat_lua_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_lua_load (filename); + weechat_lua_load (filename, NULL); } /* @@ -597,7 +620,7 @@ weechat_lua_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), LUA_PLUGIN_NAME, name); } - weechat_lua_load (filename); + weechat_lua_load (filename, NULL); free (filename); } } @@ -623,6 +646,27 @@ weechat_lua_unload_all () } /* + * Evaluates lua code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_lua_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + /* TODO: implement lua eval */ + (void) buffer; + (void) send_to_buffer_as_input; + (void) exec_commands; + (void) code; + + return 1; +} + +/* * Callback for command "/lua". */ @@ -631,12 +675,12 @@ weechat_lua_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -706,7 +750,8 @@ weechat_lua_command_cb (const void *pointer, void *data, /* load lua script */ path_script = plugin_script_search_path (weechat_lua_plugin, ptr_name); - weechat_lua_load ((path_script) ? path_script : ptr_name); + weechat_lua_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -722,6 +767,43 @@ weechat_lua_command_cb (const void *pointer, void *data, } lua_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_lua_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + /* TODO: implement /lua eval */ + weechat_printf (NULL, + "%sCommand \"/lua eval\" is not yet implemented", + weechat_prefix ("error")); + } else WEECHAT_COMMAND_ERROR; } @@ -768,6 +850,28 @@ weechat_lua_hdata_cb (const void *pointer, void *data, } /* + * Returns lua info "lua_eval". + */ + +const char * +weechat_lua_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + static const char *not_implemented = "not yet implemented"; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + (void) arguments; + return not_implemented; + + return NULL; +} + +/* * Returns infolist with lua scripts. */ @@ -929,6 +1033,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_lua_command_cb; init.callback_completion = &weechat_lua_completion_cb; init.callback_hdata = &weechat_lua_hdata_cb; + init.callback_info_eval = &weechat_lua_info_eval_cb; init.callback_infolist = &weechat_lua_infolist_cb; init.callback_signal_debug_dump = &weechat_lua_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_lua_signal_script_action_cb; @@ -955,6 +1060,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ lua_quiet = 1; plugin_script_end (plugin, &lua_scripts, &weechat_lua_unload_all); + if (lua_script_eval) + { + weechat_lua_unload (lua_script_eval); + lua_script_eval = NULL; + } lua_quiet = 0; /* free some data */ @@ -964,6 +1074,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (lua_action_remove_list); if (lua_action_autoload_list) free (lua_action_autoload_list); + /* weechat_string_dyn_free (lua_buffer_output, 1); */ + if (lua_eval_output) + free (lua_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/perl/weechat-perl-api.c b/src/plugins/perl/weechat-perl-api.c index 30c376c6d..92e915301 100644 --- a/src/plugins/perl/weechat-perl-api.c +++ b/src/plugins/perl/weechat-perl-api.c @@ -108,9 +108,6 @@ API_FUNC(register) char *charset; dXSARGS; - /* make C compiler happy */ - (void) items; - API_INIT_FUNC(0, "register", API_RETURN_ERROR); if (perl_registered_script) { @@ -5063,6 +5060,7 @@ weechat_perl_api_init (pTHX) HV *stash; newXS ("DynaLoader::boot_DynaLoader", boot_DynaLoader, __FILE__); + newXS ("weechat::__output__", weechat_perl_output, "weechat"); /* interface functions */ API_DEF_FUNC(register); diff --git a/src/plugins/perl/weechat-perl.c b/src/plugins/perl/weechat-perl.c index a56cf258b..31671d8ab 100644 --- a/src/plugins/perl/weechat-perl.c +++ b/src/plugins/perl/weechat-perl.c @@ -42,6 +42,20 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_perl_plugin = NULL; int perl_quiet = 0; + +struct t_plugin_script *perl_script_eval = NULL; +int perl_eval_mode = 0; +int perl_eval_send_input = 0; +int perl_eval_exec_commands = 0; +struct t_gui_buffer *perl_eval_buffer = NULL; +char *perl_eval_output = NULL; +#define PERL_EVAL_SCRIPT \ + "sub script_perl_eval {\n" \ + " eval \"$_[0]\";\n" \ + "}\n" \ + "weechat::register('" WEECHAT_SCRIPT_EVAL_NAME "', '', '1.0', " \ + "'" WEECHAT_LICENSE "', 'Evaluation of script code', '', '');\n" + struct t_plugin_script *perl_scripts = NULL; struct t_plugin_script *last_perl_script = NULL; struct t_plugin_script *perl_current_script = NULL; @@ -51,6 +65,7 @@ const char *perl_current_script_filename = NULL; PerlInterpreter *perl_current_interpreter = NULL; #endif /* MULTIPLICITY */ int perl_quit_or_upgrade = 0; +char **perl_buffer_output = NULL; /* * string used to execute action "install": @@ -94,9 +109,21 @@ char *perl_weechat_code = #ifndef MULTIPLICITY "package %s;" #endif /* MULTIPLICITY */ - "$SIG{__WARN__} = sub { weechat::print('', 'perl\twarning: '.$_[0]) };" - "$SIG{__DIE__} = sub { weechat::print('', 'perl\terror: '.$_[0]) };" - "do '%s';" + "$SIG{__WARN__} = sub { weechat::print('', '%s '.$_[0]); };" + "$SIG{__DIE__} = sub { weechat::print('', '%s '.$_[0]); };" + "tie(*STDOUT, 'weechat_output');" + "tie(*STDERR, 'weechat_output');" + "do %s%s%s" + "package weechat_output;" + "sub TIEHANDLE { bless {}; }" + "sub PRINT {" + " weechat::__output__($_[1]);" + "}" + "sub PRINTF {" + " my $self = shift;" + " my $fmt = shift;" + " weechat::__output__(sprintf($fmt, @_));" + "}" }; /* @@ -186,6 +213,91 @@ weechat_perl_hash_to_hashtable (SV *hash, int size, const char *type_keys, } /* + * Flushes output. + */ + +void +weechat_perl_output_flush () +{ + const char *ptr_command; + char *command; + int length; + + if (!*perl_buffer_output[0]) + return; + + if (perl_eval_mode) + { + /* if there's no buffer, we catch the output, so there's no flush */ + if (!perl_eval_buffer) + return; + + if (perl_eval_send_input) + { + if (perl_eval_exec_commands) + ptr_command = *perl_buffer_output; + else + ptr_command = weechat_string_input_for_buffer (*perl_buffer_output); + if (ptr_command) + { + weechat_command (perl_eval_buffer, *perl_buffer_output); + } + else + { + length = 1 + strlen (*perl_buffer_output) + 1; + command = malloc (length); + if (command) + { + snprintf (command, length, "%c%s", + *perl_buffer_output[0], *perl_buffer_output); + weechat_command (perl_eval_buffer, + (command[0]) ? command : " "); + free (command); + } + } + } + else + { + weechat_printf (perl_eval_buffer, "%s", *perl_buffer_output); + } + } + else + { + /* script (no eval mode) */ + weechat_printf (NULL, + weechat_gettext ("%s: stdout/stderr: %s"), + PERL_PLUGIN_NAME, *perl_buffer_output); + } + + weechat_string_dyn_copy (perl_buffer_output, NULL); +} + +/* + * Redirection for stdout and stderr. + */ + +XS (weechat_perl_output) +{ + char *msg, *ptr_msg, *ptr_newline; + dXSARGS; + + if (items < 1) + return; + + msg = SvPV_nolen (ST (0)); + ptr_msg = msg; + while ((ptr_newline = strchr (ptr_msg, '\n')) != NULL) + { + ptr_newline[0] = '\0'; + weechat_string_dyn_concat (perl_buffer_output, ptr_msg); + weechat_perl_output_flush (); + ptr_newline[0] = '\n'; + ptr_msg = ++ptr_newline; + } + weechat_string_dyn_concat (perl_buffer_output, ptr_msg); +} + +/* * Executes a perl function. */ @@ -258,24 +370,29 @@ weechat_perl_exec (struct t_plugin_script *script, SPAGAIN; + weechat_perl_output_flush (); + if (SvTRUE (ERRSV)) { weechat_printf (NULL, weechat_gettext ("%s%s: error: %s"), weechat_prefix ("error"), PERL_PLUGIN_NAME, SvPV_nolen (ERRSV)); - (void) POPs; /* poping the 'undef' */ + (void) POPs; /* pop the "undef" */ mem_err = 0; } else { if (count != 1) { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must " - "return one valid value (%d)"), - weechat_prefix ("error"), PERL_PLUGIN_NAME, - function, count); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), PERL_PLUGIN_NAME, + function); + } mem_err = 0; } else @@ -302,16 +419,27 @@ weechat_perl_exec (struct t_plugin_script *script, } else { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" is " - "internally misused"), - weechat_prefix ("error"), PERL_PLUGIN_NAME, - function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf ( + NULL, + weechat_gettext ("%s%s: function \"%s\" must return " + "a valid value"), + weechat_prefix ("error"), PERL_PLUGIN_NAME, + function); + } mem_err = 0; } } } + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: error in function \"%s\""), + weechat_prefix ("error"), PERL_PLUGIN_NAME, function); + } + PUTBACK; FREETMPS; LEAVE; @@ -338,14 +466,17 @@ weechat_perl_exec (struct t_plugin_script *script, /* * Loads a perl script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_perl_load (const char *filename) +struct t_plugin_script * +weechat_perl_load (const char *filename, const char *code) { + char str_warning[512], str_error[512]; + struct t_plugin_script temp_script; struct stat buf; char *perl_code; @@ -364,12 +495,16 @@ weechat_perl_load (const char *filename) temp_script.shutdown_func = NULL; temp_script.charset = NULL; - if (stat (filename, &buf) != 0) + if (!code) { - weechat_printf (NULL, - weechat_gettext ("%s%s: script \"%s\" not found"), - weechat_prefix ("error"), PERL_PLUGIN_NAME, filename); - return 0; + if (stat (filename, &buf) != 0) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: script \"%s\" not found"), + weechat_prefix ("error"), PERL_PLUGIN_NAME, + filename); + return NULL; + } } if ((weechat_perl_plugin->debug >= 2) || !perl_quiet) @@ -392,27 +527,48 @@ weechat_perl_load (const char *filename) weechat_gettext ("%s%s: unable to create new " "sub-interpreter"), weechat_prefix ("error"), PERL_PLUGIN_NAME); - return 0; + return NULL; } + snprintf (str_warning, sizeof (str_warning), + weechat_gettext ("%s: warning:"), + PERL_PLUGIN_NAME); + snprintf (str_error, sizeof (str_error), + weechat_gettext ("%s: error:"), + PERL_PLUGIN_NAME); + PERL_SET_CONTEXT (perl_current_interpreter); perl_construct (perl_current_interpreter); temp_script.interpreter = (PerlInterpreter *) perl_current_interpreter; perl_parse (perl_current_interpreter, weechat_perl_api_init, perl_args_count, perl_args, NULL); - length = strlen (perl_weechat_code) - 2 + strlen (filename) + 1; + length = strlen (perl_weechat_code) + strlen (str_warning) + + strlen (str_error) - 2 + 4 + strlen ((code) ? code : filename) + 4 + 1; perl_code = malloc (length); if (!perl_code) - return 0; - snprintf (perl_code, length, perl_weechat_code, filename); + return NULL; + snprintf (perl_code, length, perl_weechat_code, + str_warning, + str_error, + (code) ? "{\n" : "'", + (code) ? code : filename, + (code) ? "\n};\n" : "';"); #else snprintf (pkgname, sizeof (pkgname), "%s%d", PKG_NAME_PREFIX, perl_num); perl_num++; - length = strlen (perl_weechat_code) - 4 + strlen (pkgname) + strlen (filename) + 1; + length = strlen (perl_weechat_code) + strlen (str_warning) + + strlen (str_error) - 4 + strlen (pkgname) + 4 + + strlen ((code) ? code : filename) + 4 + 1; perl_code = malloc (length); if (!perl_code) - return 0; - snprintf (perl_code, length, perl_weechat_code, pkgname, filename); + return NULL; + snprintf (perl_code, length, perl_weechat_code, + pkgname, + str_warning, + str_error, + (code) ? "{\n" : "'", + (code) ? code : filename, + (code) ? "\n};\n" : "';"); #endif /* MULTIPLICITY */ eval_pv (perl_code, TRUE); free (perl_code); @@ -440,7 +596,7 @@ weechat_perl_load (const char *filename) perl_current_script = NULL; } - return 0; + return NULL; } if (!perl_registered_script) @@ -453,7 +609,7 @@ weechat_perl_load (const char *filename) perl_destruct (perl_current_interpreter); perl_free (perl_current_interpreter); #endif /* MULTIPLICITY */ - return 0; + return NULL; } perl_current_script = perl_registered_script; @@ -475,7 +631,7 @@ weechat_perl_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, perl_current_script->filename); - return 1; + return perl_current_script; } /* @@ -488,7 +644,7 @@ weechat_perl_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_perl_load (filename); + weechat_perl_load (filename, NULL); } /* @@ -620,7 +776,7 @@ weechat_perl_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), PERL_PLUGIN_NAME, name); } - weechat_perl_load (filename); + weechat_perl_load (filename, NULL); free (filename); } } @@ -633,6 +789,56 @@ weechat_perl_reload_name (const char *name) } /* + * Evaluates perl code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_perl_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + void *func_argv[1], *result; + + if (!perl_script_eval) + { + perl_quiet = 1; + perl_script_eval = weechat_perl_load (WEECHAT_SCRIPT_EVAL_NAME, + PERL_EVAL_SCRIPT); + perl_quiet = 0; + if (!perl_script_eval) + return 0; + } + + weechat_perl_output_flush (); + + perl_eval_mode = 1; + perl_eval_send_input = send_to_buffer_as_input; + perl_eval_exec_commands = exec_commands; + perl_eval_buffer = buffer; + + func_argv[0] = (char *)code; + result = weechat_perl_exec (perl_script_eval, + WEECHAT_SCRIPT_EXEC_IGNORE, + "script_perl_eval", + "s", func_argv); + /* result is ignored */ + if (result) + free (result); + + weechat_perl_output_flush (); + + perl_eval_mode = 0; + perl_eval_send_input = 0; + perl_eval_exec_commands = 0; + perl_eval_buffer = NULL; + + return 1; +} + +/* * Callback for command "/perl". */ @@ -641,12 +847,12 @@ weechat_perl_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -716,7 +922,8 @@ weechat_perl_command_cb (const void *pointer, void *data, /* load perl script */ path_script = plugin_script_search_path (weechat_perl_plugin, ptr_name); - weechat_perl_load ((path_script) ? path_script : ptr_name); + weechat_perl_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -732,6 +939,39 @@ weechat_perl_command_cb (const void *pointer, void *data, } perl_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_perl_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + } else WEECHAT_COMMAND_ERROR; } @@ -778,6 +1018,29 @@ weechat_perl_hdata_cb (const void *pointer, void *data, } /* + * Returns perl info "perl_eval". + */ + +const char * +weechat_perl_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + weechat_perl_eval (NULL, 0, 0, (arguments) ? arguments : ""); + if (perl_eval_output) + free (perl_eval_output); + perl_eval_output = strdup (*perl_buffer_output); + weechat_string_dyn_copy (perl_buffer_output, NULL); + + return perl_eval_output; +} + +/* * Returns infolist with perl scripts. */ @@ -967,6 +1230,11 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) ""); #endif /* PERL_VERSION_STRING */ + /* init stdout/stderr buffer */ + perl_buffer_output = weechat_string_dyn_alloc (256); + if (!perl_buffer_output) + return WEECHAT_RC_ERROR; + #ifndef MULTIPLICITY perl_main = perl_alloc (); @@ -987,6 +1255,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_perl_command_cb; init.callback_completion = &weechat_perl_completion_cb; init.callback_hdata = &weechat_perl_hdata_cb; + init.callback_info_eval = &weechat_perl_info_eval_cb; init.callback_infolist = &weechat_perl_infolist_cb; init.callback_signal_debug_dump = &weechat_perl_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_perl_signal_script_action_cb; @@ -1018,6 +1287,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ perl_quiet = 1; plugin_script_end (plugin, &perl_scripts, &weechat_perl_unload_all); + if (perl_script_eval) + { + weechat_perl_unload (perl_script_eval); + perl_script_eval = NULL; + } perl_quiet = 0; #ifndef MULTIPLICITY @@ -1046,6 +1320,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (perl_action_remove_list); if (perl_action_autoload_list) free (perl_action_autoload_list); + weechat_string_dyn_free (perl_buffer_output, 1); + if (perl_eval_output) + free (perl_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/perl/weechat-perl.h b/src/plugins/perl/weechat-perl.h index 8bee709cf..318f28ca5 100644 --- a/src/plugins/perl/weechat-perl.h +++ b/src/plugins/perl/weechat-perl.h @@ -41,6 +41,7 @@ extern HV *weechat_perl_hashtable_to_hash (struct t_hashtable *hashtable); extern struct t_hashtable *weechat_perl_hash_to_hashtable (SV *hash, int size, const char *type_keys, const char *type_values); +extern XS (weechat_perl_output); extern void *weechat_perl_exec (struct t_plugin_script *script, int ret_type, const char *function, const char *format, void **argv); diff --git a/src/plugins/php/weechat-php.c b/src/plugins/php/weechat-php.c index 2fcbc5fd1..8bad793ff 100644 --- a/src/plugins/php/weechat-php.c +++ b/src/plugins/php/weechat-php.c @@ -39,7 +39,15 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_php_plugin; -int php_quiet; +int php_quiet = 0; + +struct t_plugin_script *php_script_eval = NULL; +int php_eval_mode = 0; +int php_eval_send_input = 0; +int php_eval_exec_commands = 0; +struct t_gui_buffer *php_eval_buffer = NULL; +char *php_eval_output = NULL; + struct t_plugin_script *php_scripts = NULL; struct t_plugin_script *last_php_script = NULL; struct t_plugin_script *php_current_script = NULL; @@ -577,7 +585,15 @@ weechat_php_exec (struct t_plugin_script *script, int ret_type, } else { - WEECHAT_SCRIPT_MSG_WRONG_ARGS(PHP_CURRENT_SCRIPT_NAME, function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" " + "must return a valid " + "value"), + weechat_prefix ("error"), PHP_PLUGIN_NAME, + function); + } } } else @@ -589,6 +605,13 @@ weechat_php_exec (struct t_plugin_script *script, int ret_type, } zend_end_try (); + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: error in function \"%s\""), + weechat_prefix ("error"), PHP_PLUGIN_NAME, function); + } + /* Cleanup */ if (params) { @@ -608,13 +631,14 @@ weechat_php_exec (struct t_plugin_script *script, int ret_type, /* * Loads a PHP script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_php_load (const char *filename) +struct t_plugin_script * +weechat_php_load (const char *filename, const char *code) { zend_file_handle file_handle; @@ -647,7 +671,7 @@ weechat_php_load (const char *filename) weechat_gettext ("%s%s: function \"register\" not " "found (or failed) in file \"%s\""), weechat_prefix ("error"), PHP_PLUGIN_NAME, filename); - return 0; + return NULL; } php_current_script = php_registered_script; @@ -661,7 +685,7 @@ weechat_php_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, php_current_script->filename); - return 1; + return php_current_script; } /* @@ -674,7 +698,7 @@ weechat_php_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_php_load (filename); + weechat_php_load (filename, NULL); } /* @@ -782,7 +806,7 @@ weechat_php_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), PHP_PLUGIN_NAME, name); } - weechat_php_load (filename); + weechat_php_load (filename, NULL); free (filename); } } @@ -795,6 +819,27 @@ weechat_php_reload_name (const char *name) } /* + * Evaluates PHP code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_php_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + /* TODO: implement PHP eval */ + (void) buffer; + (void) send_to_buffer_as_input; + (void) exec_commands; + (void) code; + + return 1; +} + +/* * Callback for command "/php". */ @@ -803,12 +848,12 @@ weechat_php_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -878,7 +923,8 @@ weechat_php_command_cb (const void *pointer, void *data, /* load PHP script */ path_script = plugin_script_search_path (weechat_php_plugin, ptr_name); - weechat_php_load ((path_script) ? path_script : ptr_name); + weechat_php_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -894,6 +940,43 @@ weechat_php_command_cb (const void *pointer, void *data, } php_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_php_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + /* TODO: implement /php eval */ + weechat_printf (NULL, + "%sCommand \"/php eval\" is not yet implemented", + weechat_prefix ("error")); + } else WEECHAT_COMMAND_ERROR; } @@ -940,6 +1023,28 @@ weechat_php_hdata_cb (const void *pointer, void *data, } /* + * Returns PHP info "php_eval". + */ + +const char * +weechat_php_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + static const char *not_implemented = "not yet implemented"; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + (void) arguments; + return not_implemented; + + return NULL; +} + +/* * Returns infolist with PHP scripts. */ @@ -1142,6 +1247,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_php_command_cb; init.callback_completion = &weechat_php_completion_cb; init.callback_hdata = &weechat_php_hdata_cb; + init.callback_info_eval = &weechat_php_info_eval_cb; init.callback_infolist = &weechat_php_infolist_cb; init.callback_signal_debug_dump = &weechat_php_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_php_signal_script_action_cb; @@ -1178,6 +1284,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ php_quiet = 1; plugin_script_end (plugin, &php_scripts, &weechat_php_unload_all); + if (php_script_eval) + { + weechat_php_unload (php_script_eval); + php_script_eval = NULL; + } php_quiet = 0; if (weechat_php_func_map) @@ -1195,6 +1306,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (php_action_remove_list); if (php_action_autoload_list) free (php_action_autoload_list); + /* weechat_string_dyn_free (php_buffer_output, 1); */ + if (php_eval_output) + free (php_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/plugin-script.c b/src/plugins/plugin-script.c index 66955b9e8..fb69f7202 100644 --- a/src/plugins/plugin-script.c +++ b/src/plugins/plugin-script.c @@ -241,6 +241,7 @@ plugin_script_init (struct t_weechat_plugin *weechat_plugin, " || autoload" " || reload %s" " || unload %s" + " || eval" " || version", "%s", string); @@ -251,6 +252,7 @@ plugin_script_init (struct t_weechat_plugin *weechat_plugin, " || load [-q] <filename>" " || autoload" " || reload|unload [-q] [<name>]" + " || eval [-o|-oc] <code>" " || version"), N_(" list: list loaded scripts\n" "listfull: list loaded scripts (verbose)\n" @@ -260,9 +262,16 @@ plugin_script_init (struct t_weechat_plugin *weechat_plugin, "then load all scripts in \"autoload\" directory)\n" " unload: unload a script (if no name given, unload all scripts)\n" "filename: script (file) to load\n" + " -q: quiet mode: do not display messages\n" " name: a script name (name used in call to \"register\" " "function)\n" - " -q: quiet mode: do not display messages\n" + " eval: evaluate script code and display result on current " + "buffer\n" + " -o: send evaluation result to the buffer without executing " + "commands\n" + " -oc: send evaluation result to the buffer and execute " + "commands\n" + " code: the script code to evaluate\n" " version: display the version of interpreter used\n" "\n" "Without argument, this command lists all loaded scripts."), @@ -282,6 +291,10 @@ plugin_script_init (struct t_weechat_plugin *weechat_plugin, N_("script name (wildcard \"*\" is allowed) " "(optional)"), init->callback_infolist, NULL, NULL); + snprintf (string, sizeof (string), "%s_eval", weechat_plugin->name); + weechat_hook_info (string, N_("evaluation of script code"), + N_("code to execute"), + init->callback_info_eval, NULL, NULL); /* add signal for "debug_dump" */ weechat_hook_signal ("debug_dump", @@ -316,7 +329,7 @@ plugin_script_init (struct t_weechat_plugin *weechat_plugin, for (i = 0; i < argc; i++) { if ((strcmp (argv[i], "-s") == 0) - || (strcmp (argv[i], "--no-script") == 0)) + || (strcmp (argv[i], "--no-script") == 0)) { auto_load_scripts = 0; } @@ -707,6 +720,41 @@ plugin_script_insert_sorted (struct t_weechat_plugin *weechat_plugin, } /* + * Allocates a new script. + * + * Returns pointer to new script, NULL if error. + */ + +struct t_plugin_script * +plugin_script_alloc (const char *filename, const char *name, + const char *author, const char *version, + const char *license, const char *description, + const char *shutdown_func, const char *charset) +{ + struct t_plugin_script *new_script; + + new_script = malloc (sizeof (*new_script)); + if (!new_script) + return NULL; + + new_script->filename = strdup (filename); + new_script->interpreter = NULL; + new_script->name = strdup (name); + new_script->author = strdup (author); + new_script->version = strdup (version); + new_script->license = strdup (license); + new_script->description = strdup (description); + new_script->shutdown_func = (shutdown_func) ? + strdup (shutdown_func) : NULL; + new_script->charset = (charset) ? strdup (charset) : NULL; + new_script->unloading = 0; + new_script->prev_script = NULL; + new_script->next_script = NULL; + + return new_script; +} + +/* * Adds a script to list of scripts. * * Returns pointer to new script, NULL if error. @@ -743,32 +791,25 @@ plugin_script_add (struct t_weechat_plugin *weechat_plugin, license, name, weechat_plugin->license); } - new_script = malloc (sizeof (*new_script)); - if (new_script) + new_script = plugin_script_alloc (filename, name, author, version, license, + description, shutdown_func, charset); + if (!new_script) { - new_script->filename = strdup (filename); - new_script->interpreter = NULL; - new_script->name = strdup (name); - new_script->author = strdup (author); - new_script->version = strdup (version); - new_script->license = strdup (license); - new_script->description = strdup (description); - new_script->shutdown_func = (shutdown_func) ? - strdup (shutdown_func) : NULL; - new_script->charset = (charset) ? strdup (charset) : NULL; - new_script->unloading = 0; + weechat_printf (NULL, + _("%s: error loading script \"%s\" " + "(not enough memory)"), + weechat_plugin->name, name); + return NULL; + } + /* add script to the list (except the internal "eval" fake script) */ + if (strcmp (new_script->name, WEECHAT_SCRIPT_EVAL_NAME) != 0) + { plugin_script_insert_sorted (weechat_plugin, scripts, last_script, new_script); - - return new_script; } - weechat_printf (NULL, - _("%s: error loading script \"%s\" (not enough memory)"), - weechat_plugin->name, name); - - return NULL; + return new_script; } /* @@ -998,27 +1039,12 @@ plugin_script_remove_configs (struct t_weechat_plugin *weechat_plugin, } /* - * Removes a script from list of scripts. + * Frees a script. */ void -plugin_script_remove (struct t_weechat_plugin *weechat_plugin, - struct t_plugin_script **scripts, - struct t_plugin_script **last_script, - struct t_plugin_script *script) +plugin_script_free (struct t_plugin_script *script) { - script->unloading = 1; - - plugin_script_close_buffers (weechat_plugin, script); - - plugin_script_remove_bar_items (weechat_plugin, script); - - plugin_script_remove_configs (weechat_plugin, script); - - /* remove all hooks created by this script */ - weechat_unhook_all (script->name); - - /* free data */ if (script->filename) free (script->filename); if (script->name) @@ -1036,6 +1062,30 @@ plugin_script_remove (struct t_weechat_plugin *weechat_plugin, if (script->charset) free (script->charset); + free (script); +} + +/* + * Removes a script from list of scripts. + */ + +void +plugin_script_remove (struct t_weechat_plugin *weechat_plugin, + struct t_plugin_script **scripts, + struct t_plugin_script **last_script, + struct t_plugin_script *script) +{ + script->unloading = 1; + + plugin_script_close_buffers (weechat_plugin, script); + + plugin_script_remove_bar_items (weechat_plugin, script); + + plugin_script_remove_configs (weechat_plugin, script); + + /* remove all hooks created by this script */ + weechat_unhook_all (script->name); + /* remove script from list */ if (script->prev_script) (script->prev_script)->next_script = script->next_script; @@ -1046,8 +1096,8 @@ plugin_script_remove (struct t_weechat_plugin *weechat_plugin, if (*last_script == script) *last_script = script->prev_script; - /* free script */ - free (script); + /* free data and script */ + plugin_script_free (script); } /* @@ -1189,7 +1239,8 @@ void plugin_script_action_install (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script *scripts, void (*script_unload)(struct t_plugin_script *script), - int (*script_load)(const char *filename), + struct t_plugin_script *(*script_load)(const char *filename, + const char *code), int *quiet, char **list) { @@ -1302,7 +1353,7 @@ plugin_script_action_install (struct t_weechat_plugin *weechat_plugin, * - script was loaded */ if ((!existing_script && autoload) || script_loaded) - (*script_load) (new_path); + (*script_load) (new_path, NULL); } else { diff --git a/src/plugins/plugin-script.h b/src/plugins/plugin-script.h index 3f359cd20..324b199f8 100644 --- a/src/plugins/plugin-script.h +++ b/src/plugins/plugin-script.h @@ -27,10 +27,13 @@ enum t_weechat_script_exec_type WEECHAT_SCRIPT_EXEC_INT = 0, WEECHAT_SCRIPT_EXEC_STRING, WEECHAT_SCRIPT_EXEC_HASHTABLE, + WEECHAT_SCRIPT_EXEC_IGNORE, }; #define WEECHAT_SCRIPT_HASHTABLE_DEFAULT_SIZE 16 +#define WEECHAT_SCRIPT_EVAL_NAME "__eval__" + #define WEECHAT_SCRIPT_MSG_NOT_INIT(__current_script, \ __function) \ weechat_printf (NULL, \ @@ -78,6 +81,10 @@ struct t_plugin_script_init struct t_hdata *(*callback_hdata)(const void *pointer, void *data, const char *hdata_name); + const char *(*callback_info_eval)(const void *pointer, + void *data, + const char *info_name, + const char *arguments); struct t_infolist *(*callback_infolist)(const void *pointer, void *data, const char *infolist_name, @@ -119,13 +126,25 @@ extern struct t_plugin_script *plugin_script_search (struct t_weechat_plugin *we const char *name); extern char *plugin_script_search_path (struct t_weechat_plugin *weechat_plugin, const char *filename); +extern struct t_plugin_script *plugin_script_alloc (const char *filename, + const char *name, + const char *author, + const char *version, + const char *license, + const char *description, + const char *shutdown_func, + const char *charset); extern struct t_plugin_script *plugin_script_add (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script **scripts, struct t_plugin_script **last_script, - const char *filename, const char *name, - const char *author, const char *version, - const char *license, const char *description, - const char *shutdown_func, const char *charset); + const char *filename, + const char *name, + const char *author, + const char *version, + const char *license, + const char *description, + const char *shutdown_func, + const char *charset); extern void plugin_script_set_buffer_callbacks (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script *scripts, struct t_plugin_script *script, @@ -136,6 +155,7 @@ extern void plugin_script_set_buffer_callbacks (struct t_weechat_plugin *weechat int (*callback_buffer_close) (const void *pointer, void *data, struct t_gui_buffer *buffer)); +extern void plugin_script_free (struct t_plugin_script *script); extern void plugin_script_remove (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script **scripts, struct t_plugin_script **last_script, @@ -147,7 +167,8 @@ extern void plugin_script_action_add (char **action_list, const char *name); extern void plugin_script_action_install (struct t_weechat_plugin *weechat_plugin, struct t_plugin_script *scripts, void (*script_unload)(struct t_plugin_script *script), - int (*script_load)(const char *filename), + struct t_plugin_script *(*script_load)(const char *filename, + const char *code), int *quiet, char **list); extern void plugin_script_action_remove (struct t_weechat_plugin *weechat_plugin, diff --git a/src/plugins/python/weechat-python.c b/src/plugins/python/weechat-python.c index bade6c072..906ce1615 100644 --- a/src/plugins/python/weechat-python.c +++ b/src/plugins/python/weechat-python.c @@ -44,7 +44,23 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_python_plugin = NULL; -int python_quiet; +int python_quiet = 0; + +struct t_plugin_script *python_script_eval = NULL; +int python_eval_mode = 0; +int python_eval_send_input = 0; +int python_eval_exec_commands = 0; +struct t_gui_buffer *python_eval_buffer = NULL; +char *python_eval_output = NULL; +#define PYTHON_EVAL_SCRIPT \ + "import weechat\n" \ + "\n" \ + "def script_python_eval(code):\n" \ + " exec(code)\n" \ + "\n" \ + "weechat.register('" WEECHAT_SCRIPT_EVAL_NAME "', '', '1.0', " \ + "'" WEECHAT_LICENSE "', 'Evaluation of script code', '', '')\n" + struct t_plugin_script *python_scripts = NULL; struct t_plugin_script *last_python_script = NULL; struct t_plugin_script *python_current_script = NULL; @@ -53,6 +69,7 @@ const char *python_current_script_filename = NULL; PyThreadState *python_mainThreadState = NULL; PyThreadState *python_current_interpreter = NULL; char *python2_bin = NULL; +char **python_buffer_output = NULL; /* outputs subroutines */ static PyObject *weechat_python_output (PyObject *self, PyObject *args); @@ -111,8 +128,6 @@ char *python_action_remove_list = NULL; */ char *python_action_autoload_list = NULL; -char python_buffer_output[128]; - /* * Gets path to python 2.x interpreter. @@ -309,6 +324,102 @@ weechat_python_dict_to_hashtable (PyObject *dict, int size, } /* + * Flushes output. + */ + +void +weechat_python_output_flush () +{ + const char *ptr_command; + char *command; + int length; + + if (!*python_buffer_output[0]) + return; + + if (python_eval_mode) + { + /* if there's no buffer, we catch the output, so there's no flush */ + if (!python_eval_buffer) + return; + + if (python_eval_send_input) + { + if (python_eval_exec_commands) + ptr_command = *python_buffer_output; + else + ptr_command = weechat_string_input_for_buffer (*python_buffer_output); + if (ptr_command) + { + weechat_command (python_eval_buffer, *python_buffer_output); + } + else + { + length = 1 + strlen (*python_buffer_output) + 1; + command = malloc (length); + if (command) + { + snprintf (command, length, "%c%s", + *python_buffer_output[0], *python_buffer_output); + weechat_command (python_eval_buffer, + (command[0]) ? command : " "); + free (command); + } + } + } + else + { + weechat_printf (python_eval_buffer, "%s", *python_buffer_output); + } + } + else + { + /* script (no eval mode) */ + weechat_printf (NULL, + weechat_gettext ("%s: stdout/stderr: %s"), + PYTHON_PLUGIN_NAME, *python_buffer_output); + } + + weechat_string_dyn_copy (python_buffer_output, NULL); +} + +/* + * Redirection for stdout and stderr. + */ + +static PyObject * +weechat_python_output (PyObject *self, PyObject *args) +{ + char *msg, *ptr_msg, *ptr_newline; + + /* make C compiler happy */ + (void) self; + + msg = NULL; + + if (!PyArg_ParseTuple (args, "s", &msg)) + { + weechat_python_output_flush (); + } + else + { + ptr_msg = msg; + while ((ptr_newline = strchr (ptr_msg, '\n')) != NULL) + { + ptr_newline[0] = '\0'; + weechat_string_dyn_concat (python_buffer_output, ptr_msg); + weechat_python_output_flush (); + ptr_newline[0] = '\n'; + ptr_msg = ++ptr_newline; + } + weechat_string_dyn_concat (python_buffer_output, ptr_msg); + } + + Py_INCREF(Py_None); + return Py_None; +} + +/* * Executes a python function. */ @@ -371,6 +482,8 @@ weechat_python_exec (struct t_plugin_script *script, rc = PyObject_CallFunction (evFunc, NULL); } + weechat_python_output_flush (); + /* * ugly hack : rc = NULL while 'return weechat.WEECHAT_RC_OK .... * because of '#define WEECHAT_RC_OK 0' @@ -414,17 +527,23 @@ weechat_python_exec (struct t_plugin_script *script, } else { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must return " - "a valid value"), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME, function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME, + function); + } + Py_XDECREF(rc); } - if (!ret_value) + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) { weechat_printf (NULL, weechat_gettext ("%s%s: error in function \"%s\""), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME, function); + weechat_prefix ("error"), PYTHON_PLUGIN_NAME, + function); } /* PyEval_ReleaseThread (python_current_script->interpreter); */ @@ -439,62 +558,6 @@ end: } /* - * Redirection for stdout and stderr. - */ - -static PyObject * -weechat_python_output (PyObject *self, PyObject *args) -{ - char *msg, *m, *p; - - /* make C compiler happy */ - (void) self; - - msg = NULL; - - if (!PyArg_ParseTuple (args, "s", &msg)) - { - if (strlen(python_buffer_output) > 0) - { - weechat_printf (NULL, - weechat_gettext ("%s: stdout/stderr: %s%s"), - PYTHON_PLUGIN_NAME, python_buffer_output, ""); - python_buffer_output[0] = '\0'; - } - } - else - { - m = msg; - while ((p = strchr (m, '\n')) != NULL) - { - *p = '\0'; - if (strlen (m) + strlen (python_buffer_output) > 0) - { - weechat_printf (NULL, - weechat_gettext ("%s: stdout/stderr: %s%s"), - PYTHON_PLUGIN_NAME, python_buffer_output, m); - } - *p = '\n'; - python_buffer_output[0] = '\0'; - m = ++p; - } - - if (strlen(m) + strlen(python_buffer_output) > sizeof(python_buffer_output)) - { - weechat_printf (NULL, - weechat_gettext ("%s: stdout/stderr: %s%s"), - PYTHON_PLUGIN_NAME, python_buffer_output, m); - python_buffer_output[0] = '\0'; - } - else - strcat (python_buffer_output, m); - } - - Py_INCREF(Py_None); - return Py_None; -} - -/* * Initializes the "weechat" module. */ @@ -582,32 +645,82 @@ void weechat_python_init_module_weechat () } /* + * Sets weechat output (to redirect stdout/stderr to WeeChat buffer). + */ + +void +weechat_python_set_output () +{ + PyObject *weechat_outputs; + +#if PY_MAJOR_VERSION >= 3 + /* python >= 3.x */ + weechat_outputs = PyModule_Create (&moduleDefOutputs); +#else + /* python <= 2.x */ + weechat_outputs = Py_InitModule("weechatOutputs", + weechat_python_output_funcs); +#endif /* PY_MAJOR_VERSION >= 3 */ + + if (weechat_outputs) + { + if (PySys_SetObject("stdout", weechat_outputs) == -1) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: unable to redirect stdout"), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + } + if (PySys_SetObject("stderr", weechat_outputs) == -1) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: unable to redirect stderr"), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + } + } + else + { + weechat_printf (NULL, + weechat_gettext ("%s%s: unable to redirect stdout and " + "stderr"), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + } +} + +/* * Loads a python script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_python_load (const char *filename) +struct t_plugin_script * +weechat_python_load (const char *filename, const char *code) { char *argv[] = { "__weechat_plugin__" , NULL }; #if PY_MAJOR_VERSION >= 3 wchar_t *wargv[] = { NULL, NULL }; #endif /* PY_MAJOR_VERSION >= 3 */ FILE *fp; - PyObject *weechat_outputs, *python_path, *path; + PyObject *python_path, *path, *module_main, *globals, *rc; const char *weechat_home; char *str_home; int len; - if ((fp = fopen (filename, "r")) == NULL) + fp = NULL; + + if (!code) { - weechat_printf (NULL, - weechat_gettext ("%s%s: script \"%s\" not found"), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME, filename); - return 0; + fp = fopen (filename, "r"); + if (!fp) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: script \"%s\" not found"), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME, + filename); + return NULL; + } } if ((weechat_python_plugin->debug >= 2) || !python_quiet) @@ -648,9 +761,10 @@ weechat_python_load (const char *filename) weechat_gettext ("%s%s: unable to create new " "sub-interpreter"), weechat_prefix ("error"), PYTHON_PLUGIN_NAME); - fclose (fp); + if (fp) + fclose (fp); /* PyEval_ReleaseLock (); */ - return 0; + return NULL; } PyThreadState_Swap (python_current_interpreter); @@ -681,70 +795,76 @@ weechat_python_load (const char *filename) } } -#if PY_MAJOR_VERSION >= 3 - /* python >= 3.x */ - weechat_outputs = PyModule_Create (&moduleDefOutputs); -#else - /* python <= 2.x */ - weechat_outputs = Py_InitModule("weechatOutputs", - weechat_python_output_funcs); -#endif /* PY_MAJOR_VERSION >= 3 */ + weechat_python_set_output (); - if (!weechat_outputs) - { - weechat_printf (NULL, - weechat_gettext ("%s%s: unable to redirect stdout and " - "stderr"), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME); - } - else + python_current_script_filename = filename; + + if (code) { - if (PySys_SetObject("stdout", weechat_outputs) == -1) + /* execute code without reading file */ + module_main = PyImport_AddModule ("__main__"); + globals = PyModule_GetDict (module_main); + rc = PyRun_String (code, Py_file_input, globals, NULL); + if (PyErr_Occurred ()) { weechat_printf (NULL, - weechat_gettext ("%s%s: unable to redirect stdout"), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + weechat_gettext ("%s%s: unable to create eval script"), + weechat_prefix ("error"), + PYTHON_PLUGIN_NAME); + PyErr_Print (); + if (rc) + Py_XDECREF(rc); + + /* if script was registered, remove it from list */ + if (python_current_script) + { + plugin_script_remove (weechat_python_plugin, + &python_scripts, &last_python_script, + python_current_script); + python_current_script = NULL; + } + + Py_EndInterpreter (python_current_interpreter); + /* PyEval_ReleaseLock (); */ + + return NULL; } - if (PySys_SetObject("stderr", weechat_outputs) == -1) + if (rc) + Py_XDECREF(rc); + } + else + { + /* read and execute code from file */ + if (PyRun_SimpleFile (fp, filename) != 0) { weechat_printf (NULL, - weechat_gettext ("%s%s: unable to redirect stderr"), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME); - } - } + weechat_gettext ("%s%s: unable to parse file \"%s\""), + weechat_prefix ("error"), PYTHON_PLUGIN_NAME, filename); + fclose (fp); - python_current_script_filename = filename; + if (PyErr_Occurred ()) + PyErr_Print (); - if (PyRun_SimpleFile (fp, filename) != 0) - { - weechat_printf (NULL, - weechat_gettext ("%s%s: unable to parse file \"%s\""), - weechat_prefix ("error"), PYTHON_PLUGIN_NAME, filename); - fclose (fp); + /* if script was registered, remove it from list */ + if (python_current_script) + { + plugin_script_remove (weechat_python_plugin, + &python_scripts, &last_python_script, + python_current_script); + python_current_script = NULL; + } - if (PyErr_Occurred ()) - PyErr_Print (); + Py_EndInterpreter (python_current_interpreter); + /* PyEval_ReleaseLock (); */ - /* if script was registered, remove it from list */ - if (python_current_script) - { - plugin_script_remove (weechat_python_plugin, - &python_scripts, &last_python_script, - python_current_script); - python_current_script = NULL; + return NULL; } - - Py_EndInterpreter (python_current_interpreter); - /* PyEval_ReleaseLock (); */ - - return 0; + fclose (fp); } if (PyErr_Occurred ()) PyErr_Print (); - fclose (fp); - if (!python_registered_script) { weechat_printf (NULL, @@ -757,7 +877,7 @@ weechat_python_load (const char *filename) Py_EndInterpreter (python_current_interpreter); /* PyEval_ReleaseLock (); */ - return 0; + return NULL; } python_current_script = python_registered_script; @@ -777,7 +897,7 @@ weechat_python_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, python_current_script->filename); - return 1; + return python_current_script; } /* @@ -790,7 +910,7 @@ weechat_python_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_python_load (filename); + weechat_python_load (filename, NULL); } /* @@ -910,7 +1030,7 @@ weechat_python_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), PYTHON_PLUGIN_NAME, name); } - weechat_python_load (filename); + weechat_python_load (filename, NULL); free (filename); } } @@ -923,6 +1043,56 @@ weechat_python_reload_name (const char *name) } /* + * Evaluates python code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_python_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + void *func_argv[1], *result; + + if (!python_script_eval) + { + python_quiet = 1; + python_script_eval = weechat_python_load (WEECHAT_SCRIPT_EVAL_NAME, + PYTHON_EVAL_SCRIPT); + python_quiet = 0; + if (!python_script_eval) + return 0; + } + + weechat_python_output_flush (); + + python_eval_mode = 1; + python_eval_send_input = send_to_buffer_as_input; + python_eval_exec_commands = exec_commands; + python_eval_buffer = buffer; + + func_argv[0] = (char *)code; + result = weechat_python_exec (python_script_eval, + WEECHAT_SCRIPT_EXEC_IGNORE, + "script_python_eval", + "s", func_argv); + /* result is ignored */ + if (result) + free (result); + + weechat_python_output_flush (); + + python_eval_mode = 0; + python_eval_send_input = 0; + python_eval_exec_commands = 0; + python_eval_buffer = NULL; + + return 1; +} + +/* * Callback for command "/python". */ @@ -931,12 +1101,12 @@ weechat_python_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -1006,7 +1176,8 @@ weechat_python_command_cb (const void *pointer, void *data, /* load python script */ path_script = plugin_script_search_path (weechat_python_plugin, ptr_name); - weechat_python_load ((path_script) ? path_script : ptr_name); + weechat_python_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -1022,6 +1193,39 @@ weechat_python_command_cb (const void *pointer, void *data, } python_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_python_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + } else WEECHAT_COMMAND_ERROR; } @@ -1051,13 +1255,30 @@ weechat_python_completion_cb (const void *pointer, void *data, } /* - * Returns python info. + * Returns hdata for python scripts. + */ + +struct t_hdata * +weechat_python_hdata_cb (const void *pointer, void *data, + const char *hdata_name) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + + return plugin_script_hdata_script (weechat_plugin, + &python_scripts, &last_python_script, + hdata_name); +} + +/* + * Returns python info "python2_bin". */ const char * -weechat_python_info_cb (const void *pointer, void *data, - const char *info_name, - const char *arguments) +weechat_python_info_python2_bin_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) { int rc; struct stat stat_buf; @@ -1065,40 +1286,42 @@ weechat_python_info_cb (const void *pointer, void *data, /* make C compiler happy */ (void) pointer; (void) data; + (void) info_name; (void) arguments; - if (weechat_strcasecmp (info_name, "python2_bin") == 0) + if (python2_bin && (strcmp (python2_bin, "python") != 0)) { - if (python2_bin && (strcmp (python2_bin, "python") != 0)) + rc = stat (python2_bin, &stat_buf); + if ((rc != 0) || (!S_ISREG(stat_buf.st_mode))) { - rc = stat (python2_bin, &stat_buf); - if ((rc != 0) || (!S_ISREG(stat_buf.st_mode))) - { - free (python2_bin); - python2_bin = weechat_python_get_python2_bin (); - } + free (python2_bin); + python2_bin = weechat_python_get_python2_bin (); } - return python2_bin; } - - return NULL; + return python2_bin; } /* - * Returns hdata for python scripts. + * Returns python info "python_eval". */ -struct t_hdata * -weechat_python_hdata_cb (const void *pointer, void *data, - const char *hdata_name) +const char * +weechat_python_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) { /* make C compiler happy */ (void) pointer; (void) data; + (void) info_name; - return plugin_script_hdata_script (weechat_plugin, - &python_scripts, &last_python_script, - hdata_name); + weechat_python_eval (NULL, 0, 0, (arguments) ? arguments : ""); + if (python_eval_output) + free (python_eval_output); + python_eval_output = strdup (*python_buffer_output); + weechat_string_dyn_copy (python_buffer_output, NULL); + + return python_eval_output; } /* @@ -1262,6 +1485,11 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) ""); #endif /* PY_VERSION */ + /* init stdout/stderr buffer */ + python_buffer_output = weechat_string_dyn_alloc (256); + if (!python_buffer_output) + return WEECHAT_RC_ERROR; + /* * hook info to get path to python 2.x interpreter * (some scripts using hook_process need that) @@ -1270,10 +1498,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_hook_info ("python2_bin", N_("path to python 2.x interpreter"), NULL, - &weechat_python_info_cb, NULL, NULL); - - /* init stdout/stderr buffer */ - python_buffer_output[0] = '\0'; + &weechat_python_info_python2_bin_cb, NULL, NULL); PyImport_AppendInittab("weechat", &weechat_python_init_module_weechat); @@ -1285,6 +1510,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_gettext ("%s%s: unable to launch global " "interpreter"), weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + weechat_string_dyn_free (python_buffer_output, 1); return WEECHAT_RC_ERROR; } @@ -1299,12 +1525,14 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_gettext ("%s%s: unable to get current " "interpreter state"), weechat_prefix ("error"), PYTHON_PLUGIN_NAME); + weechat_string_dyn_free (python_buffer_output, 1); return WEECHAT_RC_ERROR; } init.callback_command = &weechat_python_command_cb; init.callback_completion = &weechat_python_completion_cb; init.callback_hdata = &weechat_python_hdata_cb; + init.callback_info_eval = &weechat_python_info_eval_cb; init.callback_infolist = &weechat_python_infolist_cb; init.callback_signal_debug_dump = &weechat_python_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_python_signal_script_action_cb; @@ -1331,6 +1559,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ python_quiet = 1; plugin_script_end (plugin, &python_scripts, &weechat_python_unload_all); + if (python_script_eval) + { + weechat_python_unload (python_script_eval); + python_script_eval = NULL; + } python_quiet = 0; /* free python interpreter */ @@ -1359,6 +1592,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (python_action_remove_list); if (python_action_autoload_list) free (python_action_autoload_list); + weechat_string_dyn_free (python_buffer_output, 1); + if (python_eval_output) + free (python_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/ruby/weechat-ruby.c b/src/plugins/ruby/weechat-ruby.c index 7d7f15ca0..039a33730 100644 --- a/src/plugins/ruby/weechat-ruby.c +++ b/src/plugins/ruby/weechat-ruby.c @@ -67,12 +67,31 @@ struct t_weechat_plugin *weechat_ruby_plugin = NULL; int ruby_quiet = 0; int ruby_hide_errors = 0; + +struct t_plugin_script *ruby_script_eval = NULL; +int ruby_eval_mode = 0; +int ruby_eval_send_input = 0; +int ruby_eval_exec_commands = 0; +struct t_gui_buffer *ruby_eval_buffer = NULL; +char *ruby_eval_output = NULL; +#define RUBY_EVAL_SCRIPT \ + "def weechat_init\n" \ + " Weechat.register('" WEECHAT_SCRIPT_EVAL_NAME "', '', '1.0', " \ + "'" WEECHAT_LICENSE "', 'Evaluation of script code', '', '')\n" \ + " return Weechat::WEECHAT_RC_OK\n" \ + "end\n" \ + "\n" \ + "def script_ruby_eval(code)\n" \ + " module_eval(code)\n" \ + "end\n" + struct t_plugin_script *ruby_scripts = NULL; struct t_plugin_script *last_ruby_script = NULL; struct t_plugin_script *ruby_current_script = NULL; struct t_plugin_script *ruby_registered_script = NULL; const char *ruby_current_script_filename = NULL; VALUE ruby_current_module; +char **ruby_buffer_output = NULL; /* * string used to execute action "install": @@ -103,8 +122,6 @@ VALUE ruby_mWeechat, ruby_mWeechatOutputs; #define MOD_NAME_PREFIX "WeechatRubyModule" int ruby_num = 0; -char ruby_buffer_output[128]; - typedef struct protect_call_arg { VALUE recv; ID mid; @@ -319,6 +336,114 @@ weechat_ruby_print_exception (VALUE err) } /* + * Function used for compatibility. + */ + +static VALUE +weechat_ruby_output_flush_ruby (VALUE self) +{ + /* make C compiler happy */ + (void) self; + + return Qnil; +} + +/* + * Flushes output. + */ + +void +weechat_ruby_output_flush () +{ + const char *ptr_command; + char *command; + int length; + + if (!*ruby_buffer_output[0]) + return; + + if (ruby_eval_mode) + { + /* if there's no buffer, we catch the output, so there's no flush */ + if (!ruby_eval_buffer) + return; + + if (ruby_eval_send_input) + { + if (ruby_eval_exec_commands) + ptr_command = *ruby_buffer_output; + else + ptr_command = weechat_string_input_for_buffer (*ruby_buffer_output); + if (ptr_command) + { + weechat_command (ruby_eval_buffer, *ruby_buffer_output); + } + else + { + length = 1 + strlen (*ruby_buffer_output) + 1; + command = malloc (length); + if (command) + { + snprintf (command, length, "%c%s", + *ruby_buffer_output[0], *ruby_buffer_output); + weechat_command (ruby_eval_buffer, + (command[0]) ? command : " "); + free (command); + } + } + } + else + { + weechat_printf (ruby_eval_buffer, "%s", *ruby_buffer_output); + } + } + else + { + /* script (no eval mode) */ + weechat_printf (NULL, + weechat_gettext ("%s: stdout/stderr: %s"), + RUBY_PLUGIN_NAME, *ruby_buffer_output); + } + + weechat_string_dyn_copy (ruby_buffer_output, NULL); +} + +/* + * Redirection for stdout and stderr. + */ + +static VALUE +weechat_ruby_output (VALUE self, VALUE str) +{ + char *msg, *m, *p; + + /* make C compiler happy */ + (void) self; + + if (ruby_hide_errors) + return Qnil; + + msg = strdup (StringValuePtr (str)); + + m = msg; + while ((p = strchr (m, '\n')) != NULL) + { + *p = '\0'; + weechat_string_dyn_concat (ruby_buffer_output, m); + weechat_ruby_output_flush (); + *p = '\n'; + m = ++p; + } + + weechat_string_dyn_concat (ruby_buffer_output, m); + + if (msg) + free (msg); + + return Qnil; +} + +/* * Executes a ruby function. */ @@ -333,6 +458,8 @@ weechat_ruby_exec (struct t_plugin_script *script, void *ret_value; struct t_plugin_script *old_ruby_current_script; + ret_value = NULL; + old_ruby_current_script = ruby_current_script; ruby_current_script = script; @@ -370,6 +497,8 @@ weechat_ruby_exec (struct t_plugin_script *script, &ruby_error, 0, NULL); } + weechat_ruby_output_flush (); + if (ruby_error) { weechat_printf (NULL, @@ -405,114 +534,55 @@ weechat_ruby_exec (struct t_plugin_script *script, } else { - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must return a " - "valid value"), - weechat_prefix ("error"), RUBY_PLUGIN_NAME, function); - ruby_current_script = old_ruby_current_script; - return WEECHAT_RC_OK; - } - - if (ret_value == NULL) - { - weechat_printf (NULL, - weechat_gettext ("%s%s: not enough memory in function " - "\"%s\""), - weechat_prefix ("error"), RUBY_PLUGIN_NAME, function); - ruby_current_script = old_ruby_current_script; - return NULL; - } - - ruby_current_script = old_ruby_current_script; - - return ret_value; -} - -/* - * Redirection for stdout and stderr. - */ - -static VALUE -weechat_ruby_output (VALUE self, VALUE str) -{ - char *msg, *p, *m; - - /* make C compiler happy */ - (void) self; - - if (ruby_hide_errors) - return Qnil; - - msg = strdup(StringValuePtr(str)); - - m = msg; - while ((p = strchr (m, '\n')) != NULL) - { - *p = '\0'; - if (strlen (m) + strlen (ruby_buffer_output) > 0) + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) { weechat_printf (NULL, - weechat_gettext ("%s%s: stdout/stderr: %s%s"), + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), weechat_prefix ("error"), RUBY_PLUGIN_NAME, - ruby_buffer_output, m); + function); } - *p = '\n'; - ruby_buffer_output[0] = '\0'; - m = ++p; } - if (strlen(m) + strlen(ruby_buffer_output) > sizeof(ruby_buffer_output)) + if ((ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) && !ret_value) { weechat_printf (NULL, - weechat_gettext ("%s%s: stdout/stderr: %s%s"), - weechat_prefix ("error"), RUBY_PLUGIN_NAME, - ruby_buffer_output, m); - ruby_buffer_output[0] = '\0'; + weechat_gettext ("%s%s: error in function \"%s\""), + weechat_prefix ("error"), RUBY_PLUGIN_NAME, function); } - else - strcat (ruby_buffer_output, m); - - if (msg) - free (msg); - - return Qnil; -} -/* - * Function used for compatibility. - */ - -static VALUE -weechat_ruby_output_flush (VALUE self) -{ - /* make C compiler happy */ - (void) self; + ruby_current_script = old_ruby_current_script; - return Qnil; + return ret_value; } /* * Loads a ruby script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_ruby_load (const char *filename) +struct t_plugin_script * +weechat_ruby_load (const char *filename, const char *code) { char modname[64]; VALUE ruby_retcode, err, argv[1]; int ruby_error; struct stat buf; - if (stat (filename, &buf) != 0) + if (!code) { - weechat_printf (NULL, - weechat_gettext ("%s%s: script \"%s\" not found"), - weechat_prefix ("error"), RUBY_PLUGIN_NAME, filename); - return 0; + if (stat (filename, &buf) != 0) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: script \"%s\" not found"), + weechat_prefix ("error"), RUBY_PLUGIN_NAME, + filename); + return NULL; + } } if ((weechat_ruby_plugin->debug >= 2) || !ruby_quiet) @@ -533,15 +603,16 @@ weechat_ruby_load (const char *filename) ruby_current_script_filename = filename; argv[0] = rb_str_new2 (filename); + argv[1] = rb_str_new2 ((code) ? code : ""); ruby_retcode = rb_protect_funcall (ruby_current_module, rb_intern ("load_eval_file"), - &ruby_error, 1, argv); + &ruby_error, 2, argv); if (ruby_retcode == Qnil) { err = rb_gv_get("$!"); weechat_ruby_print_exception(err); - return 0; + return NULL; } if (NUM2INT(ruby_retcode) != 0) @@ -578,7 +649,7 @@ weechat_ruby_load (const char *filename) "@load_eval_file_error")); } - return 0; + return NULL; } (void) rb_protect_funcall (ruby_current_module, rb_intern ("weechat_init"), @@ -602,7 +673,7 @@ weechat_ruby_load (const char *filename) ruby_current_script = NULL; } - return 0; + return NULL; } if (!ruby_registered_script) @@ -611,7 +682,7 @@ weechat_ruby_load (const char *filename) weechat_gettext ("%s%s: function \"register\" not " "found (or failed) in file \"%s\""), weechat_prefix ("error"), RUBY_PLUGIN_NAME, filename); - return 0; + return NULL; } ruby_current_script = ruby_registered_script; @@ -631,7 +702,7 @@ weechat_ruby_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, ruby_current_script->filename); - return 1; + return ruby_current_script; } /* @@ -644,7 +715,7 @@ weechat_ruby_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_ruby_load (filename); + weechat_ruby_load (filename, NULL); } /* @@ -745,7 +816,7 @@ weechat_ruby_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), RUBY_PLUGIN_NAME, name); } - weechat_ruby_load (filename); + weechat_ruby_load (filename, NULL); free (filename); } } @@ -771,6 +842,57 @@ weechat_ruby_unload_all () } /* + * Evaluates ruby code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_ruby_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + void *func_argv[1], *result; + char empty_arg[1] = { '\0' }; + + if (!ruby_script_eval) + { + ruby_quiet = 1; + ruby_script_eval = weechat_ruby_load (WEECHAT_SCRIPT_EVAL_NAME, + RUBY_EVAL_SCRIPT); + ruby_quiet = 0; + if (!ruby_script_eval) + return 0; + } + + weechat_ruby_output_flush (); + + ruby_eval_mode = 1; + ruby_eval_send_input = send_to_buffer_as_input; + ruby_eval_exec_commands = exec_commands; + ruby_eval_buffer = buffer; + + func_argv[0] = (code) ? (char *)code : empty_arg; + result = weechat_ruby_exec (ruby_script_eval, + WEECHAT_SCRIPT_EXEC_IGNORE, + "script_ruby_eval", + "s", func_argv); + /* result is ignored */ + if (result) + free (result); + + weechat_ruby_output_flush (); + + ruby_eval_mode = 0; + ruby_eval_send_input = 0; + ruby_eval_exec_commands = 0; + ruby_eval_buffer = NULL; + + return 1; +} + +/* * Callback for command "/ruby". */ @@ -779,12 +901,12 @@ weechat_ruby_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -854,7 +976,8 @@ weechat_ruby_command_cb (const void *pointer, void *data, /* load ruby script */ path_script = plugin_script_search_path (weechat_ruby_plugin, ptr_name); - weechat_ruby_load ((path_script) ? path_script : ptr_name); + weechat_ruby_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -870,6 +993,39 @@ weechat_ruby_command_cb (const void *pointer, void *data, } ruby_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_ruby_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + } else WEECHAT_COMMAND_ERROR; } @@ -916,6 +1072,29 @@ weechat_ruby_hdata_cb (const void *pointer, void *data, } /* + * Returns ruby info "ruby_eval". + */ + +const char * +weechat_ruby_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + weechat_ruby_eval (NULL, 0, 0, (arguments) ? arguments : ""); + if (ruby_eval_output) + free (ruby_eval_output); + ruby_eval_output = strdup (*ruby_buffer_output); + weechat_string_dyn_copy (ruby_buffer_output, NULL); + + return ruby_eval_output; +} + +/* * Returns infolist with ruby scripts. */ @@ -1061,6 +1240,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) { struct t_plugin_script_init init; int ruby_error; + VALUE err; char *weechat_ruby_code = { "$stdout = WeechatOutputs\n" "$stderr = WeechatOutputs\n" @@ -1081,12 +1261,16 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) "\n" "class Module\n" "\n" - " def load_eval_file (file)\n" - " lines = ''\n" - " begin\n" - " lines = File.read(file)\n" - " rescue => e\n" - " return 1\n" + " def load_eval_file (file, code)\n" + " if !code.empty?\n" + " lines = code\n" + " else\n" + " lines = ''\n" + " begin\n" + " lines = File.read(file)\n" + " rescue => e\n" + " return 1\n" + " end\n" " end\n" "\n" " begin\n" @@ -1113,6 +1297,10 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) "\n" " return 0\n" " end\n" + "\n" + " def eval_code (code)\n" + " module_eval(code)\n" + " end\n" "end\n" }; @@ -1132,7 +1320,9 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) ruby_error = 0; /* init stdout/stderr buffer */ - ruby_buffer_output[0] = '\0'; + ruby_buffer_output = weechat_string_dyn_alloc (256); + if (!ruby_buffer_output) + return WEECHAT_RC_ERROR; #if (defined(RUBY_API_VERSION_MAJOR) && defined(RUBY_API_VERSION_MINOR)) && (RUBY_API_VERSION_MAJOR >= 2 || (RUBY_API_VERSION_MAJOR == 1 && RUBY_API_VERSION_MINOR >= 9)) RUBY_INIT_STACK; @@ -1149,7 +1339,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) rb_define_singleton_method (ruby_mWeechatOutputs, "p", weechat_ruby_output, 1); rb_define_singleton_method (ruby_mWeechatOutputs, "flush", - weechat_ruby_output_flush, 0); + weechat_ruby_output_flush_ruby, 0); ruby_script ("__weechat_plugin__"); @@ -1163,8 +1353,9 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) weechat_gettext ("%s%s: unable to eval WeeChat ruby " "internal code"), weechat_prefix ("error"), RUBY_PLUGIN_NAME); - VALUE err = rb_gv_get ("$!"); + err = rb_gv_get ("$!"); weechat_ruby_print_exception (err); + weechat_string_dyn_free (ruby_buffer_output, 1); return WEECHAT_RC_ERROR; } @@ -1173,6 +1364,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_ruby_command_cb; init.callback_completion = &weechat_ruby_completion_cb; init.callback_hdata = &weechat_ruby_hdata_cb; + init.callback_info_eval = &weechat_ruby_info_eval_cb; init.callback_infolist = &weechat_ruby_infolist_cb; init.callback_signal_debug_dump = &weechat_ruby_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_ruby_signal_script_action_cb; @@ -1199,6 +1391,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ ruby_quiet = 1; plugin_script_end (plugin, &ruby_scripts, &weechat_ruby_unload_all); + if (ruby_script_eval) + { + weechat_ruby_unload (ruby_script_eval); + ruby_script_eval = NULL; + } ruby_quiet = 0; ruby_cleanup (0); @@ -1210,6 +1407,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (ruby_action_remove_list); if (ruby_action_autoload_list) free (ruby_action_autoload_list); + weechat_string_dyn_free (ruby_buffer_output, 1); + if (ruby_eval_output) + free (ruby_eval_output); return WEECHAT_RC_OK; } diff --git a/src/plugins/tcl/weechat-tcl.c b/src/plugins/tcl/weechat-tcl.c index 839175907..d06bfefb8 100644 --- a/src/plugins/tcl/weechat-tcl.c +++ b/src/plugins/tcl/weechat-tcl.c @@ -45,6 +45,14 @@ WEECHAT_PLUGIN_PRIORITY(4000); struct t_weechat_plugin *weechat_tcl_plugin = NULL; int tcl_quiet = 0; + +struct t_plugin_script *tcl_script_eval = NULL; +int tcl_eval_mode = 0; +int tcl_eval_send_input = 0; +int tcl_eval_exec_commands = 0; +struct t_gui_buffer *tcl_eval_buffer = NULL; +char *tcl_eval_output = NULL; + struct t_plugin_script *tcl_scripts = NULL; struct t_plugin_script *last_tcl_script = NULL; struct t_plugin_script *tcl_current_script = NULL; @@ -237,8 +245,9 @@ weechat_tcl_exec (struct t_plugin_script *script, if (Tcl_EvalObjEx (interp, cmdlist, TCL_EVAL_DIRECT) == TCL_OK) { - Tcl_ListObjReplace (interp, cmdlist, 0, llength, 0, NULL); /* remove elements, decrement their ref count */ - Tcl_DecrRefCount (cmdlist); /* -1 */ + /* remove elements, decrement their ref count */ + Tcl_ListObjReplace (interp, cmdlist, 0, llength, 0, NULL); + Tcl_DecrRefCount (cmdlist); /* -1 */ ret_val = NULL; if (ret_type == WEECHAT_SCRIPT_EXEC_STRING) { @@ -269,15 +278,21 @@ weechat_tcl_exec (struct t_plugin_script *script, if (ret_val) return ret_val; - weechat_printf (NULL, - weechat_gettext ("%s%s: function \"%s\" must return a " - "valid value"), - weechat_prefix ("error"), TCL_PLUGIN_NAME, function); + if (ret_type != WEECHAT_SCRIPT_EXEC_IGNORE) + { + weechat_printf (NULL, + weechat_gettext ("%s%s: function \"%s\" must " + "return a valid value"), + weechat_prefix ("error"), TCL_PLUGIN_NAME, + function); + } + return NULL; } - Tcl_ListObjReplace (interp, cmdlist, 0, llength, 0, NULL); /* remove elements, decrement their ref count */ - Tcl_DecrRefCount (cmdlist); /* -1 */ + /* remove elements, decrement their ref count */ + Tcl_ListObjReplace (interp, cmdlist, 0, llength, 0, NULL); + Tcl_DecrRefCount (cmdlist); /* -1 */ weechat_printf (NULL, weechat_gettext ("%s%s: unable to run function \"%s\": %s"), weechat_prefix ("error"), TCL_PLUGIN_NAME, function, @@ -290,13 +305,14 @@ weechat_tcl_exec (struct t_plugin_script *script, /* * Loads a tcl script. * - * Returns: - * 1: OK - * 0: error + * If code is NULL, the content of filename is read and executed. + * If code is not NULL, it is executed (the file is not read). + * + * Returns pointer to new registered script, NULL if error. */ -int -weechat_tcl_load (const char *filename) +struct t_plugin_script * +weechat_tcl_load (const char *filename, const char *code) { int i; Tcl_Interp *interp; @@ -307,7 +323,7 @@ weechat_tcl_load (const char *filename) weechat_printf (NULL, weechat_gettext ("%s%s: script \"%s\" not found"), weechat_prefix ("error"), TCL_PLUGIN_NAME, filename); - return 0; + return NULL; } if ((weechat_tcl_plugin->debug >= 2) || !tcl_quiet) @@ -325,7 +341,7 @@ weechat_tcl_load (const char *filename) weechat_gettext ("%s%s: unable to create new " "interpreter"), weechat_prefix ("error"), TCL_PLUGIN_NAME); - return 0; + return NULL; } tcl_current_script_filename = filename; @@ -348,7 +364,7 @@ weechat_tcl_load (const char *filename) tcl_current_script = NULL; } - return 0; + return NULL; } if (!tcl_registered_script) @@ -358,7 +374,7 @@ weechat_tcl_load (const char *filename) "found (or failed) in file \"%s\""), weechat_prefix ("error"), TCL_PLUGIN_NAME, filename); Tcl_DeleteInterp (interp); - return 0; + return NULL; } tcl_current_script = tcl_registered_script; @@ -376,7 +392,7 @@ weechat_tcl_load (const char *filename) WEECHAT_HOOK_SIGNAL_STRING, tcl_current_script->filename); - return 1; + return tcl_current_script; } /* @@ -389,7 +405,7 @@ weechat_tcl_load_cb (void *data, const char *filename) /* make C compiler happy */ (void) data; - weechat_tcl_load (filename); + weechat_tcl_load (filename, NULL); } /* @@ -501,7 +517,7 @@ weechat_tcl_reload_name (const char *name) weechat_gettext ("%s: script \"%s\" unloaded"), TCL_PLUGIN_NAME, name); } - weechat_tcl_load (filename); + weechat_tcl_load (filename, NULL); free (filename); } } @@ -514,6 +530,27 @@ weechat_tcl_reload_name (const char *name) } /* + * Evaluates tcl code. + * + * Returns: + * 1: OK + * 0: error + */ + +int +weechat_tcl_eval (struct t_gui_buffer *buffer, int send_to_buffer_as_input, + int exec_commands, const char *code) +{ + /* TODO: implement tcl eval */ + (void) buffer; + (void) send_to_buffer_as_input; + (void) exec_commands; + (void) code; + + return 1; +} + +/* * Callback for command "/tcl". */ @@ -522,12 +559,12 @@ weechat_tcl_command_cb (const void *pointer, void *data, struct t_gui_buffer *buffer, int argc, char **argv, char **argv_eol) { - char *ptr_name, *path_script; + char *ptr_name, *ptr_code, *path_script; + int i, send_to_buffer_as_input, exec_commands; /* make C compiler happy */ (void) pointer; (void) data; - (void) buffer; if (argc == 1) { @@ -597,7 +634,8 @@ weechat_tcl_command_cb (const void *pointer, void *data, /* load tcl script */ path_script = plugin_script_search_path (weechat_tcl_plugin, ptr_name); - weechat_tcl_load ((path_script) ? path_script : ptr_name); + weechat_tcl_load ((path_script) ? path_script : ptr_name, + NULL); if (path_script) free (path_script); } @@ -613,6 +651,43 @@ weechat_tcl_command_cb (const void *pointer, void *data, } tcl_quiet = 0; } + else if (weechat_strcasecmp (argv[1], "eval") == 0) + { + send_to_buffer_as_input = 0; + exec_commands = 0; + ptr_code = argv_eol[2]; + for (i = 2; i < argc; i++) + { + if (argv[i][0] == '-') + { + if (strcmp (argv[i], "-o") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 0; + ptr_code = argv_eol[i + 1]; + } + else if (strcmp (argv[i], "-oc") == 0) + { + if (i + 1 >= argc) + WEECHAT_COMMAND_ERROR; + send_to_buffer_as_input = 1; + exec_commands = 1; + ptr_code = argv_eol[i + 1]; + } + } + else + break; + } + if (!weechat_tcl_eval (buffer, send_to_buffer_as_input, + exec_commands, ptr_code)) + WEECHAT_COMMAND_ERROR; + /* TODO: implement /tcl eval */ + weechat_printf (NULL, + "%sCommand \"/tcl eval\" is not yet implemented", + weechat_prefix ("error")); + } else WEECHAT_COMMAND_ERROR; } @@ -659,6 +734,28 @@ weechat_tcl_hdata_cb (const void *pointer, void *data, } /* + * Returns tcl info "tcl_eval". + */ + +const char * +weechat_tcl_info_eval_cb (const void *pointer, void *data, + const char *info_name, + const char *arguments) +{ + static const char *not_implemented = "not yet implemented"; + + /* make C compiler happy */ + (void) pointer; + (void) data; + (void) info_name; + + (void) arguments; + return not_implemented; + + return NULL; +} + +/* * Returns infolist with tcl scripts. */ @@ -820,6 +917,7 @@ weechat_plugin_init (struct t_weechat_plugin *plugin, int argc, char *argv[]) init.callback_command = &weechat_tcl_command_cb; init.callback_completion = &weechat_tcl_completion_cb; init.callback_hdata = &weechat_tcl_hdata_cb; + init.callback_info_eval = &weechat_tcl_info_eval_cb; init.callback_infolist = &weechat_tcl_infolist_cb; init.callback_signal_debug_dump = &weechat_tcl_signal_debug_dump_cb; init.callback_signal_script_action = &weechat_tcl_signal_script_action_cb; @@ -846,6 +944,11 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) /* unload all scripts */ tcl_quiet = 1; plugin_script_end (plugin, &tcl_scripts, &weechat_tcl_unload_all); + if (tcl_script_eval) + { + weechat_tcl_unload (tcl_script_eval); + tcl_script_eval = NULL; + } tcl_quiet = 0; /* free some data */ @@ -855,6 +958,9 @@ weechat_plugin_end (struct t_weechat_plugin *plugin) free (tcl_action_remove_list); if (tcl_action_autoload_list) free (tcl_action_autoload_list); + /* weechat_string_dyn_free (tcl_buffer_output, 1); */ + if (tcl_eval_output) + free (tcl_eval_output); return WEECHAT_RC_OK; } |