4 #include <glib-object.h>
6 #include <glib/gi18n-lib.h>
7 #include "chimara-if.h"
8 #include "chimara-glk.h"
9 #include "chimara-marshallers.h"
12 static gboolean supported_formats[CHIMARA_IF_NUM_FORMATS][CHIMARA_IF_NUM_INTERPRETERS] = {
13 /* Frotz Nitfol Glulxe Git */
14 { TRUE, TRUE, FALSE, FALSE }, /* Z5 */
15 { TRUE, TRUE, FALSE, FALSE }, /* Z6 */
16 { TRUE, TRUE, FALSE, FALSE }, /* Z8 */
17 { TRUE, TRUE, FALSE, FALSE }, /* Zblorb */
18 { FALSE, FALSE, TRUE, TRUE }, /* Glulx */
19 { FALSE, FALSE, TRUE, TRUE } /* Gblorb */
21 static gchar *format_names[CHIMARA_IF_NUM_FORMATS] = {
22 N_("Z-code version 5"),
23 N_("Z-code version 6"),
24 N_("Z-code version 8"),
29 static gchar *interpreter_names[CHIMARA_IF_NUM_INTERPRETERS] = {
30 N_("Frotz"), N_("Nitfol"), N_("Glulxe"), N_("Git")
32 static gchar *plugin_names[CHIMARA_IF_NUM_INTERPRETERS] = {
33 "frotz", "nitfol", "glulxe", "git"
36 typedef struct _ChimaraIFPrivate {
37 ChimaraIFInterpreter preferred_interpreter[CHIMARA_IF_NUM_FORMATS];
40 #define CHIMARA_IF_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), CHIMARA_TYPE_IF, ChimaraIFPrivate))
41 #define CHIMARA_IF_USE_PRIVATE(o, n) ChimaraIFPrivate *n = CHIMARA_IF_PRIVATE(o)
53 static guint chimara_if_signals[LAST_SIGNAL] = { 0 };
55 G_DEFINE_TYPE(ChimaraIF, chimara_if, CHIMARA_TYPE_GLK);
58 chimara_if_init(ChimaraIF *self)
60 CHIMARA_IF_USE_PRIVATE(self, priv);
61 priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z5] = CHIMARA_IF_INTERPRETER_FROTZ;
62 priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z6] = CHIMARA_IF_INTERPRETER_FROTZ;
63 priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z8] = CHIMARA_IF_INTERPRETER_FROTZ;
64 priv->preferred_interpreter[CHIMARA_IF_FORMAT_Z_BLORB] = CHIMARA_IF_INTERPRETER_FROTZ;
65 priv->preferred_interpreter[CHIMARA_IF_FORMAT_GLULX] = CHIMARA_IF_INTERPRETER_GLULXE;
66 priv->preferred_interpreter[CHIMARA_IF_FORMAT_GLULX_BLORB] = CHIMARA_IF_INTERPRETER_GLULXE;
70 chimara_if_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
75 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
80 chimara_if_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
86 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
91 chimara_if_finalize(GObject *object)
93 G_OBJECT_CLASS(chimara_if_parent_class)->finalize(object);
97 chimara_if_command(ChimaraIF *self, gchar *input, gchar *response)
99 /* Default signal handler */
103 chimara_if_class_init(ChimaraIFClass *klass)
105 /* Override methods of parent classes */
106 GObjectClass *object_class = G_OBJECT_CLASS(klass);
107 object_class->set_property = chimara_if_set_property;
108 object_class->get_property = chimara_if_get_property;
109 object_class->finalize = chimara_if_finalize;
112 klass->command = chimara_if_command;
113 /* Gtk-Doc for command */
114 chimara_if_signals[COMMAND] = g_signal_new("command",
115 G_OBJECT_CLASS_TYPE(klass), 0,
116 G_STRUCT_OFFSET(ChimaraIFClass, command), NULL, NULL,
117 chimara_marshal_VOID__STRING_STRING,
118 G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);
121 /* Gtk-Doc for property */
122 /* g_object_class_install_property(object_class, PROPERTY, ...); */
125 g_type_class_add_private(klass, sizeof(ChimaraIFPrivate));
128 /* PUBLIC FUNCTIONS */
133 * Creates and initializes a new #ChimaraIF widget.
135 * Return value: a #ChimaraIF widget, with a floating reference.
140 /* This is a library entry point; initialize the library */
142 return GTK_WIDGET(g_object_new(CHIMARA_TYPE_IF, NULL));
146 chimara_if_set_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format, ChimaraIFInterpreter interpreter)
148 g_return_if_fail(self && CHIMARA_IS_IF(self));
149 g_return_if_fail(format < CHIMARA_IF_NUM_FORMATS);
150 g_return_if_fail(format < CHIMARA_IF_NUM_INTERPRETERS);
152 CHIMARA_IF_USE_PRIVATE(self, priv);
154 if(supported_formats[format][interpreter])
155 priv->preferred_interpreter[format] = interpreter;
157 g_warning("Format '%s' is not supported by interpreter '%s'", format_names[format], interpreter_names[interpreter]);
161 chimara_if_get_preferred_interpreter(ChimaraIF *self, ChimaraIFFormat format)
163 g_return_val_if_fail(self && CHIMARA_IS_IF(self), -1);
164 g_return_val_if_fail(format < CHIMARA_IF_NUM_FORMATS, -1);
165 CHIMARA_IF_USE_PRIVATE(self, priv);
166 return priv->preferred_interpreter[format];
169 /* Opens a '.la' file and finds the name of the plugin library. g_free() the
170 * string when done. */
172 find_dlname(const gchar *pluginfile, GError **error)
174 /* Find the name of the shared library */
176 FILE *plugin = fopen(pluginfile, "r");
179 g_set_error(error, G_FILE_ERROR, errno, "Error opening '%s': %s", pluginfile, g_strerror(errno));
185 while((length = getline(&line, &buflen, plugin)) != -1)
187 if(g_str_has_prefix(line, "dlname='"))
189 dlname = g_strndup(line + 8, length - 10);
196 g_set_error(error, G_FILE_ERROR, errno, "Error reading '%s': %s", pluginfile, g_strerror(errno));
201 g_set_error(error, G_FILE_ERROR, errno, "Error closing '%s': %s", pluginfile, g_strerror(errno));
208 chimara_if_run_game(ChimaraIF *self, gchar *gamefile, GError **error)
210 g_return_val_if_fail(self && CHIMARA_IS_IF(self), FALSE);
211 g_return_val_if_fail(gamefile, FALSE);
213 CHIMARA_IF_USE_PRIVATE(self, priv);
215 /* Find out what format the game is */
216 /* TODO: Look inside the file instead of just looking at the extension */
217 ChimaraIFFormat format = CHIMARA_IF_FORMAT_Z5;
218 if(g_str_has_suffix(gamefile, ".z5"))
219 format = CHIMARA_IF_FORMAT_Z5;
220 else if(g_str_has_suffix(gamefile, ".z6"))
221 format = CHIMARA_IF_FORMAT_Z6;
222 else if(g_str_has_suffix(gamefile, ".z8"))
223 format = CHIMARA_IF_FORMAT_Z8;
224 else if(g_str_has_suffix(gamefile, ".zlb") || g_str_has_suffix(gamefile, ".zblorb"))
225 format = CHIMARA_IF_FORMAT_Z_BLORB;
226 else if(g_str_has_suffix(gamefile, ".ulx"))
227 format = CHIMARA_IF_FORMAT_GLULX;
228 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"))
229 format = CHIMARA_IF_FORMAT_GLULX_BLORB;
231 /* Now decide what interpreter to use */
232 ChimaraIFInterpreter interpreter = priv->preferred_interpreter[format];
233 gchar *libtoolfile = g_strconcat(plugin_names[interpreter], ".la", NULL);
235 /* If there is a plugin in the source tree, use that */
236 gboolean use_installed = FALSE;
237 gchar *libtoolpath = g_build_filename("..", "interpreters", plugin_names[interpreter], libtoolfile, NULL);
238 if( !g_file_test(libtoolpath, G_FILE_TEST_EXISTS) )
242 gchar *libtoolpath = g_build_filename(PLUGINDIR, libtoolfile, NULL);
243 if( !g_file_test(libtoolpath, G_FILE_TEST_EXISTS) )
247 g_warning("Cannot open %s plugin file", interpreter_names[interpreter]);
248 /* TODO: set error */
252 use_installed = TRUE;
257 gchar *dlname = find_dlname(libtoolpath, error);
265 pluginpath = g_build_filename(PLUGINDIR, dlname, NULL);
268 pluginpath = g_build_filename("..", "interpreters", plugin_names[interpreter], LT_OBJDIR, dlname, NULL);
270 char *argv[3] = { pluginpath, gamefile, NULL };
271 gboolean retval = chimara_glk_run(CHIMARA_GLK(self), pluginpath, 2, argv, error);