2005-02-17 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / glib / dbus-binding-tool-glib.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-binding-tool-glib.c: Output C glue
3  *
4  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
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.
12  *
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.
17  *
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
21  *
22  */
23
24 #include <config.h>
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>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <unistd.h>
36
37 #define MARSHAL_PREFIX "dbus_glib_marshal"
38
39 typedef struct
40 {
41   GIOChannel *channel;
42   
43   GError **error;
44   
45   GHashTable *generated;
46 } DBusBindingToolCData;
47
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);
51
52 static char *
53 compute_marshaller (MethodInfo *method, GError **error)
54 {
55   GSList *elt;
56   GString *ret;
57   gboolean first;
58
59   /* All methods required to return boolean for now;
60    * will be conditional on method info later */
61   ret = g_string_new ("BOOLEAN:");
62
63   first = TRUE;
64   /* Append input arguments */
65   for (elt = method_info_get_args (method); elt; elt = elt->next)
66     {
67       ArgInfo *arg = elt->data;
68
69       if (arg_info_get_direction (arg) == ARG_IN)
70         {
71           const char *marshal_name = dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg));
72           if (!marshal_name)
73             {
74               g_set_error (error,
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);
80               return NULL;
81             }
82           if (!first)
83             g_string_append (ret, ",");
84           else
85             first = FALSE;
86           g_string_append (ret, marshal_name);
87         }
88     }
89
90   /* Append pointer for each out arg storage */
91   for (elt = method_info_get_args (method); elt; elt = elt->next)
92     {
93       ArgInfo *arg = elt->data;
94
95       if (arg_info_get_direction (arg) == ARG_OUT)
96         {
97           if (!first)
98             g_string_append (ret, ",");
99           else
100             first = FALSE;
101           g_string_append (ret, "POINTER");
102         }
103     }
104
105   /* Final GError parameter */
106   if (!first)
107     g_string_append (ret, ",");
108   g_string_append (ret, "POINTER");
109
110   return g_string_free (ret, FALSE);
111
112 }
113
114 static char *
115 compute_marshaller_name (MethodInfo *method, GError **error)
116 {
117   GSList *elt;
118   GString *ret;
119
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_");
123
124   /* Append input arguments */
125   for (elt = method_info_get_args (method); elt; elt = elt->next)
126     {
127       ArgInfo *arg = elt->data;
128
129       if (arg_info_get_direction (arg) == ARG_IN)
130         {
131           const char *marshal_name;
132           int type; 
133
134           type = arg_info_get_type (arg);
135           marshal_name = dbus_gvalue_genmarshal_name_from_type (type);
136           if (!marshal_name)
137             {
138               g_set_error (error,
139                            DBUS_BINDING_TOOL_ERROR,
140                            DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
141                            _("Unsupported conversion from D-BUS type %d to glib-genmarshal type"),
142                            type);
143               g_string_free (ret, TRUE);
144               return NULL;
145             }
146
147           g_string_append (ret, "_");
148           g_string_append (ret, dbus_gvalue_genmarshal_name_from_type (arg_info_get_type (arg)));
149         }
150     }
151
152   /* Append pointer for each out arg storage */
153   for (elt = method_info_get_args (method); elt; elt = elt->next)
154     {
155       ArgInfo *arg = elt->data;
156
157       if (arg_info_get_direction (arg) == ARG_OUT)
158         {
159           g_string_append (ret, "_POINTER");
160         }
161     }
162
163   /* Final GError parameter */
164   g_string_append (ret, "_POINTER");
165
166   return g_string_free (ret, FALSE);
167 }
168
169 static gboolean
170 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
171 {
172   GSList *tmp;
173
174   tmp = list;
175   while (tmp != NULL)
176     {
177       if (!gather_marshallers (tmp->data, data, error))
178         return FALSE;
179       tmp = tmp->next;
180     }
181   return TRUE;
182 }
183
184 static gboolean
185 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
186 {
187   if (base_info_get_type (base) == INFO_TYPE_NODE)
188     {
189       if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
190                                     data, error))
191         return FALSE;
192       if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
193                                     data, error))
194         return FALSE;
195     }
196   else
197     {
198       InterfaceInfo *interface;
199       GSList *methods;
200       GSList *tmp;
201       const char *interface_c_name;
202
203       interface = (InterfaceInfo *) base;
204       interface_c_name = interface_info_get_binding_name (interface, "C");
205       if (interface_c_name == NULL)
206         {
207           return TRUE;
208         }
209
210       methods = interface_info_get_methods (interface);
211
212       /* Generate the necessary marshallers for the methods. */
213
214       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
215         {
216           MethodInfo *method;
217           char *marshaller_name;
218
219           method = (MethodInfo *) tmp->data;
220           if (method_info_get_binding_name (method, "C") == NULL)
221             {
222               continue;
223             }
224
225           marshaller_name = compute_marshaller (method, error);
226           if (!marshaller_name)
227             return FALSE;
228
229           if (g_hash_table_lookup (data->generated, marshaller_name))
230             {
231               g_free (marshaller_name);
232               continue;
233             }
234
235           g_hash_table_insert (data->generated, marshaller_name, NULL);
236         }
237
238     }
239   return TRUE;
240 }
241
242 static gboolean
243 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
244 {
245   GSList *tmp;
246
247   tmp = list;
248   while (tmp != NULL)
249     {
250       if (!generate_glue (tmp->data, data, error))
251         return FALSE;
252       tmp = tmp->next;
253     }
254   return TRUE;
255 }
256
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)
258
259 static gboolean
260 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
261 {
262   char *str;
263   va_list args;
264   GIOStatus status;
265   gsize written;
266   gboolean ret;
267
268   va_start (args, error);
269
270   str = g_strdup_vprintf (fmt, args);
271   if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
272     ret = TRUE;
273   else
274     ret = FALSE;
275
276   g_free (str);
277
278   va_end (args);
279
280   return ret;
281 }
282
283 static gboolean
284 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
285 {
286   if (base_info_get_type (base) == INFO_TYPE_NODE)
287     {
288       if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
289                                data, error))
290         return FALSE;
291       if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
292                                data, error))
293         return FALSE;
294     }
295   else
296     {
297       GIOChannel *channel;
298       InterfaceInfo *interface;
299       GSList *methods;
300       GSList *tmp;
301       gsize i;
302       int count;
303       const char *interface_c_name;
304       GString *object_introspection_data_blob;
305
306       channel = data->channel;
307
308       interface = (InterfaceInfo *) base;
309       interface_c_name = interface_info_get_binding_name (interface, "C");
310       if (interface_c_name == NULL)
311         {
312           return TRUE;
313         }
314
315       object_introspection_data_blob = g_string_new_len ("", 0);
316
317       methods = interface_info_get_methods (interface);
318       count = 0;
319
320       /* Table of marshalled methods. */
321
322       if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, interface_info_get_binding_name (interface, "C")))
323         goto io_lose;
324       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
325         {
326           MethodInfo *method;
327           char *marshaller_name;
328           const char *method_c_name;
329           GSList *args;
330
331           method = (MethodInfo *) tmp->data;
332           method_c_name = method_info_get_binding_name (method, "C");
333           if (method_c_name == NULL)
334             {
335               continue;
336             }
337
338           if (!write_printf_to_iochannel ("  { (GCallback) %s, ", channel, error,
339                                           method_c_name))
340             goto io_lose;
341
342           marshaller_name = compute_marshaller_name (method, error);
343           if (!marshaller_name)
344             goto io_lose;
345
346           if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
347                                           marshaller_name,
348                                           object_introspection_data_blob->len))
349             {
350               g_free (marshaller_name);
351               goto io_lose;
352             }
353
354           /* Object method data blob format:
355            * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
356            */
357
358           g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
359           g_string_append_c (object_introspection_data_blob, '\0');
360
361           g_string_append (object_introspection_data_blob, method_info_get_name (method));
362           g_string_append_c (object_introspection_data_blob, '\0');
363
364           for (args = method_info_get_args (method); args; args = args->next)
365             {
366               ArgInfo *arg;
367               char direction;
368
369               arg = args->data;
370
371               g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
372               g_string_append_c (object_introspection_data_blob, '\0');
373
374               switch (arg_info_get_direction (arg))
375                 {
376                 case ARG_IN:
377                   direction = 'I';
378                   break;
379                 case ARG_OUT:
380                   direction = 'O';
381                   break;
382                 case ARG_INVALID:
383                   break;
384                 }
385               g_string_append_c (object_introspection_data_blob, direction);
386               g_string_append_c (object_introspection_data_blob, '\0');
387
388               g_string_append_c (object_introspection_data_blob, arg_info_get_type (arg));
389               g_string_append_c (object_introspection_data_blob, '\0');
390             }
391
392           g_string_append_c (object_introspection_data_blob, '\0');
393
394           count++;
395         }
396       WRITE_OR_LOSE ("};\n\n");
397
398       /* Information about the object. */
399
400       if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
401                                       channel, error, interface_c_name))
402         goto io_lose;
403       WRITE_OR_LOSE ("  0,\n");
404       if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, interface_c_name))
405         goto io_lose;
406       if (!write_printf_to_iochannel ("  %d,\n", channel, error, count))
407         goto io_lose;
408       WRITE_OR_LOSE("  \"");
409       for (i = 0; i < object_introspection_data_blob->len; i++)
410         {
411           if (object_introspection_data_blob->str[i] != '\0')
412             {
413               if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
414                 return FALSE;
415             }
416           else
417             {
418               if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
419                 return FALSE;
420             }
421         }
422       WRITE_OR_LOSE ("\"\n};\n\n");
423
424       g_string_free (object_introspection_data_blob, TRUE);
425     }
426   return TRUE;
427  io_lose:
428   return FALSE;
429 }
430
431 static void
432 write_marshaller (gpointer key, gpointer value, gpointer user_data)
433 {
434   DBusBindingToolCData *data;
435   const char *marshaller;
436   gsize bytes_written;
437
438   data = user_data;
439   marshaller = key;
440
441   if (data->error && *data->error)
442     return;
443
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);
446 }
447
448 gboolean
449 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, GError **error)
450 {
451   gboolean ret;
452   GPtrArray *argv;
453   gint child_stdout;
454   GIOChannel *genmarshal_stdout;
455   GPid child_pid;
456   DBusBindingToolCData data;
457   char *tempfile_name;
458   gint tempfile_fd;
459   GIOStatus iostatus;
460   char buf[4096];
461   gsize bytes_read, bytes_written;
462
463   memset (&data, 0, sizeof (data));
464
465   data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
466   data.error = error;
467   genmarshal_stdout = NULL;
468   tempfile_name = NULL;
469
470   if (!gather_marshallers (info, &data, error))
471     goto io_lose;
472
473   tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
474                                  &tempfile_name, error);
475   if (tempfile_fd < 0)
476     goto io_lose;
477
478   data.channel = g_io_channel_unix_new (tempfile_fd);
479   if (!g_io_channel_set_encoding (data.channel, NULL, error))
480     goto io_lose;
481   g_hash_table_foreach (data.generated, write_marshaller, &data); 
482   if (error && *error != NULL)
483     {
484       ret = FALSE;
485       g_io_channel_close (data.channel);
486       g_io_channel_unref (data.channel);
487       goto io_lose;
488     }
489
490   g_io_channel_close (data.channel);
491   g_io_channel_unref (data.channel);
492   
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,
502                                  G_SPAWN_SEARCH_PATH,
503                                  NULL, NULL,
504                                  &child_pid,
505                                  NULL,
506                                  &child_stdout, NULL, error))
507     {
508       g_ptr_array_free (argv, TRUE);
509       goto io_lose;
510     }
511   g_ptr_array_free (argv, TRUE);
512
513   genmarshal_stdout = g_io_channel_unix_new (child_stdout);
514   if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
515     goto io_lose;
516
517   WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
518
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)
522       goto io_lose;
523   if (iostatus != G_IO_STATUS_EOF)
524     goto io_lose;
525
526   g_io_channel_close (genmarshal_stdout);
527
528   WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
529
530   g_io_channel_ref (data.channel);
531   data.channel = channel;
532   if (!generate_glue (info, &data, error))
533     goto io_lose;
534   
535   ret = TRUE;
536  cleanup:
537   if (tempfile_name)
538     unlink (tempfile_name);
539   g_free (tempfile_name);
540   if (genmarshal_stdout)
541     g_io_channel_unref (genmarshal_stdout);
542   if (data.channel)
543     g_io_channel_unref (data.channel);
544   g_hash_table_destroy (data.generated);
545
546   return ret;
547  io_lose:
548   ret = FALSE;
549   goto cleanup;
550 }
551
552 static char *
553 iface_to_c_prefix (const char *iface)
554 {
555   char **components;
556   char **component;
557   GString *ret;
558   gboolean first;
559   
560   components = g_strsplit (iface, ".", 0);
561
562   first = TRUE;
563   ret = g_string_new ("");
564   for (component = components; *component; component++)
565     {
566       if (!first)
567         g_string_append_c (ret, '_');
568       else
569         first = FALSE;
570       g_string_append (ret, *component);
571     }
572   g_strfreev (components);
573   return g_string_free (ret, FALSE);
574 }
575
576 static char *
577 compute_client_method_name (InterfaceInfo *iface, MethodInfo *method)
578 {
579   GString *ret;
580   char *method_name_uscored;
581   char *iface_prefix;
582
583   iface_prefix = iface_to_c_prefix (interface_info_get_name (iface));
584   ret = g_string_new (iface_prefix);
585   g_free (iface_prefix);
586   
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);
592 }
593
594 static gboolean
595 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
596 {
597   GSList *args;
598
599   for (args = method_info_get_args (method); args; args = args->next)
600     {
601       ArgInfo *arg;
602       const char *type_str;
603       int direction;
604
605       arg = args->data;
606
607       WRITE_OR_LOSE (", ");
608
609       direction = arg_info_get_direction (arg);
610
611       /* FIXME - broken for containers */
612       type_str = dbus_gvalue_ctype_from_type (arg_info_get_type (arg), direction == ARG_IN);
613
614       if (!type_str)
615         {
616           g_set_error (error,
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));
621           return FALSE;
622         }
623
624       switch (direction)
625         {
626         case ARG_IN:
627           if (!write_printf_to_iochannel ("%s IN_%s", channel, error,
628                                           type_str,
629                                           arg_info_get_name (arg)))
630             goto io_lose;
631           break;
632         case ARG_OUT:
633           if (!write_printf_to_iochannel ("%s* OUT_%s", channel, error,
634                                           type_str,
635                                           arg_info_get_name (arg)))
636             goto io_lose;
637           break;
638         case ARG_INVALID:
639           break;
640         }
641     }
642
643   return TRUE;
644  io_lose:
645   return FALSE;
646 }
647
648 static gboolean
649 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
650 {
651   GSList *args;
652
653   for (args = method_info_get_args (method); args; args = args->next)
654     {
655       ArgInfo *arg;
656       const char *type_str;
657
658       arg = args->data;
659
660       if (direction != arg_info_get_direction (arg))
661         continue;
662
663       /* FIXME - broken for containers */
664       type_str = dbus_gvalue_binding_type_from_type (arg_info_get_type (arg));
665       if (!type_str)
666         {
667           g_set_error (error,
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));
672           return FALSE;
673         }
674
675       
676       switch (direction)
677         {
678         case ARG_IN:
679           if (!write_printf_to_iochannel ("                                  %s, &IN_%s,\n", channel, error,
680                                           type_str, arg_info_get_name (arg)))
681             goto io_lose;
682           break;
683         case ARG_OUT:
684           if (!write_printf_to_iochannel ("                               %s, OUT_%s,\n", channel, error,
685                                           type_str, arg_info_get_name (arg)))
686             goto io_lose;
687           break;
688         case ARG_INVALID:
689           break;
690         }
691     }
692
693   return TRUE;
694  io_lose:
695   return FALSE;
696 }
697
698 static gboolean
699 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
700 {
701   GSList *tmp;
702
703   tmp = list;
704   while (tmp != NULL)
705     {
706       if (!generate_client_glue (tmp->data, data, error))
707         return FALSE;
708       tmp = tmp->next;
709     }
710   return TRUE;
711 }
712
713 static gboolean
714 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
715 {
716   if (base_info_get_type (base) == INFO_TYPE_NODE)
717     {
718       if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
719                                       data, error))
720         return FALSE;
721       if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
722                                       data, error))
723         return FALSE;
724     }
725   else
726     {
727       GIOChannel *channel;
728       InterfaceInfo *interface;
729       GSList *methods;
730       GSList *tmp;
731       int count;
732
733       channel = data->channel;
734
735       interface = (InterfaceInfo *) base;
736
737       methods = interface_info_get_methods (interface);
738       count = 0;
739
740       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
741         {
742           MethodInfo *method;
743           char *method_name;
744
745           method = (MethodInfo *) tmp->data;
746
747           method_name = compute_client_method_name (interface, method);
748
749           WRITE_OR_LOSE ("static gboolean\n");
750           if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
751                                           method_name))
752             goto io_lose;
753           g_free (method_name);
754
755           if (!write_formal_parameters (interface, method, channel, error))
756             goto io_lose;
757
758           WRITE_OR_LOSE (", GError **error)\n\n");
759           
760           WRITE_OR_LOSE ("{\n");
761           WRITE_OR_LOSE ("  gboolean ret;\n\n");
762           WRITE_OR_LOSE ("  DBusGPendingCall *call;\n\n");
763           
764           if (!write_printf_to_iochannel ("  call = dbus_g_proxy_begin_call (proxy, \"%s\",\n",
765                                           channel, error,
766                                           method_info_get_name (method)))
767             goto io_lose;
768
769           if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
770             goto io_lose;
771
772           WRITE_OR_LOSE ("                                  DBUS_TYPE_INVALID);\n");
773           WRITE_OR_LOSE ("  ret = dbus_g_proxy_end_call (proxy, call, error,\n");
774           
775           if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
776             goto io_lose;
777
778           WRITE_OR_LOSE ("                               DBUS_TYPE_INVALID);\n");
779
780           WRITE_OR_LOSE ("  dbus_g_pending_call_unref (call);\n");
781           WRITE_OR_LOSE ("  return ret;\n");
782
783           WRITE_OR_LOSE ("}\n\n");
784         }
785     }
786   return TRUE;
787  io_lose:
788   return FALSE;
789 }
790
791
792 gboolean
793 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, GError **error)
794 {
795   DBusBindingToolCData data;
796   gboolean ret;
797
798   memset (&data, 0, sizeof (data));
799   
800   data.channel = channel;
801
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");
806
807   ret = generate_client_glue (info, &data, error);
808
809   return ret;
810  io_lose:
811   return FALSE;
812 }