diff options
Diffstat (limited to 'gnome-autoar/autoar-private.c')
-rw-r--r-- | gnome-autoar/autoar-private.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/gnome-autoar/autoar-private.c b/gnome-autoar/autoar-private.c new file mode 100644 index 0000000..d80e5e7 --- /dev/null +++ b/gnome-autoar/autoar-private.c @@ -0,0 +1,281 @@ +/* vim: set sw=2 ts=2 sts=2 et: */ +/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * autoar-private.c + * Some common functions used in several classes of gnome-autoar + * This file does NOT declare any new classes and it should NOT + * be used outside the library itself! + * + * Copyright (C) 2013, 2014 Ting-Wei Lan + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + * + */ + +#include "config.h" +#include "autoar-private.h" + +#include "autoar-misc.h" + +#include <glib.h> +#include <gobject/gvaluecollector.h> +#include <string.h> + +/** + * SECTION:autoar-common + * @Short_description: Miscellaneous functions used by gnome-autoar + * @Title: autoar-common + * @Include: gnome-autoar/autoar.h + * + * Public utility functions used internally by other gnome-autoar functions. + **/ + +typedef struct _AutoarCommonSignalData AutoarCommonSignalData; + +struct _AutoarCommonSignalData +{ + GValue instance_and_params[3]; /* Maximum number of parameters + 1 */ + gssize used_values; /* Number of GValues to be unset */ + guint signal_id; + GQuark detail; +}; + +/** + * autoar_common_get_filename_extension: + * @filename: a filename + * + * Gets the extension of a filename. + * + * Returns: (transfer none): a pointer to the extension of the filename + **/ +G_GNUC_INTERNAL char* +autoar_common_get_filename_extension (const char *filename) +{ + char *dot_location; + + dot_location = strrchr (filename, '.'); + if (dot_location == NULL || dot_location == filename) { + return (char*)filename; + } + + if (dot_location - 4 > filename && strncmp (dot_location - 4, ".tar", 4) == 0) + dot_location -= 4; + else if (dot_location - 5 > filename && strncmp (dot_location - 5, ".cpio", 5) == 0) + dot_location -= 5; + + return dot_location; +} + +/** + * autoar_common_get_basename_remove_extension: + * @filename: a filename + * + * Gets the basename of a path without its file name extension. + * + * Returns: (transfer full): a new filename without extension. Free the + * returned string with g_free(). + **/ +G_GNUC_INTERNAL char* +autoar_common_get_basename_remove_extension (const char *filename) +{ + char *dot_location; + char *basename; + + if (filename == NULL) { + return NULL; + } + + /* filename must not be directory, so we do not get a bad basename. */ + basename = g_path_get_basename (filename); + + dot_location = autoar_common_get_filename_extension (basename); + if (dot_location != basename) + *dot_location = '\0'; + + g_debug ("autoar_common_get_basename_remove_extension: %s => %s", + filename, + basename); + return basename; +} + +static void +autoar_common_signal_data_free (AutoarCommonSignalData *signal_data) +{ + int i; + + for (i = 0; i < signal_data->used_values; i++) + g_value_unset (signal_data->instance_and_params + i); + + g_free (signal_data); +} + +static gboolean +autoar_common_g_signal_emit_main_context (void *data) +{ + AutoarCommonSignalData *signal_data = data; + g_signal_emitv (signal_data->instance_and_params, + signal_data->signal_id, + signal_data->detail, + NULL); + autoar_common_signal_data_free (signal_data); + return FALSE; +} + +/** + * autoar_common_g_signal_emit: + * @instance: the instance the signal is being emitted on. + * @in_thread: %TRUE if you are not call this function inside the main thread. + * @signal_id: the signal id + * @detail: the detail + * @...: parameters to be passed to the signal. + * + * This is a wrapper for g_signal_emit(). If @in_thread is %FALSE, this + * function is the same as g_signal_emit(). If @in_thread is %TRUE, the + * signal will be emitted from the main thread. This function will send + * the signal emission job via g_main_context_invoke(), but it does not + * wait for the signal emission job to be completed. Hence, the signal + * may emitted after autoar_common_g_signal_emit() is returned. + **/ +G_GNUC_INTERNAL void +autoar_common_g_signal_emit (gpointer instance, + gboolean in_thread, + guint signal_id, + GQuark detail, + ...) +{ + va_list ap; + + va_start (ap, detail); + if (in_thread) { + int i; + gchar *error; + GSignalQuery query; + AutoarCommonSignalData *data; + + error = NULL; + data = g_new0 (AutoarCommonSignalData, 1); + data->signal_id = signal_id; + data->detail = detail; + data->used_values = 1; + g_value_init (data->instance_and_params, G_TYPE_FROM_INSTANCE (instance)); + g_value_set_instance (data->instance_and_params, instance); + + g_signal_query (signal_id, &query); + if (query.signal_id == 0) { + autoar_common_signal_data_free (data); + va_end (ap); + return; + } + + for (i = 0; i < query.n_params; i++) { + G_VALUE_COLLECT_INIT (data->instance_and_params + i + 1, + query.param_types[i], + ap, + 0, + &error); + if (error != NULL) + break; + data->used_values++; + } + + if (error == NULL) { + g_main_context_invoke (NULL, autoar_common_g_signal_emit_main_context, data); + } else { + autoar_common_signal_data_free (data); + g_debug ("G_VALUE_COLLECT_INIT: Error: %s", error); + g_free (error); + va_end (ap); + return; + } + } else { + g_signal_emit_valist (instance, signal_id, detail, ap); + } + va_end (ap); +} + +/** + * autoar_common_g_object_unref: + * @object: a #GObject + * + * This is a wrapper for g_object_unref(). If @object is %NULL, this function + * does nothing. Otherwise, it will call g_object_unref() on the @object. + **/ +G_GNUC_INTERNAL void +autoar_common_g_object_unref (gpointer object) +{ + if (object != NULL) + g_object_unref (object); +} + +/** + * autoar_common_g_error_new_a: + * @a: a archive object + * @pathname: the file which causes error, or %NULL + * + * Creates a new #GError with error messages got from libarchive. + * + * Returns: (transfer full): a #GError. Free with g_error_free(). + **/ +G_GNUC_INTERNAL GError* +autoar_common_g_error_new_a (struct archive *a, + const char *pathname) +{ + GError *newerror; + newerror = g_error_new (AUTOAR_LIBARCHIVE_ERROR, + archive_errno (a), + "%s%s%s%s", + pathname != NULL ? "\'" : "", + pathname != NULL ? pathname : "", + pathname != NULL ? "\': " : "", + archive_error_string (a)); + return newerror; +} + +/** + * autoar_common_g_error_new_a_entry: + * @a: a archive object + * @entry: a archive_entry object + * + * Gets pathname from @entry and call autoar_common_g_error_new_a(). + * + * Returns: (transfer full): a #GError. Free with g_error_free(). + **/ +G_GNUC_INTERNAL GError* +autoar_common_g_error_new_a_entry (struct archive *a, + struct archive_entry *entry) +{ + return autoar_common_g_error_new_a (a, archive_entry_pathname (entry)); +} + +/** + * autoar_common_g_file_get_name: + * @file: a #GFile + * + * Gets a string represents the @file. It will be the path of @file if + * available. Otherwise, it will be the URI of @file. + * + * Returns: (transfer full): a string represents the file. Free the string + * with g_free(). + **/ +G_GNUC_INTERNAL char* +autoar_common_g_file_get_name (GFile *file) +{ + char *name; + name = g_file_get_path (file); + if (name == NULL) + name = g_file_get_uri (file); + return name; +} |