2005-03-09 Colin Walters <walters@verbum.org>
authorColin Walters <walters@verbum.org>
Wed, 9 Mar 2005 17:09:11 +0000 (17:09 +0000)
committerColin Walters <walters@verbum.org>
Wed, 9 Mar 2005 17:09:11 +0000 (17:09 +0000)
* glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls
to this are generated for client-side wrappers.  Invokes a
D-BUS method and returns reply values.

* glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New
function; writes signature string for argument direction.
(write_args_for_direction): Change to pass input values directly
instead of via address, and fix indentation.
(generate_client_glue): Change to invoke dbus_g_proxy_invoke.  Also
make generated wrappers inlineable.

* dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add
note about using dbus_type_is_fixed.

* dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to
dbus/dbus-signature.c as dbus_type_is_fixed.

All callers updated.

* dbus/dbus-signature.c (dbus_type_is_fixed): Moved here
from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed.

* dbus/dbus-signature.h: Prototype.

* glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix
error printf code.

* test/glib/test-dbus-glib.c (main): Be sure to clear error as
appropriate instead of just freeing it.
(main): Free returned strings using g_free.

* test/glib/Makefile.am (test-service-glib-glue.h)
(test-service-glib-bindings.h): Add dependency on dbus-binding-tool.

* glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT;
simply maps a simple D-BUS type to GType.
(dbus_dbus_type_to_gtype): Function which maps D-BUS type to
GType.
(dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and
initialize the value with it.
(dbus_gvalue_binding_type_from_type): Unused, delete.
(dbus_gvalue_demarshal): Switch to hardcoding demarshalling for
various types instead of unmarshalling to value data directly.
Remove can_convert boolean.
(dbus_gvalue_marshal): Remove duplicate initialization; switch to
returning directly instead of using can_convert boolean.
(dbus_gvalue_store): New function; not related to D-BUS per-se.
Stores a GValue in a pointer to a value of its corresponding C
type.

* glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type,
add dbus_gvalue_store.

15 files changed:
ChangeLog
dbus/dbus-glib.h
dbus/dbus-marshal-basic.c
dbus/dbus-marshal-byteswap.c
dbus/dbus-marshal-recursive-util.c
dbus/dbus-marshal-recursive.c
dbus/dbus-message.c
dbus/dbus-signature.c
dbus/dbus-signature.h
glib/dbus-binding-tool-glib.c
glib/dbus-gproxy.c
glib/dbus-gvalue.c
glib/dbus-gvalue.h
test/glib/Makefile.am
test/glib/test-dbus-glib.c

index 844b73c..c57228a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,58 @@
+2005-03-09  Colin Walters  <walters@verbum.org>
+
+       * glib/dbus-gproxy.c (dbus_g_proxy_invoke): New method; calls
+       to this are generated for client-side wrappers.  Invokes a
+       D-BUS method and returns reply values.  
+
+       * glib/dbus-binding-tool-glib.c (write_args_sig_for_direction): New
+       function; writes signature string for argument direction.
+       (write_args_for_direction): Change to pass input values directly
+       instead of via address, and fix indentation.
+       (generate_client_glue): Change to invoke dbus_g_proxy_invoke.  Also
+       make generated wrappers inlineable.
+
+       * dbus/dbus-message.c (dbus_message_iter_get_fixed_array): Add
+       note about using dbus_type_is_fixed.
+
+       * dbus/dbus-marshal-basic.c (_dbus_type_is_fixed): Moved to
+       dbus/dbus-signature.c as dbus_type_is_fixed.
+
+       All callers updated.
+
+       * dbus/dbus-signature.c (dbus_type_is_fixed): Moved here
+       from dbus/dbus-marshal-basic.c:_dbus_type_is_fixed.
+
+       * dbus/dbus-signature.h: Prototype.
+
+       * glib/dbus-binding-tool-glib.c (compute_marshaller_name): Fix
+       error printf code.
+
+       * test/glib/test-dbus-glib.c (main): Be sure to clear error as
+       appropriate instead of just freeing it.
+       (main): Free returned strings using g_free.
+
+       * test/glib/Makefile.am (test-service-glib-glue.h)
+       (test-service-glib-bindings.h): Add dependency on dbus-binding-tool.
+
+       * glib/dbus-gvalue.c (MAP_BASIC): Refactored from MAP_BASIC_INIT;
+       simply maps a simple D-BUS type to GType.
+       (dbus_dbus_type_to_gtype): Function which maps D-BUS type to
+       GType.
+       (dbus_gvalue_init): Just invoke dbus_dbus_type_to_gtype and
+       initialize the value with it.
+       (dbus_gvalue_binding_type_from_type): Unused, delete.
+       (dbus_gvalue_demarshal): Switch to hardcoding demarshalling for
+       various types instead of unmarshalling to value data directly.
+       Remove can_convert boolean.
+       (dbus_gvalue_marshal): Remove duplicate initialization; switch to
+       returning directly instead of using can_convert boolean.
+       (dbus_gvalue_store): New function; not related to D-BUS per-se.
+       Stores a GValue in a pointer to a value of its corresponding C
+       type.
+
+       * glib/dbus-gvalue.h: Remove dbus_gvalue_binding_type_from_type,
+       add dbus_gvalue_store.
+
 2005-03-08  Joe Shaw  <joeshaw@novell.com>
 
        Fix a bunch of lifecycle and memory management problems
index a9aad54..e1b4a70 100644 (file)
@@ -174,6 +174,13 @@ void              dbus_g_proxy_call_no_reply         (DBusGProxy        *proxy,
 
 const char*       dbus_g_proxy_get_bus_name          (DBusGProxy        *proxy);
 
+gboolean          dbus_g_proxy_invoke                (DBusGProxy        *proxy,
+                                                     const char        *method,
+                                                     const char        *insig,
+                                                     const char        *outsig,
+                                                     GError           **error,
+                                                     ...);
+
 #undef DBUS_INSIDE_DBUS_GLIB_H
 
 G_END_DECLS
index fde58d5..ea0648a 100644 (file)
@@ -620,7 +620,7 @@ _dbus_marshal_read_fixed_multi  (const DBusString *str,
   int array_len;
   int alignment;
 
-  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_fixed (element_type));
   _dbus_assert (dbus_type_is_basic (element_type));
 
 #if 0
@@ -1054,7 +1054,7 @@ marshal_fixed_multi (DBusString           *str,
 
 /**
  * Marshals a block of values of fixed-length type all at once, as an
- * optimization.  _dbus_type_is_fixed() returns #TRUE for fixed-length
+ * optimization.  dbus_type_is_fixed() returns #TRUE for fixed-length
  * types, which are the basic types minus the string-like types.
  *
  * The value argument should be the adddress of an
@@ -1080,7 +1080,7 @@ _dbus_marshal_write_fixed_multi (DBusString *str,
 {
   const void* vp = *(const DBusBasicValue**)value;
   
-  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_fixed (element_type));
   _dbus_assert (n_elements >= 0);
 
 #if 0
@@ -1299,34 +1299,6 @@ _dbus_type_is_valid (int typecode)
 }
 
 /**
- * Tells you whether values of this type can change length if you set
- * them to some other value. For this purpose, you assume that the
- * first byte of the old and new value would be in the same location,
- * so alignment padding is not a factor.
- *
- * @returns #FALSE if the type can occupy different lengths
- */
-dbus_bool_t
-_dbus_type_is_fixed (int typecode)
-{
-  switch (typecode)
-    {
-    case DBUS_TYPE_BYTE:
-    case DBUS_TYPE_BOOLEAN:
-    case DBUS_TYPE_INT16:
-    case DBUS_TYPE_UINT16:
-    case DBUS_TYPE_INT32:
-    case DBUS_TYPE_UINT32:
-    case DBUS_TYPE_INT64:
-    case DBUS_TYPE_UINT64:
-    case DBUS_TYPE_DOUBLE:
-      return TRUE;
-    default:
-      return FALSE;
-    }
-}
-
-/**
  * Returns a string describing the given type.
  *
  * @param typecode the type to describe
index c8ec894..7571e2f 100644 (file)
@@ -23,6 +23,7 @@
 
 #include "dbus-marshal-byteswap.h"
 #include "dbus-marshal-basic.h"
+#include "dbus-signature.h"
 
 /**
  * @addtogroup DBusMarshal
@@ -103,7 +104,7 @@ byteswap_body_helper (DBusTypeReader       *reader,
 
                 p = _DBUS_ALIGN_ADDRESS (p, alignment);
                 
-                if (_dbus_type_is_fixed (elem_type))
+                if (dbus_type_is_fixed (elem_type))
                   {
                     if (alignment > 1)
                       _dbus_swap_array (p, array_len / alignment, alignment);
index e1b00e5..0d06bc2 100644 (file)
@@ -3074,7 +3074,7 @@ array_write_value (TestTypeNode   *node,
     goto oom;
 
   if (arrays_write_fixed_in_blocks &&
-      _dbus_type_is_fixed (element_type) &&
+      dbus_type_is_fixed (element_type) &&
       child->klass->write_multi)
     {
       if (!node_write_multi (child, block, &sub, seed, n_copies))
@@ -3138,7 +3138,7 @@ array_read_or_set_value (TestTypeNode   *node,
       _dbus_type_reader_recurse (reader, &sub);
 
       if (realign_root == NULL && arrays_write_fixed_in_blocks &&
-          _dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
+          dbus_type_is_fixed (_dbus_type_reader_get_element_type (reader)) &&
           child->klass->read_multi)
         {
           if (!node_read_multi (child, &sub, seed, n_copies))
index 432e6f0..6fcbd62 100644 (file)
@@ -1018,7 +1018,7 @@ _dbus_type_reader_read_fixed_multi (const DBusTypeReader  *reader,
                                                 reader->type_pos);
 
   _dbus_assert (element_type != DBUS_TYPE_INVALID); /* why we don't use get_current_type() */
-  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_fixed (element_type));
 
   alignment = _dbus_type_get_alignment (element_type);
 
@@ -1464,7 +1464,7 @@ _dbus_type_reader_set_basic (DBusTypeReader       *reader,
 
   _dbus_assert (dbus_type_is_basic (current_type));
 
-  if (_dbus_type_is_fixed (current_type))
+  if (dbus_type_is_fixed (current_type))
     {
       reader_set_basic_fixed_length (reader, current_type, value);
       return TRUE;
@@ -2404,7 +2404,7 @@ _dbus_type_writer_write_basic (DBusTypeWriter *writer,
 
 /**
  * Writes a block of fixed-length basic values, i.e. those that are
- * both _dbus_type_is_fixed() and _dbus_type_is_basic(). The block
+ * both dbus_type_is_fixed() and _dbus_type_is_basic(). The block
  * must be written inside an array.
  *
  * The value parameter should be the address of said array of values,
@@ -2423,7 +2423,7 @@ _dbus_type_writer_write_fixed_multi (DBusTypeWriter        *writer,
                                      int                    n_elements)
 {
   _dbus_assert (writer->container_type == DBUS_TYPE_ARRAY);
-  _dbus_assert (_dbus_type_is_fixed (element_type));
+  _dbus_assert (dbus_type_is_fixed (element_type));
   _dbus_assert (writer->type_pos_is_expectation);
   _dbus_assert (n_elements >= 0);
 
index 672a72b..b090fab 100644 (file)
@@ -1270,7 +1270,7 @@ dbus_message_append_args_valist (DBusMessage *message,
                                                  &array))
             goto failed;
           
-          if (_dbus_type_is_fixed (element_type))
+          if (dbus_type_is_fixed (element_type))
             {
               const DBusBasicValue **value;
               int n_elements;
@@ -1676,6 +1676,9 @@ dbus_message_iter_get_basic (DBusMessageIter  *iter,
  * such as integers, bool, double. The block read will be from the
  * current position in the array until the end of the array.
  *
+ * This function should only be used if #dbus_type_is_fixed returns
+ * #TRUE for the element type.
+ *
  * The value argument should be the address of a location to store the
  * returned array. So for int32 it should be a "const dbus_int32_t**"
  * The returned value is by reference and should not be freed.
@@ -1693,7 +1696,7 @@ dbus_message_iter_get_fixed_array (DBusMessageIter  *iter,
 
   _dbus_return_if_fail (_dbus_message_iter_check (real));
   _dbus_return_if_fail (value != NULL);
-  _dbus_return_if_fail (_dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader)));
+  _dbus_return_if_fail (dbus_type_is_fixed (_dbus_type_reader_get_element_type (&real->u.reader)));
 
   _dbus_type_reader_read_fixed_multi (&real->u.reader,
                                       value, n_elements);
@@ -1778,7 +1781,7 @@ _dbus_message_iter_get_args_valist (DBusMessageIter *iter,
               goto out;
             }
 
-          if (_dbus_type_is_fixed (spec_element_type))
+          if (dbus_type_is_fixed (spec_element_type))
             {
               ptr = va_arg (var_args, const DBusBasicValue**);
               n_elements_p = va_arg (var_args, int*);
@@ -2138,7 +2141,7 @@ dbus_message_iter_append_fixed_array (DBusMessageIter *iter,
 
   _dbus_return_val_if_fail (_dbus_message_iter_append_check (real), FALSE);
   _dbus_return_val_if_fail (real->iter_type == DBUS_MESSAGE_ITER_TYPE_WRITER, FALSE);
-  _dbus_return_val_if_fail (_dbus_type_is_fixed (element_type), FALSE);
+  _dbus_return_val_if_fail (dbus_type_is_fixed (element_type), FALSE);
   _dbus_return_val_if_fail (real->u.writer.container_type == DBUS_TYPE_ARRAY, FALSE);
   _dbus_return_val_if_fail (value != NULL, FALSE);
   _dbus_return_val_if_fail (n_elements >= 0, FALSE);
index 698c21e..7cbae7c 100644 (file)
@@ -262,6 +262,36 @@ dbus_type_is_basic (int typecode)
   return !(typecode == DBUS_TYPE_INVALID || TYPE_IS_CONTAINER (typecode));
 }
 
+/**
+ * Tells you whether values of this type can change length if you set
+ * them to some other value. For this purpose, you assume that the
+ * first byte of the old and new value would be in the same location,
+ * so alignment padding is not a factor.
+ *
+ * This function is useful to determine whether #dbus_message_iter_get_fixed_array
+ * may be used.
+ *
+ * @returns #FALSE if the type can occupy different lengths
+ */
+dbus_bool_t
+dbus_type_is_fixed (int typecode)
+{
+  switch (typecode)
+    {
+    case DBUS_TYPE_BYTE:
+    case DBUS_TYPE_BOOLEAN:
+    case DBUS_TYPE_INT16:
+    case DBUS_TYPE_UINT16:
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
 
 #ifdef DBUS_BUILD_TESTS
 
index 3c50795..fd64ed1 100644 (file)
@@ -65,6 +65,7 @@ dbus_bool_t     dbus_signature_validate_single       (const char       *signatur
 
 dbus_bool_t     dbus_type_is_basic                   (int            typecode);
 dbus_bool_t     dbus_type_is_container               (int            typecode);
+dbus_bool_t     dbus_type_is_fixed                   (int            typecode);
 
 DBUS_END_DECLS
 
index 641f07d..5bd413e 100644 (file)
@@ -140,7 +140,7 @@ compute_marshaller_name (MethodInfo *method, GError **error)
              g_set_error (error,
                           DBUS_BINDING_TOOL_ERROR,
                           DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
-                          _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
+                          _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
                           type);
              g_string_free (ret, TRUE);
              return NULL;
@@ -647,42 +647,54 @@ write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *c
 }
 
 static gboolean
-write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
 {
   GSList *args;
 
+  WRITE_OR_LOSE ("\"");
+
   for (args = method_info_get_args (method); args; args = args->next)
     {
       ArgInfo *arg;
-      const char *type_str;
 
       arg = args->data;
 
       if (direction != arg_info_get_direction (arg))
        continue;
 
-      type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
-      if (!type_str)
-       {
-         g_set_error (error,
-                      DBUS_BINDING_TOOL_ERROR,
-                      DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
-                      _("Unsupported conversion from D-BUS type %s"),
-                      arg_info_get_type (arg));
-         return FALSE;
-       }
+      if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
+       goto io_lose;
+    }
+
+  WRITE_OR_LOSE ("\", ");
+
+  return TRUE;
+ io_lose:
+  return FALSE;
+}
+
+static gboolean
+write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
+{
+  GSList *args;
+
+  for (args = method_info_get_args (method); args; args = args->next)
+    {
+      ArgInfo *arg;
+
+      arg = args->data;
+
+      if (direction != arg_info_get_direction (arg))
+       continue;
 
-      
       switch (direction)
        {
        case ARG_IN:
-         if (!write_printf_to_iochannel ("                                  %s, &IN_%s,\n", channel, error,
-                                         type_str, arg_info_get_name (arg)))
+         if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
            goto io_lose;
          break;
        case ARG_OUT:
-         if (!write_printf_to_iochannel ("                               %s, OUT_%s,\n", channel, error,
-                                         type_str, arg_info_get_name (arg)))
+         if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
            goto io_lose;
          break;
        case ARG_INVALID:
@@ -746,7 +758,7 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
 
          method_name = compute_client_method_name (interface, method);
 
-         WRITE_OR_LOSE ("static gboolean\n");
+         WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
          if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
                                          method_name))
            goto io_lose;
@@ -758,29 +770,26 @@ generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error
          WRITE_OR_LOSE (", GError **error)\n\n");
          
          WRITE_OR_LOSE ("{\n");
-         WRITE_OR_LOSE ("  gboolean ret;\n\n");
-         WRITE_OR_LOSE ("  DBusGPendingCall *call;\n\n");
          
-         if (!write_printf_to_iochannel ("  call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
-                                         channel, error,
+         if (!write_printf_to_iochannel ("  return dbus_g_proxy_invoke (proxy, \"%s\", ", channel, error,
                                          method_info_get_name (method)))
            goto io_lose;
 
-         if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
+         if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
            goto io_lose;
 
-         WRITE_OR_LOSE ("                                  DBUS_TYPE_INVALID);\n");
-         WRITE_OR_LOSE ("  ret = dbus_g_proxy_end_call (proxy, call, error,\n");
-         
-         if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
+         if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
            goto io_lose;
 
-         WRITE_OR_LOSE ("                               DBUS_TYPE_INVALID);\n");
+         WRITE_OR_LOSE ("error, ");
 
-         WRITE_OR_LOSE ("  dbus_g_pending_call_unref (call);\n");
-         WRITE_OR_LOSE ("  return ret;\n");
+         if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
+           goto io_lose;
+
+         if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
+           goto io_lose;
 
-         WRITE_OR_LOSE ("}\n\n");
+         WRITE_OR_LOSE ("NULL);\n}\n\n");
        }
     }
   return TRUE;
index 65f14e1..b5e977a 100644 (file)
  */
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-signature.h>
 #include "dbus-gutils.h"
 #include "dbus-gmarshal.h"
 #include "dbus-gvalue.h"
 #include "dbus-gobject.h"
 #include <string.h>
+#include <glib/gi18n.h>
+#include <gobject/gvaluecollector.h>
 
 /**
  * @addtogroup DBusGLibInternals
@@ -1397,6 +1400,208 @@ dbus_g_proxy_end_call (DBusGProxy          *proxy,
 }
 
 /**
+ * Function for invoking a method and receiving reply values.
+ * Normally this is not used directly - calls to it are generated
+ * from client-side wrappers (see dbus-binding-tool).
+ *
+ * This function takes two type signatures, one for method arguments,
+ * and one for return values.  The remaining arguments after the
+ * error parameter should be values of the input arguments,
+ * followed by pointer values to storage for return values.
+ *
+ * @param proxy a proxy for a remote interface
+ * @param method method to invoke
+ * @param insig signature of input values
+ * @param outsig signature of output values
+ * @param error return location for an error
+ * @returns #FALSE if an error is set, TRUE otherwise
+ */
+gboolean
+dbus_g_proxy_invoke (DBusGProxy        *proxy,
+                    const char        *method,
+                    const char        *insig,
+                    const char        *outsig,
+                    GError           **error,
+                    ...)
+{
+  DBusPendingCall *pending;
+  DBusMessage *message;
+  DBusMessage *reply;
+  va_list args;
+  va_list args_unwind;
+  int n_retvals_processed;
+  DBusMessageIter msgiter;
+  DBusSignatureIter sigiter;
+  int expected_type;
+  gboolean ret;
+  DBusError derror;
+  
+  g_return_val_if_fail (DBUS_IS_G_PROXY (proxy), FALSE);
+  g_return_val_if_fail (!DBUS_G_PROXY_DESTROYED (proxy), FALSE);
+
+  va_start (args, error);
+  /* Keep around a copy of output arguments so we
+   * can free on error. */
+  G_VA_COPY (args_unwind, args);
+
+  ret = FALSE;
+  pending = NULL;
+  reply = NULL;
+  n_retvals_processed = 0;
+  message = dbus_message_new_method_call (proxy->name,
+                                          proxy->path,
+                                          proxy->interface,
+                                          method);
+  if (message == NULL)
+    goto oom;
+
+  dbus_signature_iter_init (&sigiter, insig);
+  dbus_message_iter_init_append (message, &msgiter);
+  while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+    {
+      GValue gvalue = {0, };
+      char *collect_err;
+
+      if (!dbus_gvalue_init (expected_type, &gvalue))
+       {
+         g_set_error (error, DBUS_GERROR,
+                      DBUS_GERROR_INVALID_ARGS,
+                      _("Unsupported type '%c'"), expected_type);
+         goto out;
+       } 
+      
+      G_VALUE_COLLECT (&gvalue, args, G_VALUE_NOCOPY_CONTENTS, &collect_err);
+
+      if (collect_err)
+       {
+         g_set_error (error, DBUS_GERROR,
+                      DBUS_GERROR_INVALID_ARGS,
+                      collect_err);
+         goto out;
+       }
+
+      /* Anything we can init must be marshallable */
+      if (!dbus_gvalue_marshal (&msgiter, &gvalue))
+       g_assert_not_reached ();
+      g_value_unset (&gvalue);
+
+      dbus_signature_iter_next (&sigiter);
+    }
+
+  if (!dbus_connection_send_with_reply (proxy->manager->connection,
+                                        message,
+                                        &pending,
+                                        -1))
+    goto oom;
+
+  dbus_pending_call_block (pending);
+  reply = dbus_pending_call_steal_reply (pending);
+
+  g_assert (reply != NULL);
+
+  dbus_error_init (&derror);
+
+  switch (dbus_message_get_type (reply))
+    {
+    case DBUS_MESSAGE_TYPE_METHOD_RETURN:
+
+      dbus_signature_iter_init (&sigiter, outsig);
+      dbus_message_iter_init (reply, &msgiter);
+      while ((expected_type = dbus_signature_iter_get_current_type (&sigiter)) != DBUS_TYPE_INVALID)
+       {
+         int arg_type;
+         gpointer *value_ret;
+         GValue gvalue = { 0, };
+
+         value_ret = va_arg (args, gpointer *);
+
+         arg_type = dbus_message_iter_get_arg_type (&msgiter);
+         if (expected_type != arg_type)
+           {
+             if (arg_type == DBUS_TYPE_INVALID)
+                 g_set_error (error, DBUS_GERROR,
+                              DBUS_GERROR_INVALID_ARGS,
+                              _("Too few arguments in reply"));
+             else
+                 g_set_error (error, DBUS_GERROR,
+                              DBUS_GERROR_INVALID_ARGS,
+                              _("Reply argument was \"%c\", expected \"%c\""),
+                              arg_type, expected_type);  
+             goto out;
+           }
+         
+         if (!dbus_gvalue_demarshal (&msgiter, &gvalue))
+           {
+             g_set_error (error,
+                          DBUS_GERROR,
+                          DBUS_GERROR_INVALID_ARGS,
+                          _("Couldn't convert argument type \"%c\""), expected_type);
+             goto out;
+           }
+         /* Anything that can be demarshaled must be storable */
+         if (!dbus_gvalue_store (&gvalue, value_ret))
+           g_assert_not_reached ();
+         g_value_unset (&gvalue);
+         
+         n_retvals_processed++;
+         dbus_signature_iter_next (&sigiter);
+         dbus_message_iter_next (&msgiter);
+       }
+      if (dbus_message_iter_get_arg_type (&msgiter) != DBUS_TYPE_INVALID)
+       {
+         g_set_error (error, DBUS_GERROR,
+                      DBUS_GERROR_INVALID_ARGS,
+                      _("Too many arguments"));
+         goto out;
+       }
+      break;
+    case DBUS_MESSAGE_TYPE_ERROR:
+      dbus_set_error_from_message (&derror, reply);
+      dbus_set_g_error (error, &derror);
+      dbus_error_free (&derror);
+      goto out;
+      break;
+    default:
+      dbus_set_error (&derror, DBUS_ERROR_FAILED,
+                      "Reply was neither a method return nor an exception");
+      dbus_set_g_error (error, &derror);
+      dbus_error_free (&derror);
+      goto out;
+      break;
+    }
+
+  ret = TRUE;
+ out:
+  va_end (args);
+
+  if (ret == FALSE)
+    {
+      int i;
+      for (i = 0; i < n_retvals_processed; i++)
+       {
+         gpointer retval;
+
+         retval = va_arg (args_unwind, gpointer);
+
+         g_free (retval);
+       }
+    }
+  va_end (args_unwind);
+
+  if (pending)
+    dbus_pending_call_unref (pending);
+  if (message)
+    dbus_message_unref (message);
+  if (reply)
+    dbus_message_unref (reply);
+  return ret;
+ oom:
+  g_error ("Out of memory");
+  ret = FALSE;
+  goto out;
+}
+
+/**
  * Sends a method call message as with dbus_g_proxy_begin_call(), but
  * does not ask for a reply or allow you to receive one.
  *
index bcda925..eae5a45 100644 (file)
 #include "dbus/dbus-signature.h"
 
 /* This is slightly evil, we don't use g_value_set_foo() functions */
-#define MAP_BASIC_INIT(d_t, g_t)                                     \
-    case DBUS_TYPE_##d_t:                                       \
-      g_value_init (value, G_TYPE_##g_t);                       \
-      break
+#define MAP_BASIC(d_t, g_t)                     \
+    case DBUS_TYPE_##d_t:                       \
+      return G_TYPE_##g_t;
 
-gboolean
-dbus_gvalue_init      (int     type,
-                      GValue *value)
+static GType
+dbus_dbus_type_to_gtype (int type)
 {
-  gboolean can_convert;
-
-  can_convert = TRUE;
-
   switch (type)
     {
-      MAP_BASIC_INIT (BOOLEAN, BOOLEAN);
-      MAP_BASIC_INIT (BYTE,    UCHAR);
-      MAP_BASIC_INIT (INT32,   INT);
-      MAP_BASIC_INIT (UINT32,  UINT);
-      MAP_BASIC_INIT (INT64,   INT64);
-      MAP_BASIC_INIT (UINT64,  UINT64);
-      MAP_BASIC_INIT (DOUBLE,  DOUBLE);
-
+      MAP_BASIC (BOOLEAN, BOOLEAN);
+      MAP_BASIC (BYTE,    UCHAR);
+      MAP_BASIC (INT32,   INT);
+      MAP_BASIC (UINT32,  UINT);
+      MAP_BASIC (INT64,   INT64);
+      MAP_BASIC (UINT64,  UINT64);
+      MAP_BASIC (DOUBLE,  DOUBLE);
     case DBUS_TYPE_INT16:
-        g_value_init (value, G_TYPE_INT);
-      break;
+      return G_TYPE_INT;
     case DBUS_TYPE_UINT16:
-        g_value_init (value, G_TYPE_UINT);
-      break;
-      
+      return G_TYPE_UINT;
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_SIGNATURE:
-        g_value_init (value, G_TYPE_STRING);
-      break;
-      
+      return G_TYPE_STRING;
     case DBUS_TYPE_STRUCT:
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_VARIANT:
     default:
-      can_convert = FALSE;
+      return G_TYPE_INVALID;
     }
-#undef MAP_BASIC_INIT
-  return can_convert;
+}
+
+#undef MAP_BASIC
+
+gboolean
+dbus_gvalue_init (int     type,
+                 GValue *value)
+{
+  GType gtype;
+
+  gtype = dbus_dbus_type_to_gtype (type);
+  if (gtype == G_TYPE_INVALID)
+    return FALSE;
+  g_value_init (value, gtype);
+  return TRUE;
 }
 
 /* FIXME - broken for containers
@@ -125,43 +126,6 @@ dbus_gvalue_genmarshal_name_from_type (const char *signature)
 }
 
 const char *
-dbus_gvalue_binding_type_from_type (const char *signature)
-{
-  int type;
-
-  type = base_type_from_signature (signature);
-
-#define STRINGIFY(x) \
-  case x: \
-    return (#x)
-  
-  switch (type)
-    {
-      STRINGIFY(DBUS_TYPE_BOOLEAN);
-      STRINGIFY(DBUS_TYPE_BYTE);
-      STRINGIFY(DBUS_TYPE_INT32);
-      STRINGIFY(DBUS_TYPE_UINT32);
-      STRINGIFY(DBUS_TYPE_INT64);
-      STRINGIFY(DBUS_TYPE_UINT64);
-      STRINGIFY(DBUS_TYPE_DOUBLE);
-    case DBUS_TYPE_INT16:
-      return "DBUS_TYPE_INT32";
-    case DBUS_TYPE_UINT16:
-      return "DBUS_TYPE_UINT32";
-    STRINGIFY(DBUS_TYPE_STRING);
-    STRINGIFY(DBUS_TYPE_OBJECT_PATH);
-    STRINGIFY(DBUS_TYPE_SIGNATURE);
-
-    case DBUS_TYPE_STRUCT:
-    case DBUS_TYPE_ARRAY:
-    case DBUS_TYPE_VARIANT:
-      return NULL;
-    }
-#undef STRINGIFY
-  return NULL;
-}
-
-const char *
 dbus_gvalue_ctype_from_type (const char *signature, gboolean in)
 {
   int type;
@@ -249,69 +213,96 @@ dbus_gtype_to_dbus_type (GType type)
 gboolean
 dbus_gvalue_demarshal (DBusMessageIter *iter, GValue *value)
 {
-  gboolean can_convert = TRUE;
-
   g_assert (sizeof (dbus_bool_t) == sizeof (value->data[0].v_int));
 
   dbus_gvalue_init (dbus_message_iter_get_arg_type (iter), value);
   
-/* This is slightly evil, we don't use g_value_set_foo() functions */
-#define MAP_BASIC(d_t, g_t)                                     \
-    case DBUS_TYPE_##d_t:                                       \
-      dbus_message_iter_get_basic (iter, &value->data[0]);      \
-      break
-
   switch (dbus_message_iter_get_arg_type (iter))
     {
-      MAP_BASIC (BOOLEAN, BOOLEAN);
-      MAP_BASIC (BYTE,    UCHAR);
-      MAP_BASIC (INT32,   INT);
-      MAP_BASIC (UINT32,  UINT);
-      MAP_BASIC (INT64,   INT64);
-      MAP_BASIC (UINT64,  UINT64);
-      MAP_BASIC (DOUBLE,  DOUBLE);
-
+    case DBUS_TYPE_BOOLEAN:
+      {
+       dbus_bool_t bool;
+       dbus_message_iter_get_basic (iter, &bool);
+       g_value_set_boolean (value, bool);
+       return TRUE;
+      }
+    case DBUS_TYPE_BYTE:
+      {
+       unsigned char byte;
+       dbus_message_iter_get_basic (iter, &byte);
+       g_value_set_uchar (value, byte);
+       return TRUE;
+      }
+    case DBUS_TYPE_INT32:
+      {
+       dbus_int32_t intval;
+       dbus_message_iter_get_basic (iter, &intval);
+       g_value_set_int (value, intval);
+       return TRUE;
+      }
+    case DBUS_TYPE_UINT32:
+      {
+       dbus_uint32_t intval;
+       dbus_message_iter_get_basic (iter, &intval);
+       g_value_set_uint (value, intval);
+       return TRUE;
+      }
+    case DBUS_TYPE_INT64:
+      {
+       dbus_int64_t intval;
+       dbus_message_iter_get_basic (iter, &intval);
+       g_value_set_int64 (value, intval);
+       return TRUE;
+      }
+    case DBUS_TYPE_UINT64:
+      {
+       dbus_uint64_t intval;
+       dbus_message_iter_get_basic (iter, &intval);
+       g_value_set_uint64 (value, intval);
+       return TRUE;
+      }
+    case DBUS_TYPE_DOUBLE:
+      {
+       double dval;
+       dbus_message_iter_get_basic (iter, &dval);
+       g_value_set_double (value, dval);
+       return TRUE;
+      }
     case DBUS_TYPE_INT16:
       {
         dbus_int16_t v;
         dbus_message_iter_get_basic (iter, &v);
         g_value_set_int (value, v);
+       return TRUE;
       }
-      break;
     case DBUS_TYPE_UINT16:
       {
         dbus_uint16_t v;
         dbus_message_iter_get_basic (iter, &v);
         g_value_set_uint (value, v);
+       return TRUE;
       }
-      break;
-      
     case DBUS_TYPE_STRING:
     case DBUS_TYPE_OBJECT_PATH:
     case DBUS_TYPE_SIGNATURE:
       {
         const char *s;
-
         dbus_message_iter_get_basic (iter, &s);
         g_value_set_string (value, s);
+       return TRUE;
       }
-      break;
-      
     case DBUS_TYPE_STRUCT:
     case DBUS_TYPE_ARRAY:
     case DBUS_TYPE_VARIANT:
     default:
-      can_convert = FALSE;
+      return FALSE;
     }
-#undef MAP_BASIC
-  return can_convert;
 }
     
 gboolean
 dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
 {
-  gboolean can_convert = TRUE;
-  GType value_type = G_VALUE_TYPE (value);
+  GType value_type;
 
   value_type = G_VALUE_TYPE (value);
   
@@ -325,7 +316,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &b))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_UCHAR:
       {
         unsigned char b = g_value_get_uchar (value);
@@ -334,7 +325,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &b))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_BOOLEAN:
       {
         dbus_bool_t b = g_value_get_boolean (value);
@@ -343,7 +334,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &b))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_INT:
       {
         dbus_int32_t v = g_value_get_int (value);
@@ -352,7 +343,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_UINT:
       {
         dbus_uint32_t v = g_value_get_uint (value);
@@ -361,7 +352,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
       /* long gets cut to 32 bits so the remote API is consistent
        * on all architectures
        */
@@ -373,7 +364,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_ULONG:
       {
         dbus_uint32_t v = g_value_get_ulong (value);
@@ -382,7 +373,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_INT64:
       {
         gint64 v = g_value_get_int64 (value);
@@ -391,7 +382,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_UINT64:
       {
         guint64 v = g_value_get_uint64 (value);
@@ -400,7 +391,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_FLOAT:
       {
         double v = g_value_get_float (value);
@@ -410,7 +401,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_DOUBLE:
       {
         double v = g_value_get_double (value);
@@ -420,7 +411,7 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
     case G_TYPE_STRING:
       /* FIXME, the GValue string may not be valid UTF-8 */
       {
@@ -430,19 +421,62 @@ dbus_gvalue_marshal (DBusMessageIter *iter, GValue *value)
                                              &v))
           goto nomem;
       }
-      break;
+      return TRUE;
       
     default:
       /* FIXME: we need to define custom boxed types for arrays
         etc. so we can map them transparently / pleasantly */
-      can_convert = FALSE;
-      break;
+      return FALSE;
     }
 
-  return can_convert;
-
  nomem:
   g_error ("no memory");
   return FALSE;
 }
 
+/* FIXME is there a better way to do this? */
+gboolean
+dbus_gvalue_store (GValue          *value,
+                  gpointer        storage)
+{
+  switch (G_VALUE_TYPE (value))
+    {
+    case G_TYPE_CHAR:
+      *((gchar *) storage) = g_value_get_char (value);
+      return TRUE;
+    case G_TYPE_UCHAR:
+      *((guchar *) storage) = g_value_get_uchar (value);
+      return TRUE;
+    case G_TYPE_BOOLEAN:
+      *((gboolean *) storage) = g_value_get_boolean (value);
+      return TRUE;
+    case G_TYPE_LONG:
+      *((glong *) storage) = g_value_get_long (value);
+      return TRUE;
+    case G_TYPE_ULONG:
+      *((gulong *) storage) = g_value_get_ulong (value);
+      return TRUE;
+    case G_TYPE_INT:
+      *((gint *) storage) = g_value_get_int (value);
+      return TRUE;
+    case G_TYPE_UINT:
+      *((guint *) storage) = g_value_get_uint (value);
+      return TRUE;
+    case G_TYPE_INT64:
+      *((gint64 *) storage) = g_value_get_int64 (value);
+      return TRUE;
+    case G_TYPE_UINT64:
+      *((guint64 *) storage) = g_value_get_uint64 (value);
+      return TRUE;
+    case G_TYPE_FLOAT:
+    case G_TYPE_DOUBLE:
+      *((gdouble *) storage) = g_value_get_double (value);
+      return TRUE;
+    case G_TYPE_STRING:
+      /* FIXME - should optimize by not duping string twice */
+      *((gchar **) storage) = g_value_dup_string (value);
+      return TRUE;
+    default:
+      return FALSE;
+    }
+}
index dc1cf32..4caa688 100644 (file)
@@ -24,8 +24,6 @@ const char *   dbus_gvalue_genmarshal_name_from_type (const char *type);
 
 const char *   dbus_gvalue_ctype_from_type           (const char *type, gboolean in);
 
-const char *   dbus_gvalue_binding_type_from_type    (const char *type);
-
 const char *   dbus_gtype_to_dbus_type    (GType            type);
 
 gboolean       dbus_gvalue_init           (int              type,
@@ -36,6 +34,8 @@ gboolean       dbus_gvalue_demarshal      (DBusMessageIter *iter,
 gboolean       dbus_gvalue_marshal        (DBusMessageIter *iter,
                                           GValue          *value);
 
+gboolean       dbus_gvalue_store          (GValue          *value,
+                                          gpointer         storage);
 
 G_END_DECLS
 
index 58f4d77..b0b8361 100644 (file)
@@ -44,10 +44,10 @@ test_service_glib_SOURCES=                          \
 
 BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h
 
-test-service-glib-glue.h: test-service-glib.xml
+test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
        $(top_builddir)/glib/dbus-binding-tool --mode=glib-server --output=test-service-glib-glue.h test-service-glib.xml
 
-test-service-glib-bindings.h: test-service-glib.xml
+test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
        $(top_builddir)/glib/dbus-binding-tool --mode=glib-client --output=test-service-glib-bindings.h test-service-glib.xml
 
 CLEANFILES = test-service-glib-glue.h test-service-glib-bindings.h
index 0c2078e..b0dc9ef 100644 (file)
@@ -267,7 +267,7 @@ main (int argc, char **argv)
     lose ("ThrowError call unexpectedly succeeded!");
 
   g_print ("ThrowError failed (as expected) returned error: %s\n", error->message);
-  g_error_free (error);
+  g_clear_error (&error);
 
   v_STRING = "foobar";
   call = dbus_g_proxy_begin_call (proxy, "Uppercase",
@@ -313,12 +313,13 @@ main (int argc, char **argv)
     lose ("(wrapped) ThrowError call unexpectedly succeeded!");
 
   g_print ("(wrapped) ThrowError failed (as expected) returned error: %s\n", error->message);
-  g_error_free (error);
+  g_clear_error (&error);
 
   if (!org_freedesktop_DBus_Tests_MyObject_uppercase (proxy, "foobar", &v_STRING_2, &error)) 
     lose_gerror ("Failed to complete (wrapped) Uppercase call", error);
   if (strcmp ("FOOBAR", v_STRING_2) != 0)
     lose ("(wrapped) Uppercase call returned unexpected string %s", v_STRING_2);
+  g_free (v_STRING_2);
 
   if (!org_freedesktop_DBus_Tests_MyObject_many_args (proxy, 26, "bazwhee", G_PI,
                                                      &v_DOUBLE_2, &v_STRING_2, &error))
@@ -330,6 +331,7 @@ main (int argc, char **argv)
 
   if (strcmp ("BAZWHEE", v_STRING_2) != 0)
     lose ("(wrapped) ManyArgs call returned unexpected string %s", v_STRING_2);
+  g_free (v_STRING_2);
 
   g_object_unref (G_OBJECT (proxy));