Main Page | Modules | Data Structures | Directories | File List | Data Fields | Related Pages

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

Generated on Fri Sep 30 19:45:35 2005 for D-BUS by  doxygen 1.4.4