00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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;
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
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;
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