diff options
author | Colin Walters <walters@verbum.org> | 2005-02-17 17:41:30 +0000 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2005-02-17 17:41:30 +0000 |
commit | 03f6615eaccc2c1f84d4252e5a627a2ac86d41d9 (patch) | |
tree | 6b7867f43ae7858f2aae4a208e01d10dd3d752a3 /glib/dbus-binding-tool-glib.c | |
parent | 9e4450872a6861bd93a01dabe14d2d16f6c84d3f (diff) |
2005-02-17 Colin Walters <walters@verbum.org>
This patch is based on initial work from
Paul Kuliniewicz <kuliniew@purdue.edu>.
* glib/dbus-gvalue.c (dbus_gvalue_init): New function; move
initialization of GValue from dbus type to here.
(dbus_gvalue_genmarshal_name_from_type): New function; generates a string
for the "glib-genmarshal" program from a DBus type.
(dbus_gvalue_binding_type_from_type): New function; turns a DBus type
into the C name for it we use in the glib bindings.
(dbus_gvalue_ctype_from_type): New function; maps a DBus type into a
glib C type (not GValue).
(dbus_gvalue_demarshal): invoke dbus_gvalue_init.
* glib/dbus-gutils.c (_dbus_gutils_wincaps_to_uscore): Moved here
from dbus-gobject.c.
* glib/dbus-gutils.h: Prototype it.
* glib/dbus-gproxy.c: Include new dbus-gobject.h.
(marshal_dbus_message_to_g_marshaller): Use new shared function
dbus_glib_marshal_dbus_message_to_gvalue_array.
* glib/dbus-gparser.c (parse_interface, parse_method): Handle c_name attribute.
Will be changed once we have annotations.
* glib/dbus-gobject.c: Change info_hash_mutex from GStaticMutex to
GStaticRWLock. Callers updated.
(wincaps_to_uscore): Move to dbus-gutils.c. Callers updated.
(string_table_next): New function for iterating over zero-terminated
string value array.
(string_table_lookup): New function; retrieves specific entry in
array.
(get_method_data): New function; look up method data in object data chunk.
(object_error_domain_prefix_from_object_info)
(object_error_code_from_object_info): New functions, but not implemented yet.
(method_interface_from_object_info): New function; retrieve interface name.
(method_name_from_object_info): New function; retrieve method name.
(method_arg_info_from_object_info): New function; retrieve argument data.
(arg_iterate): New function; iterates over serialized argument data.
(method_dir_signature_from_object_info): New function; returns a
GString holding type signature for arguments for just one
direction (input or output).
(method_input_signature_from_object_info)
(method_output_signature_from_object_info): New functions.
(dbus_glib_marshal_dbus_message_to_gvalue_array): New shared function;
converts dbus message arguments into a GValue array. Used for both
signal handling and method invocation.
(struct DBusGlibWriteIterfaceData): New utility structure.
(write_interface): New function; generate introspection XML for
an interface.
(introspect_interfaces): New function; gathers all interface->methods,
generates introspection XML for them.
(handle_introspect): Invoke introspect_interfaces.
(get_object_property): Be sure to zero-initalize stack-allocated GValue.
(lookup_object_and_method): New function; examines an incoming message
and attempts to match it up (via interface, method name, and argument
signature) with a known object and method.
(gerror_domaincode_to_dbus_error_name): New function; converts a
GError domain and code into a DBus error name. Needs GError data
added to object introspection to work well.
(gerror_to_dbus_error_message): Creates a DBusMessage error return from
GError.
(invoke_object_method): New function to invoke an object method
looked up via lookup_object_and_method. Parses the incoming
message, turns it into a GValue array, then invokes the marshaller
specified in the DBusGMethodInfo. Creates a new message with
either return values or error message as appropriate.
(gobject_message_function): Invoke lookup_object_and_method and
invoke_object_method.
* glib/dbus-glib-tool.c: Include dbus-binding-tool-glib.h.
(enum DBusBindingOutputMode): New enum for binding output modes.
(pretty_print): Print binding names.
(dbus_binding_tool_error_quark): GError bits.
(version): Fix typo.
(main): Create GIOChannel for output. Parse new --mode argument,
possible values are "pretty-print", "glib-server", "glib-client".
Use mode to invoke appropriate function.
* glib/dbus-gobject.h: Prototype dbus_glib_marshal_dbus_message_to_gvalue_array.
* glib/dbus-glib-tool.h: New header, just includes GError bits
for now.
* glib/dbus-gidl.c (struct InterfaceInfo): Add bindings hashtable;
maps binding style to name.
(struct MethodInfo): Ditto.
(get_hash_keys, get_hash_key): Utility function, returns keys for
a GHashTable.
(interface_info_new, method_info_new): Initialize bindings.
(interface_info_unref, method_info_unref): Destroy bindings.
(method_info_get_binding_names, method_info_get_binding_name)
(interface_info_get_binding_names, interface_info_get_binding_name):
Functions for retrieving binding names.
(method_info_set_binding_name, interface_info_set_binding_name):
Functions for setting binding names.
* glib/dbus-binding-tool-glib.h: New file, has prototypes
for glib binding generation.
* glib/dbus-binding-tool-glib.c: New file, implements server-side
and client-side glib glue generation.
* glib/Makefile.am (dbus_binding_tool_SOURCES): Add
dbus-binding-tool-glib.c, dbus-binding-tool-glib.h,
dbus-glib-tool.h.
* dbus/dbus-glib.h (struct DBusGMethodMarshaller): Remove in favor
of using GClosureMarshal directly.
(struct DBusGObjectInfo): Add n_infos member.
* test/glib/test-service-glib.xml: New file; contains introspection data
for MyTestObject used in test-service-glib.c.
* test/glib/test-service-glib.c (enum MyObjectError): New GError enum.
(my_object_do_nothing, my_object_increment, my_object_throw_error)
(my_object_uppercase, my_object_many_args): New test methods.
(main): Use dbus_g_object_class_install_info to include generated object
info.
* test/glib/Makefile.am: Generate server-side glue for test-service-glib.c,
as well as client-side bindings.
* test/glib/test-dbus-glib.c: Include test-service-glib-bindings.h.
(main): Activate TestSuiteGLibService; test invoke a bunch of its methods
using both the dbus_gproxy stuff directly as well as the generated bindings.
Diffstat (limited to 'glib/dbus-binding-tool-glib.c')
-rw-r--r-- | glib/dbus-binding-tool-glib.c | 812 |
1 files changed, 812 insertions, 0 deletions
diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c new file mode 100644 index 00000000..98c13341 --- /dev/null +++ b/glib/dbus-binding-tool-glib.c @@ -0,0 +1,812 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* dbus-binding-tool-glib.c: Output C glue + * + * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> +#include "dbus-gidl.h" +#include "dbus-gparser.h" +#include "dbus-gutils.h" +#include "dbus-gvalue.h" +#include "dbus-glib-tool.h" +#include "dbus-binding-tool-glib.h" +#include <glib/gi18n.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define MARSHAL_PREFIX "dbus_glib_marshal" + +typedef struct +{ + GIOChannel *channel; + + GError **error; + + GHashTable *generated; +} DBusBindingToolCData; + +static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error); +static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); +static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); + +static char * +compute_marshaller (MethodInfo *method, GError **error) +{ + GSList *elt; + GString *ret; + gboolean first; + + /* All methods required to return boolean for now; + * will be conditional on method info later */ + ret = g_string_new ("BOOLEAN:"); + + first = TRUE; + /* Append input arguments */ + for (elt = method_info_get_args (method); elt; elt = elt->next) + { + ArgInfo *arg = elt->data; + + if (arg_info_get_direction (arg) == ARG_IN) + { + const char *marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)); + if (!marshal_name) + { + 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"), + arg_info_get_type (arg)); + g_string_free (ret, TRUE); + return NULL; + } + if (!first) + g_string_append (ret, ","); + else + first = FALSE; + g_string_append (ret, marshal_name); + } + } + + /* Append pointer for each out arg storage */ + for (elt = method_info_get_args (method); elt; elt = elt->next) + { + ArgInfo *arg = elt->data; + + if (arg_info_get_direction (arg) == ARG_OUT) + { + if (!first) + g_string_append (ret, ","); + else + first = FALSE; + g_string_append (ret, "POINTER"); + } + } + + /* Final GError parameter */ + if (!first) + g_string_append (ret, ","); + g_string_append (ret, "POINTER"); + + return g_string_free (ret, FALSE); + +} + +static char * +compute_marshaller_name (MethodInfo *method, GError **error) +{ + GSList *elt; + GString *ret; + + /* All methods required to return boolean for now; + * will be conditional on method info later */ + ret = g_string_new (MARSHAL_PREFIX "_BOOLEAN_"); + + /* Append input arguments */ + for (elt = method_info_get_args (method); elt; elt = elt->next) + { + ArgInfo *arg = elt->data; + + if (arg_info_get_direction (arg) == ARG_IN) + { + const char *marshal_name; + int type; + + type = arg_info_get_type (arg); + marshal_name = dbus_gvalue_genmarshal_name_from_type (type); + if (!marshal_name) + { + 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"), + type); + g_string_free (ret, TRUE); + return NULL; + } + + g_string_append (ret, "_"); + g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg))); + } + } + + /* Append pointer for each out arg storage */ + for (elt = method_info_get_args (method); elt; elt = elt->next) + { + ArgInfo *arg = elt->data; + + if (arg_info_get_direction (arg) == ARG_OUT) + { + g_string_append (ret, "_POINTER"); + } + } + + /* Final GError parameter */ + g_string_append (ret, "_POINTER"); + + return g_string_free (ret, FALSE); +} + +static gboolean +gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error) +{ + GSList *tmp; + + tmp = list; + while (tmp != NULL) + { + if (!gather_marshallers (tmp->data, data, error)) + return FALSE; + tmp = tmp->next; + } + return TRUE; +} + +static gboolean +gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) +{ + if (base_info_get_type (base) == INFO_TYPE_NODE) + { + if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base), + data, error)) + return FALSE; + if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base), + data, error)) + return FALSE; + } + else + { + InterfaceInfo *interface; + GSList *methods; + GSList *tmp; + const char *interface_c_name; + + interface = (InterfaceInfo *) base; + interface_c_name = interface_info_get_binding_name (interface, "C"); + if (interface_c_name == NULL) + { + return TRUE; + } + + methods = interface_info_get_methods (interface); + + /* Generate the necessary marshallers for the methods. */ + + for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) + { + MethodInfo *method; + char *marshaller_name; + + method = (MethodInfo *) tmp->data; + if (method_info_get_binding_name (method, "C") == NULL) + { + continue; + } + + marshaller_name = compute_marshaller (method, error); + if (!marshaller_name) + return FALSE; + + if (g_hash_table_lookup (data->generated, marshaller_name)) + { + g_free (marshaller_name); + continue; + } + + g_hash_table_insert (data->generated, marshaller_name, NULL); + } + + } + return TRUE; +} + +static gboolean +generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error) +{ + GSList *tmp; + + tmp = list; + while (tmp != NULL) + { + if (!generate_glue (tmp->data, data, error)) + return FALSE; + tmp = tmp->next; + } + return TRUE; +} + +#define WRITE_OR_LOSE(x) do { gsize bytes_written; if (!g_io_channel_write_chars (channel, x, -1, &bytes_written, error)) goto io_lose; } while (0) + +static gboolean +write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...) +{ + char *str; + va_list args; + GIOStatus status; + gsize written; + gboolean ret; + + va_start (args, error); + + str = g_strdup_vprintf (fmt, args); + if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL) + ret = TRUE; + else + ret = FALSE; + + g_free (str); + + va_end (args); + + return ret; +} + +static gboolean +generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) +{ + if (base_info_get_type (base) == INFO_TYPE_NODE) + { + if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base), + data, error)) + return FALSE; + if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base), + data, error)) + return FALSE; + } + else + { + GIOChannel *channel; + InterfaceInfo *interface; + GSList *methods; + GSList *tmp; + gsize i; + int count; + const char *interface_c_name; + GString *object_introspection_data_blob; + + channel = data->channel; + + interface = (InterfaceInfo *) base; + interface_c_name = interface_info_get_binding_name (interface, "C"); + if (interface_c_name == NULL) + { + return TRUE; + } + + object_introspection_data_blob = g_string_new_len ("", 0); + + methods = interface_info_get_methods (interface); + count = 0; + + /* Table of marshalled methods. */ + + if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_binding_name (interface, "C"))) + goto io_lose; + for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) + { + MethodInfo *method; + char *marshaller_name; + const char *method_c_name; + GSList *args; + + method = (MethodInfo *) tmp->data; + method_c_name = method_info_get_binding_name (method, "C"); + if (method_c_name == NULL) + { + continue; + } + + if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error, + method_c_name)) + goto io_lose; + + marshaller_name = compute_marshaller_name (method, error); + if (!marshaller_name) + goto io_lose; + + if (!write_printf_to_iochannel ("%s, %d },\n", channel, error, + marshaller_name, + object_introspection_data_blob->len)) + { + g_free (marshaller_name); + goto io_lose; + } + + /* Object method data blob format: + * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0 + */ + + g_string_append (object_introspection_data_blob, interface_info_get_name (interface)); + g_string_append_c (object_introspection_data_blob, '\0'); + + g_string_append (object_introspection_data_blob, method_info_get_name (method)); + g_string_append_c (object_introspection_data_blob, '\0'); + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + char direction; + + arg = args->data; + + g_string_append (object_introspection_data_blob, arg_info_get_name (arg)); + g_string_append_c (object_introspection_data_blob, '\0'); + + switch (arg_info_get_direction (arg)) + { + case ARG_IN: + direction = 'I'; + break; + case ARG_OUT: + direction = 'O'; + break; + case ARG_INVALID: + break; + } + g_string_append_c (object_introspection_data_blob, direction); + g_string_append_c (object_introspection_data_blob, '\0'); + + g_string_append_c (object_introspection_data_blob, arg_info_get_type (arg)); + g_string_append_c (object_introspection_data_blob, '\0'); + } + + g_string_append_c (object_introspection_data_blob, '\0'); + + count++; + } + WRITE_OR_LOSE ("};\n\n"); + + /* Information about the object. */ + + if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", + channel, error, interface_c_name)) + goto io_lose; + WRITE_OR_LOSE (" 0,\n"); + if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name)) + goto io_lose; + if (!write_printf_to_iochannel (" %d,\n", channel, error, count)) + goto io_lose; + WRITE_OR_LOSE(" \""); + for (i = 0; i < object_introspection_data_blob->len; i++) + { + if (object_introspection_data_blob->str[i] != '\0') + { + if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error)) + return FALSE; + } + else + { + if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) + return FALSE; + } + } + WRITE_OR_LOSE ("\"\n};\n\n"); + + g_string_free (object_introspection_data_blob, TRUE); + } + return TRUE; + io_lose: + return FALSE; +} + +static void +write_marshaller (gpointer key, gpointer value, gpointer user_data) +{ + DBusBindingToolCData *data; + const char *marshaller; + gsize bytes_written; + + data = user_data; + marshaller = key; + + if (data->error && *data->error) + return; + + if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL) + g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error); +} + +gboolean +dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error) +{ + gboolean ret; + GPtrArray *argv; + gint child_stdout; + GIOChannel *genmarshal_stdout; + GPid child_pid; + DBusBindingToolCData data; + char *tempfile_name; + gint tempfile_fd; + GIOStatus iostatus; + char buf[4096]; + gsize bytes_read, bytes_written; + + memset (&data, 0, sizeof (data)); + + data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); + data.error = error; + genmarshal_stdout = NULL; + tempfile_name = NULL; + + if (!gather_marshallers (info, &data, error)) + goto io_lose; + + tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX", + &tempfile_name, error); + if (tempfile_fd < 0) + goto io_lose; + + data.channel = g_io_channel_unix_new (tempfile_fd); + if (!g_io_channel_set_encoding (data.channel, NULL, error)) + goto io_lose; + g_hash_table_foreach (data.generated, write_marshaller, &data); + if (error && *error != NULL) + { + ret = FALSE; + g_io_channel_close (data.channel); + g_io_channel_unref (data.channel); + goto io_lose; + } + + g_io_channel_close (data.channel); + g_io_channel_unref (data.channel); + + /* Now spawn glib-genmarshal to insert all our required marshallers */ + argv = g_ptr_array_new (); + g_ptr_array_add (argv, "glib-genmarshal"); + g_ptr_array_add (argv, "--header"); + g_ptr_array_add (argv, "--body"); + g_ptr_array_add (argv, "--prefix=" MARSHAL_PREFIX); + g_ptr_array_add (argv, tempfile_name); + g_ptr_array_add (argv, NULL); + if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL, + G_SPAWN_SEARCH_PATH, + NULL, NULL, + &child_pid, + NULL, + &child_stdout, NULL, error)) + { + g_ptr_array_free (argv, TRUE); + goto io_lose; + } + g_ptr_array_free (argv, TRUE); + + genmarshal_stdout = g_io_channel_unix_new (child_stdout); + if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error)) + goto io_lose; + + WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n"); + + while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf), + &bytes_read, error)) == G_IO_STATUS_NORMAL) + if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL) + goto io_lose; + if (iostatus != G_IO_STATUS_EOF) + goto io_lose; + + g_io_channel_close (genmarshal_stdout); + + WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n"); + + g_io_channel_ref (data.channel); + data.channel = channel; + if (!generate_glue (info, &data, error)) + goto io_lose; + + ret = TRUE; + cleanup: + if (tempfile_name) + unlink (tempfile_name); + g_free (tempfile_name); + if (genmarshal_stdout) + g_io_channel_unref (genmarshal_stdout); + if (data.channel) + g_io_channel_unref (data.channel); + g_hash_table_destroy (data.generated); + + return ret; + io_lose: + ret = FALSE; + goto cleanup; +} + +static char * +iface_to_c_prefix (const char *iface) +{ + char **components; + char **component; + GString *ret; + gboolean first; + + components = g_strsplit (iface, ".", 0); + + first = TRUE; + ret = g_string_new (""); + for (component = components; *component; component++) + { + if (!first) + g_string_append_c (ret, '_'); + else + first = FALSE; + g_string_append (ret, *component); + } + g_strfreev (components); + return g_string_free (ret, FALSE); +} + +static char * +compute_client_method_name (InterfaceInfo *iface, MethodInfo *method) +{ + GString *ret; + char *method_name_uscored; + char *iface_prefix; + + iface_prefix = iface_to_c_prefix (interface_info_get_name (iface)); + ret = g_string_new (iface_prefix); + g_free (iface_prefix); + + method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method)); + g_string_append_c (ret, '_'); + g_string_append (ret, method_name_uscored); + g_free (method_name_uscored); + return g_string_free (ret, FALSE); +} + +static gboolean +write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error) +{ + GSList *args; + + for (args = method_info_get_args (method); args; args = args->next) + { + ArgInfo *arg; + const char *type_str; + int direction; + + arg = args->data; + + WRITE_OR_LOSE (", "); + + direction = arg_info_get_direction (arg); + + /* FIXME - broken for containers */ + type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN); + + if (!type_str) + { + g_set_error (error, + DBUS_BINDING_TOOL_ERROR, + DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, + _("Unsupported conversion from D-BUS type %d to glib C type"), + arg_info_get_type (arg)); + return FALSE; + } + + switch (direction) + { + case ARG_IN: + if (!write_printf_to_iochannel ("%s IN_%s", channel, error, + type_str, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_OUT: + if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error, + type_str, + arg_info_get_name (arg))) + goto io_lose; + break; + case ARG_INVALID: + break; + } + } + + 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; + const char *type_str; + + arg = args->data; + + if (direction != arg_info_get_direction (arg)) + continue; + + /* FIXME - broken for containers */ + 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 %c"), + (char) arg_info_get_type (arg)); + return FALSE; + } + + + switch (direction) + { + case ARG_IN: + if (!write_printf_to_iochannel (" %s, &IN_%s,\n", channel, error, + type_str, 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))) + goto io_lose; + break; + case ARG_INVALID: + break; + } + } + + return TRUE; + io_lose: + return FALSE; +} + +static gboolean +generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error) +{ + GSList *tmp; + + tmp = list; + while (tmp != NULL) + { + if (!generate_client_glue (tmp->data, data, error)) + return FALSE; + tmp = tmp->next; + } + return TRUE; +} + +static gboolean +generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) +{ + if (base_info_get_type (base) == INFO_TYPE_NODE) + { + if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base), + data, error)) + return FALSE; + if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base), + data, error)) + return FALSE; + } + else + { + GIOChannel *channel; + InterfaceInfo *interface; + GSList *methods; + GSList *tmp; + int count; + + channel = data->channel; + + interface = (InterfaceInfo *) base; + + methods = interface_info_get_methods (interface); + count = 0; + + for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) + { + MethodInfo *method; + char *method_name; + + method = (MethodInfo *) tmp->data; + + method_name = compute_client_method_name (interface, method); + + WRITE_OR_LOSE ("static gboolean\n"); + if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error, + method_name)) + goto io_lose; + g_free (method_name); + + if (!write_formal_parameters (interface, method, channel, error)) + goto io_lose; + + 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, + method_info_get_name (method))) + goto io_lose; + + if (!write_args_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)) + goto io_lose; + + WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n"); + + WRITE_OR_LOSE (" dbus_g_pending_call_unref (call);\n"); + WRITE_OR_LOSE (" return ret;\n"); + + WRITE_OR_LOSE ("}\n\n"); + } + } + return TRUE; + io_lose: + return FALSE; +} + + +gboolean +dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error) +{ + DBusBindingToolCData data; + gboolean ret; + + memset (&data, 0, sizeof (data)); + + data.channel = channel; + + WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n"); + WRITE_OR_LOSE ("#include <glib/gtypes.h>\n"); + WRITE_OR_LOSE ("#include <glib/gerror.h>\n"); + WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n"); + + ret = generate_client_glue (info, &data, error); + + return ret; + io_lose: + return FALSE; +} |