dbus-glib-tool.c

00001 /* -*- mode: C; c-file-style: "gnu" -*- */
00002 /* dbus-glib-tool.c Tool used by apps using glib bindings
00003  *
00004  * Copyright (C) 2003, 2004 Red Hat, Inc.
00005  *
00006  * Licensed under the Academic Free License version 2.1
00007  *
00008  * This program is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * This program is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  *
00022  */
00023 
00024 #include <config.h>
00025 #include "dbus-gidl.h"
00026 #include "dbus-gparser.h"
00027 #include "dbus-gutils.h"
00028 #include "dbus-glib-tool.h"
00029 #include "dbus-binding-tool-glib.h"
00030 #include <locale.h>
00031 #include <libintl.h>
00032 #define _(x) dgettext (GETTEXT_PACKAGE, x)
00033 #define N_(x) x
00034 #include <stdio.h>
00035 #include <stdlib.h>
00036 #include <errno.h>
00037 #include <sys/stat.h>
00038 #include <string.h>
00039 #include <time.h>
00040 
00041 #ifdef DBUS_BUILD_TESTS
00042 static void run_all_tests (const char *test_data_dir);
00043 #endif
00044 
00045 typedef enum {
00046   DBUS_BINDING_OUTPUT_NONE,
00047   DBUS_BINDING_OUTPUT_PRETTY,
00048   DBUS_BINDING_OUTPUT_GLIB_SERVER,
00049   DBUS_BINDING_OUTPUT_GLIB_CLIENT
00050 } DBusBindingOutputMode;
00051 
00052 static void
00053 indent (int depth)
00054 {
00055   depth *= 2; /* 2-space indent */
00056   
00057   while (depth > 0)
00058     {
00059       putc (' ', stdout);
00060       --depth;
00061     }
00062 }
00063 
00064 static void pretty_print (BaseInfo *base,
00065                           int       depth);
00066 
00067 static void
00068 pretty_print_list (GSList *list,
00069                    int     depth)
00070 {
00071   GSList *tmp;
00072   
00073   tmp = list;
00074   while (tmp != NULL)
00075     {
00076       pretty_print (tmp->data, depth);
00077       tmp = tmp->next;
00078     }
00079 }
00080 
00081 static void
00082 pretty_print (BaseInfo *base,
00083               int       depth)
00084 {
00085   InfoType t;
00086   const char *name;
00087 
00088   t = base_info_get_type (base);
00089   name = base_info_get_name (base);
00090 
00091   indent (depth);
00092   
00093   switch (t)
00094     {
00095     case INFO_TYPE_NODE:
00096       {
00097         NodeInfo *n = (NodeInfo*) base;
00098         
00099         if (name == NULL)
00100           printf (_("<anonymous node> {\n"));
00101         else
00102           printf (_("node \"%s\" {\n"), name);
00103 
00104         pretty_print_list (node_info_get_interfaces (n), depth + 1);
00105         pretty_print_list (node_info_get_nodes (n), depth + 1);
00106 
00107         indent (depth);
00108         printf ("}\n");
00109       }
00110       break;
00111     case INFO_TYPE_INTERFACE:
00112       {
00113         InterfaceInfo *i = (InterfaceInfo*) base;
00114         GSList *annotations, *elt;
00115 
00116         g_assert (name != NULL);
00117 
00118         printf (_("interface \"%s\" {\n"), name);
00119 
00120         annotations = interface_info_get_annotations (i);
00121         for (elt = annotations; elt; elt = elt->next)
00122           {
00123             const char *name = elt->data;
00124             const char *value = interface_info_get_annotation (i, name);
00125 
00126             printf (_(" (binding \"%s\": \"%s\") "),
00127                     name, value);
00128           }
00129         g_slist_free (annotations);
00130 
00131         pretty_print_list (interface_info_get_methods (i), depth + 1);
00132         pretty_print_list (interface_info_get_signals (i), depth + 1);
00133         pretty_print_list (interface_info_get_properties (i), depth + 1);
00134 
00135         indent (depth);
00136         printf ("}\n");
00137       }
00138       break;
00139     case INFO_TYPE_METHOD:
00140       {
00141         MethodInfo *m = (MethodInfo*) base;
00142         GSList *annotations, *elt;
00143 
00144         g_assert (name != NULL);
00145 
00146         annotations = method_info_get_annotations (m);
00147         printf (_("method \"%s\""), name);
00148         for (elt = annotations; elt; elt = elt->next)
00149           {
00150             const char *name = elt->data;
00151             const char *value = method_info_get_annotation (m, name);
00152 
00153             printf (_(" (annotation \"%s\": \"%s\") "),
00154                     name, value);
00155           }
00156         g_slist_free (annotations);
00157 
00158         pretty_print_list (method_info_get_args (m), depth + 1);
00159 
00160         indent (depth);
00161         printf (")\n");
00162       }
00163       break;
00164     case INFO_TYPE_SIGNAL:
00165       {
00166         SignalInfo *s = (SignalInfo*) base;
00167 
00168         g_assert (name != NULL);
00169 
00170         printf (_("signal \"%s\" (\n"), name);
00171 
00172         pretty_print_list (signal_info_get_args (s), depth + 1);
00173 
00174         indent (depth);
00175         printf (")\n");
00176       }
00177       break;
00178     case INFO_TYPE_PROPERTY:
00179       {
00180         PropertyInfo *a = (PropertyInfo*) base;
00181         const char *pt = property_info_get_type (a);
00182         PropertyAccessFlags acc = property_info_get_access (a);
00183 
00184         printf ("%s%s %s",
00185                 acc & PROPERTY_READ ? "read" : "",
00186                 acc & PROPERTY_WRITE ? "write" : "",
00187                 pt);
00188         if (name)
00189           printf (" %s\n", name);
00190         else
00191           printf ("\n");
00192       }
00193       break;
00194     case INFO_TYPE_ARG:
00195       {
00196         ArgInfo *a = (ArgInfo*) base;
00197         const char *at = arg_info_get_type (a);
00198         ArgDirection d = arg_info_get_direction (a);
00199 
00200         printf ("%s %s",
00201                 d == ARG_IN ? "in" : "out",
00202                 at);
00203         if (name)
00204           printf (" %s\n", name);
00205         else
00206           printf ("\n");
00207       }
00208       break;
00209     }
00210 }
00211 
00212 GQuark
00213 dbus_binding_tool_error_quark (void)
00214 {
00215   static GQuark quark = 0;
00216   if (!quark)
00217     quark = g_quark_from_static_string ("dbus_binding_tool_error");
00218 
00219   return quark;
00220 }
00221 
00222 static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
00223 static void lose_gerror (const char *prefix, GError *error) G_GNUC_NORETURN;
00224 
00225 static void
00226 lose (const char *str, ...)
00227 {
00228   va_list args;
00229 
00230   va_start (args, str);
00231 
00232   vfprintf (stderr, str, args);
00233   fputc ('\n', stderr);
00234 
00235   va_end (args);
00236 
00237   exit (1);
00238 }
00239 
00240 static void
00241 lose_gerror (const char *prefix, GError *error) 
00242 {
00243   lose ("%s: %s", prefix, error->message);
00244 }
00245 
00246 static void
00247 usage (int ecode)
00248 {
00249   fprintf (stderr, "dbus-binding-tool [--version] [--help]\n");
00250   fprintf (stderr, "dbus-binding-tool --mode=[pretty|glib-server|glib-client] [--prefix=SYMBOL_PREFIX] [--ignore-unsupported] [--force] [--output=FILE] [\n");
00251   fprintf (stderr, "dbus-binding-tool --mode=glib-server --prefix=SYMBOL_PREFIX [--ignore-unsupported] [--force] [--output=FILE] [\n");
00252   exit (ecode);
00253 }
00254 
00255 static void
00256 version (void)
00257 {
00258   printf ("D-BUS Binding Tool %s\n"
00259           "Copyright (C) 2003-2005 Red Hat, Inc.\n"
00260           "This is free software; see the source for copying conditions.\n"
00261           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
00262           VERSION);
00263   exit (0);
00264 }
00265 
00266 int
00267 main (int argc, char **argv)
00268 {
00269   const char *output_file;
00270   const char *prefix;
00271   char *output_file_tmp;
00272   int i;
00273   GSList *files;
00274   DBusBindingOutputMode outputmode;
00275   gboolean end_of_args;
00276   GSList *tmp;
00277   GIOChannel *channel;
00278   GError *error;
00279   time_t newest_src;
00280   struct stat srcbuf;
00281   struct stat targetbuf;
00282   gboolean force;
00283   gboolean ignore_unsupported;
00284   gboolean has_prefix = FALSE;
00285 
00286   setlocale (LC_ALL, "");
00287   bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
00288   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
00289   textdomain (GETTEXT_PACKAGE); 
00290 
00291   g_type_init ();
00292 
00293   outputmode = DBUS_BINDING_OUTPUT_NONE;
00294   end_of_args = FALSE;
00295   files = NULL;
00296   output_file = NULL;
00297   prefix = "";
00298   ignore_unsupported = FALSE;
00299   force = FALSE;
00300   i = 1;
00301   while (i < argc)
00302     {
00303       const char *arg = argv[i];
00304 
00305       if (!end_of_args)
00306         {
00307           if (strcmp (arg, "--help") == 0 ||
00308               strcmp (arg, "-h") == 0 ||
00309               strcmp (arg, "-?") == 0)
00310             usage (0);
00311           else if (strcmp (arg, "--version") == 0)
00312             version ();
00313           else if (strcmp (arg, "--force") == 0)
00314             force = TRUE;
00315 #ifdef DBUS_BUILD_TESTS
00316           else if (strcmp (arg, "--self-test") == 0)
00317             run_all_tests (NULL);
00318 #endif /* DBUS_BUILD_TESTS */
00319           else if (strncmp (arg, "--mode=", 7) == 0)
00320             {
00321               const char *mode = arg + 7;
00322               if (!strcmp (mode, "pretty"))
00323                 outputmode = DBUS_BINDING_OUTPUT_PRETTY;
00324               else if (!strcmp (mode, "glib-server"))
00325                 outputmode = DBUS_BINDING_OUTPUT_GLIB_SERVER;
00326               else if (!strcmp (mode, "glib-client"))
00327                 outputmode = DBUS_BINDING_OUTPUT_GLIB_CLIENT;
00328               else
00329                 usage (1);
00330             }
00331           else if (strcmp (arg, "--ignore-unsupported") == 0)
00332             ignore_unsupported = TRUE;
00333           else if (strncmp (arg, "--output=", 9) == 0)
00334             {
00335               output_file = arg + 9;
00336             }
00337           else if (strncmp (arg, "--prefix=", 9) == 0)
00338             {
00339               has_prefix = TRUE;
00340               prefix = arg + 9;
00341             }
00342           else if (arg[0] == '-' &&
00343                    arg[1] == '-' &&
00344                    arg[2] == '\0')
00345             end_of_args = TRUE;
00346           else if (arg[0] == '-')
00347             {
00348               usage (1);
00349             }
00350           else
00351             {
00352               files = g_slist_prepend (files, (char*) arg);
00353             }
00354         }
00355       else
00356         files = g_slist_prepend (files, (char*) arg);
00357       
00358       ++i;
00359     }
00360 
00361   if (outputmode == DBUS_BINDING_OUTPUT_GLIB_SERVER && !has_prefix)
00362     usage (1);
00363 
00364   error = NULL;
00365 
00366   files = g_slist_reverse (files);
00367 
00368   if (output_file && !force)
00369     {
00370       newest_src = 0;
00371       for (tmp = files; tmp != NULL; tmp = tmp->next)
00372         {
00373           const char *filename;
00374 
00375           filename = tmp->data;
00376           if (stat (filename, &srcbuf) < 0)
00377             lose ("Couldn't stat %s: %s", filename, g_strerror (errno));
00378 
00379           if (srcbuf.st_mtime > newest_src)
00380             newest_src = srcbuf.st_mtime;
00381         }
00382 
00383       if (stat (output_file, &targetbuf) > 0
00384           && targetbuf.st_mtime >= newest_src)
00385         exit (0);
00386     }
00387   
00388   if (output_file)
00389     {
00390       output_file_tmp = g_strconcat (output_file, ".tmp", NULL);
00391 
00392       if (!(channel = g_io_channel_new_file (output_file_tmp, "w", &error)))
00393         lose_gerror (_("Couldn't open temporary file"), error);
00394     }
00395   else
00396     {
00397       channel = g_io_channel_unix_new (fileno (stdout));
00398       output_file_tmp = NULL; /* silence gcc */
00399     }
00400   if (!g_io_channel_set_encoding (channel, NULL, &error))
00401     lose_gerror (_("Couldn't set channel encoding to NULL"), error);
00402 
00403 
00404   for (tmp = files; tmp != NULL; tmp = tmp->next)
00405     {
00406       NodeInfo *node;
00407       GError *error;
00408       const char *filename;
00409 
00410       filename = tmp->data;
00411 
00412       error = NULL;
00413       node = description_load_from_file (filename,
00414                                          &error);
00415       if (node == NULL)
00416         {
00417           lose_gerror (_("Unable to load \"%s\""), error);
00418         }
00419       else
00420         {
00421           switch (outputmode)
00422             {
00423             case DBUS_BINDING_OUTPUT_PRETTY:
00424               pretty_print ((BaseInfo*) node, 0);
00425               break;
00426             case DBUS_BINDING_OUTPUT_GLIB_SERVER:
00427               if (!dbus_binding_tool_output_glib_server ((BaseInfo *) node, channel, prefix, &error))
00428                 lose_gerror (_("Compilation failed"), error);
00429               break;
00430             case DBUS_BINDING_OUTPUT_GLIB_CLIENT:
00431               if (!dbus_binding_tool_output_glib_client ((BaseInfo *) node, channel, ignore_unsupported, &error))
00432                 lose_gerror (_("Compilation failed"), error);
00433               break;
00434             case DBUS_BINDING_OUTPUT_NONE:
00435               break;
00436             }
00437         }
00438 
00439       if (node)
00440         node_info_unref (node);
00441     }
00442 
00443   if (g_io_channel_shutdown (channel, TRUE, &error) != G_IO_STATUS_NORMAL)
00444     lose_gerror (_("Failed to shutdown IO channel"), error);
00445   g_io_channel_unref (channel);
00446 
00447   if (output_file)
00448     {
00449       if (rename (output_file_tmp, output_file) < 0)
00450         lose ("Failed to rename %s to %s: %s", output_file_tmp, output_file,
00451               g_strerror (errno));
00452       g_free (output_file_tmp);
00453     }
00454 
00455   return 0;
00456 }
00457 
00458 
00459 #ifdef DBUS_BUILD_TESTS
00460 static void
00461 test_die (const char *failure)
00462 {
00463   lose ("Unit test failed: %s", failure);
00464 }
00465 
00471 static gboolean
00472 _dbus_gtool_test (const char *test_data_dir)
00473 {
00474 
00475   return TRUE;
00476 }
00477 
00478 static void
00479 run_all_tests (const char *test_data_dir)
00480 {
00481   if (test_data_dir == NULL)
00482     test_data_dir = g_getenv ("DBUS_TEST_DATA");
00483 
00484   if (test_data_dir != NULL)
00485     printf ("Test data in %s\n", test_data_dir);
00486   else
00487     printf ("No test data!\n");
00488 
00489   printf ("%s: running binding tests\n", "dbus-binding-tool");
00490   if (!_dbus_gtool_test (test_data_dir))
00491     test_die ("gtool");
00492 
00493   printf ("%s: completed successfully\n", "dbus-binding-tool");
00494 }
00495 
00496 #endif /* DBUS_BUILD_TESTS */

Generated on Wed Oct 3 10:04:23 2007 for D-BUSGLibBindings by  doxygen 1.5.1