This repository has been archived on 2020-04-11. You can view files and clone it, but cannot push or open issues or pull requests.
gnoemoe/src/gm-script.c.old

664 lines
15 KiB
C

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#ifdef HASRUBY
#include <gtk/gtk.h>
#include <ruby.h>
#include <libgnomevfs/gnome-vfs-mime-utils.h>
#include <libgnomevfs/gnome-vfs.h>
#include <sys/stat.h>
#include <sys/types.h>
#include "debug.h"
#include "gm-world.h"
#include "gm-app.h"
#include "gm-script.h"
#include "gm-scripts-dialog.h"
#include "gm-net.h"
#include "gm-support.h"
#define RB_CALLBACK(x) (VALUE (*)())(x)
static VALUE script_world_name(VALUE self);
VALUE script_world_create(world *wld);
void script_world_class_init();
void script_client_class_init();
static VALUE cWorld, cClient;
static gboolean didInit = FALSE;
static GList *funcs = NULL;
static GList *scriptFiles = NULL;
static gchar *fileInsp;
static GList *mondirs = NULL;
void gm_script_monitor_cb(GnomeVFSMonitorHandle *handle,
const gchar *monitor_uri, const gchar *info_uri,
GnomeVFSMonitorEventType event_type,
gpointer user_data) {
gchar *filename = gnome_vfs_get_local_path_from_uri(info_uri);
switch (event_type) {
case GNOME_VFS_MONITOR_EVENT_CHANGED:
gm_script_reload_file(filename);
break;
case GNOME_VFS_MONITOR_EVENT_DELETED:
gm_script_remove_file(filename);
break;
case GNOME_VFS_MONITOR_EVENT_CREATED:
gm_script_add_file(filename);
break;
default:
g_free(filename);
return;
break;
}
if_scripts_update();
g_free(filename);
}
void
script_destroy_function(script_function *fi) {
g_free(fi->name);
g_free(fi->fname);
g_free(fi->filename);
g_free(fi->description);
g_free(fi);
}
script_function *
script_find(gchar *name) {
GList *func;
script_function *f;
for (func = funcs; func; func = func->next) {
f = (script_function *)func->data;
if (strcasecmp(f->name, name) == 0) {
return f;
}
}
return NULL;
}
gboolean
script_add(gchar *name, gchar *fname, gchar *description, gchar *filename) {
script_function *func;
gchar *basedir = PACKAGE_DATA_DIR "/" PACKAGE "/scripts";
if (script_find(name) == NULL) {
func = g_new(script_function, 1);
if (strncmp(filename, basedir, strlen(basedir)) == 0) {
func->type = ST_SHARE;
} else {
func->type = ST_USER;
}
func->name = g_strdup(name);
func->fname = g_strdup(fname);
func->filename = g_strdup(filename);
func->description = g_strdup(description);
funcs = g_list_append(funcs, func);
return TRUE;
} else {
return FALSE;
}
}
VALUE
register_func(int argc, VALUE *argv, VALUE self) {
char *name, *fname = NULL, *description = NULL;
gchar *msg;
if (argc > 1) {
name = rb_string_value_cstr(&argv[0]);
description = rb_string_value_cstr(&argv[1]);
if (argc == 2) {
fname = name;
} else {
fname = rb_string_value_cstr(&argv[2]);
}
if (script_add(name, fname, description, fileInsp)) {
msg = g_strdup_printf(_("Register function '%s' from '%s'"), name, fileInsp);
debug_msg(1, "register_func: adding script function %s from %s", name, fileInsp);
if_scripts_add(SCRIPTC_MSG, msg);
g_free(msg);
return Qtrue;
} else {
msg = g_strdup_printf(_("Script '%s' is already defined"), name);
debug_msg(1, "register_func: script function %s already defined!", name);
if_scripts_add(SCRIPTC_ERROR, msg);
g_free(msg);
return Qfalse;
}
} else {
return Qfalse;
}
}
VALUE
register_functions_wrap(VALUE arg) {
return rb_eval_string("register_functions");
}
void
script_define_world(VALUE *wld) {
rb_define_variable("$world", wld);
}
void
script_error() {
int c;
VALUE lasterr;
char *err;
gchar *msg;
VALUE ary;
if(!NIL_P(ruby_errinfo)) {
lasterr = rb_gv_get("$!");
err = RSTRING(rb_obj_as_string(lasterr))->ptr;
debug_msg(1, "script_error: Error while executing Ruby code: %s", err);
msg = g_strdup_printf(_("Error on executing: %s"), err);
if_scripts_add(SCRIPTC_ERROR, msg);
g_free(msg);
ary = rb_funcall(ruby_errinfo, rb_intern("backtrace"), 0);
debug_msg(1, "script_error: Ruby backtrace:");
if_scripts_add(SCRIPTC_ERROR, _("Ruby backtrace:"));
for (c = 0; c < RARRAY(ary)->len; c++) {
debug_msg(1, "script_error: \tfrom %s", RSTRING(RARRAY(ary)->ptr[c])->ptr);
msg = g_strdup_printf(_("\tfrom %s"), RSTRING(RARRAY(ary)->ptr[c])->ptr);
if_scripts_add(SCRIPTC_ERROR, msg);
g_free(msg);
}
}
}
int
do_ruby(VALUE (*body)(), VALUE arg) {
int status;
rb_protect(body, arg, &status);
if (status != 0) {
script_error();
ruby_cleanup(status);
return 0;
}
return 1;
}
VALUE
function_run(script_info *arg) {
VALUE ret;
gchar *argstr;
gchar *funcAll;
if (arg->argstr) {
argstr = str_escape(arg->argstr);
funcAll = g_strconcat(arg->name, "(\"", argstr, "\")", NULL);
g_free(argstr);
} else {
funcAll = g_strconcat(arg->name, "()", NULL);
}
ret = rb_eval_string(funcAll);
g_free(funcAll);
return ret;
}
gboolean
script_run(world *wld, script_function *f, gchar *argstr) {
VALUE rWld;
VALUE rClient;
gchar *msg;
script_info *info = g_new(script_info, 1);
info->name = g_strdup(f->fname);
if (argstr) {
info->argstr = g_strdup(argstr);
msg = g_strdup_printf(_("Run script '%s' from '%s' (%s)"), f->fname,
f->filename, argstr);
} else {
info->argstr = NULL;
msg = g_strdup_printf(_("Run script '%s' from '%s' ()"), f->fname,
f->filename);
}
if_scripts_add(SCRIPTC_RUN, msg);
g_free(msg);
do_ruby(RB_CALLBACK(rb_load_file), (VALUE) f->filename);
ruby_exec();
rWld = script_world_create(wld);
rb_define_variable("$world", &rWld);
rClient = rb_class_new_instance(0, NULL, cClient);
rb_define_variable("$client", &rClient);
do_ruby(RB_CALLBACK(function_run), (VALUE) info);
g_free(info->name);
if (info->argstr) {
g_free(info->argstr);
}
g_free(info);
return TRUE;
}
GList *script_get_scripts() {
return funcs;
}
GList *script_get_files() {
return scriptFiles;
}
void
script_register_functions(gchar *filename) {
gchar *msg;
fileInsp = filename;
debug_msg(1, "script_register_functions: registering functions in %s", filename);
msg = g_strdup_printf(_("Registering functions from '%s'"), filename);
if_scripts_add(SCRIPTC_MSG, msg);
g_free(msg);
if (!do_ruby(RB_CALLBACK(rb_load_file), (VALUE) filename)) {
return;
}
ruby_exec();
rb_define_global_function("register_func", &register_func, -1);
do_ruby(RB_CALLBACK(register_functions_wrap), 0);
}
void
script_remove_file(const gchar *uri) {
GList *f, *l;
script_function *func;
gchar *msg;
l = g_list_copy(scriptFiles);
for (f = l; f; f = f->next) {
if (strcmp(f->data, uri) == 0) {
scriptFiles = g_list_remove(scriptFiles, f->data);
g_free(f->data);
}
}
g_list_free(l);
l = g_list_copy(funcs);
for (f = l; f; f = f->next) {
func = (script_function *)(f->data);
if (strcmp(func->filename, uri) == 0) {
msg = g_strdup_printf(_("Removing function `%s' from `%s'!"), func->name,
func->filename);
debug_msg(1, "script_remove_file: %s", msg);
if_scripts_add(SCRIPTC_MSG, msg);
g_free(msg);
funcs = g_list_remove(funcs, func);
script_destroy_function(func);
}
}
g_list_free(l);
}
gboolean
script_add_file(const gchar *uri) {
GList *f;
gchar *msg;
for (f = scriptFiles; f; f = f->next) {
if (strcmp(f->data, uri) == 0) {
msg = g_strdup_printf(_("File `%s' already added!"), uri);
debug_msg(1, "script_add_file: %s", msg);
if_scripts_add(SCRIPTC_MSG, msg);
g_free(msg);
return FALSE;
}
}
msg = g_strdup_printf(_("File `%s' added!"), uri);
debug_msg(1, "script_add_file: %s", msg);
if_scripts_add(SCRIPTC_MSG, msg);
g_free(msg);
scriptFiles = g_list_append(scriptFiles, strdup(uri));
script_register_functions((gchar *)uri);
return TRUE;
}
void
script_reload_file(const gchar *uri) {
script_remove_file(uri);
script_add_file(uri);
}
void
script_check_dir(gchar *dirname) {
gchar *filename;
gchar *file;
GDir *d;
GnomeVFSMonitorHandle *handle;
if (g_file_test(dirname, G_FILE_TEST_EXISTS) &&
g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
if ((d = g_dir_open(dirname, 0, NULL))) {
while ((file = (gchar *)g_dir_read_name(d))) {
filename = g_strconcat(dirname, "/", file, NULL);
script_add_file(filename);
g_free(filename);
}
}
} else if (!g_file_test(dirname, G_FILE_TEST_EXISTS)) {
mkdir(dirname, 0750);
}
if (g_file_test(dirname, G_FILE_TEST_EXISTS)) {
gnome_vfs_monitor_add(&handle, dirname, GNOME_VFS_MONITOR_DIRECTORY,
script_monitor_cb, NULL);
mondirs = g_list_append(mondirs, handle);
}
}
void
script_init() {
gchar *path = g_strconcat(main_get_app_path(), "/scripts", NULL);
ruby_init();
if (!didInit) {
script_world_class_init();
script_client_class_init();
}
script_check_dir(path);
script_check_dir(PACKAGE_DATA_DIR "/" PACKAGE "/scripts");
g_free(path);
didInit = TRUE;
}
void
script_fini() {
GList *f;
script_function *fi;
gchar *filename;
for (f = funcs; f; f = f->next) {
fi = (script_function *)f->data;
script_destroy_function(fi);
}
g_list_free(funcs);
funcs = NULL;
for (f = scriptFiles; f; f = f->next) {
filename = (gchar *)(f->data);
g_free(filename);
}
g_list_free(scriptFiles);
scriptFiles = NULL;
for (f = mondirs; f; f = f->next) {
gnome_vfs_monitor_cancel((GnomeVFSMonitorHandle *)f->data);
}
g_list_free(mondirs);
mondirs = NULL;
ruby_finalize();
}
void
script_flush_and_reload() {
if_scripts_add(SCRIPTC_MSG, _("Flushing scripts..."));
script_fini();
if_scripts_add(SCRIPTC_MSG, _("Reloading scripts..."));
script_init();
}
/* CLASS FUNCTIONS */
static VALUE
script_world_name(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
return rb_str_new2(options_get_str(wld->settings, "name"));
}
static VALUE
script_world_host(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
return rb_str_new2(options_get_str(wld->settings, "host"));
}
static VALUE
script_world_port(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
return rb_str_new2(options_get_str(wld->settings, "port"));
}
static VALUE
script_world_writeln(VALUE self, VALUE str) {
world *wld;
gchar *strVal;
Data_Get_Struct(self, world, wld);
strVal = rb_string_value_cstr(&str);
world_writeln(wld, strVal);
return Qnil;
}
static VALUE
script_world_sendln(VALUE self, VALUE str) {
world *wld;
gchar *strVal;
Data_Get_Struct(self, world, wld);
strVal = rb_string_value_cstr(&str);
net_send_line(wld, (unsigned char *)strVal);
return Qnil;
}
static VALUE
script_world_input(VALUE self, VALUE str) {
world *wld;
gchar *strVal;
Data_Get_Struct(self, world, wld);
strVal = rb_string_value_cstr(&str);
world_process_input(wld, strVal);
return Qnil;
}
static VALUE
script_world_loaded(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
if (wld->loaded) {
return Qtrue;
} else {
return Qfalse;
}
}
static VALUE
script_world_connected(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
if (wld->net.state == NET_CONNECTED) {
return Qtrue;
} else {
return Qfalse;
}
}
static VALUE
script_world_quit(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
world_unload(wld);
return Qnil;
}
static VALUE
script_world_connect(int argc, VALUE *argv, VALUE self) {
world *wld;
gchar *strHost, *strPort;
Data_Get_Struct(self, world, wld);
if (argc == 0) {
strHost = options_get_str(wld->settings, "host");
} else {
strHost = rb_string_value_cstr(&(argv[0]));
}
if (argc == 0 || argc == 1) {
strPort = options_get_str(wld->settings, "port");
} else {
strPort = rb_string_value_cstr(&(argv[1]));
}
net_connect_to(wld, strHost, strPort);
return Qnil;
}
static VALUE
script_world_disconnect(VALUE self) {
world *wld;
Data_Get_Struct(self, world, wld);
net_do_disconnect(wld);
return Qnil;
}
void
script_world_class_init() {
cWorld = rb_define_class("World", rb_cObject);
rb_define_method(cWorld, "name", script_world_name, 0);
rb_define_method(cWorld, "host", script_world_host, 0);
rb_define_method(cWorld, "port", script_world_port, 0);
rb_define_method(cWorld, "writeln", script_world_writeln, 1);
rb_define_method(cWorld, "println", script_world_writeln, 1);
rb_define_method(cWorld, "sendln", script_world_sendln, 1);
rb_define_method(cWorld, "input", script_world_input, 1);
rb_define_method(cWorld, "quit", script_world_quit, 0);
rb_define_method(cWorld, "connect", script_world_connect, -1);
rb_define_method(cWorld, "disconnect", script_world_disconnect, 0);
rb_define_method(cWorld, "loaded?", script_world_loaded, 0);
rb_define_method(cWorld, "connected?", script_world_connected, 0);
}
VALUE
script_world_create(world *wld) {
VALUE tData = Data_Wrap_Struct(cWorld, 0, 0, wld);
return tData;
}
static VALUE
script_client_version(VALUE self) {
return rb_str_new2(VERSION);
}
static VALUE
script_client_worlds(VALUE self) {
GList *wld;
VALUE ar = rb_ary_new();
VALUE oWld;
for (wld = world_get_worlds(); wld; wld = wld->next) {
oWld = script_world_create((world *)(wld->data));
rb_ary_push(ar, oWld);
}
return ar;
}
static VALUE
script_client_open(VALUE self, VALUE str) {
world *wld;
gchar *strVal;
strVal = rb_string_value_cstr(&str);
wld = world_get_by_name(strVal);
if (wld == NULL) {
return Qfalse;
} else {
world_load(wld);
return Qtrue;
}
}
void
script_client_class_init() {
cClient = rb_define_class("Client", rb_cObject);
rb_define_method(cClient, "version", script_client_version, 0);
rb_define_method(cClient, "worlds", script_client_worlds, 0);
rb_define_method(cClient, "open", script_client_open, 1);
}
#endif