From: fliep Date: Tue, 13 Oct 2009 22:49:10 +0000 (+0000) Subject: Added chimara_if_run() which, given a game file, autodetects the type by its extensio... X-Git-Tag: v0.9~322 X-Git-Url: https://git.stderr.nl/gitweb?a=commitdiff_plain;h=0121bfb334acf7756e068776bf40890c6fe14e13;p=projects%2Fchimara%2Fchimara.git Added chimara_if_run() which, given a game file, autodetects the type by its extension and runs it. --- diff --git a/configure.ac b/configure.ac index 51a5cf2..1718592 100644 --- a/configure.ac +++ b/configure.ac @@ -26,8 +26,8 @@ AC_SUBST(LT_VERSION_INFO) ### DECLARE COMPILERS ######################################################### -AC_PROG_CC # C compiler AC_USE_SYSTEM_EXTENSIONS # Define _GNU_SOURCE if using GCC +AC_PROG_CC # C compiler AM_PROG_CC_C_O # Automake requires this for per-target CFLAGS AC_C_INLINE # Define inline keyword AC_PROG_YACC # Building nitfol requires yacc @@ -87,6 +87,12 @@ PKG_CHECK_MODULES([TEST], [ gmodule-2.0 ]) +# Plugin flags; include '-module' in each Makefile.am, because AC_SUBSTed +# variables are black boxes to Automake, so it has to know about it being a +# module in the makefile itself. +PLUGIN_LIBTOOL_FLAGS='-avoid-version -shared -export-symbols-regex "^glk"' +AC_SUBST(PLUGIN_LIBTOOL_FLAGS) + ### OUTPUT #################################################################### # Output platform-specific definitions to config.h diff --git a/interpreters/frotz/Makefile.am b/interpreters/frotz/Makefile.am index 02d88ef..f1a0100 100644 --- a/interpreters/frotz/Makefile.am +++ b/interpreters/frotz/Makefile.am @@ -1,12 +1,10 @@ -PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk" - pkglib_LTLIBRARIES = frotz.la frotz_la_SOURCES = buffer.c err.c fastmem.c files.c input.c main.c math.c \ object.c process.c quetzal.c random.c redirect.c sound.c stream.c table.c \ text.c variable.c glkscreen.c glkmisc.c frotz.h glkfrotz.h glkio.h setup.h frotz_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libchimara frotz_la_CFLAGS = -Wno-pointer-sign $(AM_CFLAGS) -frotz_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) +frotz_la_LDFLAGS = -module $(PLUGIN_LIBTOOL_FLAGS) frotzdocdir = $(datadir)/doc/$(PACKAGE)/frotz dist_frotzdoc_DATA = AUTHORS COPYING README TODO diff --git a/interpreters/git/Makefile.am b/interpreters/git/Makefile.am index 051eeb3..ac41315 100644 --- a/interpreters/git/Makefile.am +++ b/interpreters/git/Makefile.am @@ -1,5 +1,3 @@ -PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk" - # Automatically generate version.h MAJOR = 1 MINOR = 2 @@ -18,7 +16,7 @@ git_la_SOURCES = version.h git.h config.h compiler.h memory.h opcodes.h \ accel.c git_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libchimara git_la_CFLAGS = -DCHIMARA_EXTENSIONS -DUSE_INLINE $(AM_CFLAGS) -git_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) +git_la_LDFLAGS = -module $(PLUGIN_LIBTOOL_FLAGS) gitdocdir = $(datadir)/doc/$(PACKAGE)/git dist_gitdoc_DATA = README.txt diff --git a/interpreters/glulxe/Makefile.am b/interpreters/glulxe/Makefile.am index eb2b661..8c36f6a 100644 --- a/interpreters/glulxe/Makefile.am +++ b/interpreters/glulxe/Makefile.am @@ -1,5 +1,3 @@ -PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk" - pkglib_LTLIBRARIES = glulxe.la glulxe_la_SOURCES = accel.c exec.c files.c funcs.c gestalt.c gestalt.h glkop.c \ glulxe.h heap.c main.c opcodes.h operand.c osdepend.c profile.c search.c \ @@ -7,7 +5,7 @@ glulxe_la_SOURCES = accel.c exec.c files.c funcs.c gestalt.c gestalt.h glkop.c \ glulxe_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libchimara glulxe_la_CFLAGS = -Wall -Wmissing-prototypes -Wstrict-prototypes -Wno-unused \ -DOS_UNIX $(AM_CFLAGS) -glulxe_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) +glulxe_la_LDFLAGS = -module $(PLUGIN_LIBTOOL_FLAGS) glulxedocdir = $(datadir)/doc/$(PACKAGE)/glulxe dist_glulxedoc_DATA = README diff --git a/interpreters/nitfol/Makefile.am b/interpreters/nitfol/Makefile.am index ccb415a..c1031b1 100644 --- a/interpreters/nitfol/Makefile.am +++ b/interpreters/nitfol/Makefile.am @@ -1,5 +1,3 @@ -PLUGIN_LIBTOOL_FLAGS=-module -avoid-version -export-symbols-regex "^glk" - GRAPHICS = no_graph.c no_graph.h # GRAPHICS = graphics.c graphics.h BLORB = blorb.c @@ -25,7 +23,7 @@ nitfol_la_SOURCES = automap.c automap.h binary.h copying.h debug.c debug.h \ nodist_nitfol_la_SOURCES = copying.c dbg_help.h startunix.c nitfol_la_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/libchimara \ -DSMART_TOKENISER -DUSE_INLINE -nitfol_la_LDFLAGS = $(PLUGIN_LIBTOOL_FLAGS) +nitfol_la_LDFLAGS = -module $(PLUGIN_LIBTOOL_FLAGS) info_TEXINFOS = nitfol.texi nitfol_TEXINFOS = dbg_help.texi options.texi diff --git a/libchimara/Makefile.am b/libchimara/Makefile.am index dd20557..b7a79e3 100644 --- a/libchimara/Makefile.am +++ b/libchimara/Makefile.am @@ -37,15 +37,17 @@ libchimara_la_SOURCES = \ libchimara_la_CPPFLAGS = \ -DG_LOG_DOMAIN=\"Chimara\" \ -DLOCALEDIR=\""$(datadir)/locale"\" \ + -DPLUGINDIR=\""$(pkglibdir)"\" \ -I$(top_srcdir) libchimara_la_CFLAGS = @CHIMARA_CFLAGS@ $(AM_CFLAGS) libchimara_la_LIBADD = @CHIMARA_LIBS@ libchimara_la_LDFLAGS = -version-info $(LT_VERSION_INFO) \ -no-undefined \ - -export-symbols-regex "^(glk|chimara_glk|glkunix|giblorb|gidispatch|garglk)_" + -export-symbols-regex "^(glk|chimara|glkunix|giblorb|gidispatch|garglk)_" libchimara_includedir = $(includedir)/chimara/libchimara libchimara_include_HEADERS = \ chimara-glk.h \ + chimara-if.h \ glk.h \ glkstart.h \ gi_blorb.h \ diff --git a/libchimara/chimara-glk.c b/libchimara/chimara-glk.c index da44193..40fddfe 100644 --- a/libchimara/chimara-glk.c +++ b/libchimara/chimara-glk.c @@ -87,14 +87,14 @@ chimara_glk_init(ChimaraGlk *self) priv->default_styles = g_hash_table_new(g_str_hash, g_str_equal); priv->program = NULL; priv->thread = NULL; - priv->event_queue = NULL; - priv->event_lock = NULL; - priv->event_queue_not_empty = NULL; - priv->event_queue_not_full = NULL; - priv->abort_lock = NULL; + priv->event_queue = g_queue_new(); + priv->event_lock = g_mutex_new(); + priv->event_queue_not_empty = g_cond_new(); + priv->event_queue_not_full = g_cond_new(); + priv->abort_lock = g_mutex_new(); priv->abort_signalled = FALSE; - priv->arrange_lock = NULL; - priv->rearranged = NULL; + priv->arrange_lock = g_mutex_new(); + priv->rearranged = g_cond_new(); priv->needs_rearrange = FALSE; priv->ignore_next_arrange_event = FALSE; priv->interrupt_handler = NULL; @@ -547,31 +547,31 @@ chimara_glk_stopped(ChimaraGlk *self) static void chimara_glk_started(ChimaraGlk *self) { - /* TODO: Add default signal handler implementation here */ + /* Default signal handler */ } static void chimara_glk_waiting(ChimaraGlk *self) { - /* TODO: Add default signal handler */ + /* Default signal handler */ } static void chimara_glk_char_input(ChimaraGlk *self, guint window_rock, guint keysym) { - /* TODO: Add default signal handler */ + /* Default signal handler */ } static void chimara_glk_line_input(ChimaraGlk *self, guint window_rock, gchar *text) { - /* TODO: Add default signal handler */ + /* Default signal handler */ } static void chimara_glk_text_buffer_output(ChimaraGlk *self, guint window_rock, gchar *text) { - /* TODO: Add default signal handler */ + /* Default signal handler */ } /* G_PARAM_STATIC_STRINGS only appeared in GTK 2.13.0 */ @@ -738,18 +738,7 @@ chimara_glk_new(void) /* This is a library entry point; initialize the library */ chimara_init(); - ChimaraGlk *self = CHIMARA_GLK(g_object_new(CHIMARA_TYPE_GLK, NULL)); - ChimaraGlkPrivate *priv = CHIMARA_GLK_PRIVATE(self); - - priv->event_queue = g_queue_new(); - priv->event_lock = g_mutex_new(); - priv->event_queue_not_empty = g_cond_new(); - priv->event_queue_not_full = g_cond_new(); - priv->abort_lock = g_mutex_new(); - priv->arrange_lock = g_mutex_new(); - priv->rearranged = g_cond_new(); - - return GTK_WIDGET(self); + return GTK_WIDGET(g_object_new(CHIMARA_TYPE_GLK, NULL)); } /** @@ -1048,7 +1037,7 @@ glk_enter(struct StartupData *startup) * Return value: %TRUE if the Glk program was started successfully. */ gboolean -chimara_glk_run(ChimaraGlk *glk, gchar *plugin, int argc, char *argv[], GError **error) +chimara_glk_run(ChimaraGlk *glk, const gchar *plugin, int argc, char *argv[], GError **error) { g_return_val_if_fail(glk || CHIMARA_IS_GLK(glk), FALSE); g_return_val_if_fail(plugin, FALSE); @@ -1063,11 +1052,13 @@ chimara_glk_run(ChimaraGlk *glk, gchar *plugin, int argc, char *argv[], GError * if(!priv->program) { g_warning( "Error opening module: %s", g_module_error() ); + /* TODO: set error */ return FALSE; } if( !g_module_symbol(priv->program, "glk_main", (gpointer *) &startup->glk_main) ) { g_warning( "Error finding glk_main(): %s", g_module_error() ); + /* TODO: set error */ return FALSE; } diff --git a/libchimara/chimara-glk.h b/libchimara/chimara-glk.h index 32725de..fc3ab79 100644 --- a/libchimara/chimara-glk.h +++ b/libchimara/chimara-glk.h @@ -52,7 +52,7 @@ void chimara_glk_set_monospace_font_string(ChimaraGlk *glk, const gchar *font); PangoFontDescription *chimara_glk_get_monospace_font_description(ChimaraGlk *glk); void chimara_glk_set_spacing(ChimaraGlk *glk, guint spacing); guint chimara_glk_get_spacing(ChimaraGlk *glk); -gboolean chimara_glk_run(ChimaraGlk *glk, gchar *plugin, int argc, char *argv[], GError **error); +gboolean chimara_glk_run(ChimaraGlk *glk, const gchar *plugin, int argc, char *argv[], GError **error); void chimara_glk_stop(ChimaraGlk *glk); void chimara_glk_wait(ChimaraGlk *glk); diff --git a/libchimara/chimara-if.c b/libchimara/chimara-if.c index b740e5e..e3553b1 100644 --- a/libchimara/chimara-if.c +++ b/libchimara/chimara-if.c @@ -1,3 +1,5 @@ +#include +#include #include #include #include @@ -12,17 +14,24 @@ static gboolean supported_formats[CHIMARA_IF_NUM_FORMATS][CHIMARA_IF_NUM_INTERPR { TRUE, TRUE, FALSE, FALSE }, /* Z5 */ { TRUE, TRUE, FALSE, FALSE }, /* Z6 */ { TRUE, TRUE, FALSE, FALSE }, /* Z8 */ - { FALSE, FALSE, TRUE, TRUE } /* Glulx */ + { TRUE, TRUE, FALSE, FALSE }, /* Zblorb */ + { FALSE, FALSE, TRUE, TRUE }, /* Glulx */ + { FALSE, FALSE, TRUE, TRUE } /* Gblorb */ }; static gchar *format_names[CHIMARA_IF_NUM_FORMATS] = { N_("Z-code version 5"), N_("Z-code version 6"), N_("Z-code version 8"), - N_("Glulx") + N_("Blorbed Z-code"), + N_("Glulx"), + N_("Blorbed Glulx") }; static gchar *interpreter_names[CHIMARA_IF_NUM_INTERPRETERS] = { N_("Frotz"), N_("Nitfol"), N_("Glulxe"), N_("Git") }; +static gchar *plugin_names[CHIMARA_IF_NUM_INTERPRETERS] = { + "frotz", "nitfol", "glulxe", "git" +}; typedef struct _ChimaraIFPrivate { ChimaraIFInterpreter preferred_interpreter[CHIMARA_IF_NUM_FORMATS]; @@ -52,7 +61,9 @@ chimara_if_init(ChimaraIF *self) priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z5] = CHIMARA_IF_INTERPRETER_FROTZ; priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z6] = CHIMARA_IF_INTERPRETER_FROTZ; priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z8] = CHIMARA_IF_INTERPRETER_FROTZ; + priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z_BLORB] = CHIMARA_IF_INTERPRETER_FROTZ; priv->preferred_interpreter[CHIMARA_IF_FORMAT_GLULX] = CHIMARA_IF_INTERPRETER_GLULXE; + priv->preferred_interpreter[CHIMARA_IF_FORMAT_GLULX_BLORB] = CHIMARA_IF_INTERPRETER_GLULXE; } static void @@ -85,7 +96,7 @@ chimara_if_finalize(GObject *object) static void chimara_if_command(ChimaraIF *self, gchar *input, gchar *response) { - /* TODO: Add default signal handler */ + /* Default signal handler */ } static void @@ -134,7 +145,7 @@ chimara_if_new(void) void chimara_if_set_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format, ChimaraIFInterpreter interpreter) { - g_return_if_fail(self); + g_return_if_fail(self && CHIMARA_IS_IF(self)); g_return_if_fail(format < CHIMARA_IF_NUM_FORMATS); g_return_if_fail(format < CHIMARA_IF_NUM_INTERPRETERS); @@ -149,8 +160,115 @@ chimara_if_set_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format, Ch ChimaraIFInterpreter chimara_if_get_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format) { - g_return_val_if_fail(self, -1); + g_return_val_if_fail(self && CHIMARA_IS_IF(self), -1); g_return_val_if_fail(format < CHIMARA_IF_NUM_FORMATS, -1); CHIMARA_IF_USE_PRIVATE(self, priv); return priv->preferred_interpreter[format]; } + +/* Opens a '.la' file and finds the name of the plugin library. g_free() the + * string when done. */ +static gchar * +find_dlname(const gchar *pluginfile, GError **error) +{ + /* Find the name of the shared library */ + gchar *dlname; + FILE *plugin = fopen(pluginfile, "r"); + if(!plugin) + { + g_set_error(error, G_FILE_ERROR, errno, "Error opening '%s': %s", pluginfile, g_strerror(errno)); + return NULL; + } + gchar *line = NULL; + size_t buflen; + ssize_t length; + while((length = getline(&line, &buflen, plugin)) != -1) + { + if(g_str_has_prefix(line, "dlname='")) + { + dlname = g_strndup(line + 8, length - 10); + break; + } + } + free(line); + if(!dlname) + { + g_set_error(error, G_FILE_ERROR, errno, "Error reading '%s': %s", pluginfile, g_strerror(errno)); + return NULL; + } + if(fclose(plugin)) + { + g_set_error(error, G_FILE_ERROR, errno, "Error closing '%s': %s", pluginfile, g_strerror(errno)); + return NULL; + } + return dlname; +} + +gboolean +chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error) +{ + g_return_val_if_fail(self && CHIMARA_IS_IF(self), FALSE); + g_return_val_if_fail(gamefile, FALSE); + + CHIMARA_IF_USE_PRIVATE(self, priv); + + /* Find out what format the game is */ + /* TODO: Look inside the file instead of just looking at the extension */ + ChimaraIFFormat format = CHIMARA_IF_FORMAT_Z5; + if(g_str_has_suffix(gamefile, ".z5")) + format = CHIMARA_IF_FORMAT_Z5; + else if(g_str_has_suffix(gamefile, ".z6")) + format = CHIMARA_IF_FORMAT_Z6; + else if(g_str_has_suffix(gamefile, ".z8")) + format = CHIMARA_IF_FORMAT_Z8; + else if(g_str_has_suffix(gamefile, ".zlb") || g_str_has_suffix(gamefile, ".zblorb")) + format = CHIMARA_IF_FORMAT_Z_BLORB; + else if(g_str_has_suffix(gamefile, ".ulx")) + format = CHIMARA_IF_FORMAT_GLULX; + else if(g_str_has_suffix(gamefile, ".blb") || g_str_has_suffix(gamefile, ".blorb") || g_str_has_suffix(gamefile, ".glb") || g_str_has_suffix(gamefile, ".gblorb")) + format = CHIMARA_IF_FORMAT_GLULX_BLORB; + + /* Now decide what interpreter to use */ + ChimaraIFInterpreter interpreter = priv->preferred_interpreter[format]; + gchar *libtoolfile = g_strconcat(plugin_names[interpreter], ".la", NULL); +#ifndef RELEASE + /* If there is a plugin in the source tree, use that */ + gboolean use_installed = FALSE; + gchar *libtoolpath = g_build_filename("..", "interpreters", plugin_names[interpreter], libtoolfile, NULL); + if( !g_file_test(libtoolpath, G_FILE_TEST_EXISTS) ) + { + g_free(libtoolpath); +#endif + gchar *libtoolpath = g_build_filename(PLUGINDIR, libtoolfile, NULL); + if( !g_file_test(libtoolpath, G_FILE_TEST_EXISTS) ) + { + g_free(libtoolpath); + g_free(libtoolfile); + g_warning("Cannot open %s plugin file", interpreter_names[interpreter]); + /* TODO: set error */ + return FALSE; + } +#ifndef RELEASE + use_installed = TRUE; + } +#endif + g_free(libtoolfile); + + gchar *dlname = find_dlname(libtoolpath, error); + g_free(libtoolpath); + if(!dlname) + return FALSE; + gchar *pluginpath; +#ifndef RELEASE + if(use_installed) +#endif + pluginpath = g_build_filename(PLUGINDIR, dlname, NULL); +#ifndef RELEASE + else + pluginpath = g_build_filename("..", "interpreters", plugin_names[interpreter], LT_OBJDIR, dlname, NULL); +#endif + char *argv[3] = { pluginpath, gamefile, NULL }; + gboolean retval = chimara_glk_run(CHIMARA_GLK(self), pluginpath, 2, argv, error); + g_free(dlname); + return retval; +} diff --git a/libchimara/chimara-if.h b/libchimara/chimara-if.h index ea5aed0..f081aaf 100644 --- a/libchimara/chimara-if.h +++ b/libchimara/chimara-if.h @@ -17,7 +17,9 @@ typedef enum _ChimaraIFFormat { CHIMARA_IF_FORMAT_Z5, CHIMARA_IF_FORMAT_Z6, CHIMARA_IF_FORMAT_Z8, + CHIMARA_IF_FORMAT_Z_BLORB, CHIMARA_IF_FORMAT_GLULX, + CHIMARA_IF_FORMAT_GLULX_BLORB, CHIMARA_IF_NUM_FORMATS } ChimaraIFFormat; @@ -43,6 +45,7 @@ GType chimara_if_get_type(void) G_GNUC_CONST; GtkWidget *chimara_if_new(void); void chimara_if_set_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format, ChimaraIFInterpreter interpreter); ChimaraIFInterpreter chimara_if_get_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format); +gboolean chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error); G_END_DECLS diff --git a/tests/main.c b/tests/main.c index e73df82..5c38111 100644 --- a/tests/main.c +++ b/tests/main.c @@ -43,6 +43,7 @@ #include "callbacks.h" #include "error.h" #include +#include /* Global pointers to widgets */ GtkBuilder *builder = NULL; @@ -63,27 +64,9 @@ on_stopped(ChimaraGlk *glk) } static void -on_waiting(ChimaraGlk *glk) +on_command(ChimaraGlk *glk, gchar *input, gchar *response) { - g_printerr("Waiting!\n"); -} - -static void -on_char_input(ChimaraGlk *glk, guint32 window_rock, guint keysym) -{ - g_printerr("Character input in window %d: key %d\n", window_rock, keysym); -} - -static void -on_line_input(ChimaraGlk *glk, guint32 window_rock, gchar *text) -{ - g_printerr("Line input in window %d: '%s'\n", window_rock, text); -} - -static void -on_text_buffer_output(ChimaraGlk *glk, guint32 window_rock, gchar *text) -{ - g_printerr("Text buffer output in window %d: '%s'\n", window_rock, text); + g_printerr("Command!\n"); } static GObject * @@ -131,16 +114,13 @@ create_window(void) return; } - glk = chimara_glk_new(); + glk = chimara_if_new(); g_object_set(glk, "border-width", 6, "spacing", 6, NULL); chimara_glk_set_default_font_string(CHIMARA_GLK(glk), "Serif 12"); chimara_glk_set_monospace_font_string(CHIMARA_GLK(glk), "Monospace 12"); g_signal_connect(glk, "started", G_CALLBACK(on_started), NULL); g_signal_connect(glk, "stopped", G_CALLBACK(on_stopped), NULL); - g_signal_connect(glk, "waiting", G_CALLBACK(on_waiting), NULL); - g_signal_connect(glk, "char-input", G_CALLBACK(on_char_input), NULL); - g_signal_connect(glk, "line-input", G_CALLBACK(on_line_input), NULL); - g_signal_connect(glk, "text-buffer-output", G_CALLBACK(on_text_buffer_output), NULL); + g_signal_connect(glk, "command", G_CALLBACK(on_command), NULL); GtkBox *vbox = GTK_BOX( gtk_builder_get_object(builder, "vbox") ); if(vbox == NULL) @@ -182,7 +162,12 @@ main(int argc, char *argv[]) g_object_unref( G_OBJECT(builder) ); g_object_unref( G_OBJECT(uimanager) ); - if( !chimara_glk_run(CHIMARA_GLK(glk), "../interpreters/frotz/.libs/frotz.so", argc, argv, &error) ) { + if(argc < 2) { + error_dialog(GTK_WINDOW(window), NULL, "Must provide a game file"); + return 1; + } + + if( !chimara_if_run_game(CHIMARA_IF(glk), argv[1], &error) ) { error_dialog(GTK_WINDOW(window), error, "Error starting Glk library: "); return 1; }