dbus-binding-tool-glib.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-binding-tool-glib.c: Output C glue
00003  *
00004  * Copyright (C) 2003, 2004, 2005 Red Hat, Inc.
00005  * Copyright (C) 2005 Nokia
00006  *
00007  * Licensed under the Academic Free License version 2.1
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00022  *
00023  */
00024 
00025 #include <config.h>
00026 #include "dbus/dbus-glib.h"
00027 #include "dbus-gidl.h"
00028 #include "dbus-gparser.h"
00029 #include "dbus-gutils.h"
00030 #include "dbus-gtype-specialized.h"
00031 #include "dbus-gsignature.h"
00032 #include "dbus-gvalue-utils.h"
00033 #include "dbus-glib-tool.h"
00034 #include "dbus-binding-tool-glib.h"
00035 #include <glib/gi18n.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <string.h>
00039 #include <unistd.h>
00040 
00041 #define MARSHAL_PREFIX "dbus_glib_marshal_"
00042 
00043 typedef struct
00044 {
00045   gboolean ignore_unsupported;
00046   const char* prefix;
00047   GIOChannel *channel;
00048   
00049   GError **error;
00050   
00051   GHashTable *generated;
00052   GString *blob;
00053   GString *signal_blob;
00054   GString *property_blob;
00055   guint count;
00056 } DBusBindingToolCData;
00057 
00058 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error);
00059 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
00060 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error);
00061 
00062 static const char *
00063 dbus_g_type_get_marshal_name (GType gtype)
00064 {
00065   switch (G_TYPE_FUNDAMENTAL (gtype))
00066     {
00067     case G_TYPE_NONE:
00068       return "NONE";
00069     case G_TYPE_BOOLEAN:
00070       return "BOOLEAN";
00071     case G_TYPE_UCHAR:
00072       return "UCHAR";
00073     case G_TYPE_INT:
00074       return "INT";
00075     case G_TYPE_UINT:
00076       return "UINT";
00077     case G_TYPE_INT64:
00078       return "INT64";
00079     case G_TYPE_UINT64:
00080       return "UINT64";
00081     case G_TYPE_DOUBLE:
00082       return "DOUBLE";
00083     case G_TYPE_STRING:
00084       return "STRING";
00085     case G_TYPE_POINTER:
00086       return "POINTER";
00087     case G_TYPE_BOXED:
00088       return "BOXED";
00089     case G_TYPE_OBJECT:
00090       return "OBJECT";
00091     default:
00092       return NULL;
00093     }
00094 }
00095 
00096 /* This entire function is kind of...ugh. */
00097 static const char *
00098 dbus_g_type_get_c_name (GType gtype)
00099 {
00100   GType subtype;
00101   if (dbus_g_type_is_struct (gtype))
00102     {
00103       return "GValueArray";
00104     }
00105   if (dbus_g_type_is_collection (gtype))
00106     {
00107       subtype = dbus_g_type_get_collection_specialization(gtype);
00108       if (_dbus_g_type_is_fixed (subtype))
00109         return "GArray";
00110       else
00111         return "GPtrArray";
00112     }
00113 
00114   if (dbus_g_type_is_map (gtype))
00115     return "GHashTable";
00116 
00117   if (g_type_is_a (gtype, G_TYPE_STRING))
00118     return "char *";
00119 
00120   /* This one is even more hacky...we get an extra *
00121    * because G_TYPE_STRV is a G_TYPE_BOXED
00122    */
00123   if (g_type_is_a (gtype, G_TYPE_STRV))
00124     return "char *";
00125 
00126   if (g_type_is_a (gtype, DBUS_TYPE_G_OBJECT_PATH))
00127     return "char";
00128 
00129   return g_type_name (gtype);
00130 }
00131 
00132 static gboolean
00133 compute_gsignature (MethodInfo *method, GType *rettype, GArray **params, GError **error)
00134 {
00135   GSList *elt;
00136   GType retval_type;
00137   GArray *ret;
00138   gboolean is_async;
00139   const char *arg_type;
00140   gboolean retval_signals_error;
00141   
00142   is_async = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL;
00143   retval_signals_error = FALSE;
00144 
00145   ret = g_array_new (TRUE, TRUE, sizeof (GType));
00146 
00147   if (is_async)
00148     retval_type = G_TYPE_NONE;
00149   else
00150     {
00151       gboolean found_retval;
00152 
00153       /* Look for return value */
00154       found_retval = FALSE;
00155       for (elt = method_info_get_args (method); elt; elt = elt->next)
00156         {
00157           ArgInfo *arg = elt->data;
00158           const char *returnval_annotation;
00159       
00160           returnval_annotation = arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL);
00161           if (returnval_annotation != NULL)
00162             {
00163               arg_type = arg_info_get_type (arg);
00164               retval_type = _dbus_gtype_from_signature (arg_type, FALSE);
00165               if (retval_type == G_TYPE_INVALID)
00166                 goto invalid_type;
00167               found_retval = TRUE;
00168               if (!strcmp (returnval_annotation, "error"))
00169                 retval_signals_error = TRUE;
00170               break;
00171             }
00172         }
00173       if (!found_retval)
00174         {
00175           retval_type = G_TYPE_BOOLEAN;
00176           retval_signals_error = TRUE;
00177         }
00178     }
00179 
00180   *rettype = retval_type;
00181 
00182   /* Handle all input arguments */
00183   for (elt = method_info_get_args (method); elt; elt = elt->next)
00184     {
00185       ArgInfo *arg = elt->data;
00186       if (arg_info_get_direction (arg) == ARG_IN)
00187         {
00188           GType gtype;
00189           
00190           arg_type = arg_info_get_type (arg);
00191           gtype = _dbus_gtype_from_signature (arg_type, FALSE);
00192           if (gtype == G_TYPE_INVALID)
00193             goto invalid_type;
00194           
00195           g_array_append_val (ret, gtype);
00196         }
00197     }
00198 
00199   if (!is_async)
00200     {
00201       /* Append pointer for each out arg storage */
00202       for (elt = method_info_get_args (method); elt; elt = elt->next)
00203         {
00204           ArgInfo *arg = elt->data;
00205 
00206           /* Skip return value */
00207           if (arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL) != NULL)
00208             continue;
00209       
00210           if (arg_info_get_direction (arg) == ARG_OUT)
00211             {
00212               GType gtype;
00213               arg_type = arg_info_get_type (arg);
00214               gtype = _dbus_gtype_from_signature (arg_type, FALSE);
00215               if (gtype == G_TYPE_INVALID)
00216                 goto invalid_type;
00217               /* We actually just need a pointer for the return value
00218                  storage */
00219               gtype = G_TYPE_POINTER;
00220               g_array_append_val (ret, gtype);
00221             }
00222         }
00223 
00224       if (retval_signals_error)
00225         {
00226           /* Final GError parameter */
00227           GType gtype = G_TYPE_POINTER;
00228           g_array_append_val (ret, gtype);
00229         }
00230     }
00231   else
00232     {
00233       /* Context pointer */
00234       GType gtype = G_TYPE_POINTER;
00235       g_array_append_val (ret, gtype);
00236     }
00237 
00238   *params = ret;
00239   return TRUE;
00240 
00241  invalid_type:
00242   g_set_error (error,
00243                DBUS_BINDING_TOOL_ERROR,
00244                DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
00245                _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"),
00246                arg_type);
00247   return FALSE;
00248 }
00249   
00250 
00251 static char *
00252 compute_marshaller (MethodInfo *method, GError **error)
00253 {
00254   GArray *signature;
00255   GType rettype;
00256   const char *marshal_name;
00257   GString *ret;
00258   guint i;
00259 
00260   if (!compute_gsignature (method, &rettype, &signature, error))
00261     return NULL;
00262 
00263   ret = g_string_new ("");
00264   marshal_name = dbus_g_type_get_marshal_name (rettype);
00265   g_assert (marshal_name != NULL);
00266   g_string_append (ret, marshal_name);
00267   g_string_append_c (ret, ':');
00268   for (i = 0; i < signature->len; i++)
00269     {
00270       marshal_name = dbus_g_type_get_marshal_name (g_array_index (signature, GType, i));
00271       g_assert (marshal_name != NULL);
00272       g_string_append (ret, marshal_name);
00273       if (i < signature->len - 1)
00274         g_string_append_c (ret, ',');
00275     }
00276   if (signature->len == 0)
00277     {
00278       marshal_name = dbus_g_type_get_marshal_name (G_TYPE_NONE);
00279       g_assert (marshal_name != NULL);
00280       g_string_append (ret, marshal_name);
00281     }
00282   g_array_free (signature, TRUE);
00283   return g_string_free (ret, FALSE);
00284 }
00285 
00286 static char *
00287 compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error)
00288 {
00289   GString *ret;
00290   GArray *signature;
00291   GType rettype;
00292   const char *marshal_name;
00293   guint i;
00294 
00295   if (!compute_gsignature (method, &rettype, &signature, error))
00296     return NULL;
00297 
00298   ret = g_string_new (MARSHAL_PREFIX);
00299   g_string_append (ret, prefix);
00300   g_string_append_c (ret, '_');
00301 
00302   marshal_name = dbus_g_type_get_marshal_name (rettype);
00303   g_assert (marshal_name != NULL);
00304   g_string_append (ret, marshal_name);
00305   g_string_append (ret, "__");
00306   for (i = 0; i < signature->len; i++)
00307     {
00308       marshal_name = dbus_g_type_get_marshal_name (g_array_index (signature, GType, i));
00309       g_assert (marshal_name != NULL);
00310       g_string_append (ret, marshal_name);
00311       if (i < signature->len - 1)
00312         g_string_append_c (ret, '_');
00313     }
00314   if (signature->len == 0)
00315     {
00316       marshal_name = dbus_g_type_get_marshal_name (G_TYPE_NONE);
00317       g_assert (marshal_name != NULL);
00318       g_string_append (ret, marshal_name);
00319     }
00320   g_array_free (signature, TRUE);
00321   return g_string_free (ret, FALSE);
00322 }
00323 
00324 static gboolean
00325 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error)
00326 {
00327   GSList *tmp;
00328 
00329   tmp = list;
00330   while (tmp != NULL)
00331     {
00332       if (!gather_marshallers (tmp->data, data, error))
00333         return FALSE;
00334       tmp = tmp->next;
00335     }
00336   return TRUE;
00337 }
00338 
00339 static gboolean
00340 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error)
00341 {
00342   if (base_info_get_type (base) == INFO_TYPE_NODE)
00343     {
00344       if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base),
00345                                     data, error))
00346         return FALSE;
00347       if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base),
00348                                     data, error))
00349         return FALSE;
00350     }
00351   else
00352     {
00353       InterfaceInfo *interface;
00354       GSList *methods;
00355       GSList *tmp;
00356       const char *interface_c_name;
00357 
00358       interface = (InterfaceInfo *) base;
00359       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
00360       if (interface_c_name == NULL)
00361         {
00362           if (!data->prefix)
00363             return TRUE;
00364         }
00365 
00366       methods = interface_info_get_methods (interface);
00367 
00368       /* Generate the necessary marshallers for the methods. */
00369 
00370       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
00371         {
00372           MethodInfo *method;
00373           char *marshaller_name;
00374 
00375           method = (MethodInfo *) tmp->data;
00376 
00377           marshaller_name = compute_marshaller (method, error);
00378           if (!marshaller_name)
00379             return FALSE;
00380 
00381           if (g_hash_table_lookup (data->generated, marshaller_name))
00382             {
00383               g_free (marshaller_name);
00384               continue;
00385             }
00386 
00387           g_hash_table_insert (data->generated, marshaller_name, NULL);
00388         }
00389 
00390     }
00391   return TRUE;
00392 }
00393 
00394 static gboolean
00395 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
00396 {
00397   GSList *tmp;
00398 
00399   tmp = list;
00400   while (tmp != NULL)
00401     {
00402       if (!generate_glue (tmp->data, data, error))
00403         return FALSE;
00404       tmp = tmp->next;
00405     }
00406   return TRUE;
00407 }
00408 
00409 #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)
00410 
00411 static gboolean
00412 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...)
00413 {
00414   char *str;
00415   va_list args;
00416   GIOStatus status;
00417   gsize written;
00418   gboolean ret;
00419 
00420   va_start (args, error);
00421 
00422   str = g_strdup_vprintf (fmt, args);
00423   if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL)
00424     ret = TRUE;
00425   else
00426     ret = FALSE;
00427 
00428   g_free (str);
00429 
00430   va_end (args);
00431 
00432   return ret;
00433 }
00434 
00435 static gboolean
00436 write_quoted_string (GIOChannel *channel, GString *string, GError **error)
00437 {
00438   guint i;
00439 
00440   WRITE_OR_LOSE ("\"");
00441   for (i = 0; i < string->len; i++)
00442     {
00443       if (string->str[i] != '\0')
00444         {
00445           if (!g_io_channel_write_chars (channel, string->str + i, 1, NULL, error))
00446             return FALSE;
00447         }
00448       else
00449         {
00450           if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
00451             return FALSE;
00452         }
00453     }
00454   WRITE_OR_LOSE ("\\0\"");
00455   return TRUE;
00456  io_lose:
00457   return FALSE;
00458 }
00459 
00460 static gboolean
00461 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
00462 {
00463   if (base_info_get_type (base) == INFO_TYPE_NODE)
00464     {
00465       GString *object_introspection_data_blob;
00466       GIOChannel *channel;
00467 
00468       channel = data->channel;
00469       
00470       object_introspection_data_blob = g_string_new_len ("", 0);
00471       
00472       data->blob = object_introspection_data_blob;
00473       data->count = 0;
00474 
00475       data->signal_blob = g_string_new_len ("", 0);
00476       data->property_blob = g_string_new_len ("", 0);
00477 
00478       if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
00479         goto io_lose;
00480 
00481       if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base),
00482                                data, error))
00483         return FALSE;
00484       if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base),
00485                                data, error))
00486         return FALSE;
00487 
00488       WRITE_OR_LOSE ("};\n\n");
00489 
00490       /* Information about the object. */
00491 
00492       if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
00493                                       channel, error, data->prefix))
00494         goto io_lose;
00495       WRITE_OR_LOSE ("  0,\n");
00496       if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, data->prefix))
00497         goto io_lose;
00498       if (!write_printf_to_iochannel ("  %d,\n", channel, error, data->count))
00499         goto io_lose;
00500 
00501       if (!write_quoted_string (channel, object_introspection_data_blob, error))
00502         goto io_lose;
00503       WRITE_OR_LOSE (",\n");
00504       if (!write_quoted_string (channel, data->signal_blob, error))
00505         goto io_lose;
00506       WRITE_OR_LOSE (",\n");
00507       if (!write_quoted_string (channel, data->property_blob, error))
00508         goto io_lose;
00509       WRITE_OR_LOSE ("\n};\n\n");
00510 
00511       g_string_free (object_introspection_data_blob, TRUE);
00512       g_string_free (data->signal_blob, TRUE);
00513       g_string_free (data->property_blob, TRUE);
00514     }
00515   else
00516     {
00517       GIOChannel *channel;
00518       InterfaceInfo *interface;
00519       GSList *methods;
00520       GSList *signals;
00521       GSList *properties;
00522       GSList *tmp;
00523       const char *interface_c_name;
00524       GString *object_introspection_data_blob;
00525 
00526       channel = data->channel;
00527       object_introspection_data_blob = data->blob;
00528 
00529       interface = (InterfaceInfo *) base;
00530       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL);
00531       if (interface_c_name == NULL)
00532         {
00533           if (data->prefix == NULL)
00534             return TRUE;
00535           interface_c_name = data->prefix;
00536         }
00537 
00538       methods = interface_info_get_methods (interface);
00539 
00540       /* Table of marshalled methods. */
00541 
00542       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
00543         {
00544           MethodInfo *method;
00545           char *marshaller_name;
00546           char *method_c_name;
00547           gboolean async = FALSE;
00548           GSList *args;
00549           gboolean found_retval = FALSE;
00550 
00551           method = (MethodInfo *) tmp->data;
00552           method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL));
00553           if (method_c_name == NULL)
00554             {
00555               char *method_name_uscored;
00556               method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
00557               method_c_name = g_strdup_printf ("%s_%s",
00558                                                interface_c_name,
00559                                                method_name_uscored);
00560               g_free (method_name_uscored);
00561             }
00562 
00563           if (!write_printf_to_iochannel ("  { (GCallback) %s, ", channel, error,
00564                                           method_c_name))
00565             goto io_lose;
00566 
00567           marshaller_name = compute_marshaller_name (method, data->prefix, error);
00568           if (!marshaller_name)
00569             goto io_lose;
00570 
00571           if (!write_printf_to_iochannel ("%s, %d },\n", channel, error,
00572                                           marshaller_name,
00573                                           object_introspection_data_blob->len))
00574             {
00575               g_free (marshaller_name);
00576               goto io_lose;
00577             }
00578 
00579           if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL)
00580             async = TRUE;
00581 
00582           /* Object method data blob format:
00583            * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0
00584            */
00585 
00586           g_string_append (object_introspection_data_blob, interface_info_get_name (interface));
00587           g_string_append_c (object_introspection_data_blob, '\0');
00588 
00589           g_string_append (object_introspection_data_blob, method_info_get_name (method));
00590           g_string_append_c (object_introspection_data_blob, '\0');
00591 
00592           g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S');
00593           g_string_append_c (object_introspection_data_blob, '\0');
00594 
00595           for (args = method_info_get_args (method); args; args = args->next)
00596             {
00597               ArgInfo *arg;
00598               char direction;
00599               const char *returnval_annotation;
00600 
00601               arg = args->data;
00602 
00603               g_string_append (object_introspection_data_blob, arg_info_get_name (arg));
00604               g_string_append_c (object_introspection_data_blob, '\0');
00605 
00606               switch (arg_info_get_direction (arg))
00607                 {
00608                 case ARG_IN:
00609                   direction = 'I';
00610                   break;
00611                 case ARG_OUT:
00612                   direction = 'O';
00613                   break;
00614                 case ARG_INVALID:
00615                 default:
00616                   g_assert_not_reached ();
00617                   direction = 0; /* silence gcc */
00618                   break;
00619                 }
00620               g_string_append_c (object_introspection_data_blob, direction);
00621               g_string_append_c (object_introspection_data_blob, '\0');
00622 
00623               if (arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_CONST) != NULL)
00624                 {
00625                   if (arg_info_get_direction (arg) == ARG_IN)
00626                     {
00627                       g_set_error (error,
00628                                    DBUS_BINDING_TOOL_ERROR,
00629                                    DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION,
00630                                    "Input argument \"%s\" cannot have const annotation in method \"%s\" of interface \"%s\"\n",
00631                                    arg_info_get_name (arg),
00632                                    method_info_get_name (method),
00633                                    interface_info_get_name (interface));
00634                       return FALSE;
00635                     }
00636                   g_string_append_c (object_introspection_data_blob, 'C');
00637                   g_string_append_c (object_introspection_data_blob, '\0');
00638                 }
00639               else if (arg_info_get_direction (arg) == ARG_OUT)
00640                 {
00641                   g_string_append_c (object_introspection_data_blob, 'F');
00642                   g_string_append_c (object_introspection_data_blob, '\0');
00643                 }
00644 
00645               returnval_annotation = arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL);
00646               if (returnval_annotation != NULL)
00647                 {
00648                   GType gtype;
00649 
00650                   if (found_retval)
00651                     {
00652                       g_set_error (error,
00653                                    DBUS_BINDING_TOOL_ERROR,
00654                                    DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION,
00655                                    "Multiple arguments with return value annotation in method \"%s\" of interface \"%s\"\n",
00656                                    method_info_get_name (method),
00657                                    interface_info_get_name (interface));
00658                       return FALSE;
00659                     }
00660                   found_retval = TRUE;
00661                   if (arg_info_get_direction (arg) == ARG_IN)
00662                     {
00663                       g_set_error (error,
00664                                    DBUS_BINDING_TOOL_ERROR,
00665                                    DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION,
00666                                    "Input argument \"%s\" cannot have return value annotation in method \"%s\" of interface \"%s\"\n",
00667                                    arg_info_get_name (arg),
00668                                    method_info_get_name (method),
00669                                    interface_info_get_name (interface));
00670                       return FALSE;
00671                     }
00672                   if (!strcmp ("", returnval_annotation))
00673                     g_string_append_c (object_introspection_data_blob, 'R');
00674                   else if (!strcmp ("error", returnval_annotation))
00675                     {
00676                       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
00677                       if (!_dbus_gtype_can_signal_error (gtype))
00678                         {
00679                           g_set_error (error,
00680                                        DBUS_BINDING_TOOL_ERROR,
00681                                        DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION,
00682                                        "Output argument \"%s\" cannot signal error with type \"%s\" in method \"%s\" of interface \"%s\"\n",
00683                                        arg_info_get_name (arg),
00684                                        g_type_name (gtype),
00685                                        method_info_get_name (method),
00686                                        interface_info_get_name (interface));
00687                           return FALSE;
00688                         }
00689                       g_string_append_c (object_introspection_data_blob, 'E');
00690                     }
00691                   else
00692                     {
00693                       g_set_error (error,
00694                                    DBUS_BINDING_TOOL_ERROR,
00695                                    DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION,
00696                                    "Invalid ReturnVal annotation for argument \"%s\" in method \"%s\" of interface \"%s\"\n",
00697                                    arg_info_get_name (arg),
00698                                    method_info_get_name (method),
00699                                    interface_info_get_name (interface));
00700                       return FALSE;
00701                     }
00702                       
00703                   g_string_append_c (object_introspection_data_blob, '\0');
00704                 }
00705               else if (arg_info_get_direction (arg) == ARG_OUT)
00706                 {
00707                   g_string_append_c (object_introspection_data_blob, 'N');
00708                   g_string_append_c (object_introspection_data_blob, '\0');
00709                 }
00710 
00711               g_string_append (object_introspection_data_blob, arg_info_get_type (arg));
00712               g_string_append_c (object_introspection_data_blob, '\0');
00713             }
00714 
00715           g_string_append_c (object_introspection_data_blob, '\0');
00716 
00717           data->count++;
00718         }
00719 
00720       signals = interface_info_get_signals (interface);
00721 
00722       for (tmp = signals; tmp != NULL; tmp = g_slist_next (tmp))
00723         {
00724           SignalInfo *sig;
00725           
00726           sig = tmp->data;
00727 
00728           g_string_append (data->signal_blob, interface_info_get_name (interface));
00729           g_string_append_c (data->signal_blob, '\0');
00730           g_string_append (data->signal_blob, signal_info_get_name (sig));
00731           g_string_append_c (data->signal_blob, '\0');
00732         }
00733 
00734       properties = interface_info_get_properties (interface);
00735 
00736       for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp))
00737         {
00738           PropertyInfo *prop;
00739           
00740           prop = tmp->data;
00741 
00742           g_string_append (data->property_blob, interface_info_get_name (interface));
00743           g_string_append_c (data->property_blob, '\0');
00744           g_string_append (data->property_blob, property_info_get_name (prop));
00745           g_string_append_c (data->property_blob, '\0');
00746         }
00747     }
00748   return TRUE;
00749  io_lose:
00750   return FALSE;
00751 }
00752 
00753 static void
00754 write_marshaller (gpointer key, gpointer value, gpointer user_data)
00755 {
00756   DBusBindingToolCData *data;
00757   const char *marshaller;
00758   gsize bytes_written;
00759 
00760   data = user_data;
00761   marshaller = key;
00762 
00763   if (data->error && *data->error)
00764     return;
00765 
00766   if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL)
00767     g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error);
00768 }
00769 
00770 gboolean
00771 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error)
00772 {
00773   gboolean ret;
00774   GPtrArray *argv;
00775   gint child_stdout;
00776   GIOChannel *genmarshal_stdout;
00777   GPid child_pid;
00778   DBusBindingToolCData data;
00779   char *tempfile_name;
00780   gint tempfile_fd;
00781   GIOStatus iostatus;
00782   char buf[4096];
00783   gsize bytes_read, bytes_written;
00784 
00785   memset (&data, 0, sizeof (data));
00786 
00787   dbus_g_type_specialized_init ();
00788   _dbus_g_type_specialized_builtins_init ();
00789 
00790   data.prefix = prefix;
00791   data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL);
00792   data.error = error;
00793   genmarshal_stdout = NULL;
00794   tempfile_name = NULL;
00795 
00796   if (!gather_marshallers (info, &data, error))
00797     goto io_lose;
00798 
00799   tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX",
00800                                  &tempfile_name, error);
00801   if (tempfile_fd < 0)
00802     goto io_lose;
00803 
00804   data.channel = g_io_channel_unix_new (tempfile_fd);
00805   if (!g_io_channel_set_encoding (data.channel, NULL, error))
00806     goto io_lose;
00807   g_hash_table_foreach (data.generated, write_marshaller, &data); 
00808   if (error && *error != NULL)
00809     {
00810       ret = FALSE;
00811       g_io_channel_close (data.channel);
00812       g_io_channel_unref (data.channel);
00813       goto io_lose;
00814     }
00815 
00816   g_io_channel_close (data.channel);
00817   g_io_channel_unref (data.channel);
00818   
00819   /* Now spawn glib-genmarshal to insert all our required marshallers */
00820   argv = g_ptr_array_new ();
00821   g_ptr_array_add (argv, "glib-genmarshal");
00822   g_ptr_array_add (argv, "--header");
00823   g_ptr_array_add (argv, "--body");
00824   g_ptr_array_add (argv, g_strdup_printf ("--prefix=%s%s", MARSHAL_PREFIX, prefix));
00825   g_ptr_array_add (argv, tempfile_name);
00826   g_ptr_array_add (argv, NULL);
00827   if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL,
00828                                  G_SPAWN_SEARCH_PATH,
00829                                  NULL, NULL,
00830                                  &child_pid,
00831                                  NULL,
00832                                  &child_stdout, NULL, error))
00833     {
00834       g_ptr_array_free (argv, TRUE);
00835       goto io_lose;
00836     }
00837   g_ptr_array_free (argv, TRUE);
00838 
00839   genmarshal_stdout = g_io_channel_unix_new (child_stdout);
00840   if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error))
00841     goto io_lose;
00842 
00843   WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
00844 
00845   while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf),
00846                                               &bytes_read, error)) == G_IO_STATUS_NORMAL)
00847     if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL)
00848       goto io_lose;
00849   if (iostatus != G_IO_STATUS_EOF)
00850     goto io_lose;
00851 
00852   g_io_channel_close (genmarshal_stdout);
00853 
00854   WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n");
00855 
00856   data.channel = channel;
00857   g_io_channel_ref (data.channel);
00858   if (!generate_glue (info, &data, error))
00859     goto io_lose;
00860   
00861   ret = TRUE;
00862  cleanup:
00863   if (tempfile_name)
00864     unlink (tempfile_name);
00865   g_free (tempfile_name);
00866   if (genmarshal_stdout)
00867     g_io_channel_unref (genmarshal_stdout);
00868   if (data.channel)
00869     g_io_channel_unref (data.channel);
00870   g_hash_table_destroy (data.generated);
00871 
00872   return ret;
00873  io_lose:
00874   ret = FALSE;
00875   goto cleanup;
00876 }
00877 
00878 static char *
00879 iface_to_c_prefix (const char *iface)
00880 {
00881   char **components;
00882   char **component;
00883   GString *ret;
00884   gboolean first;
00885   
00886   components = g_strsplit (iface, ".", 0);
00887 
00888   first = TRUE;
00889   ret = g_string_new ("");
00890   for (component = components; *component; component++)
00891     {
00892       if (!first)
00893         g_string_append_c (ret, '_');
00894       else
00895         first = FALSE;
00896       g_string_append (ret, *component);
00897     }
00898   g_strfreev (components);
00899   return g_string_free (ret, FALSE);
00900 }
00901 
00902 static char *
00903 compute_client_method_name (const char *iface_prefix, MethodInfo *method)
00904 {
00905   char *method_name_uscored, *ret;
00906 
00907   method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method));
00908   ret = g_strdup_printf ("%s_%s", iface_prefix, method_name_uscored);
00909   g_free (method_name_uscored);
00910 
00911   return ret;
00912 }
00913 
00914 static gboolean
00915 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
00916 {
00917   GSList *args;
00918 
00919   for (args = method_info_get_args (method); args; args = args->next)
00920     {
00921       ArgInfo *arg;
00922       const char *type_str;
00923       const char *type_suffix;
00924       GType gtype;
00925       int direction;
00926 
00927       arg = args->data;
00928 
00929       WRITE_OR_LOSE (", ");
00930 
00931       direction = arg_info_get_direction (arg);
00932 
00933       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
00934       if (gtype == G_TYPE_INVALID)
00935         {
00936           g_set_error (error,
00937                        DBUS_BINDING_TOOL_ERROR,
00938                        DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
00939                        _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
00940                        arg_info_get_type (arg),
00941                        method_info_get_name (method),
00942                        interface_info_get_name (iface));
00943           return FALSE;
00944         }
00945       type_str = dbus_g_type_get_c_name (gtype);
00946       g_assert (type_str);
00947       /* Variants are special...*/
00948       if (gtype == G_TYPE_VALUE)
00949         {
00950           if (direction == ARG_IN)
00951             type_suffix = "*";
00952           else
00953             type_suffix = "";
00954         }
00955       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
00956               || g_type_is_a (gtype, G_TYPE_OBJECT)
00957            || g_type_is_a (gtype, G_TYPE_POINTER)))
00958         type_suffix = "*";
00959       else
00960         type_suffix = "";
00961 
00962 
00963       switch (direction)
00964         {
00965         case ARG_IN:
00966           if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
00967                                           type_str,
00968                                           type_suffix,
00969                                           arg_info_get_name (arg)))
00970             goto io_lose;
00971           break;
00972         case ARG_OUT:
00973           if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
00974                                           type_str,
00975                                           type_suffix,
00976                                           arg_info_get_name (arg)))
00977             goto io_lose;
00978           break;
00979         case ARG_INVALID:
00980           break;
00981         }
00982     }
00983 
00984   return TRUE;
00985  io_lose:
00986   return FALSE;
00987 }
00988 
00989 #define MAP_FUNDAMENTAL(NAME) \
00990    case G_TYPE_ ## NAME: \
00991      return g_strdup ("G_TYPE_" #NAME);
00992 #define MAP_KNOWN(NAME) \
00993     if (gtype == NAME) \
00994       return g_strdup (#NAME)
00995 static char *
00996 dbus_g_type_get_lookup_function (GType gtype)
00997 {
00998   char *type_lookup;
00999   switch (gtype)
01000     {
01001       MAP_FUNDAMENTAL(CHAR);
01002       MAP_FUNDAMENTAL(UCHAR);
01003       MAP_FUNDAMENTAL(BOOLEAN);
01004       MAP_FUNDAMENTAL(LONG);
01005       MAP_FUNDAMENTAL(ULONG);
01006       MAP_FUNDAMENTAL(INT);
01007       MAP_FUNDAMENTAL(UINT);
01008       MAP_FUNDAMENTAL(INT64);
01009       MAP_FUNDAMENTAL(UINT64);
01010       MAP_FUNDAMENTAL(FLOAT);
01011       MAP_FUNDAMENTAL(DOUBLE);
01012       MAP_FUNDAMENTAL(STRING);
01013     }
01014   if (dbus_g_type_is_collection (gtype))
01015     {
01016       GType elt_gtype;
01017       char *sublookup;
01018 
01019       elt_gtype = dbus_g_type_get_collection_specialization (gtype);
01020       sublookup = dbus_g_type_get_lookup_function (elt_gtype);
01021       g_assert (sublookup);
01022 
01023       if (_dbus_g_type_is_fixed (elt_gtype))
01024         {
01025           type_lookup = g_strdup_printf ("dbus_g_type_get_collection "
01026               "(\"GArray\", %s)", sublookup);
01027         }
01028       else
01029         {
01030           type_lookup = g_strdup_printf ("dbus_g_type_get_collection "
01031               "(\"GPtrArray\", %s)", sublookup);
01032         }
01033 
01034       g_free (sublookup);
01035 
01036       return type_lookup;
01037     }
01038   else if (dbus_g_type_is_map (gtype))
01039     {
01040       GType key_gtype;
01041       char *key_lookup;
01042       GType value_gtype;
01043       char *value_lookup;
01044       
01045       key_gtype = dbus_g_type_get_map_key_specialization (gtype);
01046       value_gtype = dbus_g_type_get_map_value_specialization (gtype);
01047       key_lookup = dbus_g_type_get_lookup_function (key_gtype);
01048       g_assert (key_lookup);
01049       value_lookup = dbus_g_type_get_lookup_function (value_gtype);
01050       g_assert (value_lookup);
01051       type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)",
01052                                      key_lookup, value_lookup);
01053       g_free (key_lookup);
01054       g_free (value_lookup);
01055       return type_lookup;
01056     }
01057   else if (dbus_g_type_is_struct (gtype))
01058     {
01059       GType value_gtype;
01060       GString *string;
01061       char *value_lookup = NULL;
01062       guint size, i;
01063 
01064       string = g_string_new ("dbus_g_type_get_struct (\"GValueArray\"");
01065 
01066       size = dbus_g_type_get_struct_size (gtype);
01067       for (i=0; i < size; i++)
01068         {
01069           value_gtype = dbus_g_type_get_struct_member_type(gtype, i);
01070           value_lookup = dbus_g_type_get_lookup_function (value_gtype);
01071           g_assert (value_lookup);
01072           g_string_append_printf (string, ", %s", value_lookup);
01073           g_free (value_lookup);
01074         }
01075       g_string_append (string, ", G_TYPE_INVALID)");
01076       return g_string_free (string, FALSE);
01077     }
01078 
01079   MAP_KNOWN(G_TYPE_VALUE);
01080   MAP_KNOWN(G_TYPE_STRV);
01081   MAP_KNOWN(G_TYPE_VALUE_ARRAY);
01082   MAP_KNOWN(DBUS_TYPE_G_PROXY);
01083   MAP_KNOWN(DBUS_TYPE_G_OBJECT_PATH);
01084   return NULL;
01085 }
01086 #undef MAP_FUNDAMENTAL
01087 #undef MAP_KNOWN
01088 
01089 static gboolean
01090 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error)
01091 {
01092   GSList *args;
01093 
01094   for (args = method_info_get_args (method); args; args = args->next)
01095     {
01096       ArgInfo *arg;
01097       GType gtype;
01098       char *type_lookup;
01099 
01100       arg = args->data;
01101 
01102       if (direction != arg_info_get_direction (arg))
01103         continue;
01104 
01105       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01106       g_assert (gtype != G_TYPE_INVALID);
01107       type_lookup = dbus_g_type_get_lookup_function (gtype);
01108       g_assert (type_lookup != NULL);
01109 
01110       switch (direction)
01111         {
01112 
01113         case ARG_IN:
01114           if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error,
01115                                           type_lookup,
01116                                           arg_info_get_name (arg)))
01117             goto io_lose;
01118           break;
01119         case ARG_OUT:
01120           if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error,
01121                                           type_lookup,
01122                                           arg_info_get_name (arg)))
01123             goto io_lose;
01124           break;
01125         case ARG_INVALID:
01126           break;
01127         }
01128       g_free (type_lookup);
01129     }
01130 
01131   return TRUE;
01132  io_lose:
01133   return FALSE;
01134 }
01135 
01136 static gboolean
01137 check_supported_parameters (MethodInfo *method)
01138 {
01139   GSList *args;
01140 
01141   for (args = method_info_get_args (method); args; args = args->next)
01142     {
01143       ArgInfo *arg;
01144       GType gtype;
01145 
01146       arg = args->data;
01147       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01148       if (gtype == G_TYPE_INVALID)
01149         return FALSE;
01150     }
01151   return TRUE;
01152 }
01153 
01154 static gboolean
01155 write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error)
01156 {
01157   GSList *args;
01158 
01159   for (args = method_info_get_args (method); args; args = args->next)
01160     {
01161       ArgInfo *arg;
01162 
01163       arg = args->data;
01164       if (arg_info_get_direction (arg) != ARG_OUT)
01165         continue;
01166             
01167       if (!write_printf_to_iochannel ("OUT_%s, ", channel, error,
01168                                       arg_info_get_name (arg)))
01169         goto io_lose;
01170      }
01171 
01172    return TRUE;
01173  io_lose:
01174   return FALSE;
01175 }
01176 
01177 static gboolean
01178 write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
01179  {
01180    GSList *args;
01181  
01182    for (args = method_info_get_args (method); args; args = args->next)
01183      {
01184        ArgInfo *arg;
01185       GType gtype;
01186       const char *type_str, *type_suffix;
01187       int dir;
01188 
01189        arg = args->data;
01190 
01191       dir = arg_info_get_direction (arg);
01192 
01193       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01194       type_str = dbus_g_type_get_c_name (gtype);
01195 
01196       if (!type_str)
01197        {
01198          g_set_error (error,
01199                       DBUS_BINDING_TOOL_ERROR,
01200                       DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
01201                       _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
01202                       arg_info_get_type (arg),
01203                       method_info_get_name (method),
01204                       interface_info_get_name (iface));
01205          return FALSE;
01206        }
01207 
01208       /* Variants are special...*/
01209       if (gtype == G_TYPE_VALUE)
01210         {
01211           if (direction == ARG_IN)
01212             type_suffix = "*";
01213           else
01214             type_suffix = "";
01215         }
01216       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
01217               || g_type_is_a (gtype, G_TYPE_OBJECT)
01218            || g_type_is_a (gtype, G_TYPE_POINTER)))
01219         type_suffix = "*";
01220       else
01221         type_suffix = "";
01222 
01223       if (direction != dir)
01224         continue;
01225 
01226           switch (dir)
01227        {
01228        case ARG_IN:
01229          if (!write_printf_to_iochannel ("  %s%s IN_%s;\n", channel, error,
01230                                          type_str, type_suffix,
01231                                          arg_info_get_name (arg)))
01232            goto io_lose;
01233          break;
01234        case ARG_OUT:
01235          if (!write_printf_to_iochannel ("  %s%s OUT_%s;\n", channel, error,
01236                                          type_str, type_suffix,
01237                                          arg_info_get_name (arg)))
01238            goto io_lose;
01239          break;
01240        case ARG_INVALID:
01241          break;
01242        }
01243      }
01244    return TRUE;
01245  io_lose:
01246   return FALSE;
01247  }
01248 
01249 static gboolean
01250 write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error)
01251 {
01252   GSList *args;
01253 
01254   for (args = method_info_get_args (method); args; args = args->next)
01255     {
01256       ArgInfo *arg;
01257       const char *type_str;
01258       const char *type_suffix;
01259       GType gtype;
01260       int direction;
01261 
01262       arg = args->data;
01263 
01264       direction = arg_info_get_direction (arg);
01265       if (dir != direction) continue;
01266       
01267       WRITE_OR_LOSE (", ");
01268 
01269       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01270       type_str = dbus_g_type_get_c_name (gtype);
01271       /* Variants are special...*/
01272       if (gtype == G_TYPE_VALUE)
01273         {
01274           if (direction == ARG_IN)
01275             type_suffix = "*";
01276           else
01277             type_suffix = "";
01278         }
01279       else if ((g_type_is_a (gtype, G_TYPE_BOXED)
01280               || g_type_is_a (gtype, G_TYPE_OBJECT)
01281            || g_type_is_a (gtype, G_TYPE_POINTER)))
01282         type_suffix = "*";
01283       else
01284         type_suffix = "";
01285 
01286       if (!type_str)
01287         {
01288           g_set_error (error,
01289                        DBUS_BINDING_TOOL_ERROR,
01290                        DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION,
01291                        _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""),
01292                        arg_info_get_type (arg),
01293                        method_info_get_name (method),
01294                        interface_info_get_name (iface));
01295           return FALSE;
01296         }
01297  
01298        switch (direction)
01299         {
01300         case ARG_IN:
01301           if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error,
01302                                           type_str,
01303                                           type_suffix,
01304                                           arg_info_get_name (arg)))
01305             goto io_lose;
01306           break;
01307         case ARG_OUT:
01308           if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error,
01309                                           type_str,
01310                                           type_suffix,
01311                                           arg_info_get_name (arg)))
01312             goto io_lose;
01313           break;
01314         case ARG_INVALID:
01315           break;
01316         }
01317     }
01318   return TRUE;
01319  io_lose:
01320   return FALSE;
01321 }
01322 
01323 static gboolean
01324 write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error)
01325  {
01326   GSList *args;
01327   
01328   for (args = method_info_get_args (method); args; args = args->next)
01329     {
01330       ArgInfo *arg;
01331       int dir;
01332       GType gtype;
01333       const char *type_lookup;
01334       
01335       arg = args->data;
01336 
01337       dir = arg_info_get_direction (arg);
01338 
01339       if (dir != direction)
01340         continue;
01341 
01342       gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01343       type_lookup = dbus_g_type_get_lookup_function (gtype);
01344 
01345       if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg)))
01346           goto io_lose;
01347     }
01348   return TRUE;
01349  io_lose:
01350   return FALSE;
01351 }
01352 
01353 static gboolean
01354 write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error)
01355 {
01356   char *method_name, *iface_prefix;
01357   const char *interface_c_name;
01358 
01359   iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
01360   interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL);
01361   if (interface_c_name == NULL)
01362     {
01363       interface_c_name = (const char *) iface_prefix;
01364     }
01365 
01366   method_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL));
01367   if (method_name == NULL)
01368     {
01369       method_name = compute_client_method_name (interface_c_name, method);
01370     }
01371   g_free(iface_prefix);
01372 
01373   /* Write the typedef for the client callback */
01374   if (!write_printf_to_iochannel ("typedef void (*%s_reply) (DBusGProxy *proxy, ", channel, error, method_name))
01375     goto io_lose;
01376   {
01377     GSList *args;
01378     for (args = method_info_get_args (method); args; args = args->next)
01379       {
01380         ArgInfo *arg;
01381         const char *type_suffix, *type_str;
01382         GType gtype;
01383         
01384         arg = args->data;
01385         
01386         if (arg_info_get_direction (arg) != ARG_OUT)
01387           continue;
01388         gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE);
01389         if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED)
01390              || g_type_is_a (gtype, G_TYPE_OBJECT)
01391              || g_type_is_a (gtype, G_TYPE_POINTER)))
01392           type_suffix = "*";
01393         else
01394           type_suffix = "";
01395         type_str = dbus_g_type_get_c_name (_dbus_gtype_from_signature (arg_info_get_type (arg), TRUE));
01396         if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg)))
01397           goto io_lose;
01398       }
01399   }
01400   WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n");
01401   
01402   
01403   /* Write the callback when the call returns */
01404   WRITE_OR_LOSE ("static void\n");
01405   if (!write_printf_to_iochannel ("%s_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)\n", channel, error, method_name))
01406     goto io_lose;
01407   WRITE_OR_LOSE ("{\n");
01408   WRITE_OR_LOSE ("  DBusGAsyncData *data = (DBusGAsyncData*) user_data;\n  GError *error = NULL;\n");
01409   if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error))
01410     goto io_lose;
01411   /* TODO: handle return boolean of end_call */
01412   WRITE_OR_LOSE ("  dbus_g_proxy_end_call (proxy, call, &error, ");
01413   if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error))
01414     goto io_lose;
01415   WRITE_OR_LOSE("G_TYPE_INVALID);\n");
01416   if (!write_printf_to_iochannel ("  (*(%s_reply)data->cb) (proxy, ", channel, error, method_name))
01417     goto io_lose;
01418   if (!write_untyped_out_args (interface, method, channel, error))
01419     goto io_lose;
01420   WRITE_OR_LOSE ("error, data->userdata);\n");
01421   WRITE_OR_LOSE ("  return;\n}\n\n");
01422   
01423 
01424   /* Write the main wrapper function */
01425   WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\nDBusGProxyCall*\n");
01426   if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error,
01427                                   method_name))
01428     goto io_lose;
01429   if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error))
01430     goto io_lose;
01431   
01432   if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name))
01433     goto io_lose;
01434   
01435   WRITE_OR_LOSE ("{\n");
01436   WRITE_OR_LOSE ("  DBusGAsyncData *stuff;\n  stuff = g_new (DBusGAsyncData, 1);\n  stuff->cb = G_CALLBACK (callback);\n  stuff->userdata = userdata;\n");
01437   if (!write_printf_to_iochannel ("  return dbus_g_proxy_begin_call (proxy, \"%s\", %s_async_callback, stuff, g_free, ", channel, error, method_info_get_name (method), method_name))
01438     goto io_lose;
01439   if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
01440     goto io_lose;
01441   WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n");
01442 
01443   g_free (method_name);
01444   return TRUE;
01445  io_lose:
01446   g_free (method_name);
01447   return FALSE;
01448  }
01449 
01450 static gboolean
01451 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error)
01452 {
01453   GSList *tmp;
01454 
01455   tmp = list;
01456   while (tmp != NULL)
01457     {
01458       if (!generate_client_glue (tmp->data, data, error))
01459         return FALSE;
01460       tmp = tmp->next;
01461     }
01462   return TRUE;
01463 }
01464 
01465 static gboolean
01466 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
01467 {
01468   if (base_info_get_type (base) == INFO_TYPE_NODE)
01469     {
01470       if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base),
01471                                       data, error))
01472         return FALSE;
01473       if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base),
01474                                       data, error))
01475         return FALSE;
01476     }
01477   else
01478     {
01479       GIOChannel *channel;
01480       InterfaceInfo *interface;
01481       GSList *methods;
01482       GSList *tmp;
01483       char *iface_prefix;
01484       const char *interface_c_name;
01485 
01486       channel = data->channel;
01487 
01488       interface = (InterfaceInfo *) base;
01489 
01490       methods = interface_info_get_methods (interface);
01491 
01492       iface_prefix = iface_to_c_prefix (interface_info_get_name (interface));
01493       interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL);
01494       if (interface_c_name == NULL)
01495       {
01496           interface_c_name = (const char *) iface_prefix;
01497       }
01498 
01499       if (!write_printf_to_iochannel ("#ifndef DBUS_GLIB_CLIENT_WRAPPERS_%s\n"
01500                                       "#define DBUS_GLIB_CLIENT_WRAPPERS_%s\n\n",
01501                                       channel, error,
01502                                       iface_prefix, iface_prefix))
01503         {
01504           g_free (iface_prefix);
01505           goto io_lose;
01506         }
01507 
01508       for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp))
01509         {
01510           MethodInfo *method;
01511           char *method_c_name;
01512           gboolean is_noreply;
01513 
01514           method = (MethodInfo *) tmp->data;
01515           method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL));
01516           if (method_c_name == NULL)
01517             {
01518               method_c_name = compute_client_method_name (interface_c_name, method);
01519             }
01520 
01521           is_noreply = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_NOREPLY) != NULL;
01522 
01523           if (data->ignore_unsupported && !check_supported_parameters (method))
01524             {
01525               g_warning ("Ignoring unsupported signature in method \"%s\" of interface \"%s\"\n",
01526                          method_info_get_name (method),
01527                          interface_info_get_name (interface));
01528               continue;
01529             }
01530 
01531 
01532           WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n");
01533           if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error,
01534                                           method_c_name))
01535             goto io_lose;
01536           g_free (method_c_name);
01537 
01538           if (!write_formal_parameters (interface, method, channel, error))
01539             goto io_lose;
01540 
01541           WRITE_OR_LOSE (", GError **error)\n\n");
01542           
01543           WRITE_OR_LOSE ("{\n");
01544 
01545           if (is_noreply) {
01546             if (!write_printf_to_iochannel ("  dbus_g_proxy_call_no_reply (proxy, \"%s\", ", channel, error,
01547                                             method_info_get_name (method)))
01548               goto io_lose;
01549             
01550             if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
01551               goto io_lose;
01552             
01553             WRITE_OR_LOSE ("G_TYPE_INVALID, ");
01554             
01555             if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
01556               goto io_lose;
01557             
01558             WRITE_OR_LOSE ("G_TYPE_INVALID);\n");
01559             
01560             WRITE_OR_LOSE ("  return TRUE;\n}\n\n");
01561           } else {
01562             if (!write_printf_to_iochannel ("  return dbus_g_proxy_call (proxy, \"%s\", ", channel, error,
01563                                             method_info_get_name (method)))
01564               goto io_lose;
01565             
01566             WRITE_OR_LOSE ("error, ");
01567             
01568             if (!write_args_for_direction (interface, method, channel, ARG_IN, error))
01569               goto io_lose;
01570             
01571             WRITE_OR_LOSE ("G_TYPE_INVALID, ");
01572             
01573             if (!write_args_for_direction (interface, method, channel, ARG_OUT, error))
01574               goto io_lose;
01575             
01576             WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n");
01577           }
01578 
01579           write_async_method_client (channel, interface, method, error);
01580         }
01581 
01582       if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix))
01583         {
01584           g_free (iface_prefix);
01585           goto io_lose;
01586         }
01587 
01588       g_free (iface_prefix);
01589     }
01590   return TRUE;
01591  io_lose:
01592   return FALSE;
01593 }
01594 
01595 
01596 gboolean
01597 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error)
01598 {
01599   DBusBindingToolCData data;
01600   gboolean ret;
01601 
01602   memset (&data, 0, sizeof (data));
01603   
01604   data.channel = channel;
01605   data.ignore_unsupported = ignore_unsupported;
01606 
01607   dbus_g_type_specialized_init ();
01608   _dbus_g_type_specialized_builtins_init ();
01609 
01610   WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n");
01611   WRITE_OR_LOSE ("#include <glib/gtypes.h>\n");
01612   WRITE_OR_LOSE ("#include <glib/gerror.h>\n");
01613   WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n");
01614   WRITE_OR_LOSE ("G_BEGIN_DECLS\n\n");
01615 
01616   ret = generate_client_glue (info, &data, error);
01617   if (!ret)
01618     goto io_lose;
01619   
01620   WRITE_OR_LOSE ("G_END_DECLS\n");
01621 
01622   return ret;
01623  io_lose:
01624   return FALSE;
01625 }

Generated on Mon Mar 17 16:28:47 2008 for D-BUSGLibBindings by  doxygen 1.5.1