[retro-gtk/wip/aplazas/c-port: 20/34] Port ModuleIterator to C
- From: Adrien Plazas <aplazas src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [retro-gtk/wip/aplazas/c-port: 20/34] Port ModuleIterator to C
- Date: Tue, 10 Oct 2017 04:54:11 +0000 (UTC)
commit 0b830ef83c61af772e36b059e1ec3ef1807d86c8
Author: Adrien Plazas <kekun plazas laposte net>
Date: Fri Sep 15 13:27:42 2017 +0200
Port ModuleIterator to C
retro-gtk/Makefile.am | 5 +-
retro-gtk/retro-module-iterator.c | 353 ++++++++++++++++++++++++++++++++++
retro-gtk/retro-module-iterator.h | 29 +++
retro-gtk/retro-module-iterator.vala | 125 ------------
retro-gtk/retro-module-query.c | 7 +-
retro-gtk/retro-module-query.h | 4 +-
6 files changed, 390 insertions(+), 133 deletions(-)
---
diff --git a/retro-gtk/Makefile.am b/retro-gtk/Makefile.am
index 00d15ef..c31c60d 100644
--- a/retro-gtk/Makefile.am
+++ b/retro-gtk/Makefile.am
@@ -41,6 +41,7 @@ retro_gtk_public_h_sources = \
retro-lightgun-id.h \
retro-log.h \
retro-memory-type.h \
+ retro-module-iterator.h \
retro-module-query.h \
retro-mouse-id.h \
retro-pixel-format.h \
@@ -94,8 +95,8 @@ libretro_gtk_la_SOURCES = \
retro-log.c \
retro-memory-type.c \
retro-module.c \
+ retro-module-iterator.c \
retro-module-query.c \
- retro-module-iterator.vala \
retro-mouse-id.c \
retro-option.c \
retro-options.c \
@@ -124,6 +125,8 @@ retro-log.c: retro-gtk-internal.h
retro-module.c: retro-gtk-internal.h
+retro-module-iterator.c: retro-gtk-internal.h
+
retro-module-query.c: retro-gtk-internal.h
retro-pa-player.c: retro-gtk-internal.h
diff --git a/retro-gtk/retro-module-iterator.c b/retro-gtk/retro-module-iterator.c
new file mode 100644
index 0000000..0ecf7fb
--- /dev/null
+++ b/retro-gtk/retro-module-iterator.c
@@ -0,0 +1,353 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#include "retro-gtk-internal.h"
+
+#include "retro-module-iterator.h"
+
+struct _RetroModuleIterator
+{
+ GObject parent_instance;
+ gchar **directories;
+ gboolean recursive;
+ gint current_directory;
+ GFileEnumerator *file_enumerator;
+ RetroCoreDescriptor *core_descriptor;
+ RetroModuleIterator *sub_directory;
+ GHashTable *visited;
+};
+
+G_DEFINE_TYPE (RetroModuleIterator, retro_module_iterator, G_TYPE_OBJECT)
+
+/* Private */
+
+static void
+retro_module_iterator_finalize (GObject *object)
+{
+ RetroModuleIterator *self = RETRO_MODULE_ITERATOR (object);
+
+ g_strfreev (self->directories);
+ g_clear_object (&self->file_enumerator);
+ g_clear_object (&self->core_descriptor);
+ g_clear_object (&self->sub_directory);
+ g_hash_table_unref (self->visited);
+
+ G_OBJECT_CLASS (retro_module_iterator_parent_class)->finalize (object);
+}
+
+static void
+retro_module_iterator_class_init (RetroModuleIteratorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = retro_module_iterator_finalize;
+}
+
+static void
+retro_module_iterator_init (RetroModuleIterator *self)
+{
+}
+
+static RetroModuleIterator *
+retro_module_iterator_new_for_subdirectory (const gchar *lookup_path,
+ GHashTable *visited_paths)
+{
+ RetroModuleIterator *self;
+
+ g_return_val_if_fail (lookup_path != NULL, NULL);
+ g_return_val_if_fail (visited_paths != NULL, NULL);
+
+ self = g_object_new (RETRO_TYPE_MODULE_ITERATOR, NULL);
+ self->directories = g_new0 (gchar *, 2);
+ self->directories[0] = g_strdup (lookup_path);
+ self->recursive = TRUE;
+ g_set_object (&self->visited, visited_paths);
+
+ return self;
+}
+
+static gboolean
+retro_module_iterator_was_current_directory_visited (RetroModuleIterator *self)
+{
+ GFile *current_directory_file;
+ gchar *current_directory_path;
+ gboolean result;
+
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), FALSE);
+
+ current_directory_file = g_file_new_for_path (self->directories[self->current_directory]);
+ current_directory_path = g_file_get_path (current_directory_file);
+ g_object_unref (current_directory_file);
+ result = g_hash_table_contains (self->visited, current_directory_path);
+ g_free (current_directory_path);
+
+ return result;
+}
+
+static void
+retro_module_iterator_set_current_directory_as_visited (RetroModuleIterator *self)
+{
+ GFile *current_directory_file;
+ gchar *current_directory_path;
+
+ g_return_if_fail (RETRO_IS_MODULE_ITERATOR (self));
+
+ current_directory_file = g_file_new_for_path (self->directories[self->current_directory]);
+ current_directory_path = g_file_get_path (current_directory_file);
+ g_object_unref (current_directory_file);
+ g_hash_table_add (self->visited, current_directory_path);
+}
+
+static gboolean
+retro_module_iterator_next_in_sub_directory (RetroModuleIterator *self)
+{
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), FALSE);
+
+ if (retro_module_iterator_next (self->sub_directory)) {
+ if (self->core_descriptor != NULL)
+ g_object_unref (self->core_descriptor);
+
+ self->core_descriptor = retro_module_iterator_get (self->sub_directory);
+
+ return TRUE;
+ }
+
+ if (self->sub_directory != NULL) {
+ g_object_unref (self->sub_directory);
+ self->sub_directory = NULL;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+retro_module_iterator_iterate_next_in_current_path (RetroModuleIterator *self,
+ GFile *directory,
+ GFileInfo *info,
+ GError **error)
+{
+ const gchar *sub_directory_basename;
+ GFile *sub_directory_file;
+ gchar *sub_directory_path;
+ const gchar *core_descriptor_basename;
+ GFile *core_descriptor_file;
+ gchar *core_descriptor_path;
+ RetroCoreDescriptor *core_descriptor;
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), FALSE);
+ g_return_val_if_fail (G_IS_FILE (directory), FALSE);
+ g_return_val_if_fail (G_IS_FILE_INFO (info), FALSE);
+
+ if (self->recursive &&
+ g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY &&
+ self->sub_directory == NULL) {
+ sub_directory_basename = g_file_info_get_name (info);
+ sub_directory_file = g_file_get_child (directory, sub_directory_basename);
+ sub_directory_path = g_file_get_path (sub_directory_file);
+ g_object_unref (sub_directory_file);
+
+ if (g_hash_table_contains (self->visited, sub_directory_path)) {
+ g_free (sub_directory_path);
+
+ return FALSE;
+ }
+
+ self->sub_directory = retro_module_iterator_new_for_subdirectory (sub_directory_path, self->visited);
+ g_free (sub_directory_path);
+
+ return retro_module_iterator_next_in_sub_directory (self);
+ }
+
+ core_descriptor_basename = g_file_info_get_name (info);
+ if (!g_str_has_suffix (core_descriptor_basename, ".libretro"))
+ return FALSE;
+
+ core_descriptor_file = g_file_get_child (directory, core_descriptor_basename);
+ core_descriptor_path = g_file_get_path (core_descriptor_file);
+ g_object_unref (core_descriptor_file);
+ core_descriptor = retro_core_descriptor_new (core_descriptor_path, &tmp_error);
+ if (G_UNLIKELY (tmp_error != NULL)) {
+ g_debug ("%s", tmp_error->message);
+
+ g_error_free (tmp_error);
+ g_free (core_descriptor_path);
+
+ return FALSE;
+ }
+
+ g_free (core_descriptor_path);
+ g_clear_object (&self->core_descriptor);
+ self->core_descriptor = core_descriptor;
+
+ return TRUE;
+}
+
+static gboolean
+retro_module_iterator_next_in_current_path (RetroModuleIterator *self,
+ GError **error)
+{
+ GFile *directory = NULL;
+ GFileInfo *info = NULL;
+ gboolean found = FALSE;
+
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), FALSE);
+
+ if (self->sub_directory != NULL &&
+ retro_module_iterator_next_in_sub_directory (self))
+ return TRUE;
+
+ directory = g_file_new_for_path (self->directories[self->current_directory]);
+
+ if (self->file_enumerator == NULL) {
+ self->file_enumerator =
+ g_file_enumerate_children (directory,
+ "",
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL,
+ &tmp_error);
+ if (G_UNLIKELY (tmp_error != NULL)) {
+ g_propagate_error (error, tmp_error);
+ g_object_unref (directory);
+ g_clear_object (&self->file_enumerator);
+
+ return FALSE;
+ }
+ }
+
+ if (self->file_enumerator == NULL) {
+ g_object_unref (directory);
+
+ return FALSE;
+ }
+
+ while (TRUE) {
+ if (info != NULL)
+ g_object_unref (info);
+
+ info = g_file_enumerator_next_file (self->file_enumerator, NULL, &tmp_error);
+ if (G_UNLIKELY (tmp_error != NULL)) {
+ g_propagate_error (error, tmp_error);
+ g_clear_object (&info);
+ g_object_unref (directory);
+
+ return FALSE;
+ }
+
+ if (info == NULL)
+ break;
+
+ found = retro_module_iterator_iterate_next_in_current_path (self, directory, info, &tmp_error);
+ if (G_UNLIKELY (tmp_error != NULL)) {
+ g_propagate_error (error, tmp_error);
+ g_object_unref (info);
+ g_object_unref (directory);
+
+ return FALSE;
+ }
+
+ if (found) {
+ g_object_unref (info);
+ g_object_unref (directory);
+
+ return TRUE;
+ }
+ }
+
+ g_clear_object (&self->file_enumerator);
+ g_object_unref (directory);
+
+ return FALSE;
+}
+
+/* Public */
+
+/**
+ * retro_module_iterator_get:
+ * @self: a #RetroModuleIterator
+ *
+ * Gets the last #RetroCoreDescriptor fetched by retro_module_iterator_next(),
+ * or %NULL if the end was reached.
+ *
+ * Returns: (nullable) (transfer full): a #RetroCoreDescriptor, or %NULL
+ */
+RetroCoreDescriptor *
+retro_module_iterator_get (RetroModuleIterator *self)
+{
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), NULL);
+
+ return self->core_descriptor != NULL ?
+ g_object_ref (self->core_descriptor) :
+ NULL;
+}
+
+/**
+ * retro_module_iterator_next:
+ * @self: a #RetroModuleIterator
+ *
+ * Fetch the next #RetroModuleIterator.
+ *
+ * Returns: %FALSE if it reached the end, %TRUE otherwise
+ */
+gboolean
+retro_module_iterator_next (RetroModuleIterator *self)
+{
+ gboolean next_in_current_path;
+ GError *tmp_error = NULL;
+
+ g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), FALSE);
+
+ while (self->directories[self->current_directory] != NULL) {
+ retro_module_iterator_set_current_directory_as_visited (self);
+
+ next_in_current_path = retro_module_iterator_next_in_current_path (self, &tmp_error);
+ if (G_UNLIKELY (tmp_error != NULL)) {
+ g_debug ("%s", tmp_error->message);
+ g_clear_error (&tmp_error);
+ next_in_current_path = FALSE;
+ }
+
+ if (next_in_current_path)
+ return TRUE;
+
+ while (self->directories[self->current_directory] != NULL &&
+ retro_module_iterator_was_current_directory_visited (self))
+ self->current_directory++;
+ }
+
+ g_clear_object (&self->file_enumerator);
+ g_clear_object (&self->core_descriptor);
+ if (self->sub_directory != NULL) {
+ g_object_unref (self->sub_directory);
+ self->sub_directory = NULL;
+ }
+
+ return FALSE;
+}
+
+/**
+ * retro_module_iterator_new:
+ * @lookup_paths: (array zero-terminated=1): paths where to look for Libretro
+ * cores
+ * @recursive: whether to run the query in sub-directories
+ *
+ * Creates a new #RetroModuleIterator.
+ *
+ * Returns: (transfer full): a new #RetroModuleIterator
+ */
+RetroModuleIterator *
+retro_module_iterator_new (const gchar * const *lookup_paths,
+ gboolean recursive)
+{
+ RetroModuleIterator *self;
+
+ g_return_val_if_fail (lookup_paths != NULL, NULL);
+
+ self = g_object_new (RETRO_TYPE_MODULE_ITERATOR, NULL);
+ self->directories = g_strdupv ((gchar **) lookup_paths);
+ self->recursive = recursive;
+ self->visited = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
+
+ return self;
+}
diff --git a/retro-gtk/retro-module-iterator.h b/retro-gtk/retro-module-iterator.h
new file mode 100644
index 0000000..300c04f
--- /dev/null
+++ b/retro-gtk/retro-module-iterator.h
@@ -0,0 +1,29 @@
+// This file is part of retro-gtk. License: GPL-3.0+.
+
+#ifndef RETRO_MODULE_ITERATOR_H
+#define RETRO_MODULE_ITERATOR_H
+
+#if !defined(__RETRO_GTK_INSIDE__) && !defined(RETRO_GTK_COMPILATION)
+# error "Only <retro-gtk.h> can be included directly."
+#endif
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+// FIXME Remove as soon as possible.
+typedef struct _RetroCoreDescriptor RetroCoreDescriptor;
+
+#define RETRO_TYPE_MODULE_ITERATOR (retro_module_iterator_get_type())
+
+G_DECLARE_FINAL_TYPE (RetroModuleIterator, retro_module_iterator, RETRO, MODULE_ITERATOR, GObject)
+
+RetroModuleIterator *retro_module_iterator_new (const gchar * const *lookup_paths,
+ gboolean recursive);
+RetroCoreDescriptor *retro_module_iterator_get (RetroModuleIterator *self);
+gboolean retro_module_iterator_next (RetroModuleIterator *self);
+
+G_END_DECLS
+
+#endif /* RETRO_MODULE_ITERATOR_H */
+
diff --git a/retro-gtk/retro-module-query.c b/retro-gtk/retro-module-query.c
index 942a14e..5336b47 100644
--- a/retro-gtk/retro-module-query.c
+++ b/retro-gtk/retro-module-query.c
@@ -19,8 +19,6 @@ G_DEFINE_TYPE (RetroModuleQuery, retro_module_query, G_TYPE_OBJECT)
static void
retro_module_query_finalize (GObject *object)
{
- RetroModuleQuery *self = RETRO_MODULE_QUERY (object);
-
G_OBJECT_CLASS (retro_module_query_parent_class)->finalize (object);
}
@@ -41,7 +39,7 @@ static gchar **
retro_module_query_get_plugin_lookup_paths ()
{
gchar **envp;
- gchar *env_plugin_path;
+ const gchar *env_plugin_path;
gchar *full_plugin_path;
gchar **result;
@@ -80,7 +78,8 @@ retro_module_query_iterator (RetroModuleQuery *self)
g_return_val_if_fail (RETRO_IS_MODULE_ITERATOR (self), NULL);
paths = retro_module_query_get_plugin_lookup_paths ();
- result = retro_module_iterator_new (paths, g_strv_length (paths), self->recursive);
+ result = retro_module_iterator_new ((const gchar * const *) paths,
+ self->recursive);
g_strfreev (paths);
return result;
diff --git a/retro-gtk/retro-module-query.h b/retro-gtk/retro-module-query.h
index 1c6e445..e3db695 100644
--- a/retro-gtk/retro-module-query.h
+++ b/retro-gtk/retro-module-query.h
@@ -8,12 +8,10 @@
#endif
#include <glib-object.h>
+#include "retro-module-iterator.h"
G_BEGIN_DECLS
-// FIXME Remove as soon as possible.
-typedef struct _RetroModuleIterator RetroModuleIterator;
-
#define RETRO_TYPE_MODULE_QUERY (retro_module_query_get_type())
G_DECLARE_FINAL_TYPE (RetroModuleQuery, retro_module_query, RETRO, MODULE_QUERY, GObject)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]