+
+/**
+ * chimara_if_run_game:
+ * @self: A #ChimaraIF widget.
+ * @game_path: Path to an interactive fiction game file.
+ * @error: Return location for an error, or %NULL.
+ *
+ * Autodetects the type of a game file and runs it using an appropriate
+ * interpreter plugin. If there is more than one interpreter that supports the
+ * file format, the preferred one will be picked, according to
+ * chimara_if_set_preferred_interpreter().
+ *
+ * Returns: %TRUE if the game was started successfully, %FALSE if not, in which
+ * case @error is set.
+ */
+gboolean
+chimara_if_run_game(ChimaraIF *self, const char *game_path, GError **error)
+{
+ g_return_val_if_fail(self && CHIMARA_IS_IF(self), FALSE);
+ g_return_val_if_fail(game_path, FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, 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(game_path, ".z5"))
+ format = CHIMARA_IF_FORMAT_Z5;
+ else if(g_str_has_suffix(game_path, ".z6"))
+ format = CHIMARA_IF_FORMAT_Z6;
+ else if(g_str_has_suffix(game_path, ".z8"))
+ format = CHIMARA_IF_FORMAT_Z8;
+ else if(g_str_has_suffix(game_path, ".zlb") || g_str_has_suffix(game_path, ".zblorb"))
+ format = CHIMARA_IF_FORMAT_Z_BLORB;
+ else if(g_str_has_suffix(game_path, ".ulx"))
+ format = CHIMARA_IF_FORMAT_GLULX;
+ else if(g_str_has_suffix(game_path, ".blb") || g_str_has_suffix(game_path, ".blorb") || g_str_has_suffix(game_path, ".glb") || g_str_has_suffix(game_path, ".gblorb"))
+ format = CHIMARA_IF_FORMAT_GLULX_BLORB;
+
+ /* Now decide what interpreter to use */
+ ChimaraIFInterpreter interpreter = priv->preferred_interpreter[format];
+ gchar *pluginfile = g_strconcat(plugin_names[interpreter], "." G_MODULE_SUFFIX, NULL);
+
+ gchar *pluginpath;
+#ifdef DEBUG
+#ifndef LT_OBJDIR
+#define LT_OBJDIR ".libs" /* Pre-2.2 libtool, so take a wild guess */
+#endif /* LT_OBJDIR */
+ /* If there is a plugin in the source tree, use that */
+ pluginpath = g_build_filename(PLUGINSOURCEDIR, plugin_names[interpreter], LT_OBJDIR, pluginfile, NULL);
+ if( !g_file_test(pluginpath, G_FILE_TEST_EXISTS) )
+ {
+ g_free(pluginpath);
+#endif /* DEBUG */
+ pluginpath = g_build_filename(PLUGINDIR, pluginfile, NULL);
+ if( !g_file_test(pluginpath, G_FILE_TEST_EXISTS) )
+ {
+ g_free(pluginpath);
+ g_free(pluginfile);
+ g_set_error(error, CHIMARA_ERROR, CHIMARA_PLUGIN_NOT_FOUND, _("No appropriate %s interpreter plugin was found"), interpreter_names[interpreter]);
+ return FALSE;
+ }
+#ifdef DEBUG
+ }
+#endif
+ g_free(pluginfile);
+
+ /* Decide what arguments to pass to the interpreters; currently only the
+ Z-machine interpreters accept command line arguments other than the game */
+ GSList *args = NULL;
+ gchar *terpnumstr = NULL, *randomstr = NULL;
+ args = g_slist_prepend(args, pluginpath);
+ switch(interpreter)
+ {
+ case CHIMARA_IF_INTERPRETER_FROTZ:
+ if(priv->flags & CHIMARA_IF_PIRACY_MODE)
+ args = g_slist_prepend(args, "-P");
+ if(priv->flags & CHIMARA_IF_TANDY_BIT)
+ args = g_slist_prepend(args, "-t");
+ if(priv->flags & CHIMARA_IF_EXPAND_ABBREVIATIONS)
+ args = g_slist_prepend(args, "-x");
+ if(priv->flags & CHIMARA_IF_IGNORE_ERRORS)
+ args = g_slist_prepend(args, "-i");
+ if(priv->interpreter_number != CHIMARA_IF_ZMACHINE_DEFAULT)
+ {
+ terpnumstr = g_strdup_printf("-I%u", priv->interpreter_number);
+ args = g_slist_prepend(args, terpnumstr);
+ }
+ if(priv->random_seed_set)
+ {
+ randomstr = g_strdup_printf("-s%d", priv->random_seed);
+ args = g_slist_prepend(args, randomstr);
+ }
+ break;
+ case CHIMARA_IF_INTERPRETER_NITFOL:
+ if(priv->flags & CHIMARA_IF_PIRACY_MODE)
+ args = g_slist_prepend(args, "-pirate");
+ if(priv->flags & CHIMARA_IF_TANDY_BIT)
+ args = g_slist_prepend(args, "-tandy");
+ if(!(priv->flags & CHIMARA_IF_EXPAND_ABBREVIATIONS))
+ args = g_slist_prepend(args, "-no-expand");
+ if(priv->flags & CHIMARA_IF_IGNORE_ERRORS)
+ args = g_slist_prepend(args, "-ignore");
+ if(!(priv->flags & CHIMARA_IF_TYPO_CORRECTION))
+ args = g_slist_prepend(args, "-no-spell");
+ if(priv->interpreter_number != CHIMARA_IF_ZMACHINE_DEFAULT)
+ {
+ terpnumstr = g_strdup_printf("-terpnum%u", priv->interpreter_number);
+ args = g_slist_prepend(args, terpnumstr);
+ }
+ if(priv->random_seed_set)
+ {
+ randomstr = g_strdup_printf("-random%d", priv->random_seed);
+ args = g_slist_prepend(args, randomstr);
+ }
+ break;
+ default:
+ ;
+ }
+
+ /* Game file and external blorb file */
+ args = g_slist_prepend(args, (gpointer)game_path);
+ if(priv->graphics_file
+ && (interpreter == CHIMARA_IF_INTERPRETER_FROTZ || interpreter == CHIMARA_IF_INTERPRETER_NITFOL)
+ && g_file_test(priv->graphics_file, G_FILE_TEST_EXISTS)) {
+ args = g_slist_prepend(args, priv->graphics_file);
+ }
+
+ /* Allocate argv to hold the arguments */
+ int argc = g_slist_length(args);
+ args = g_slist_prepend(args, NULL);
+ char **argv = g_new0(char *, argc + 1);
+
+ /* Fill argv */
+ args = g_slist_reverse(args);
+ int count;
+ GSList *ptr;
+ for(count = 0, ptr = args; ptr; count++, ptr = g_slist_next(ptr))
+ argv[count] = g_strdup(ptr->data);
+
+ /* Set the story name */
+ /* We peek into ChimaraGlk's private data here, because GObject has no
+ equivalent to "protected" */
+ CHIMARA_GLK_USE_PRIVATE(self, glk_priv);
+ glk_priv->story_name = g_path_get_basename(game_path);
+ g_object_notify(G_OBJECT(self), "story-name");
+
+ gboolean retval = chimara_glk_run(CHIMARA_GLK(self), pluginpath, argc, argv, error);
+ g_strfreev(argv);
+ if(terpnumstr)
+ g_free(terpnumstr);
+ if(randomstr)
+ g_free(randomstr);
+ g_free(pluginpath);
+
+ /* Set current format and interpreter if plugin was started successfully */
+ if(retval)
+ {
+ priv->format = format;
+ priv->interpreter = interpreter;
+ }
+ return retval;
+}
+
+/**
+ * chimara_if_run_game_file:
+ * @self: A #ChimaraIF widget.
+ * @game_file: a #GFile pointing to an interactive fiction game file.
+ * @error: Return location for an error, or %NULL.
+ *
+ * Autodetects the type of a game file and runs it using an appropriate
+ * interpreter plugin. See chimara_if_run_game() for more information.
+ *
+ * Returns: %TRUE if the game was started successfully, %FALSE if not, in which
+ * case @error is set.
+ */
+gboolean
+chimara_if_run_game_file(ChimaraIF *self, GFile *game_file, GError **error)
+{
+ g_return_val_if_fail(self || CHIMARA_IS_IF(self), FALSE);
+ g_return_val_if_fail(game_file || G_IS_FILE(game_file), FALSE);
+ g_return_val_if_fail(error == NULL || *error == NULL, FALSE);
+
+ char *path = g_file_get_path(game_file);
+ gboolean retval = chimara_if_run_game(self, path, error);
+ g_free(path);
+ return retval;
+}
+
+/**
+ * chimara_if_get_format:
+ * @self: A #ChimaraIF widget.
+ *
+ * Returns the file format of the currently running game.
+ *
+ * Returns: a #ChimaraIFFormat constant.
+ */
+ChimaraIFFormat
+chimara_if_get_format(ChimaraIF *self)
+{
+ g_return_val_if_fail(self && CHIMARA_IS_IF(self), CHIMARA_IF_FORMAT_NONE);
+ CHIMARA_IF_USE_PRIVATE(self, priv);
+ return priv->format;
+}
+
+/**
+ * chimara_if_get_interpreter:
+ * @self: A #ChimaraIF widget.
+ *
+ * Returns the interpreter plugin currently running.
+ *
+ * Returns: a #ChimaraIFInterpreter constant.
+ */
+ChimaraIFInterpreter
+chimara_if_get_interpreter(ChimaraIF *self)
+{
+ g_return_val_if_fail(self && CHIMARA_IS_IF(self), CHIMARA_IF_FORMAT_NONE);
+ CHIMARA_IF_USE_PRIVATE(self, priv);
+ return priv->interpreter;
+}