diff options
author | Colin Walters <walters@verbum.org> | 2013-06-14 19:06:32 -0400 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2013-06-14 19:06:58 -0400 |
commit | 077fc095208e8429400763f0e41ac7c8884e8c1e (patch) | |
tree | e53229f7ab4da2b88d3dc481a8ab6e7189935b15 | |
parent | 72d437cf9349ccfb8723ea09b381b17c0a23ab88 (diff) | |
download | libgsystem-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.c | 94 | ||||
-rw-r--r-- | gsystem-file-utils.h | 6 |
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); |