2005-07-06 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  * Copyright (C) 2005 Nokia
6  *
7  * Licensed under the Academic Free License version 2.1
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  */
24
25 #include <config.h>
26 #include "dbus-gidl.h"
27 #include "dbus-gparser.h"
28 #include "dbus-gutils.h"
29 #include "dbus-gvalue.h"
30 #include "dbus-gvalue-utils.h"
31 #include "dbus-glib-tool.h"
32 #include "dbus-binding-tool-glib.h"
33 #include <glib/gi18n.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #define MARSHAL_PREFIX "dbus_glib_marshal_"
40
41 typedef struct
42 {
43   gboolean ignore_unsupported;
44   const char* prefix;
45   GIOChannel *channel;
46   
47   GError **error;
48   
49   GHashTable *generated;
50   GString *blob;
51   GString *signal_blob;
52   GString *property_blob;
53   guint count;
54 } DBusBindingToolCData;
55
56 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
57 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
58 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
59
60 static const char *
61 dbus_g_type_get_marshal_name (GType gtype)
62 {
63   switch (G_TYPE_FUNDAMENTAL (gtype))
64     {
65     case G_TYPE_BOOLEAN:
66       return "BOOLEAN";
67     case G_TYPE_UCHAR:
68       return "UCHAR";
69     case G_TYPE_INT:
70       return "INT";
71     case G_TYPE_UINT:
72       return "UINT";
73     case G_TYPE_INT64:
74       return "INT64";
75     case G_TYPE_UINT64:
76       return "UINT64";
77     case G_TYPE_DOUBLE:
78       return "DOUBLE";
79     case G_TYPE_STRING:
80       return "STRING";
81     case G_TYPE_POINTER:
82       return "POINTER";
83     case G_TYPE_BOXED:
84       return "BOXED";
85     case G_TYPE_OBJECT:
86       return "OBJECT";
87     default:
88       return NULL;
89     }
90 }
91
92 /* This entire function is kind of...ugh. */
93 static const char *
94 dbus_g_type_get_c_name (GType gtype)
95 {
96   if (dbus_g_type_is_collection (gtype))
97     return "GArray";
98   if (dbus_g_type_is_map (gtype))
99     return "GHashTable";
100   
101   if (g_type_is_a (gtype, G_TYPE_STRING)
102       || g_type_is_a (gtype, DBUS_TYPE_G_OBJECT_PATH))
103     return "char *";
104
105   /* This one is even more hacky...we get an extra *
106    * because G_TYPE_STRV is a G_TYPE_BOXED
107    */
108   if (g_type_is_a (gtype, G_TYPE_STRV))
109     return "char *";
110   
111   return g_type_name (gtype);
112 }
113
114 static char *
115 compute_marshaller (MethodInfo *method, GError **error)
116 {
117   GSList *elt;
118   GString *ret;
119   gboolean first;
120
121   /* All methods required to return boolean for now;
122    * will be conditional on method info later */
123   ret = g_string_new ("BOOLEAN:");
124
125   first = TRUE;
126   /* Append input arguments */
127   for (elt = method_info_get_args (method); elt; elt = elt->next)
128     {
129       ArgInfo *arg = elt->data;
130
131       if (arg_info_get_direction (arg) == ARG_IN)
132         {
133           const char *marshal_name;
134           GType gtype;
135
136           gtype = dbus_gtype_from_signature (arg_info_get_type (arg), FALSE);
137           if (gtype == G_TYPE_INVALID)
138             {
139               g_set_error (error,
140                            DBUS_BINDING_TOOL_ERROR,
141                            DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
142                            _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
143                            arg_info_get_type (arg));
144               g_string_free (ret, TRUE);
145               return NULL;
146             }
147
148           marshal_name = dbus_g_type_get_marshal_name (gtype);
149           g_assert (marshal_name);
150
151           if (!first)
152             g_string_append (ret, ",");
153           else
154             first = FALSE;
155           g_string_append (ret, marshal_name);
156         }
157     }
158
159   if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
160     {
161       if (!first)
162         g_string_append (ret, ",");
163       g_string_append (ret, "POINTER");
164       first = FALSE;
165     }
166   else
167     {
168       /* Append pointer for each out arg storage */
169       for (elt = method_info_get_args (method); elt; elt = elt->next)
170         {
171           ArgInfo *arg = elt->data;
172
173           if (arg_info_get_direction (arg) == ARG_OUT)
174             {
175               if (!first)
176                 g_string_append (ret, ",");
177               else
178                 first = FALSE;
179               g_string_append (ret, "POINTER");
180             }
181         }
182       /* Final GError parameter */
183       if (!first)
184         g_string_append (ret, ",");
185       g_string_append (ret, "POINTER");
186
187     }
188
189   return g_string_free (ret, FALSE);
190
191 }
192
193 static char *
194 compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
195 {
196   GSList *elt;
197   GString *ret;
198
199   /* All methods required to return boolean for now;
200    * will be conditional on method info later */
201   ret = g_string_new (MARSHAL_PREFIX);
202   g_string_append (ret, prefix);
203   g_string_append (ret, "_BOOLEAN_");
204
205   /* Append input arguments */
206   for (elt = method_info_get_args (method); elt; elt = elt->next)
207     {
208       ArgInfo *arg = elt->data;
209
210       if (arg_info_get_direction (arg) == ARG_IN)
211         {
212           const char *marshal_name;
213           const char *type;
214           GType gtype;
215
216           type = arg_info_get_type (arg);
217           gtype = dbus_gtype_from_signature (type, FALSE);
218           if (gtype == G_TYPE_INVALID)
219             {
220               g_set_error (error,
221                            DBUS_BINDING_TOOL_ERROR,
222                            DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
223                            _("Unsupported conversion from D-BUS type %s to glib type"),
224                            type);
225               g_string_free (ret, TRUE);
226               return NULL;
227             }
228           marshal_name = dbus_g_type_get_marshal_name (gtype);
229           g_assert (marshal_name != NULL);
230
231           g_string_append (ret, "_");
232           g_string_append (ret, marshal_name);
233         }
234     }
235
236   if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
237     {
238       g_string_append (ret, "_POINTER");
239     }
240   else
241     {
242       /* Append pointer for each out arg storage */
243       for (elt = method_info_get_args (method); elt; elt = elt->next)
244         {
245           ArgInfo *arg = elt->data;
246
247           if (arg_info_get_direction (arg) == ARG_OUT)
248             {
249               g_string_append (ret, "_POINTER");
250             }
251         }
252       /* Final GError parameter */
253       g_string_append (ret, "_POINTER");
254     }
255
256   return g_string_free (ret, FALSE);
257 }
258
259 static gboolean
260 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
261 {
262   GSList *tmp;
263
264   tmp = list;
265   while (tmp != NULL)
266     {
267       if (!gather_marshallers (tmp->data, data, error))
268         return FALSE;
269       tmp = tmp->next;
270     }
271   return TRUE;
272 }
273
274 static gboolean
275 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
276 {
277   if (base_info_get_type (base) == INFO_TYPE_NODE)
278     {
279       if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
280                                     data, error))
281         return FALSE;
282       if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
283                                     data, error))
284         return FALSE;
285     }
286   else
287     {
288       InterfaceInfo *interface;
289       GSList *methods;
290       GSList *tmp;
291       const char *interface_c_name;
292
293       interface = (InterfaceInfo *) base;
294       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
295       if (interface_c_name == NULL)
296         {
297           if (!data->prefix)
298             return TRUE;
299         }
300
301       methods = interface_info_get_methods (interface);
302
303       /* Generate the necessary marshallers for the methods. */
304
305       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
306         {
307           MethodInfo *method;
308           char *marshaller_name;
309
310           method = (MethodInfo *) tmp->data;
311
312           marshaller_name = compute_marshaller (method, error);
313           if (!marshaller_name)
314             return FALSE;
315
316           if (g_hash_table_lookup (data->generated, marshaller_name))
317             {
318               g_free (marshaller_name);
319               continue;
320             }
321
322           g_hash_table_insert (data->generated, marshaller_name, NULL);
323         }
324
325     }
326   return TRUE;
327 }
328
329 static gboolean
330 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
331 {
332   GSList *tmp;
333
334   tmp = list;
335   while (tmp != NULL)
336     {
337       if (!generate_glue (tmp->data, data, error))
338         return FALSE;
339       tmp = tmp->next;
340     }
341   return TRUE;
342 }
343
344 #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)
345
346 static gboolean
347 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
348 {
349   char *str;
350   va_list args;
351   GIOStatus status;
352   gsize written;
353   gboolean ret;
354
355   va_start (args, error);
356
357   str = g_strdup_vprintf (fmt, args);
358   if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
359     ret = TRUE;
360   else
361     ret = FALSE;
362
363   g_free (str);
364
365   va_end (args);
366
367   return ret;
368 }
369
370 static gboolean
371 write_quoted_string (GIOChannel *channel, GString *string, GError **error)
372 {
373   guint i;
374
375   WRITE_OR_LOSE ("\"");
376   for (i = 0; i < string->len; i++)
377     {
378       if (string->str[i] != '\0')
379         {
380           if (!g_io_channel_write_chars (channel, string->str + i, 1, NULL, error))
381             return FALSE;
382         }
383       else
384         {
385           if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
386             return FALSE;
387         }
388     }
389   WRITE_OR_LOSE ("\\0\"");
390   return TRUE;
391  io_lose:
392   return FALSE;
393 }
394
395 static gboolean
396 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
397 {
398   if (base_info_get_type (base) == INFO_TYPE_NODE)
399     {
400       GString *object_introspection_data_blob;
401       GIOChannel *channel;
402
403       channel = data->channel;
404       
405       object_introspection_data_blob = g_string_new_len ("", 0);
406       
407       data->blob = object_introspection_data_blob;
408       data->count = 0;
409
410       data->signal_blob = g_string_new_len ("", 0);
411       data->property_blob = g_string_new_len ("", 0);
412
413       if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
414         goto io_lose;
415
416       if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
417                                data, error))
418         return FALSE;
419       if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
420                                data, error))
421         return FALSE;
422
423       WRITE_OR_LOSE ("};\n\n");
424
425       /* Information about the object. */
426
427       if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
428                                       channel, error, data->prefix))
429         goto io_lose;
430       WRITE_OR_LOSE ("  0,\n");
431       if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, data->prefix))
432         goto io_lose;
433       if (!write_printf_to_iochannel ("  %d,\n", channel, error, data->count))
434         goto io_lose;
435
436       if (!write_quoted_string (channel, object_introspection_data_blob, error))
437         goto io_lose;
438       WRITE_OR_LOSE (",\n");
439       if (!write_quoted_string (channel, data->signal_blob, error))
440         goto io_lose;
441       WRITE_OR_LOSE (",\n");
442       if (!write_quoted_string (channel, data->property_blob, error))
443         goto io_lose;
444       WRITE_OR_LOSE ("\n};\n\n");
445
446       g_string_free (object_introspection_data_blob, TRUE);
447       g_string_free (data->signal_blob, TRUE);
448       g_string_free (data->property_blob, TRUE);
449     }
450   else
451     {
452       GIOChannel *channel;
453       InterfaceInfo *interface;
454       GSList *methods;
455       GSList *signals;
456       GSList *properties;
457       GSList *tmp;
458       const char *interface_c_name;
459       GString *object_introspection_data_blob;
460
461       channel = data->channel;
462       object_introspection_data_blob = data->blob;
463
464       interface = (InterfaceInfo *) base;
465       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
466       if (interface_c_name == NULL)
467         {
468           if (data->prefix == NULL)
469             return TRUE;
470           interface_c_name = data->prefix;
471         }
472
473       methods = interface_info_get_methods (interface);
474
475       /* Table of marshalled methods. */
476
477       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
478         {
479           MethodInfo *method;
480           char *marshaller_name;
481           char *method_c_name;
482           gboolean async = FALSE;
483           GSList *args;
484
485           method = (MethodInfo *) tmp->data;
486           method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL));
487           if (method_c_name == NULL)
488             {
489               char *method_name_uscored;
490               method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
491               method_c_name = g_strdup_printf ("%s_%s",
492                                                interface_c_name,
493                                                method_name_uscored);
494               g_free (method_name_uscored);
495             }
496
497           if (!write_printf_to_iochannel ("  { (GCallback) %s, ", channel, error,
498                                           method_c_name))
499             goto io_lose;
500
501           marshaller_name = compute_marshaller_name (method, data->prefix, error);
502           if (!marshaller_name)
503             goto io_lose;
504
505           if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
506                                           marshaller_name,
507                                           object_introspection_data_blob->len))
508             {
509               g_free (marshaller_name);
510               goto io_lose;
511             }
512
513           if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
514             async = TRUE;
515
516           /* Object method data blob format:
517            * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
518            */
519
520           g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
521           g_string_append_c (object_introspection_data_blob, '\0');
522
523           g_string_append (object_introspection_data_blob, method_info_get_name (method));
524           g_string_append_c (object_introspection_data_blob, '\0');
525
526           g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S');
527           g_string_append_c (object_introspection_data_blob, '\0');
528
529           for (args = method_info_get_args (method); args; args = args->next)
530             {
531               ArgInfo *arg;
532               char direction;
533
534               arg = args->data;
535
536               g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
537               g_string_append_c (object_introspection_data_blob, '\0');
538
539               switch (arg_info_get_direction (arg))
540                 {
541                 case ARG_IN:
542                   direction = 'I';
543                   break;
544                 case ARG_OUT:
545                   direction = 'O';
546                   break;
547                 case ARG_INVALID:
548                 default:
549                   g_assert_not_reached ();
550                   direction = 0; /* silence gcc */
551                   break;
552                 }
553               g_string_append_c (object_introspection_data_blob, direction);
554               g_string_append_c (object_introspection_data_blob, '\0');
555
556               g_string_append (object_introspection_data_blob, arg_info_get_type (arg));
557               g_string_append_c (object_introspection_data_blob, '\0');
558             }
559
560           g_string_append_c (object_introspection_data_blob, '\0');
561
562           data->count++;
563         }
564
565       signals = interface_info_get_signals (interface);
566
567       for (tmp = signals; tmp != NULL; tmp = g_slist_next (tmp))
568         {
569           SignalInfo *sig;
570           
571           sig = tmp->data;
572
573           g_string_append (data->signal_blob, interface_info_get_name (interface));
574           g_string_append_c (data->signal_blob, '\0');
575           g_string_append (data->signal_blob, signal_info_get_name (sig));
576           g_string_append_c (data->signal_blob, '\0');
577         }
578
579       properties = interface_info_get_properties (interface);
580
581       for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp))
582         {
583           PropertyInfo *prop;
584           
585           prop = tmp->data;
586
587           g_string_append (data->property_blob, interface_info_get_name (interface));
588           g_string_append_c (data->property_blob, '\0');
589           g_string_append (data->property_blob, property_info_get_name (prop));
590           g_string_append_c (data->property_blob, '\0');
591         }
592     }
593   return TRUE;
594  io_lose:
595   return FALSE;
596 }
597
598 static void
599 write_marshaller (gpointer key, gpointer value, gpointer user_data)
600 {
601   DBusBindingToolCData *data;
602   const char *marshaller;
603   gsize bytes_written;
604
605   data = user_data;
606   marshaller = key;
607
608   if (data->error && *data->error)
609     return;
610
611   if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
612     g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
613 }
614
615 gboolean
616 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error)
617 {
618   gboolean ret;
619   GPtrArray *argv;
620   gint child_stdout;
621   GIOChannel *genmarshal_stdout;
622   GPid child_pid;
623   DBusBindingToolCData data;
624   char *tempfile_name;
625   gint tempfile_fd;
626   GIOStatus iostatus;
627   char buf[4096];
628   gsize bytes_read, bytes_written;
629
630   memset (&data, 0, sizeof (data));
631
632   dbus_g_value_types_init ();
633
634   data.prefix = prefix;
635   data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
636   data.error = error;
637   genmarshal_stdout = NULL;
638   tempfile_name = NULL;
639
640   if (!gather_marshallers (info, &data, error))
641     goto io_lose;
642
643   tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
644                                  &tempfile_name, error);
645   if (tempfile_fd < 0)
646     goto io_lose;
647
648   data.channel = g_io_channel_unix_new (tempfile_fd);
649   if (!g_io_channel_set_encoding (data.channel, NULL, error))
650     goto io_lose;
651   g_hash_table_foreach (data.generated, write_marshaller, &data); 
652   if (error && *error != NULL)
653     {
654       ret = FALSE;
655       g_io_channel_close (data.channel);
656       g_io_channel_unref (data.channel);
657       goto io_lose;
658     }
659
660   g_io_channel_close (data.channel);
661   g_io_channel_unref (data.channel);
662   
663   /* Now spawn glib-genmarshal to insert all our required marshallers */
664   argv = g_ptr_array_new ();
665   g_ptr_array_add (argv, "glib-genmarshal");
666   g_ptr_array_add (argv, "--header");
667   g_ptr_array_add (argv, "--body");
668   g_ptr_array_add (argv, g_strdup_printf ("--prefix=%s%s", MARSHAL_PREFIX, prefix));
669   g_ptr_array_add (argv, tempfile_name);
670   g_ptr_array_add (argv, NULL);
671   if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
672                                  G_SPAWN_SEARCH_PATH,
673                                  NULL, NULL,
674                                  &child_pid,
675                                  NULL,
676                                  &child_stdout, NULL, error))
677     {
678       g_ptr_array_free (argv, TRUE);
679       goto io_lose;
680     }
681   g_ptr_array_free (argv, TRUE);
682
683   genmarshal_stdout = g_io_channel_unix_new (child_stdout);
684   if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
685     goto io_lose;
686
687   WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
688
689   while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
690                                               &bytes_read, error)) == G_IO_STATUS_NORMAL)
691     if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
692       goto io_lose;
693   if (iostatus != G_IO_STATUS_EOF)
694     goto io_lose;
695
696   g_io_channel_close (genmarshal_stdout);
697
698   WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
699
700   data.channel = channel;
701   g_io_channel_ref (data.channel);
702   if (!generate_glue (info, &data, error))
703     goto io_lose;
704   
705   ret = TRUE;
706  cleanup:
707   if (tempfile_name)
708     unlink (tempfile_name);
709   g_free (tempfile_name);
710   if (genmarshal_stdout)
711     g_io_channel_unref (genmarshal_stdout);
712   if (data.channel)
713     g_io_channel_unref (data.channel);
714   g_hash_table_destroy (data.generated);
715
716   return ret;
717  io_lose:
718   ret = FALSE;
719   goto cleanup;
720 }
721
722 static char *
723 iface_to_c_prefix (const char *iface)
724 {
725   char **components;
726   char **component;
727   GString *ret;
728   gboolean first;
729   
730   components = g_strsplit (iface, ".", 0);
731
732   first = TRUE;
733   ret = g_string_new ("");
734   for (component = components; *component; component++)
735     {
736       if (!first)
737         g_string_append_c (ret, '_');
738       else
739         first = FALSE;
740       g_string_append (ret, *component);
741     }
742   g_strfreev (components);
743   return g_string_free (ret, FALSE);
744 }
745
746 static char *
747 compute_client_method_name (const char *iface_prefix, MethodInfo *method)
748 {
749   GString *ret;
750   char *method_name_uscored;
751
752   ret = g_string_new (iface_prefix);
753   
754   method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
755   g_string_append_c (ret, '_');
756   g_string_append (ret, method_name_uscored);
757   g_free (method_name_uscored);
758   return g_string_free (ret, FALSE);
759 }
760
761 static gboolean
762 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
763 {
764   GSList *args;
765
766   for (args = method_info_get_args (method); args; args = args->next)
767     {
768       ArgInfo *arg;
769       const char *type_str;
770       const char *type_suffix;
771       GType gtype;
772       int direction;
773
774       arg = args->data;
775
776       WRITE_OR_LOSE (", ");
777
778       direction = arg_info_get_direction (arg);
779
780       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
781       if (gtype == G_TYPE_INVALID)
782         {
783           g_set_error (error,
784                        DBUS_BINDING_TOOL_ERROR,
785                        DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
786                        _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
787                        arg_info_get_type (arg),
788                        method_info_get_name (method),
789                        interface_info_get_name (iface));
790           return FALSE;
791         }
792       type_str = dbus_g_type_get_c_name (gtype);
793       g_assert (type_str);
794       /* Variants are special...*/
795       if (gtype == G_TYPE_VALUE)
796         {
797           if (direction == ARG_IN)
798             type_suffix = "*";
799           else
800             type_suffix = "";
801         }
802       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
803               || g_type_is_a (gtype, G_TYPE_OBJECT)
804            || g_type_is_a (gtype, G_TYPE_POINTER)))
805         type_suffix = "*";
806       else
807         type_suffix = "";
808
809
810       switch (direction)
811         {
812         case ARG_IN:
813           if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
814                                           type_str,
815                                           type_suffix,
816                                           arg_info_get_name (arg)))
817             goto io_lose;
818           break;
819         case ARG_OUT:
820           if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
821                                           type_str,
822                                           type_suffix,
823                                           arg_info_get_name (arg)))
824             goto io_lose;
825           break;
826         case ARG_INVALID:
827           break;
828         }
829     }
830
831   return TRUE;
832  io_lose:
833   return FALSE;
834 }
835
836 #define MAP_FUNDAMENTAL(NAME) \
837    case G_TYPE_ ## NAME: \
838      return g_strdup ("G_TYPE_" #NAME);
839 #define MAP_KNOWN(NAME) \
840     if (gtype == NAME) \
841       return g_strdup (#NAME)
842 static char *
843 dbus_g_type_get_lookup_function (GType gtype)
844 {
845   char *type_lookup;
846   switch (gtype)
847     {
848       MAP_FUNDAMENTAL(CHAR);
849       MAP_FUNDAMENTAL(UCHAR);
850       MAP_FUNDAMENTAL(BOOLEAN);
851       MAP_FUNDAMENTAL(LONG);
852       MAP_FUNDAMENTAL(ULONG);
853       MAP_FUNDAMENTAL(INT);
854       MAP_FUNDAMENTAL(UINT);
855       MAP_FUNDAMENTAL(INT64);
856       MAP_FUNDAMENTAL(UINT64);
857       MAP_FUNDAMENTAL(FLOAT);
858       MAP_FUNDAMENTAL(DOUBLE);
859       MAP_FUNDAMENTAL(STRING);
860     }
861   if (dbus_g_type_is_collection (gtype))
862     {
863       GType elt_gtype;
864       char *sublookup;
865       
866       elt_gtype = dbus_g_type_get_collection_specialization (gtype);
867       sublookup = dbus_g_type_get_lookup_function (elt_gtype);
868       g_assert (sublookup);
869       type_lookup = g_strdup_printf ("dbus_g_type_get_collection (\"GArray\", %s)",
870                                      sublookup);
871       g_free (sublookup);
872       return type_lookup;
873     }
874   else if (dbus_g_type_is_map (gtype))
875     {
876       GType key_gtype;
877       char *key_lookup;
878       GType value_gtype;
879       char *value_lookup;
880       
881       key_gtype = dbus_g_type_get_map_key_specialization (gtype);
882       value_gtype = dbus_g_type_get_map_value_specialization (gtype);
883       key_lookup = dbus_g_type_get_lookup_function (key_gtype);
884       g_assert (key_lookup);
885       value_lookup = dbus_g_type_get_lookup_function (value_gtype);
886       g_assert (value_lookup);
887       type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)",
888                                      key_lookup, value_lookup);
889       g_free (key_lookup);
890       g_free (value_lookup);
891       return type_lookup;
892     }
893   MAP_KNOWN(G_TYPE_VALUE);
894   MAP_KNOWN(G_TYPE_STRV);
895   MAP_KNOWN(DBUS_TYPE_G_PROXY);
896   MAP_KNOWN(DBUS_TYPE_G_OBJECT_PATH);
897   return NULL;
898 }
899 #undef MAP_FUNDAMENTAL
900 #undef MAP_KNOWN
901
902 static gboolean
903 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
904 {
905   GSList *args;
906
907   for (args = method_info_get_args (method); args; args = args->next)
908     {
909       ArgInfo *arg;
910       GType gtype;
911       char *type_lookup;
912
913       arg = args->data;
914
915       if (direction != arg_info_get_direction (arg))
916         continue;
917
918       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
919       g_assert (gtype != G_TYPE_INVALID);
920       type_lookup = dbus_g_type_get_lookup_function (gtype);
921       g_assert (type_lookup != NULL);
922
923       switch (direction)
924         {
925
926         case ARG_IN:
927           if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error,
928                                           type_lookup,
929                                           arg_info_get_name (arg)))
930             goto io_lose;
931           break;
932         case ARG_OUT:
933           if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error,
934                                           type_lookup,
935                                           arg_info_get_name (arg)))
936             goto io_lose;
937           break;
938         case ARG_INVALID:
939           break;
940         }
941       g_free (type_lookup);
942     }
943
944   return TRUE;
945  io_lose:
946   return FALSE;
947 }
948
949 static gboolean
950 check_supported_parameters (MethodInfo *method)
951 {
952   GSList *args;
953
954   for (args = method_info_get_args (method); args; args = args->next)
955     {
956       ArgInfo *arg;
957       GType gtype;
958
959       arg = args->data;
960       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
961       if (gtype == G_TYPE_INVALID)
962         return FALSE;
963     }
964   return TRUE;
965 }
966
967 static gboolean
968 write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
969 {
970   GSList *args;
971
972   for (args = method_info_get_args (method); args; args = args->next)
973     {
974       ArgInfo *arg;
975
976       arg = args->data;
977       if (arg_info_get_direction (arg) != ARG_OUT)
978         continue;
979             
980       if (!write_printf_to_iochannel ("OUT_%s, ", channel, error,
981                                       arg_info_get_name (arg)))
982         goto io_lose;
983      }
984
985    return TRUE;
986  io_lose:
987   return FALSE;
988 }
989
990 static gboolean
991 write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
992  {
993    GSList *args;
994  
995    for (args = method_info_get_args (method); args; args = args->next)
996      {
997        ArgInfo *arg;
998       GType gtype;
999       const char *type_str, *type_suffix;
1000       int dir;
1001
1002        arg = args->data;
1003
1004       dir = arg_info_get_direction (arg);
1005
1006       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
1007       type_str = dbus_g_type_get_c_name (gtype);
1008
1009       if (!type_str)
1010        {
1011          g_set_error (error,
1012                       DBUS_BINDING_TOOL_ERROR,
1013                       DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
1014                       _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
1015                       arg_info_get_type (arg),
1016                       method_info_get_name (method),
1017                       interface_info_get_name (iface));
1018          return FALSE;
1019        }
1020
1021       /* Variants are special...*/
1022       if (gtype == G_TYPE_VALUE)
1023         {
1024           if (direction == ARG_IN)
1025             type_suffix = "*";
1026           else
1027             type_suffix = "";
1028         }
1029       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
1030               || g_type_is_a (gtype, G_TYPE_OBJECT)
1031            || g_type_is_a (gtype, G_TYPE_POINTER)))
1032         type_suffix = "*";
1033       else
1034         type_suffix = "";
1035
1036       if (direction != dir)
1037         continue;
1038
1039           switch (dir)
1040        {
1041        case ARG_IN:
1042          if (!write_printf_to_iochannel ("  %s%s IN_%s;\n", channel, error,
1043                                          type_str, type_suffix,
1044                                          arg_info_get_name (arg)))
1045            goto io_lose;
1046          break;
1047        case ARG_OUT:
1048          if (!write_printf_to_iochannel ("  %s%s OUT_%s;\n", channel, error,
1049                                          type_str, type_suffix,
1050                                          arg_info_get_name (arg)))
1051            goto io_lose;
1052          break;
1053        case ARG_INVALID:
1054          break;
1055        }
1056      }
1057    return TRUE;
1058  io_lose:
1059   return FALSE;
1060  }
1061
1062 static gboolean
1063 write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error)
1064 {
1065   GSList *args;
1066
1067   for (args = method_info_get_args (method); args; args = args->next)
1068     {
1069       ArgInfo *arg;
1070       const char *type_str;
1071       const char *type_suffix;
1072       GType gtype;
1073       int direction;
1074
1075       arg = args->data;
1076
1077       direction = arg_info_get_direction (arg);
1078       if (dir != direction) continue;
1079       
1080       WRITE_OR_LOSE (", ");
1081
1082       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
1083       type_str = dbus_g_type_get_c_name (gtype);
1084       /* Variants are special...*/
1085       if (gtype == G_TYPE_VALUE)
1086         {
1087           if (direction == ARG_IN)
1088             type_suffix = "*";
1089           else
1090             type_suffix = "";
1091         }
1092       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
1093               || g_type_is_a (gtype, G_TYPE_OBJECT)
1094            || g_type_is_a (gtype, G_TYPE_POINTER)))
1095         type_suffix = "*";
1096       else
1097         type_suffix = "";
1098
1099       if (!type_str)
1100         {
1101           g_set_error (error,
1102                        DBUS_BINDING_TOOL_ERROR,
1103                        DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
1104                        _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
1105                        arg_info_get_type (arg),
1106                        method_info_get_name (method),
1107                        interface_info_get_name (iface));
1108           return FALSE;
1109         }
1110  
1111        switch (direction)
1112         {
1113         case ARG_IN:
1114           if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
1115                                           type_str,
1116                                           type_suffix,
1117                                           arg_info_get_name (arg)))
1118             goto io_lose;
1119           break;
1120         case ARG_OUT:
1121           if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
1122                                           type_str,
1123                                           type_suffix,
1124                                           arg_info_get_name (arg)))
1125             goto io_lose;
1126           break;
1127         case ARG_INVALID:
1128           break;
1129         }
1130     }
1131   return TRUE;
1132  io_lose:
1133   return FALSE;
1134 }
1135
1136 static gboolean
1137 write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
1138  {
1139   GSList *args;
1140   
1141   for (args = method_info_get_args (method); args; args = args->next)
1142     {
1143       ArgInfo *arg;
1144       int dir;
1145       GType gtype;
1146       const char *type_lookup;
1147       
1148       arg = args->data;
1149
1150       dir = arg_info_get_direction (arg);
1151
1152       if (dir != direction)
1153         continue;
1154
1155       gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
1156       type_lookup = dbus_g_type_get_lookup_function (gtype);
1157
1158       if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg)))
1159           goto io_lose;
1160     }
1161   return TRUE;
1162  io_lose:
1163   return FALSE;
1164 }
1165
1166 static gboolean
1167 write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error)
1168 {
1169   char *method_name, *iface_prefix;
1170   iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
1171   method_name = compute_client_method_name (iface_prefix, method);
1172   
1173   /* Write the typedef for the client callback */
1174   if (!write_printf_to_iochannel ("typedef void (*%s_reply) (", channel, error, method_name))
1175     goto io_lose;
1176   {
1177     GSList *args;
1178     for (args = method_info_get_args (method); args; args = args->next)
1179       {
1180         ArgInfo *arg;
1181         const char *type_suffix, *type_str;
1182         GType gtype;
1183         
1184         arg = args->data;
1185         
1186         if (arg_info_get_direction (arg) != ARG_OUT)
1187           continue;
1188         gtype = dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
1189         if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED)
1190              || g_type_is_a (gtype, G_TYPE_OBJECT)
1191              || g_type_is_a (gtype, G_TYPE_POINTER)))
1192           type_suffix = "*";
1193         else
1194           type_suffix = "";
1195         type_str = dbus_g_type_get_c_name (dbus_gtype_from_signature (arg_info_get_type (arg), TRUE));
1196         if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg)))
1197           goto io_lose;
1198       }
1199   }
1200   WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n");
1201   
1202   
1203   /* Write the callback when the call returns */
1204   WRITE_OR_LOSE ("static void\n");
1205   if (!write_printf_to_iochannel ("%s_async_callback (DBusGPendingCall *pending, DBusGAsyncData *data)\n", channel, error, method_name))
1206     goto io_lose;
1207   WRITE_OR_LOSE ("{\n");
1208   WRITE_OR_LOSE ("  GError *error = NULL;\n");
1209   if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error))
1210     goto io_lose;
1211   WRITE_OR_LOSE ("  dbus_g_proxy_end_call (data->proxy, pending, &error, ");
1212   if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error))
1213     goto io_lose;
1214   WRITE_OR_LOSE("G_TYPE_INVALID);\n");
1215   if (!write_printf_to_iochannel ("  (*(%s_reply)data->cb) (", channel, error, method_name))
1216     goto io_lose;
1217   if (!write_untyped_out_args (interface, method, channel, error))
1218     goto io_lose;
1219   WRITE_OR_LOSE ("error, data->userdata);\n");
1220   WRITE_OR_LOSE ("  return;\n}\n\n");
1221   
1222
1223   /* Write the main wrapper function */
1224   WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
1225   if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error,
1226                                   method_name))
1227     goto io_lose;
1228   if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error))
1229     goto io_lose;
1230   
1231   if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name))
1232     goto io_lose;
1233   
1234   WRITE_OR_LOSE ("{\n");
1235   WRITE_OR_LOSE ("  DBusGPendingCall *pending;\n  DBusGAsyncData *stuff;\n  stuff = g_new (DBusGAsyncData, 1);\n  stuff->proxy = proxy;\n  stuff->cb = callback;\n  stuff->userdata = userdata;\n");
1236   if (!write_printf_to_iochannel ("  pending = dbus_g_proxy_begin_call (proxy, \"%s\", ", channel, error, method_info_get_name (method)))
1237     goto io_lose;
1238   if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
1239     goto io_lose;
1240   WRITE_OR_LOSE ("G_TYPE_INVALID);\n");
1241
1242   if (!write_printf_to_iochannel ("  dbus_g_pending_call_set_notify(pending, (DBusGPendingCallNotify)%s_async_callback, stuff, g_free);\n", channel, error, method_name))
1243     goto io_lose;
1244
1245   WRITE_OR_LOSE ("  return TRUE;\n}\n\n");
1246
1247   g_free (method_name);
1248   return TRUE;
1249  io_lose:
1250   return FALSE;
1251  }
1252
1253 static gboolean
1254 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
1255 {
1256   GSList *tmp;
1257
1258   tmp = list;
1259   while (tmp != NULL)
1260     {
1261       if (!generate_client_glue (tmp->data, data, error))
1262         return FALSE;
1263       tmp = tmp->next;
1264     }
1265   return TRUE;
1266 }
1267
1268 static gboolean
1269 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
1270 {
1271   if (base_info_get_type (base) == INFO_TYPE_NODE)
1272     {
1273       if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
1274                                       data, error))
1275         return FALSE;
1276       if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
1277                                       data, error))
1278         return FALSE;
1279     }
1280   else
1281     {
1282       GIOChannel *channel;
1283       InterfaceInfo *interface;
1284       GSList *methods;
1285       GSList *tmp;
1286       int count;
1287       char *iface_prefix;
1288
1289       channel = data->channel;
1290
1291       interface = (InterfaceInfo *) base;
1292
1293       methods = interface_info_get_methods (interface);
1294       count = 0;
1295
1296       iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
1297
1298       if (!write_printf_to_iochannel ("#ifndef DBUS_GLIB_CLIENT_WRAPPERS_%s\n"
1299                                       "#define DBUS_GLIB_CLIENT_WRAPPERS_%s\n\n",
1300                                       channel, error,
1301                                       iface_prefix, iface_prefix))
1302         {
1303           g_free (iface_prefix);
1304           goto io_lose;
1305         }
1306
1307       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
1308         {
1309           MethodInfo *method;
1310           char *method_name;
1311
1312           method = (MethodInfo *) tmp->data;
1313
1314           if (data->ignore_unsupported && !check_supported_parameters (method))
1315             {
1316               g_warning ("Ignoring unsupported signature in method \"%s\" of interface \"%s\"\n",
1317                          method_info_get_name (method),
1318                          interface_info_get_name (interface));
1319               continue;
1320             }
1321
1322           method_name = compute_client_method_name (iface_prefix, method);
1323
1324           WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
1325           if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
1326                                           method_name))
1327             goto io_lose;
1328           g_free (method_name);
1329
1330           if (!write_formal_parameters (interface, method, channel, error))
1331             goto io_lose;
1332
1333           WRITE_OR_LOSE (", GError **error)\n\n");
1334           
1335           WRITE_OR_LOSE ("{\n");
1336           
1337           if (!write_printf_to_iochannel ("  return dbus_g_proxy_call (proxy, \"%s\", ", channel, error,
1338                                           method_info_get_name (method)))
1339             goto io_lose;
1340
1341           WRITE_OR_LOSE ("error, ");
1342
1343           if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
1344             goto io_lose;
1345
1346           WRITE_OR_LOSE ("G_TYPE_INVALID, ");
1347
1348           if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
1349             goto io_lose;
1350
1351           WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n");
1352
1353 #if 0
1354           write_async_method_client (channel, interface, method, error);
1355 #endif
1356         }
1357
1358       if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
1359         {
1360           g_free (iface_prefix);
1361           goto io_lose;
1362         }
1363     }
1364   return TRUE;
1365  io_lose:
1366   return FALSE;
1367 }
1368
1369
1370 gboolean
1371 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error)
1372 {
1373   DBusBindingToolCData data;
1374   gboolean ret;
1375
1376   dbus_g_value_types_init ();
1377
1378   memset (&data, 0, sizeof (data));
1379   
1380   data.channel = channel;
1381   data.ignore_unsupported = ignore_unsupported;
1382
1383   WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
1384   WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
1385   WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
1386   WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
1387   WRITE_OR_LOSE ("G_BEGIN_DECLS\n\n");
1388
1389   ret = generate_client_glue (info, &data, error);
1390   if (!ret)
1391     goto io_lose;
1392   
1393   WRITE_OR_LOSE ("G_END_DECLS\n");
1394
1395   return ret;
1396  io_lose:
1397   return FALSE;
1398 }