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