[gupnp] Route _valist functions to _hash functions.
- From: Krzesimir Nowak <krnowak src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gupnp] Route _valist functions to _hash functions.
- Date: Thu, 28 Feb 2013 14:35:36 +0000 (UTC)
commit d80d05f19854f6711b342bdf6039a40d15a5c2af
Author: Krzesimir Nowak <krnowak openismus com>
Date: Thu Feb 28 10:40:27 2013 +0100
Route _valist functions to _hash functions.
To avoid some strange copying and storing of var_args in _valist
functions we just convert va_list into GHashTable, call _hash function
variants and convert GHashTable into va_list again if necessary.
Also, amend some documentation of _valist functions - these are not
particularly friendly for language bindings.
libgupnp/gupnp-service-proxy.c | 325 ++++++++++++++++++++++++----------------
1 files changed, 196 insertions(+), 129 deletions(-)
---
diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c
index c23020d..e6d58e1 100644
--- a/libgupnp/gupnp-service-proxy.c
+++ b/libgupnp/gupnp-service-proxy.c
@@ -90,9 +90,6 @@ struct _GUPnPServiceProxyAction {
GError *error; /* If non-NULL, description of error that
occurred when preparing message */
-
- va_list var_args; /* The va_list after begin_action_valist has
- gone through it. Used by send_action_valist(). */
};
typedef struct {
@@ -410,6 +407,132 @@ stop_main_loop (GUPnPServiceProxy *proxy,
g_main_loop_quit ((GMainLoop *) user_data);
}
+/* This is a skip variant of G_VALUE_LCOPY, same as there is
+ * G_VALUE_COLLECT_SKIP for G_VALUE_COLLECT.
+ */
+#define VALUE_LCOPY_SKIP(value_type, var_args) \
+ G_STMT_START { \
+ GTypeValueTable *_vtable = g_type_value_table_peek (value_type); \
+ const gchar *_lcopy_format = _vtable->lcopy_format; \
+ \
+ while (*_lcopy_format) { \
+ switch (*_lcopy_format++) { \
+ case G_VALUE_COLLECT_INT: \
+ va_arg ((var_args), gint); \
+ break; \
+ case G_VALUE_COLLECT_LONG: \
+ va_arg ((var_args), glong); \
+ break; \
+ case G_VALUE_COLLECT_INT64: \
+ va_arg ((var_args), gint64); \
+ break; \
+ case G_VALUE_COLLECT_DOUBLE: \
+ va_arg ((var_args), gdouble); \
+ break; \
+ case G_VALUE_COLLECT_POINTER: \
+ va_arg ((var_args), gpointer); \
+ break; \
+ default: \
+ g_assert_not_reached (); \
+ } \
+ } \
+ } G_STMT_END
+
+/* Initializes hash table to hold arg names as keys and GValues of
+ * given type, but without any specific value. Note that if you are
+ * going to use OUT_HASH_TABLE_TO_VAR_ARGS then you have to store a
+ * copy of var_args with G_VA_COPY before using this macro.
+ */
+#define VAR_ARGS_TO_OUT_HASH_TABLE(var_args, hash) \
+ G_STMT_START { \
+ const gchar *arg_name = va_arg (var_args, const gchar *); \
+ \
+ while (arg_name != NULL) { \
+ GValue *value = g_new0 (GValue, 1); \
+ GType type = va_arg (var_args, GType); \
+ \
+ VALUE_LCOPY_SKIP (type, var_args); \
+ g_value_init (value, type); \
+ g_hash_table_insert (hash, g_strdup (arg_name), value); \
+ arg_name = va_arg (var_args, const gchar *); \
+ } \
+ } G_STMT_END
+
+/* Initializes hash table to hold arg names as keys and GValues of
+ * given type and value.
+ */
+#define VAR_ARGS_TO_IN_HASH_TABLE(var_args, hash) \
+ G_STMT_START { \
+ const gchar *arg_name = va_arg (var_args, const gchar *); \
+ \
+ while (arg_name != NULL) { \
+ GValue *value = g_new0 (GValue, 1); \
+ gchar *error = NULL; \
+ GType type = va_arg (var_args, GType); \
+ \
+ G_VALUE_COLLECT_INIT (value, \
+ type, \
+ var_args, \
+ G_VALUE_NOCOPY_CONTENTS, \
+ &error); \
+ if (error == NULL) { \
+ g_hash_table_insert (hash, g_strdup (arg_name), value); \
+ } else { \
+ g_warning ("Failed to collect value of type %s for %s: %s", \
+ g_type_name (type), \
+ arg_name, \
+ error); \
+ g_free (error); \
+ } \
+ arg_name = va_arg (var_args, const gchar *); \
+ } \
+ } G_STMT_END
+
+/* Puts values stored in hash table with GValues into var args.
+ */
+#define OUT_HASH_TABLE_TO_VAR_ARGS(hash, var_args) \
+ G_STMT_START { \
+ const gchar *arg_name = va_arg (var_args, const gchar *); \
+ \
+ while (arg_name != NULL) { \
+ GValue *value = g_hash_table_lookup (hash, arg_name); \
+ GType type = va_arg (var_args, GType); \
+ \
+ if (value == NULL) { \
+ g_warning ("No value for %s", arg_name); \
+ G_VALUE_COLLECT_SKIP (type, var_args); \
+ } else if (G_VALUE_TYPE (value) != type) { \
+ g_warning ("Different GType in value (%s) and in var args (%s) for %s.", \
+ G_VALUE_TYPE_NAME (value), \
+ g_type_name (type), \
+ arg_name); \
+ } else { \
+ gchar *error = NULL; \
+ \
+ G_VALUE_LCOPY (value, var_args, 0, &error); \
+ if (error != NULL) { \
+ g_warning ("Failed to lcopy the value of type %s for %s: %s", \
+ g_type_name (type), \
+ arg_name, \
+ error); \
+ g_free (error); \
+ } \
+ } \
+ arg_name = va_arg (var_args, const gchar *); \
+ } \
+ } G_STMT_END
+
+/* GDestroyNotify for GHashTable holding GValues.
+ */
+static void
+value_free (gpointer data)
+{
+ GValue *value = (GValue *) data;
+
+ g_value_unset (value);
+ g_free (value);
+}
+
/**
* gupnp_service_proxy_send_action_valist:
* @proxy: A #GUPnPServiceProxy
@@ -419,8 +542,7 @@ stop_main_loop (GUPnPServiceProxy *proxy,
* parameter value, followed by %NULL, and then tuples of out parameter name,
* out parameter type, and out parameter value location
*
- * See gupnp_service_proxy_send_action(); this version takes a va_list for
- * use by language bindings.
+ * See gupnp_service_proxy_send_action().
*
* Return value: %TRUE if sending the action was succesful.
**/
@@ -430,34 +552,44 @@ gupnp_service_proxy_send_action_valist (GUPnPServiceProxy *proxy,
GError **error,
va_list var_args)
{
- GMainLoop *main_loop;
- GUPnPServiceProxyAction *handle;
+ GHashTable *in_hash;
+ GHashTable *out_hash;
+ va_list var_args_copy;
+ gboolean result;
+ GError *local_error;
g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE);
g_return_val_if_fail (action, FALSE);
- main_loop = g_main_loop_new (g_main_context_get_thread_default (),
- TRUE);
-
- handle = gupnp_service_proxy_begin_action_valist (proxy,
- action,
- stop_main_loop,
- main_loop,
- var_args);
-
- /* Loop till we get a reply (or time out) */
- if (g_main_loop_is_running (main_loop))
- g_main_loop_run (main_loop);
-
- g_main_loop_unref (main_loop);
+ in_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ value_free);
+ VAR_ARGS_TO_IN_HASH_TABLE (var_args, in_hash);
+ G_VA_COPY (var_args_copy, var_args);
+ out_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ value_free);
+ VAR_ARGS_TO_OUT_HASH_TABLE (var_args, out_hash);
+
+ local_error = NULL;
+ result = gupnp_service_proxy_send_action_hash (proxy,
+ action,
+ &local_error,
+ in_hash,
+ out_hash);
- if (!gupnp_service_proxy_end_action_valist (proxy,
- handle,
- error,
- handle->var_args))
- return FALSE;
+ if (local_error == NULL) {
+ OUT_HASH_TABLE_TO_VAR_ARGS (out_hash, var_args_copy);
+ } else {
+ g_propagate_error (error, local_error);
+ }
+ va_end (var_args_copy);
+ g_hash_table_unref (in_hash);
+ g_hash_table_unref (out_hash);
- return TRUE;
+ return result;
}
/**
@@ -822,8 +954,7 @@ write_in_parameter (const char *arg_name,
* @var_args: A va_list of tuples of in parameter name, in parameter type, and
* in parameter value
*
- * See gupnp_service_proxy_begin_action(); this version takes a va_list for
- * use by language bindings.
+ * See gupnp_service_proxy_begin_action().
*
* Returns: (transfer none): A #GUPnPServiceProxyAction handle. This will
* be freed when calling gupnp_service_proxy_cancel_action() or
@@ -837,58 +968,25 @@ gupnp_service_proxy_begin_action_valist
gpointer user_data,
va_list var_args)
{
- const char *arg_name;
GUPnPServiceProxyAction *ret;
+ GHashTable *in_hash;
g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), NULL);
g_return_val_if_fail (action, NULL);
g_return_val_if_fail (callback, NULL);
- /* Create message */
- ret = begin_action_msg (proxy, action, callback, user_data);
-
- if (ret->error) {
- callback (proxy, ret, user_data);
-
- return ret;
- }
- /* Arguments */
- arg_name = va_arg (var_args, const char *);
- while (arg_name) {
- GType arg_type;
- GValue value = { 0, };
- char *collect_error = NULL;
-
- arg_type = va_arg (var_args, GType);
- g_value_init (&value, arg_type);
-
- G_VALUE_COLLECT (&value, var_args, G_VALUE_NOCOPY_CONTENTS,
- &collect_error);
- if (!collect_error) {
- write_in_parameter (arg_name, &value, ret->msg_str);
-
- g_value_unset (&value);
-
- } else {
- g_warning ("Error collecting value: %s\n",
- collect_error);
-
- g_free (collect_error);
-
- /* we purposely leak the value here, it might not be
- * in a sane state if an error condition occoured
- */
- }
-
- arg_name = va_arg (var_args, const char *);
- }
-
- /* Finish and send off */
- finish_action_msg (ret, action);
-
- /* Save the current position in the va_list for send_action_valist() */
- G_VA_COPY (ret->var_args, var_args);
+ in_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ value_free);
+ VAR_ARGS_TO_IN_HASH_TABLE (var_args, in_hash);
+ ret = gupnp_service_proxy_begin_action_hash (proxy,
+ action,
+ callback,
+ user_data,
+ in_hash);
+ g_hash_table_unref (in_hash);
return ret;
}
@@ -1203,8 +1301,7 @@ read_out_parameter (const char *arg_name,
* and out parameter value location. The out parameter values should be
* freed after use
*
- * See gupnp_service_proxy_end_action(); this version takes a va_list for
- * use by language bindings.
+ * See gupnp_service_proxy_end_action().
*
* Return value: %TRUE on success.
**/
@@ -1214,66 +1311,36 @@ gupnp_service_proxy_end_action_valist (GUPnPServiceProxy *proxy,
GError **error,
va_list var_args)
{
- xmlDoc *response;
- xmlNode *params;
- const char *arg_name;
+ GHashTable *out_hash;
+ va_list var_args_copy;
+ gboolean result;
+ GError *local_error;
g_return_val_if_fail (GUPNP_IS_SERVICE_PROXY (proxy), FALSE);
g_return_val_if_fail (action, FALSE);
g_return_val_if_fail (proxy == action->proxy, FALSE);
- /* Check for saved error from begin_action() */
- if (action->error) {
- if (error)
- *error = action->error;
- else
- g_error_free (action->error);
-
- gupnp_service_proxy_action_free (action);
-
- return FALSE;
- }
-
- /* Check response for errors and do initial parsing */
- response = check_action_response (proxy, action, ¶ms, error);
- if (response == NULL) {
- gupnp_service_proxy_action_free (action);
-
- return FALSE;
- }
-
- /* Arguments */
- arg_name = va_arg (var_args, const char *);
- while (arg_name) {
- GType arg_type;
- GValue value = { 0, };
- char *copy_error = NULL;
-
- arg_type = va_arg (var_args, GType);
-
- g_value_init (&value, arg_type);
-
- read_out_parameter (arg_name, &value, params);
-
- G_VALUE_LCOPY (&value, var_args, 0, ©_error);
-
- g_value_unset (&value);
-
- if (copy_error) {
- g_warning ("Error copying value: %s", copy_error);
-
- g_free (copy_error);
- }
+ out_hash = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ value_free);
+ G_VA_COPY (var_args_copy, var_args);
+ VAR_ARGS_TO_OUT_HASH_TABLE (var_args, out_hash);
+ local_error = NULL;
+ result = gupnp_service_proxy_end_action_hash (proxy,
+ action,
+ &local_error,
+ out_hash);
- arg_name = va_arg (var_args, const char *);
+ if (error != NULL) {
+ g_propagate_error (error, local_error);
+ } else {
+ OUT_HASH_TABLE_TO_VAR_ARGS (out_hash, var_args_copy);
}
+ va_end (var_args_copy);
+ g_hash_table_unref (out_hash);
- /* Cleanup */
- gupnp_service_proxy_action_free (action);
-
- xmlFreeDoc (response);
-
- return TRUE;
+ return result;
}
/**
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]