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

Generated on Tue Feb 24 16:47:59 2009 for D-BUSGLibBindings by  doxygen 1.5.1