2005-02-17 Colin Walters <walters@verbum.org>
[platform/upstream/dbus.git] / glib / dbus-glib-tool.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* dbus-glib-tool.c Tool used by apps using glib bindings
3  *
4  * Copyright (C) 2003, 2004 Red Hat, Inc.
5  *
6  * Licensed under the Academic Free License version 2.1
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  */
23
24 #include <config.h>
25 #include "dbus-gidl.h"
26 #include "dbus-gparser.h"
27 #include "dbus-gutils.h"
28 #include "dbus-binding-tool-glib.h"
29 #include <locale.h>
30 #include <libintl.h>
31 #define _(x) dgettext (GETTEXT_PACKAGE, x)
32 #define N_(x) x
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #ifdef DBUS_BUILD_TESTS
38 static void run_all_tests (const char *test_data_dir);
39 #endif
40
41 typedef enum {
42   DBUS_BINDING_OUTPUT_NONE,
43   DBUS_BINDING_OUTPUT_PRETTY,
44   DBUS_BINDING_OUTPUT_GLIB_SERVER,
45   DBUS_BINDING_OUTPUT_GLIB_CLIENT,
46 } DBusBindingOutputMode;
47
48 static void
49 indent (int depth)
50 {
51   depth *= 2; /* 2-space indent */
52   
53   while (depth > 0)
54     {
55       putc (' ', stdout);
56       --depth;
57     }
58 }
59
60 static void pretty_print (BaseInfo *base,
61                           int       depth);
62
63 static void
64 pretty_print_list (GSList *list,
65                    int     depth)
66 {
67   GSList *tmp;
68   
69   tmp = list;
70   while (tmp != NULL)
71     {
72       pretty_print (tmp->data, depth);
73       tmp = tmp->next;
74     }
75 }
76
77 static void
78 pretty_print (BaseInfo *base,
79               int       depth)
80 {
81   InfoType t;
82   const char *name;
83
84   t = base_info_get_type (base);
85   name = base_info_get_name (base);
86
87   indent (depth);
88   
89   switch (t)
90     {
91     case INFO_TYPE_NODE:
92       {
93         NodeInfo *n = (NodeInfo*) base;
94         
95         if (name == NULL)
96           printf (_("<anonymous node> {\n"));
97         else
98           printf (_("node \"%s\" {\n"), name);
99
100         pretty_print_list (node_info_get_interfaces (n), depth + 1);
101         pretty_print_list (node_info_get_nodes (n), depth + 1);
102
103         indent (depth);
104         printf ("}\n");
105       }
106       break;
107     case INFO_TYPE_INTERFACE:
108       {
109         InterfaceInfo *i = (InterfaceInfo*) base;
110         GSList *binding_types, *elt;
111
112         g_assert (name != NULL);
113
114         printf (_("interface \"%s\" {\n"), name);
115
116         binding_types = interface_info_get_binding_names (i);
117         for (elt = binding_types; elt; elt = elt->next)
118           {
119             const char *binding_type = elt->data;
120             const char *binding_name = interface_info_get_binding_name (i, binding_type);
121
122             printf (_(" (binding \"%s\": \"%s\") "),
123                     binding_type, binding_name);
124           }
125         g_slist_free (binding_types);
126
127         pretty_print_list (interface_info_get_methods (i), depth + 1);
128         pretty_print_list (interface_info_get_signals (i), depth + 1);
129         pretty_print_list (interface_info_get_properties (i), depth + 1);
130
131         indent (depth);
132         printf ("}\n");
133       }
134       break;
135     case INFO_TYPE_METHOD:
136       {
137         MethodInfo *m = (MethodInfo*) base;
138         GSList *binding_types, *elt;
139
140         g_assert (name != NULL);
141
142         binding_types = method_info_get_binding_names (m);
143         printf (_("method \"%s\""), name);
144         for (elt = binding_types; elt; elt = elt->next)
145           {
146             const char *binding_type = elt->data;
147             const char *binding_name = method_info_get_binding_name (m, binding_type);
148
149             printf (_(" (binding \"%s\": \"%s\") "),
150                     binding_type, binding_name);
151           }
152         g_slist_free (binding_types);
153
154         pretty_print_list (method_info_get_args (m), depth + 1);
155
156         indent (depth);
157         printf (")\n");
158       }
159       break;
160     case INFO_TYPE_SIGNAL:
161       {
162         SignalInfo *s = (SignalInfo*) base;
163
164         g_assert (name != NULL);
165
166         printf (_("signal \"%s\" (\n"), name);
167
168         pretty_print_list (signal_info_get_args (s), depth + 1);
169
170         indent (depth);
171         printf (")\n");
172       }
173       break;
174     case INFO_TYPE_PROPERTY:
175       {
176         PropertyInfo *a = (PropertyInfo*) base;
177         int pt = property_info_get_type (a);
178         PropertyAccessFlags acc = property_info_get_access (a);
179
180         printf ("%s%s %s",
181                 acc & PROPERTY_READ ? "read" : "",
182                 acc & PROPERTY_WRITE ? "write" : "",
183                 _dbus_gutils_type_to_string (pt));
184         if (name)
185           printf (" %s\n", name);
186         else
187           printf ("\n");
188       }
189       break;
190     case INFO_TYPE_ARG:
191       {
192         ArgInfo *a = (ArgInfo*) base;
193         int at = arg_info_get_type (a);
194         ArgDirection d = arg_info_get_direction (a);
195
196         printf ("%s %s",
197                 d == ARG_IN ? "in" : "out",
198                 _dbus_gutils_type_to_string (at));
199         if (name)
200           printf (" %s\n", name);
201         else
202           printf ("\n");
203       }
204       break;
205     }
206 }
207
208 GQuark
209 dbus_binding_tool_error_quark (void)
210 {
211   static GQuark quark = 0;
212   if (!quark)
213     quark = g_quark_from_static_string ("dbus_binding_tool_error");
214
215   return quark;
216 }
217
218 static void
219 usage (int ecode)
220 {
221   fprintf (stderr, "dbus-binding-tool [--version] [--help] [--pretty-print]\n");
222   exit (ecode);
223 }
224
225 static void
226 version (void)
227 {
228   printf ("D-BUS Binding Tool %s\n"
229           "Copyright (C) 2003-2005 Red Hat, Inc.\n"
230           "This is free software; see the source for copying conditions.\n"
231           "There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n",
232           VERSION);
233   exit (0);
234 }
235
236 int
237 main (int argc, char **argv)
238 {
239   const char *prev_arg;
240   int i;
241   GSList *files;
242   DBusBindingOutputMode outputmode;
243   gboolean end_of_args;
244   GSList *tmp;
245   GIOChannel *channel;
246   GError *error;
247
248   setlocale (LC_ALL, "");
249   bindtextdomain (GETTEXT_PACKAGE, DBUS_LOCALEDIR);
250   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
251   textdomain (GETTEXT_PACKAGE); 
252
253   g_type_init ();
254
255   outputmode = DBUS_BINDING_OUTPUT_NONE;
256   end_of_args = FALSE;
257   files = NULL;
258   prev_arg = NULL;
259   i = 1;
260   while (i < argc)
261     {
262       const char *arg = argv[i];
263
264       if (!end_of_args)
265         {
266           if (strcmp (arg, "--help") == 0 ||
267               strcmp (arg, "-h") == 0 ||
268               strcmp (arg, "-?") == 0)
269             usage (0);
270           else if (strcmp (arg, "--version") == 0)
271             version ();
272 #ifdef DBUS_BUILD_TESTS
273           else if (strcmp (arg, "--self-test") == 0)
274             run_all_tests (NULL);
275 #endif /* DBUS_BUILD_TESTS */
276           else if (strncmp (arg, "--mode=", 7) == 0)
277             {
278               const char *mode = arg + 7;
279               if (!strcmp (mode, "pretty"))
280                 outputmode = DBUS_BINDING_OUTPUT_PRETTY;
281               else if (!strcmp (mode, "glib-server"))
282                 outputmode = DBUS_BINDING_OUTPUT_GLIB_SERVER;
283               else if (!strcmp (mode, "glib-client"))
284                 outputmode = DBUS_BINDING_OUTPUT_GLIB_CLIENT;
285               else
286                 usage (1);
287             }
288           else if (arg[0] == '-' &&
289                    arg[1] == '-' &&
290                    arg[2] == '\0')
291             end_of_args = TRUE;
292           else if (arg[0] == '-')
293             {
294               usage (1);
295             }
296           else
297             {
298               files = g_slist_prepend (files, (char*) arg);
299             }
300         }
301       else
302         files = g_slist_prepend (files, (char*) arg);
303       
304       prev_arg = arg;
305       
306       ++i;
307     }
308
309   error = NULL;
310   channel = g_io_channel_unix_new (fileno (stdout));
311   if (!g_io_channel_set_encoding (channel, NULL, &error))
312     {
313       fprintf (stderr, _("Couldn't set channel encoding to NULL: %s\n"),
314                error->message);
315       exit (1);
316     }
317
318   files = g_slist_reverse (files);
319
320   tmp = files;
321   while (tmp != NULL)
322     {
323       NodeInfo *node;
324       GError *error;
325       const char *filename;
326
327       filename = tmp->data;
328
329       error = NULL;
330       node = description_load_from_file (filename,
331                                          &error);
332       if (node == NULL)
333         {
334           g_assert (error != NULL);
335           fprintf (stderr, _("Unable to load \"%s\": %s\n"),
336                    filename, error->message);
337           g_error_free (error);
338           exit (1);
339         }
340       else
341         {
342           switch (outputmode)
343             {
344             case DBUS_BINDING_OUTPUT_PRETTY:
345               pretty_print ((BaseInfo*) node, 0);
346               break;
347             case DBUS_BINDING_OUTPUT_GLIB_SERVER:
348               if (!dbus_binding_tool_output_glib_server ((BaseInfo *) node, channel, &error))
349                 {
350                   g_error (_("Compilation failed: %s\n"), error->message);
351                   exit (1);
352                 }
353               break;
354             case DBUS_BINDING_OUTPUT_GLIB_CLIENT:
355               if (!dbus_binding_tool_output_glib_client ((BaseInfo *) node, channel, &error))
356                 {
357                   g_error (_("Compilation failed: %s\n"), error->message);
358                   exit (1);
359                 }
360               break;
361             case DBUS_BINDING_OUTPUT_NONE:
362               break;
363             }
364         }
365
366       if (node)
367         node_info_unref (node);
368       
369       tmp = tmp->next;
370     }
371
372   if (!g_io_channel_flush (channel, &error))
373     {
374       g_error (_("Failed to flush IO channel: %s"), error->message);
375       exit (1);
376     }
377   
378   return 0;
379 }
380
381
382 #ifdef DBUS_BUILD_TESTS
383 static void
384 test_die (const char *failure)
385 {
386   fprintf (stderr, "Unit test failed: %s\n", failure);
387   exit (1);
388 }
389
390 /**
391  * @ingroup DBusGTool
392  * Unit test for GLib utility tool
393  * @returns #TRUE on success.
394  */
395 static gboolean
396 _dbus_gtool_test (const char *test_data_dir)
397 {
398
399   return TRUE;
400 }
401
402 static void
403 run_all_tests (const char *test_data_dir)
404 {
405   if (test_data_dir == NULL)
406     test_data_dir = g_getenv ("DBUS_TEST_DATA");
407
408   if (test_data_dir != NULL)
409     printf ("Test data in %s\n", test_data_dir);
410   else
411     printf ("No test data!\n");
412
413   printf ("%s: running binding tests\n", "dbus-binding-tool");
414   if (!_dbus_gtool_test (test_data_dir))
415     test_die ("gtool");
416
417   printf ("%s: completed successfully\n", "dbus-binding-tool");
418 }
419
420 #endif /* DBUS_BUILD_TESTS */