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"
45 GHashTable *generated;
46 } DBusBindingToolCData;
48 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
49 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
50 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
53 compute_marshaller (MethodInfo *method, GError **error)
59 /* All methods required to return boolean for now;
60 * will be conditional on method info later */
61 ret = g_string_new ("BOOLEAN:");
64 /* Append input arguments */
65 for (elt = method_info_get_args (method); elt; elt = elt->next)
67 ArgInfo *arg = elt->data;
69 if (arg_info_get_direction (arg) == ARG_IN)
71 const char *marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
75 DBUS_BINDING_TOOL_ERROR,
76 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
77 _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
78 arg_info_get_type (arg));
79 g_string_free (ret, TRUE);
83 g_string_append (ret, ",");
86 g_string_append (ret, marshal_name);
90 /* Append pointer for each out arg storage */
91 for (elt = method_info_get_args (method); elt; elt = elt->next)
93 ArgInfo *arg = elt->data;
95 if (arg_info_get_direction (arg) == ARG_OUT)
98 g_string_append (ret, ",");
101 g_string_append (ret, "POINTER");
105 /* Final GError parameter */
107 g_string_append (ret, ",");
108 g_string_append (ret, "POINTER");
110 return g_string_free (ret, FALSE);
115 compute_marshaller_name (MethodInfo *method, GError **error)
120 /* All methods required to return boolean for now;
121 * will be conditional on method info later */
122 ret = g_string_new (MARSHAL_PREFIX "_BOOLEAN_");
124 /* Append input arguments */
125 for (elt = method_info_get_args (method); elt; elt = elt->next)
127 ArgInfo *arg = elt->data;
129 if (arg_info_get_direction (arg) == ARG_IN)
131 const char *marshal_name;
134 type = arg_info_get_type (arg);
135 marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
139 DBUS_BINDING_TOOL_ERROR,
140 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
141 _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
143 g_string_free (ret, TRUE);
147 g_string_append (ret, "_");
148 g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)));
152 /* Append pointer for each out arg storage */
153 for (elt = method_info_get_args (method); elt; elt = elt->next)
155 ArgInfo *arg = elt->data;
157 if (arg_info_get_direction (arg) == ARG_OUT)
159 g_string_append (ret, "_POINTER");
163 /* Final GError parameter */
164 g_string_append (ret, "_POINTER");
166 return g_string_free (ret, FALSE);
170 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
177 if (!gather_marshallers (tmp->data, data, error))
185 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
187 if (base_info_get_type (base) == INFO_TYPE_NODE)
189 if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
192 if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
198 InterfaceInfo *interface;
201 const char *interface_c_name;
203 interface = (InterfaceInfo *) base;
204 interface_c_name = interface_info_get_binding_name (interface, "C");
205 if (interface_c_name == NULL)
210 methods = interface_info_get_methods (interface);
212 /* Generate the necessary marshallers for the methods. */
214 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
217 char *marshaller_name;
219 method = (MethodInfo *) tmp->data;
220 if (method_info_get_binding_name (method, "C") == NULL)
225 marshaller_name = compute_marshaller (method, error);
226 if (!marshaller_name)
229 if (g_hash_table_lookup (data->generated, marshaller_name))
231 g_free (marshaller_name);
235 g_hash_table_insert (data->generated, marshaller_name, NULL);
243 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
250 if (!generate_glue (tmp->data, data, error))
257 #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)
260 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
268 va_start (args, error);
270 str = g_strdup_vprintf (fmt, args);
271 if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
284 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
286 if (base_info_get_type (base) == INFO_TYPE_NODE)
288 if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
291 if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
298 InterfaceInfo *interface;
303 const char *interface_c_name;
304 GString *object_introspection_data_blob;
306 channel = data->channel;
308 interface = (InterfaceInfo *) base;
309 interface_c_name = interface_info_get_binding_name (interface, "C");
310 if (interface_c_name == NULL)
315 object_introspection_data_blob = g_string_new_len ("", 0);
317 methods = interface_info_get_methods (interface);
320 /* Table of marshalled methods. */
322 if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_binding_name (interface, "C")))
324 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
327 char *marshaller_name;
328 const char *method_c_name;
331 method = (MethodInfo *) tmp->data;
332 method_c_name = method_info_get_binding_name (method, "C");
333 if (method_c_name == NULL)
338 if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error,
342 marshaller_name = compute_marshaller_name (method, error);
343 if (!marshaller_name)
346 if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
348 object_introspection_data_blob->len))
350 g_free (marshaller_name);
354 /* Object method data blob format:
355 * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
358 g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
359 g_string_append_c (object_introspection_data_blob, '\0');
361 g_string_append (object_introspection_data_blob, method_info_get_name (method));
362 g_string_append_c (object_introspection_data_blob, '\0');
364 for (args = method_info_get_args (method); args; args = args->next)
371 g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
372 g_string_append_c (object_introspection_data_blob, '\0');
374 switch (arg_info_get_direction (arg))
385 g_string_append_c (object_introspection_data_blob, direction);
386 g_string_append_c (object_introspection_data_blob, '\0');
388 g_string_append_c (object_introspection_data_blob, arg_info_get_type (arg));
389 g_string_append_c (object_introspection_data_blob, '\0');
392 g_string_append_c (object_introspection_data_blob, '\0');
396 WRITE_OR_LOSE ("};\n\n");
398 /* Information about the object. */
400 if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
401 channel, error, interface_c_name))
403 WRITE_OR_LOSE (" 0,\n");
404 if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, interface_c_name))
406 if (!write_printf_to_iochannel (" %d,\n", channel, error, count))
408 WRITE_OR_LOSE(" \"");
409 for (i = 0; i < object_introspection_data_blob->len; i++)
411 if (object_introspection_data_blob->str[i] != '\0')
413 if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
418 if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
422 WRITE_OR_LOSE ("\"\n};\n\n");
424 g_string_free (object_introspection_data_blob, TRUE);
432 write_marshaller (gpointer key, gpointer value, gpointer user_data)
434 DBusBindingToolCData *data;
435 const char *marshaller;
441 if (data->error && *data->error)
444 if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
445 g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
449 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error)
454 GIOChannel *genmarshal_stdout;
456 DBusBindingToolCData data;
461 gsize bytes_read, bytes_written;
463 memset (&data, 0, sizeof (data));
465 data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
467 genmarshal_stdout = NULL;
468 tempfile_name = NULL;
470 if (!gather_marshallers (info, &data, error))
473 tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
474 &tempfile_name, error);
478 data.channel = g_io_channel_unix_new (tempfile_fd);
479 if (!g_io_channel_set_encoding (data.channel, NULL, error))
481 g_hash_table_foreach (data.generated, write_marshaller, &data);
482 if (error && *error != NULL)
485 g_io_channel_close (data.channel);
486 g_io_channel_unref (data.channel);
490 g_io_channel_close (data.channel);
491 g_io_channel_unref (data.channel);
493 /* Now spawn glib-genmarshal to insert all our required marshallers */
494 argv = g_ptr_array_new ();
495 g_ptr_array_add (argv, "glib-genmarshal");
496 g_ptr_array_add (argv, "--header");
497 g_ptr_array_add (argv, "--body");
498 g_ptr_array_add (argv, "--prefix=" MARSHAL_PREFIX);
499 g_ptr_array_add (argv, tempfile_name);
500 g_ptr_array_add (argv, NULL);
501 if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
506 &child_stdout, NULL, error))
508 g_ptr_array_free (argv, TRUE);
511 g_ptr_array_free (argv, TRUE);
513 genmarshal_stdout = g_io_channel_unix_new (child_stdout);
514 if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
517 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
519 while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
520 &bytes_read, error)) == G_IO_STATUS_NORMAL)
521 if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
523 if (iostatus != G_IO_STATUS_EOF)
526 g_io_channel_close (genmarshal_stdout);
528 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
530 g_io_channel_ref (data.channel);
531 data.channel = channel;
532 if (!generate_glue (info, &data, error))
538 unlink (tempfile_name);
539 g_free (tempfile_name);
540 if (genmarshal_stdout)
541 g_io_channel_unref (genmarshal_stdout);
543 g_io_channel_unref (data.channel);
544 g_hash_table_destroy (data.generated);
553 iface_to_c_prefix (const char *iface)
560 components = g_strsplit (iface, ".", 0);
563 ret = g_string_new ("");
564 for (component = components; *component; component++)
567 g_string_append_c (ret, '_');
570 g_string_append (ret, *component);
572 g_strfreev (components);
573 return g_string_free (ret, FALSE);
577 compute_client_method_name (InterfaceInfo *iface, MethodInfo *method)
580 char *method_name_uscored;
583 iface_prefix = iface_to_c_prefix (interface_info_get_name (iface));
584 ret = g_string_new (iface_prefix);
585 g_free (iface_prefix);
587 method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
588 g_string_append_c (ret, '_');
589 g_string_append (ret, method_name_uscored);
590 g_free (method_name_uscored);
591 return g_string_free (ret, FALSE);
595 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
599 for (args = method_info_get_args (method); args; args = args->next)
602 const char *type_str;
607 WRITE_OR_LOSE (", ");
609 direction = arg_info_get_direction (arg);
611 /* FIXME - broken for containers */
612 type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
617 DBUS_BINDING_TOOL_ERROR,
618 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
619 _("Unsupported conversion from D-BUS type %d to glib C type"),
620 arg_info_get_type (arg));
627 if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
629 arg_info_get_name (arg)))
633 if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
635 arg_info_get_name (arg)))
649 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
653 for (args = method_info_get_args (method); args; args = args->next)
656 const char *type_str;
660 if (direction != arg_info_get_direction (arg))
663 /* FIXME - broken for containers */
664 type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
668 DBUS_BINDING_TOOL_ERROR,
669 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
670 _("Unsupported conversion from D-BUS type %c"),
671 (char) arg_info_get_type (arg));
679 if (!write_printf_to_iochannel (" %s, &IN_%s,\n", channel, error,
680 type_str, arg_info_get_name (arg)))
684 if (!write_printf_to_iochannel (" %s, OUT_%s,\n", channel, error,
685 type_str, arg_info_get_name (arg)))
699 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
706 if (!generate_client_glue (tmp->data, data, error))
714 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
716 if (base_info_get_type (base) == INFO_TYPE_NODE)
718 if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
721 if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
728 InterfaceInfo *interface;
733 channel = data->channel;
735 interface = (InterfaceInfo *) base;
737 methods = interface_info_get_methods (interface);
740 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
745 method = (MethodInfo *) tmp->data;
747 method_name = compute_client_method_name (interface, method);
749 WRITE_OR_LOSE ("static gboolean\n");
750 if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
753 g_free (method_name);
755 if (!write_formal_parameters (interface, method, channel, error))
758 WRITE_OR_LOSE (", GError **error)\n\n");
760 WRITE_OR_LOSE ("{\n");
761 WRITE_OR_LOSE (" gboolean ret;\n\n");
762 WRITE_OR_LOSE (" DBusGPendingCall *call;\n\n");
764 if (!write_printf_to_iochannel (" call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
766 method_info_get_name (method)))
769 if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
772 WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n");
773 WRITE_OR_LOSE (" ret = dbus_g_proxy_end_call (proxy, call, error,\n");
775 if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
778 WRITE_OR_LOSE (" DBUS_TYPE_INVALID);\n");
780 WRITE_OR_LOSE (" dbus_g_pending_call_unref (call);\n");
781 WRITE_OR_LOSE (" return ret;\n");
783 WRITE_OR_LOSE ("}\n\n");
793 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error)
795 DBusBindingToolCData data;
798 memset (&data, 0, sizeof (data));
800 data.channel = channel;
802 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
803 WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
804 WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
805 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
807 ret = generate_client_glue (info, &data, error);