1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-binding-tool-glib.c: Output C glue
4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
6 * Licensed under the Academic Free License version 2.1
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "dbus-gidl.h"
26 #include "dbus-gparser.h"
27 #include "dbus-gutils.h"
28 #include "dbus-gvalue.h"
29 #include "dbus-glib-tool.h"
30 #include "dbus-binding-tool-glib.h"
31 #include <glib/gi18n.h>
37 #define MARSHAL_PREFIX "dbus_glib_marshal"
41 gboolean ignore_unsupported;
46 GHashTable *generated;
47 } DBusBindingToolCData;
49 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
50 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
51 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
54 compute_marshaller (MethodInfo *method, GError **error)
60 /* All methods required to return boolean for now;
61 * will be conditional on method info later */
62 ret = g_string_new ("BOOLEAN:");
65 /* Append input arguments */
66 for (elt = method_info_get_args (method); elt; elt = elt->next)
68 ArgInfo *arg = elt->data;
70 if (arg_info_get_direction (arg) == ARG_IN)
72 const char *marshal_name;
74 marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
78 DBUS_BINDING_TOOL_ERROR,
79 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
80 _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
81 arg_info_get_type (arg));
82 g_string_free (ret, TRUE);
86 g_string_append (ret, ",");
89 g_string_append (ret, marshal_name);
93 /* Append pointer for each out arg storage */
94 for (elt = method_info_get_args (method); elt; elt = elt->next)
96 ArgInfo *arg = elt->data;
98 if (arg_info_get_direction (arg) == ARG_OUT)
101 g_string_append (ret, ",");
104 g_string_append (ret, "POINTER");
108 /* Final GError parameter */
110 g_string_append (ret, ",");
111 g_string_append (ret, "POINTER");
113 return g_string_free (ret, FALSE);
118 compute_marshaller_name (MethodInfo *method, GError **error)
123 /* All methods required to return boolean for now;
124 * will be conditional on method info later */
125 ret = g_string_new (MARSHAL_PREFIX "_BOOLEAN_");
127 /* Append input arguments */
128 for (elt = method_info_get_args (method); elt; elt = elt->next)
130 ArgInfo *arg = elt->data;
132 if (arg_info_get_direction (arg) == ARG_IN)
134 const char *marshal_name;
137 type = arg_info_get_type (arg);
138 marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
142 DBUS_BINDING_TOOL_ERROR,
143 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
144 _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
146 g_string_free (ret, TRUE);
150 g_string_append (ret, "_");
151 g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (type));
155 /* Append pointer for each out arg storage */
156 for (elt = method_info_get_args (method); elt; elt = elt->next)
158 ArgInfo *arg = elt->data;
160 if (arg_info_get_direction (arg) == ARG_OUT)
162 g_string_append (ret, "_POINTER");
166 /* Final GError parameter */
167 g_string_append (ret, "_POINTER");
169 return g_string_free (ret, FALSE);
173 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
180 if (!gather_marshallers (tmp->data, data, error))
188 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
190 if (base_info_get_type (base) == INFO_TYPE_NODE)
192 if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
195 if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
201 InterfaceInfo *interface;
204 const char *interface_c_name;
206 interface = (InterfaceInfo *) base;
207 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
208 if (interface_c_name == NULL)
213 methods = interface_info_get_methods (interface);
215 /* Generate the necessary marshallers for the methods. */
217 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
220 char *marshaller_name;
222 method = (MethodInfo *) tmp->data;
223 if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL) == NULL)
228 marshaller_name = compute_marshaller (method, error);
229 if (!marshaller_name)
232 if (g_hash_table_lookup (data->generated, marshaller_name))
234 g_free (marshaller_name);
238 g_hash_table_insert (data->generated, marshaller_name, NULL);
246 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
253 if (!generate_glue (tmp->data, data, error))
260 #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)
263 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
271 va_start (args, error);
273 str = g_strdup_vprintf (fmt, args);
274 if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
287 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
289 if (base_info_get_type (base) == INFO_TYPE_NODE)
291 if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
294 if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
301 InterfaceInfo *interface;
306 const char *interface_c_name;
307 GString *object_introspection_data_blob;
309 channel = data->channel;
311 interface = (InterfaceInfo *) base;
312 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
313 if (interface_c_name == NULL)
318 object_introspection_data_blob = g_string_new_len ("", 0);
320 methods = interface_info_get_methods (interface);
323 /* Table of marshalled methods. */
325 if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL)))
327 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
330 char *marshaller_name;
331 const char *method_c_name;
334 method = (MethodInfo *) tmp->data;
335 method_c_name = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL);
336 if (method_c_name == NULL)
341 if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error,
345 marshaller_name = compute_marshaller_name (method, error);
346 if (!marshaller_name)
349 if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
351 object_introspection_data_blob->len))
353 g_free (marshaller_name);
357 /* Object method data blob format:
358 * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
361 g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
362 g_string_append_c (object_introspection_data_blob, '\0');
364 g_string_append (object_introspection_data_blob, method_info_get_name (method));
365 g_string_append_c (object_introspection_data_blob, '\0');
367 for (args = method_info_get_args (method); args; args = args->next)
374 g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
375 g_string_append_c (object_introspection_data_blob, '\0');
377 switch (arg_info_get_direction (arg))
387 g_assert_not_reached ();
388 direction = 0; /* silence gcc */
391 g_string_append_c (object_introspection_data_blob, direction);
392 g_string_append_c (object_introspection_data_blob, '\0');
394 g_string_append (object_introspection_data_blob, arg_info_get_type (arg));
395 g_string_append_c (object_introspection_data_blob, '\0');
398 g_string_append_c (object_introspection_data_blob, '\0');
402 WRITE_OR_LOSE ("};\n\n");
404 /* Information about the object. */
406 if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
407 channel, error, interface_c_name))
409 WRITE_OR_LOSE (" 0,\n");
410 if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name))
412 if (!write_printf_to_iochannel (" %d,\n", channel, error, count))
414 WRITE_OR_LOSE(" \"");
415 for (i = 0; i < object_introspection_data_blob->len; i++)
417 if (object_introspection_data_blob->str[i] != '\0')
419 if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
424 if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
428 WRITE_OR_LOSE ("\"\n};\n\n");
430 g_string_free (object_introspection_data_blob, TRUE);
438 write_marshaller (gpointer key, gpointer value, gpointer user_data)
440 DBusBindingToolCData *data;
441 const char *marshaller;
447 if (data->error && *data->error)
450 if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
451 g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
455 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error)
460 GIOChannel *genmarshal_stdout;
462 DBusBindingToolCData data;
467 gsize bytes_read, bytes_written;
469 memset (&data, 0, sizeof (data));
471 data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
473 genmarshal_stdout = NULL;
474 tempfile_name = NULL;
476 if (!gather_marshallers (info, &data, error))
479 tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
480 &tempfile_name, error);
484 data.channel = g_io_channel_unix_new (tempfile_fd);
485 if (!g_io_channel_set_encoding (data.channel, NULL, error))
487 g_hash_table_foreach (data.generated, write_marshaller, &data);
488 if (error && *error != NULL)
491 g_io_channel_close (data.channel);
492 g_io_channel_unref (data.channel);
496 g_io_channel_close (data.channel);
497 g_io_channel_unref (data.channel);
499 /* Now spawn glib-genmarshal to insert all our required marshallers */
500 argv = g_ptr_array_new ();
501 g_ptr_array_add (argv, "glib-genmarshal");
502 g_ptr_array_add (argv, "--header");
503 g_ptr_array_add (argv, "--body");
504 g_ptr_array_add (argv, "--prefix=" MARSHAL_PREFIX);
505 g_ptr_array_add (argv, tempfile_name);
506 g_ptr_array_add (argv, NULL);
507 if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
512 &child_stdout, NULL, error))
514 g_ptr_array_free (argv, TRUE);
517 g_ptr_array_free (argv, TRUE);
519 genmarshal_stdout = g_io_channel_unix_new (child_stdout);
520 if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
523 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
525 while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
526 &bytes_read, error)) == G_IO_STATUS_NORMAL)
527 if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
529 if (iostatus != G_IO_STATUS_EOF)
532 g_io_channel_close (genmarshal_stdout);
534 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
536 data.channel = channel;
537 g_io_channel_ref (data.channel);
538 if (!generate_glue (info, &data, error))
544 unlink (tempfile_name);
545 g_free (tempfile_name);
546 if (genmarshal_stdout)
547 g_io_channel_unref (genmarshal_stdout);
549 g_io_channel_unref (data.channel);
550 g_hash_table_destroy (data.generated);
559 iface_to_c_prefix (const char *iface)
566 components = g_strsplit (iface, ".", 0);
569 ret = g_string_new ("");
570 for (component = components; *component; component++)
573 g_string_append_c (ret, '_');
576 g_string_append (ret, *component);
578 g_strfreev (components);
579 return g_string_free (ret, FALSE);
583 compute_client_method_name (const char *iface_prefix, MethodInfo *method)
586 char *method_name_uscored;
588 ret = g_string_new (iface_prefix);
590 method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
591 g_string_append_c (ret, '_');
592 g_string_append (ret, method_name_uscored);
593 g_free (method_name_uscored);
594 return g_string_free (ret, FALSE);
598 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
602 for (args = method_info_get_args (method); args; args = args->next)
605 const char *type_str;
610 WRITE_OR_LOSE (", ");
612 direction = arg_info_get_direction (arg);
614 type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
619 DBUS_BINDING_TOOL_ERROR,
620 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
621 _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
622 arg_info_get_type (arg),
623 method_info_get_name (method),
624 interface_info_get_name (iface));
631 if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
633 arg_info_get_name (arg)))
637 if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
639 arg_info_get_name (arg)))
653 write_args_sig_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
657 WRITE_OR_LOSE ("\"");
659 for (args = method_info_get_args (method); args; args = args->next)
665 if (direction != arg_info_get_direction (arg))
668 if (!write_printf_to_iochannel ("%s", channel, error, arg_info_get_type (arg)))
672 WRITE_OR_LOSE ("\", ");
680 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
684 for (args = method_info_get_args (method); args; args = args->next)
690 if (direction != arg_info_get_direction (arg))
696 if (!write_printf_to_iochannel ("IN_%s, ", channel, error, arg_info_get_name (arg)))
700 if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, arg_info_get_name (arg)))
714 check_supported_parameters (MethodInfo *method)
718 for (args = method_info_get_args (method); args; args = args->next)
722 if (!dbus_gvalue_ctype_from_type (arg_info_get_type (arg),
723 arg_info_get_direction (arg)))
730 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
737 if (!generate_client_glue (tmp->data, data, error))
745 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
747 if (base_info_get_type (base) == INFO_TYPE_NODE)
749 if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
752 if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
759 InterfaceInfo *interface;
765 channel = data->channel;
767 interface = (InterfaceInfo *) base;
769 methods = interface_info_get_methods (interface);
772 iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
774 if (!write_printf_to_iochannel ("#ifndef DBUS_GLIB_CLIENT_WRAPPERS_%s\n"
775 "#define DBUS_GLIB_CLIENT_WRAPPERS_%s\n\n",
777 iface_prefix, iface_prefix))
779 g_free (iface_prefix);
783 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
788 method = (MethodInfo *) tmp->data;
790 if (data->ignore_unsupported && !check_supported_parameters (method))
792 g_warning ("Ignoring unsupported signature in method \"%s\" of interface \"%s\"\n",
793 method_info_get_name (method),
794 interface_info_get_name (interface));
798 method_name = compute_client_method_name (iface_prefix, method);
800 WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
801 if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
804 g_free (method_name);
806 if (!write_formal_parameters (interface, method, channel, error))
809 WRITE_OR_LOSE (", GError **error)\n\n");
811 WRITE_OR_LOSE ("{\n");
813 if (!write_printf_to_iochannel (" return dbus_g_proxy_invoke (proxy, \"%s\", ", channel, error,
814 method_info_get_name (method)))
817 if (!write_args_sig_for_direction (interface, method, channel, ARG_IN, error))
820 if (!write_args_sig_for_direction (interface, method, channel, ARG_OUT, error))
823 WRITE_OR_LOSE ("error, ");
825 if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
828 if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
831 WRITE_OR_LOSE ("NULL);\n}\n\n");
834 if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
836 g_free (iface_prefix);
847 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error)
849 DBusBindingToolCData data;
852 memset (&data, 0, sizeof (data));
854 data.channel = channel;
855 data.ignore_unsupported = ignore_unsupported;
857 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
858 WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
859 WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
860 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
861 WRITE_OR_LOSE ("G_BEGIN_DECLS\n\n");
863 ret = generate_client_glue (info, &data, error);
867 WRITE_OR_LOSE ("G_END_DECLS\n");