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 #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;
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
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;
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