summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Walters <walters@verbum.org>2013-06-14 19:06:32 -0400
committerColin Walters <walters@verbum.org>2013-06-14 19:06:58 -0400
commit077fc095208e8429400763f0e41ac7c8884e8c1e (patch)
treee53229f7ab4da2b88d3dc481a8ab6e7189935b15
parent72d437cf9349ccfb8723ea09b381b17c0a23ab88 (diff)
downloadlibgsystem-077fc095208e8429400763f0e41ac7c8884e8c1e.tar.gz
fileutils: Add gs_file_enumerator_iterate()
This is much more convenient to use correctly from C.
-rw-r--r--gsystem-file-utils.c94
-rw-r--r--gsystem-file-utils.h6
2 files changed, 100 insertions, 0 deletions
diff --git a/gsystem-file-utils.c b/gsystem-file-utils.c
index 9422f86..00f86f6 100644
--- a/gsystem-file-utils.c
+++ b/gsystem-file-utils.c
@@ -545,6 +545,100 @@ gs_file_get_basename_cached (GFile *file)
}
/**
+ * gs_file_enumerator_iterate:
+ * @direnum: an open #GFileEnumerator
+ * @out_info: (out) (transfer none) (allow-none): Output location for the next #GFileInfo
+ * @out_child: (out) (transfer none) (allow-none): Output location for the next #GFile, or %NULL
+ * @cancellable: a #GCancellable
+ * @error: a #GError
+ *
+ * This is a version of g_file_enumerator_next_file() that's easier to
+ * use correctly from C programs. With g_file_enumerator_next_file(),
+ * the gboolean return value signifies "end of iteration or error", which
+ * requires allocation of a temporary #GError.
+ *
+ * In contrast, with this function, a %FALSE return from
+ * gs_file_enumerator_iterate() <emphasis>always</emphasis> means
+ * "error". End of iteration is signaled by @out_info being %NULL.
+ *
+ * Another crucial difference is that the references for @out_info and
+ * @out_child are owned by @direnum (they are cached as hidden
+ * properties). You must not unref them in your own code. This makes
+ * memory management significantly easier for C code in combination
+ * with loops.
+ *
+ * Finally, this function optionally allows retrieving a #GFile as
+ * well.
+ *
+ * The code pattern for correctly using gs_file_enumerator_iterate() from C
+ * is:
+ *
+ * |[
+ * direnum = g_file_enumerate_children (file, ...);
+ * while (TRUE)
+ * {
+ * GFileInfo *info;
+ * if (!gs_file_enumerator_iterate (direnum, &info, NULL, cancellable, error))
+ * goto out;
+ * if (!info)
+ * break;
+ * ... do stuff with "info"; do not unref it! ...
+ * }
+ *
+ * out:
+ * g_object_unref (direnum); // Note: frees the last @info
+ * ]|
+ */
+gboolean
+gs_file_enumerator_iterate (GFileEnumerator *direnum,
+ GFileInfo **out_info,
+ GFile **out_child,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = FALSE;
+ GError *temp_error = NULL;
+
+ static GQuark cached_info_quark;
+ static GQuark cached_child_quark;
+ static gsize quarks_initialized;
+
+ g_return_val_if_fail (direnum != NULL, FALSE);
+ g_return_val_if_fail (out_info != NULL, FALSE);
+
+ if (g_once_init_enter (&quarks_initialized))
+ {
+ cached_info_quark = g_quark_from_static_string ("gsystem-cached-info");
+ cached_child_quark = g_quark_from_static_string ("gsystem-cached-child");
+ g_once_init_leave (&quarks_initialized, 1);
+ }
+
+
+ *out_info = g_file_enumerator_next_file (direnum, cancellable, &temp_error);
+ if (out_child)
+ *out_child = NULL;
+ if (temp_error != NULL)
+ {
+ g_propagate_error (error, temp_error);
+ goto out;
+ }
+ else if (*out_info != NULL)
+ {
+ g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, *out_info, (GDestroyNotify)g_object_unref);
+ if (out_child != NULL)
+ {
+ const char *name = g_file_info_get_name (*out_info);
+ *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
+ g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
+ }
+ }
+
+ ret = TRUE;
+ out:
+ return ret;
+}
+
+/**
* gs_file_rename:
* @from: Current path
* @to: New path
diff --git a/gsystem-file-utils.h b/gsystem-file-utils.h
index 0cabcb5..83f65ce 100644
--- a/gsystem-file-utils.h
+++ b/gsystem-file-utils.h
@@ -29,6 +29,12 @@ const char *gs_file_get_path_cached (GFile *file);
const char *gs_file_get_basename_cached (GFile *file);
+gboolean gs_file_enumerator_iterate (GFileEnumerator *direnum,
+ GFileInfo **out_info,
+ GFile **out_child,
+ GCancellable *cancellable,
+ GError **error);
+
GInputStream *gs_file_read_noatime (GFile *file,
GCancellable *cancellable,
GError **error);