|
1 /* -*- mode: C; c-file-style: "gnu" -*- */ |
|
2 /* dbus-binding-tool-glib.c: Output C glue |
|
3 * |
|
4 * Copyright (C) 2003, 2004, 2005 Red Hat, Inc. |
|
5 * Copyright (C) 2005 Nokia |
|
6 * Portion Copyright © 2008 Nokia Corporation and/or its subsidiary(-ies). All rights reserved. |
|
7 * Licensed under the Academic Free License version 2.1 |
|
8 * |
|
9 * This program is free software; you can redistribute it and/or modify |
|
10 * it under the terms of the GNU General Public License as published by |
|
11 * the Free Software Foundation; either version 2 of the License, or |
|
12 * (at your option) any later version. |
|
13 * |
|
14 * This program is distributed in the hope that it will be useful, |
|
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
17 * GNU General Public License for more details. |
|
18 * |
|
19 * You should have received a copy of the GNU General Public License |
|
20 * along with this program; if not, write to the Free Software |
|
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|
22 * |
|
23 */ |
|
24 |
|
25 #ifndef __SYMBIAN32__ |
|
26 #include <config.h> |
|
27 #else |
|
28 #include "config.h" |
|
29 #endif //__SYMBIAN32__ |
|
30 #include "dbus/dbus-glib.h" |
|
31 #include "dbus-gidl.h" |
|
32 #include "dbus-gparser.h" |
|
33 #include "dbus-gutils.h" |
|
34 #include "dbus-gtype-specialized.h" |
|
35 #include "dbus-gsignature.h" |
|
36 #include "dbus-gvalue-utils.h" |
|
37 #include "dbus-glib-tool.h" |
|
38 #include "dbus-binding-tool-glib.h" |
|
39 |
|
40 #ifndef __SYMBIAN32__ |
|
41 #include <glib/gi18n.h> |
|
42 #include <libintl.h> |
|
43 #define _(x) dgettext (GETTEXT_PACKAGE, x) |
|
44 #define N_(x) x |
|
45 #else |
|
46 |
|
47 #define _(x) x |
|
48 #define N_(x) x |
|
49 #endif |
|
50 |
|
51 #include <stdio.h> |
|
52 #include <stdlib.h> |
|
53 #include <string.h> |
|
54 #include <unistd.h> |
|
55 |
|
56 #define MARSHAL_PREFIX "dbus_glib_marshal_" |
|
57 |
|
58 typedef struct |
|
59 { |
|
60 gboolean ignore_unsupported; |
|
61 const char* prefix; |
|
62 GIOChannel *channel; |
|
63 |
|
64 GError **error; |
|
65 |
|
66 GHashTable *generated; |
|
67 GString *blob; |
|
68 GString *signal_blob; |
|
69 GString *property_blob; |
|
70 guint count; |
|
71 } DBusBindingToolCData; |
|
72 |
|
73 static gboolean gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error); |
|
74 static gboolean generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); |
|
75 static gboolean generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error); |
|
76 |
|
77 static const char * |
|
78 dbus_g_type_get_marshal_name (GType gtype) |
|
79 { |
|
80 switch (G_TYPE_FUNDAMENTAL (gtype)) |
|
81 { |
|
82 case G_TYPE_NONE: |
|
83 return "NONE"; |
|
84 case G_TYPE_BOOLEAN: |
|
85 return "BOOLEAN"; |
|
86 case G_TYPE_UCHAR: |
|
87 return "UCHAR"; |
|
88 case G_TYPE_INT: |
|
89 return "INT"; |
|
90 case G_TYPE_UINT: |
|
91 return "UINT"; |
|
92 case G_TYPE_INT64: |
|
93 return "INT64"; |
|
94 case G_TYPE_UINT64: |
|
95 return "UINT64"; |
|
96 case G_TYPE_DOUBLE: |
|
97 return "DOUBLE"; |
|
98 case G_TYPE_STRING: |
|
99 return "STRING"; |
|
100 case G_TYPE_POINTER: |
|
101 return "POINTER"; |
|
102 case G_TYPE_BOXED: |
|
103 return "BOXED"; |
|
104 case G_TYPE_OBJECT: |
|
105 return "OBJECT"; |
|
106 default: |
|
107 return NULL; |
|
108 } |
|
109 } |
|
110 |
|
111 /* This entire function is kind of...ugh. */ |
|
112 static const char * |
|
113 dbus_g_type_get_c_name (GType gtype) |
|
114 { |
|
115 GType subtype; |
|
116 if (dbus_g_type_is_struct (gtype)) |
|
117 { |
|
118 return "GValueArray"; |
|
119 } |
|
120 if (dbus_g_type_is_collection (gtype)) |
|
121 { |
|
122 subtype = dbus_g_type_get_collection_specialization(gtype); |
|
123 if (_dbus_g_type_is_fixed (subtype)) |
|
124 return "GArray"; |
|
125 else |
|
126 return "GPtrArray"; |
|
127 } |
|
128 |
|
129 if (dbus_g_type_is_map (gtype)) |
|
130 return "GHashTable"; |
|
131 |
|
132 if (g_type_is_a (gtype, G_TYPE_STRING)) |
|
133 return "char *"; |
|
134 |
|
135 /* This one is even more hacky...we get an extra * |
|
136 * because G_TYPE_STRV is a G_TYPE_BOXED |
|
137 */ |
|
138 if (g_type_is_a (gtype, G_TYPE_STRV)) |
|
139 return "char *"; |
|
140 |
|
141 if (g_type_is_a (gtype, DBUS_TYPE_G_OBJECT_PATH)) |
|
142 return "char"; |
|
143 |
|
144 return g_type_name (gtype); |
|
145 } |
|
146 |
|
147 static gboolean |
|
148 compute_gsignature (MethodInfo *method, GType *rettype, GArray **params, GError **error) |
|
149 { |
|
150 GSList *elt; |
|
151 GType retval_type; |
|
152 GArray *ret; |
|
153 gboolean is_async; |
|
154 const char *arg_type; |
|
155 gboolean retval_signals_error; |
|
156 |
|
157 is_async = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL; |
|
158 retval_signals_error = FALSE; |
|
159 |
|
160 ret = g_array_new (TRUE, TRUE, sizeof (GType)); |
|
161 |
|
162 if (is_async) |
|
163 retval_type = G_TYPE_NONE; |
|
164 else |
|
165 { |
|
166 gboolean found_retval; |
|
167 |
|
168 /* Look for return value */ |
|
169 found_retval = FALSE; |
|
170 for (elt = method_info_get_args (method); elt; elt = elt->next) |
|
171 { |
|
172 ArgInfo *arg = elt->data; |
|
173 const char *returnval_annotation; |
|
174 |
|
175 returnval_annotation = arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL); |
|
176 if (returnval_annotation != NULL) |
|
177 { |
|
178 arg_type = arg_info_get_type (arg); |
|
179 retval_type = _dbus_gtype_from_signature (arg_type, FALSE); |
|
180 if (retval_type == G_TYPE_INVALID) |
|
181 goto invalid_type; |
|
182 found_retval = TRUE; |
|
183 if (!strcmp (returnval_annotation, "error")) |
|
184 retval_signals_error = TRUE; |
|
185 break; |
|
186 } |
|
187 } |
|
188 if (!found_retval) |
|
189 { |
|
190 retval_type = G_TYPE_BOOLEAN; |
|
191 retval_signals_error = TRUE; |
|
192 } |
|
193 } |
|
194 |
|
195 *rettype = retval_type; |
|
196 |
|
197 /* Handle all input arguments */ |
|
198 for (elt = method_info_get_args (method); elt; elt = elt->next) |
|
199 { |
|
200 ArgInfo *arg = elt->data; |
|
201 if (arg_info_get_direction (arg) == ARG_IN) |
|
202 { |
|
203 GType gtype; |
|
204 |
|
205 arg_type = arg_info_get_type (arg); |
|
206 gtype = _dbus_gtype_from_signature (arg_type, FALSE); |
|
207 if (gtype == G_TYPE_INVALID) |
|
208 goto invalid_type; |
|
209 |
|
210 g_array_append_val (ret, gtype); |
|
211 } |
|
212 } |
|
213 |
|
214 if (!is_async) |
|
215 { |
|
216 /* Append pointer for each out arg storage */ |
|
217 for (elt = method_info_get_args (method); elt; elt = elt->next) |
|
218 { |
|
219 ArgInfo *arg = elt->data; |
|
220 |
|
221 /* Skip return value */ |
|
222 if (arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL) != NULL) |
|
223 continue; |
|
224 |
|
225 if (arg_info_get_direction (arg) == ARG_OUT) |
|
226 { |
|
227 GType gtype; |
|
228 arg_type = arg_info_get_type (arg); |
|
229 gtype = _dbus_gtype_from_signature (arg_type, FALSE); |
|
230 if (gtype == G_TYPE_INVALID) |
|
231 goto invalid_type; |
|
232 /* We actually just need a pointer for the return value |
|
233 storage */ |
|
234 gtype = G_TYPE_POINTER; |
|
235 g_array_append_val (ret, gtype); |
|
236 } |
|
237 } |
|
238 |
|
239 if (retval_signals_error) |
|
240 { |
|
241 /* Final GError parameter */ |
|
242 GType gtype = G_TYPE_POINTER; |
|
243 g_array_append_val (ret, gtype); |
|
244 } |
|
245 } |
|
246 else |
|
247 { |
|
248 /* Context pointer */ |
|
249 GType gtype = G_TYPE_POINTER; |
|
250 g_array_append_val (ret, gtype); |
|
251 } |
|
252 |
|
253 *params = ret; |
|
254 return TRUE; |
|
255 |
|
256 invalid_type: |
|
257 g_set_error (error, |
|
258 DBUS_BINDING_TOOL_ERROR, |
|
259 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, |
|
260 _("Unsupported conversion from D-BUS type %s to glib-genmarshal type"), |
|
261 arg_type); |
|
262 return FALSE; |
|
263 } |
|
264 |
|
265 |
|
266 static char * |
|
267 compute_marshaller (MethodInfo *method, GError **error) |
|
268 { |
|
269 GArray *signature; |
|
270 GType rettype; |
|
271 const char *marshal_name; |
|
272 GString *ret; |
|
273 guint i; |
|
274 |
|
275 if (!compute_gsignature (method, &rettype, &signature, error)) |
|
276 return NULL; |
|
277 |
|
278 ret = g_string_new (""); |
|
279 marshal_name = dbus_g_type_get_marshal_name (rettype); |
|
280 g_assert (marshal_name != NULL); |
|
281 g_string_append (ret, marshal_name); |
|
282 g_string_append_c (ret, ':'); |
|
283 for (i = 0; i < signature->len; i++) |
|
284 { |
|
285 marshal_name = dbus_g_type_get_marshal_name (g_array_index (signature, GType, i)); |
|
286 g_assert (marshal_name != NULL); |
|
287 g_string_append (ret, marshal_name); |
|
288 if (i < signature->len - 1) |
|
289 g_string_append_c (ret, ','); |
|
290 } |
|
291 if (signature->len == 0) |
|
292 { |
|
293 marshal_name = dbus_g_type_get_marshal_name (G_TYPE_NONE); |
|
294 g_assert (marshal_name != NULL); |
|
295 g_string_append (ret, marshal_name); |
|
296 } |
|
297 g_array_free (signature, TRUE); |
|
298 return g_string_free (ret, FALSE); |
|
299 } |
|
300 |
|
301 static char * |
|
302 compute_marshaller_name (MethodInfo *method, const char *prefix, GError **error) |
|
303 { |
|
304 GString *ret; |
|
305 GArray *signature; |
|
306 GType rettype; |
|
307 const char *marshal_name; |
|
308 guint i; |
|
309 |
|
310 if (!compute_gsignature (method, &rettype, &signature, error)) |
|
311 return NULL; |
|
312 |
|
313 ret = g_string_new (MARSHAL_PREFIX); |
|
314 g_string_append (ret, prefix); |
|
315 g_string_append_c (ret, '_'); |
|
316 |
|
317 marshal_name = dbus_g_type_get_marshal_name (rettype); |
|
318 g_assert (marshal_name != NULL); |
|
319 g_string_append (ret, marshal_name); |
|
320 g_string_append (ret, "__"); |
|
321 for (i = 0; i < signature->len; i++) |
|
322 { |
|
323 marshal_name = dbus_g_type_get_marshal_name (g_array_index (signature, GType, i)); |
|
324 g_assert (marshal_name != NULL); |
|
325 g_string_append (ret, marshal_name); |
|
326 if (i < signature->len - 1) |
|
327 g_string_append_c (ret, '_'); |
|
328 } |
|
329 if (signature->len == 0) |
|
330 { |
|
331 marshal_name = dbus_g_type_get_marshal_name (G_TYPE_NONE); |
|
332 g_assert (marshal_name != NULL); |
|
333 g_string_append (ret, marshal_name); |
|
334 } |
|
335 g_array_free (signature, TRUE); |
|
336 return g_string_free (ret, FALSE); |
|
337 } |
|
338 |
|
339 static gboolean |
|
340 gather_marshallers_list (GSList *list, DBusBindingToolCData *data, GError **error) |
|
341 { |
|
342 GSList *tmp; |
|
343 |
|
344 tmp = list; |
|
345 while (tmp != NULL) |
|
346 { |
|
347 if (!gather_marshallers (tmp->data, data, error)) |
|
348 return FALSE; |
|
349 tmp = tmp->next; |
|
350 } |
|
351 return TRUE; |
|
352 } |
|
353 |
|
354 static gboolean |
|
355 gather_marshallers (BaseInfo *base, DBusBindingToolCData *data, GError **error) |
|
356 { |
|
357 if (base_info_get_type (base) == INFO_TYPE_NODE) |
|
358 { |
|
359 if (!gather_marshallers_list (node_info_get_nodes ((NodeInfo *) base), |
|
360 data, error)) |
|
361 return FALSE; |
|
362 if (!gather_marshallers_list (node_info_get_interfaces ((NodeInfo *) base), |
|
363 data, error)) |
|
364 return FALSE; |
|
365 } |
|
366 else |
|
367 { |
|
368 InterfaceInfo *interface; |
|
369 GSList *methods; |
|
370 GSList *tmp; |
|
371 const char *interface_c_name; |
|
372 |
|
373 interface = (InterfaceInfo *) base; |
|
374 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); |
|
375 if (interface_c_name == NULL) |
|
376 { |
|
377 if (!data->prefix) |
|
378 return TRUE; |
|
379 } |
|
380 |
|
381 methods = interface_info_get_methods (interface); |
|
382 |
|
383 /* Generate the necessary marshallers for the methods. */ |
|
384 |
|
385 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) |
|
386 { |
|
387 MethodInfo *method; |
|
388 char *marshaller_name; |
|
389 |
|
390 method = (MethodInfo *) tmp->data; |
|
391 |
|
392 marshaller_name = compute_marshaller (method, error); |
|
393 if (!marshaller_name) |
|
394 return FALSE; |
|
395 |
|
396 if (g_hash_table_lookup (data->generated, marshaller_name)) |
|
397 { |
|
398 g_free (marshaller_name); |
|
399 continue; |
|
400 } |
|
401 |
|
402 g_hash_table_insert (data->generated, marshaller_name, NULL); |
|
403 } |
|
404 |
|
405 } |
|
406 return TRUE; |
|
407 } |
|
408 |
|
409 static gboolean |
|
410 generate_glue_list (GSList *list, DBusBindingToolCData *data, GError **error) |
|
411 { |
|
412 GSList *tmp; |
|
413 |
|
414 tmp = list; |
|
415 while (tmp != NULL) |
|
416 { |
|
417 if (!generate_glue (tmp->data, data, error)) |
|
418 return FALSE; |
|
419 tmp = tmp->next; |
|
420 } |
|
421 return TRUE; |
|
422 } |
|
423 |
|
424 #define WRITE_OR_LOSE(x) do { gsize bytes_written; if (!g_io_channel_write_chars (channel, x, -1, &bytes_written, error)) goto io_lose; } while (0) |
|
425 |
|
426 static gboolean |
|
427 write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, ...) |
|
428 { |
|
429 char *str; |
|
430 va_list args; |
|
431 GIOStatus status; |
|
432 gsize written; |
|
433 gboolean ret; |
|
434 |
|
435 va_start (args, error); |
|
436 |
|
437 str = g_strdup_vprintf (fmt, args); |
|
438 if ((status = g_io_channel_write_chars (channel, str, -1, &written, error)) == G_IO_STATUS_NORMAL) |
|
439 ret = TRUE; |
|
440 else |
|
441 ret = FALSE; |
|
442 |
|
443 g_free (str); |
|
444 |
|
445 va_end (args); |
|
446 |
|
447 return ret; |
|
448 } |
|
449 |
|
450 static gboolean |
|
451 write_quoted_string (GIOChannel *channel, GString *string, GError **error) |
|
452 { |
|
453 guint i; |
|
454 |
|
455 WRITE_OR_LOSE ("\""); |
|
456 for (i = 0; i < string->len; i++) |
|
457 { |
|
458 if (string->str[i] != '\0') |
|
459 { |
|
460 if (!g_io_channel_write_chars (channel, string->str + i, 1, NULL, error)) |
|
461 return FALSE; |
|
462 } |
|
463 else |
|
464 { |
|
465 if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error)) |
|
466 return FALSE; |
|
467 } |
|
468 } |
|
469 WRITE_OR_LOSE ("\\0\""); |
|
470 return TRUE; |
|
471 io_lose: |
|
472 return FALSE; |
|
473 } |
|
474 |
|
475 static gboolean |
|
476 generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) |
|
477 { |
|
478 if (base_info_get_type (base) == INFO_TYPE_NODE) |
|
479 { |
|
480 GString *object_introspection_data_blob; |
|
481 GIOChannel *channel; |
|
482 |
|
483 channel = data->channel; |
|
484 |
|
485 object_introspection_data_blob = g_string_new_len ("", 0); |
|
486 |
|
487 data->blob = object_introspection_data_blob; |
|
488 data->count = 0; |
|
489 |
|
490 data->signal_blob = g_string_new_len ("", 0); |
|
491 data->property_blob = g_string_new_len ("", 0); |
|
492 |
|
493 if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix)) |
|
494 goto io_lose; |
|
495 |
|
496 if (!generate_glue_list (node_info_get_nodes ((NodeInfo *) base), |
|
497 data, error)) |
|
498 return FALSE; |
|
499 if (!generate_glue_list (node_info_get_interfaces ((NodeInfo *) base), |
|
500 data, error)) |
|
501 return FALSE; |
|
502 |
|
503 WRITE_OR_LOSE ("};\n\n"); |
|
504 |
|
505 /* Information about the object. */ |
|
506 |
|
507 if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n", |
|
508 channel, error, data->prefix)) |
|
509 goto io_lose; |
|
510 WRITE_OR_LOSE (" 0,\n"); |
|
511 if (!write_printf_to_iochannel (" dbus_glib_%s_methods,\n", channel, error, data->prefix)) |
|
512 goto io_lose; |
|
513 if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count)) |
|
514 goto io_lose; |
|
515 |
|
516 if (!write_quoted_string (channel, object_introspection_data_blob, error)) |
|
517 goto io_lose; |
|
518 WRITE_OR_LOSE (",\n"); |
|
519 if (!write_quoted_string (channel, data->signal_blob, error)) |
|
520 goto io_lose; |
|
521 WRITE_OR_LOSE (",\n"); |
|
522 if (!write_quoted_string (channel, data->property_blob, error)) |
|
523 goto io_lose; |
|
524 WRITE_OR_LOSE ("\n};\n\n"); |
|
525 |
|
526 g_string_free (object_introspection_data_blob, TRUE); |
|
527 g_string_free (data->signal_blob, TRUE); |
|
528 g_string_free (data->property_blob, TRUE); |
|
529 } |
|
530 else |
|
531 { |
|
532 GIOChannel *channel; |
|
533 InterfaceInfo *interface; |
|
534 GSList *methods; |
|
535 GSList *signals; |
|
536 GSList *properties; |
|
537 GSList *tmp; |
|
538 const char *interface_c_name; |
|
539 GString *object_introspection_data_blob; |
|
540 |
|
541 channel = data->channel; |
|
542 object_introspection_data_blob = data->blob; |
|
543 |
|
544 interface = (InterfaceInfo *) base; |
|
545 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_C_SYMBOL); |
|
546 if (interface_c_name == NULL) |
|
547 { |
|
548 if (data->prefix == NULL) |
|
549 return TRUE; |
|
550 interface_c_name = data->prefix; |
|
551 } |
|
552 |
|
553 methods = interface_info_get_methods (interface); |
|
554 |
|
555 /* Table of marshalled methods. */ |
|
556 |
|
557 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) |
|
558 { |
|
559 MethodInfo *method; |
|
560 char *marshaller_name; |
|
561 char *method_c_name; |
|
562 gboolean async = FALSE; |
|
563 GSList *args; |
|
564 gboolean found_retval = FALSE; |
|
565 |
|
566 method = (MethodInfo *) tmp->data; |
|
567 method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_C_SYMBOL)); |
|
568 if (method_c_name == NULL) |
|
569 { |
|
570 char *method_name_uscored; |
|
571 method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method)); |
|
572 method_c_name = g_strdup_printf ("%s_%s", |
|
573 interface_c_name, |
|
574 method_name_uscored); |
|
575 g_free (method_name_uscored); |
|
576 } |
|
577 |
|
578 if (!write_printf_to_iochannel (" { (GCallback) %s, ", channel, error, |
|
579 method_c_name)) |
|
580 goto io_lose; |
|
581 |
|
582 marshaller_name = compute_marshaller_name (method, data->prefix, error); |
|
583 if (!marshaller_name) |
|
584 goto io_lose; |
|
585 |
|
586 if (!write_printf_to_iochannel ("%s, %d },\n", channel, error, |
|
587 marshaller_name, |
|
588 object_introspection_data_blob->len)) |
|
589 { |
|
590 g_free (marshaller_name); |
|
591 goto io_lose; |
|
592 } |
|
593 |
|
594 if (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_ASYNC) != NULL) |
|
595 async = TRUE; |
|
596 |
|
597 /* Object method data blob format: |
|
598 * <iface>\0<name>\0(<argname>\0<argdirection>\0<argtype>\0)*\0 |
|
599 */ |
|
600 |
|
601 g_string_append (object_introspection_data_blob, interface_info_get_name (interface)); |
|
602 g_string_append_c (object_introspection_data_blob, '\0'); |
|
603 |
|
604 g_string_append (object_introspection_data_blob, method_info_get_name (method)); |
|
605 g_string_append_c (object_introspection_data_blob, '\0'); |
|
606 |
|
607 g_string_append_c (object_introspection_data_blob, async ? 'A' : 'S'); |
|
608 g_string_append_c (object_introspection_data_blob, '\0'); |
|
609 |
|
610 for (args = method_info_get_args (method); args; args = args->next) |
|
611 { |
|
612 ArgInfo *arg; |
|
613 char direction; |
|
614 const char *returnval_annotation; |
|
615 |
|
616 arg = args->data; |
|
617 |
|
618 g_string_append (object_introspection_data_blob, arg_info_get_name (arg)); |
|
619 g_string_append_c (object_introspection_data_blob, '\0'); |
|
620 |
|
621 switch (arg_info_get_direction (arg)) |
|
622 { |
|
623 case ARG_IN: |
|
624 direction = 'I'; |
|
625 break; |
|
626 case ARG_OUT: |
|
627 direction = 'O'; |
|
628 break; |
|
629 case ARG_INVALID: |
|
630 default: |
|
631 g_assert_not_reached (); |
|
632 direction = 0; /* silence gcc */ |
|
633 break; |
|
634 } |
|
635 g_string_append_c (object_introspection_data_blob, direction); |
|
636 g_string_append_c (object_introspection_data_blob, '\0'); |
|
637 |
|
638 if (arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_CONST) != NULL) |
|
639 { |
|
640 if (arg_info_get_direction (arg) == ARG_IN) |
|
641 { |
|
642 g_set_error (error, |
|
643 DBUS_BINDING_TOOL_ERROR, |
|
644 DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, |
|
645 "Input argument \"%s\" cannot have const annotation in method \"%s\" of interface \"%s\"\n", |
|
646 arg_info_get_name (arg), |
|
647 method_info_get_name (method), |
|
648 interface_info_get_name (interface)); |
|
649 return FALSE; |
|
650 } |
|
651 g_string_append_c (object_introspection_data_blob, 'C'); |
|
652 g_string_append_c (object_introspection_data_blob, '\0'); |
|
653 } |
|
654 else if (arg_info_get_direction (arg) == ARG_OUT) |
|
655 { |
|
656 g_string_append_c (object_introspection_data_blob, 'F'); |
|
657 g_string_append_c (object_introspection_data_blob, '\0'); |
|
658 } |
|
659 |
|
660 returnval_annotation = arg_info_get_annotation (arg, DBUS_GLIB_ANNOTATION_RETURNVAL); |
|
661 if (returnval_annotation != NULL) |
|
662 { |
|
663 GType gtype; |
|
664 |
|
665 if (found_retval) |
|
666 { |
|
667 g_set_error (error, |
|
668 DBUS_BINDING_TOOL_ERROR, |
|
669 DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, |
|
670 "Multiple arguments with return value annotation in method \"%s\" of interface \"%s\"\n", |
|
671 method_info_get_name (method), |
|
672 interface_info_get_name (interface)); |
|
673 return FALSE; |
|
674 } |
|
675 found_retval = TRUE; |
|
676 if (arg_info_get_direction (arg) == ARG_IN) |
|
677 { |
|
678 g_set_error (error, |
|
679 DBUS_BINDING_TOOL_ERROR, |
|
680 DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, |
|
681 "Input argument \"%s\" cannot have return value annotation in method \"%s\" of interface \"%s\"\n", |
|
682 arg_info_get_name (arg), |
|
683 method_info_get_name (method), |
|
684 interface_info_get_name (interface)); |
|
685 return FALSE; |
|
686 } |
|
687 if (!strcmp ("", returnval_annotation)) |
|
688 g_string_append_c (object_introspection_data_blob, 'R'); |
|
689 else if (!strcmp ("error", returnval_annotation)) |
|
690 { |
|
691 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
692 if (!_dbus_gtype_can_signal_error (gtype)) |
|
693 { |
|
694 g_set_error (error, |
|
695 DBUS_BINDING_TOOL_ERROR, |
|
696 DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, |
|
697 "Output argument \"%s\" cannot signal error with type \"%s\" in method \"%s\" of interface \"%s\"\n", |
|
698 arg_info_get_name (arg), |
|
699 g_type_name (gtype), |
|
700 method_info_get_name (method), |
|
701 interface_info_get_name (interface)); |
|
702 return FALSE; |
|
703 } |
|
704 g_string_append_c (object_introspection_data_blob, 'E'); |
|
705 } |
|
706 else |
|
707 { |
|
708 g_set_error (error, |
|
709 DBUS_BINDING_TOOL_ERROR, |
|
710 DBUS_BINDING_TOOL_ERROR_INVALID_ANNOTATION, |
|
711 "Invalid ReturnVal annotation for argument \"%s\" in method \"%s\" of interface \"%s\"\n", |
|
712 arg_info_get_name (arg), |
|
713 method_info_get_name (method), |
|
714 interface_info_get_name (interface)); |
|
715 return FALSE; |
|
716 } |
|
717 |
|
718 g_string_append_c (object_introspection_data_blob, '\0'); |
|
719 } |
|
720 else if (arg_info_get_direction (arg) == ARG_OUT) |
|
721 { |
|
722 g_string_append_c (object_introspection_data_blob, 'N'); |
|
723 g_string_append_c (object_introspection_data_blob, '\0'); |
|
724 } |
|
725 |
|
726 g_string_append (object_introspection_data_blob, arg_info_get_type (arg)); |
|
727 g_string_append_c (object_introspection_data_blob, '\0'); |
|
728 } |
|
729 |
|
730 g_string_append_c (object_introspection_data_blob, '\0'); |
|
731 |
|
732 data->count++; |
|
733 } |
|
734 |
|
735 signals = interface_info_get_signals (interface); |
|
736 |
|
737 for (tmp = signals; tmp != NULL; tmp = g_slist_next (tmp)) |
|
738 { |
|
739 SignalInfo *sig; |
|
740 |
|
741 sig = tmp->data; |
|
742 |
|
743 g_string_append (data->signal_blob, interface_info_get_name (interface)); |
|
744 g_string_append_c (data->signal_blob, '\0'); |
|
745 g_string_append (data->signal_blob, signal_info_get_name (sig)); |
|
746 g_string_append_c (data->signal_blob, '\0'); |
|
747 } |
|
748 |
|
749 properties = interface_info_get_properties (interface); |
|
750 |
|
751 for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp)) |
|
752 { |
|
753 PropertyInfo *prop; |
|
754 |
|
755 prop = tmp->data; |
|
756 |
|
757 g_string_append (data->property_blob, interface_info_get_name (interface)); |
|
758 g_string_append_c (data->property_blob, '\0'); |
|
759 g_string_append (data->property_blob, property_info_get_name (prop)); |
|
760 g_string_append_c (data->property_blob, '\0'); |
|
761 } |
|
762 } |
|
763 return TRUE; |
|
764 io_lose: |
|
765 return FALSE; |
|
766 } |
|
767 |
|
768 static void |
|
769 write_marshaller (gpointer key, gpointer value, gpointer user_data) |
|
770 { |
|
771 DBusBindingToolCData *data; |
|
772 const char *marshaller; |
|
773 gsize bytes_written; |
|
774 |
|
775 data = user_data; |
|
776 marshaller = key; |
|
777 |
|
778 if (data->error && *data->error) |
|
779 return; |
|
780 |
|
781 if (g_io_channel_write_chars (data->channel, marshaller, -1, &bytes_written, data->error) == G_IO_STATUS_NORMAL) |
|
782 g_io_channel_write_chars (data->channel, "\n", -1, &bytes_written, data->error); |
|
783 } |
|
784 |
|
785 gboolean |
|
786 dbus_binding_tool_output_glib_server (BaseInfo *info, GIOChannel *channel, const char *prefix, GError **error) |
|
787 { |
|
788 gboolean ret; |
|
789 GPtrArray *argv; |
|
790 gint child_stdout; |
|
791 GIOChannel *genmarshal_stdout; |
|
792 GPid child_pid; |
|
793 DBusBindingToolCData data; |
|
794 char *tempfile_name; |
|
795 gint tempfile_fd; |
|
796 GIOStatus iostatus; |
|
797 char buf[4096]; |
|
798 gsize bytes_read, bytes_written; |
|
799 |
|
800 memset (&data, 0, sizeof (data)); |
|
801 |
|
802 dbus_g_type_specialized_init (); |
|
803 _dbus_g_type_specialized_builtins_init (); |
|
804 |
|
805 data.prefix = prefix; |
|
806 data.generated = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) g_free, NULL); |
|
807 data.error = error; |
|
808 genmarshal_stdout = NULL; |
|
809 tempfile_name = NULL; |
|
810 |
|
811 if (!gather_marshallers (info, &data, error)) |
|
812 goto io_lose; |
|
813 |
|
814 tempfile_fd = g_file_open_tmp ("dbus-binding-tool-c-marshallers.XXXXXX", |
|
815 &tempfile_name, error); |
|
816 if (tempfile_fd < 0) |
|
817 goto io_lose; |
|
818 |
|
819 data.channel = g_io_channel_unix_new (tempfile_fd); |
|
820 if (!g_io_channel_set_encoding (data.channel, NULL, error)) |
|
821 goto io_lose; |
|
822 g_hash_table_foreach (data.generated, write_marshaller, &data); |
|
823 if (error && *error != NULL) |
|
824 { |
|
825 ret = FALSE; |
|
826 g_io_channel_close (data.channel); |
|
827 g_io_channel_unref (data.channel); |
|
828 goto io_lose; |
|
829 } |
|
830 |
|
831 g_io_channel_close (data.channel); |
|
832 g_io_channel_unref (data.channel); |
|
833 |
|
834 /* Now spawn glib-genmarshal to insert all our required marshallers */ |
|
835 argv = g_ptr_array_new (); |
|
836 g_ptr_array_add (argv, "glib-genmarshal"); |
|
837 g_ptr_array_add (argv, "--header"); |
|
838 g_ptr_array_add (argv, "--body"); |
|
839 g_ptr_array_add (argv, g_strdup_printf ("--prefix=%s%s", MARSHAL_PREFIX, prefix)); |
|
840 g_ptr_array_add (argv, tempfile_name); |
|
841 g_ptr_array_add (argv, NULL); |
|
842 if (!g_spawn_async_with_pipes (NULL, (char**)argv->pdata, NULL, |
|
843 G_SPAWN_SEARCH_PATH, |
|
844 NULL, NULL, |
|
845 &child_pid, |
|
846 NULL, |
|
847 &child_stdout, NULL, error)) |
|
848 { |
|
849 g_ptr_array_free (argv, TRUE); |
|
850 goto io_lose; |
|
851 } |
|
852 g_ptr_array_free (argv, TRUE); |
|
853 |
|
854 genmarshal_stdout = g_io_channel_unix_new (child_stdout); |
|
855 if (!g_io_channel_set_encoding (genmarshal_stdout, NULL, error)) |
|
856 goto io_lose; |
|
857 |
|
858 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n"); |
|
859 |
|
860 while ((iostatus = g_io_channel_read_chars (genmarshal_stdout, buf, sizeof (buf), |
|
861 &bytes_read, error)) == G_IO_STATUS_NORMAL) |
|
862 if (g_io_channel_write_chars (channel, buf, bytes_read, &bytes_written, error) != G_IO_STATUS_NORMAL) |
|
863 goto io_lose; |
|
864 if (iostatus != G_IO_STATUS_EOF) |
|
865 goto io_lose; |
|
866 |
|
867 g_io_channel_close (genmarshal_stdout); |
|
868 |
|
869 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n"); |
|
870 |
|
871 data.channel = channel; |
|
872 g_io_channel_ref (data.channel); |
|
873 if (!generate_glue (info, &data, error)) |
|
874 goto io_lose; |
|
875 |
|
876 ret = TRUE; |
|
877 cleanup: |
|
878 if (tempfile_name) |
|
879 unlink (tempfile_name); |
|
880 g_free (tempfile_name); |
|
881 if (genmarshal_stdout) |
|
882 g_io_channel_unref (genmarshal_stdout); |
|
883 if (data.channel) |
|
884 g_io_channel_unref (data.channel); |
|
885 g_hash_table_destroy (data.generated); |
|
886 |
|
887 return ret; |
|
888 io_lose: |
|
889 ret = FALSE; |
|
890 goto cleanup; |
|
891 } |
|
892 |
|
893 static char * |
|
894 iface_to_c_prefix (const char *iface) |
|
895 { |
|
896 char **components; |
|
897 char **component; |
|
898 GString *ret; |
|
899 gboolean first; |
|
900 |
|
901 components = g_strsplit (iface, ".", 0); |
|
902 |
|
903 first = TRUE; |
|
904 ret = g_string_new (""); |
|
905 for (component = components; *component; component++) |
|
906 { |
|
907 if (!first) |
|
908 g_string_append_c (ret, '_'); |
|
909 else |
|
910 first = FALSE; |
|
911 g_string_append (ret, *component); |
|
912 } |
|
913 g_strfreev (components); |
|
914 return g_string_free (ret, FALSE); |
|
915 } |
|
916 |
|
917 static char * |
|
918 compute_client_method_name (const char *iface_prefix, MethodInfo *method) |
|
919 { |
|
920 char *method_name_uscored, *ret; |
|
921 |
|
922 method_name_uscored = _dbus_gutils_wincaps_to_uscore (method_info_get_name (method)); |
|
923 ret = g_strdup_printf ("%s_%s", iface_prefix, method_name_uscored); |
|
924 g_free (method_name_uscored); |
|
925 |
|
926 return ret; |
|
927 } |
|
928 |
|
929 static gboolean |
|
930 write_formal_parameters (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error) |
|
931 { |
|
932 GSList *args; |
|
933 |
|
934 for (args = method_info_get_args (method); args; args = args->next) |
|
935 { |
|
936 ArgInfo *arg; |
|
937 const char *type_str; |
|
938 const char *type_suffix; |
|
939 GType gtype; |
|
940 int direction; |
|
941 |
|
942 arg = args->data; |
|
943 |
|
944 WRITE_OR_LOSE (", "); |
|
945 |
|
946 direction = arg_info_get_direction (arg); |
|
947 |
|
948 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
949 if (gtype == G_TYPE_INVALID) |
|
950 { |
|
951 g_set_error (error, |
|
952 DBUS_BINDING_TOOL_ERROR, |
|
953 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, |
|
954 _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""), |
|
955 arg_info_get_type (arg), |
|
956 method_info_get_name (method), |
|
957 interface_info_get_name (iface)); |
|
958 return FALSE; |
|
959 } |
|
960 type_str = dbus_g_type_get_c_name (gtype); |
|
961 g_assert (type_str); |
|
962 /* Variants are special...*/ |
|
963 if (gtype == G_TYPE_VALUE) |
|
964 { |
|
965 if (direction == ARG_IN) |
|
966 type_suffix = "*"; |
|
967 else |
|
968 type_suffix = ""; |
|
969 } |
|
970 else if ((g_type_is_a (gtype, G_TYPE_BOXED) |
|
971 || g_type_is_a (gtype, G_TYPE_OBJECT) |
|
972 || g_type_is_a (gtype, G_TYPE_POINTER))) |
|
973 type_suffix = "*"; |
|
974 else |
|
975 type_suffix = ""; |
|
976 |
|
977 |
|
978 switch (direction) |
|
979 { |
|
980 case ARG_IN: |
|
981 if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error, |
|
982 type_str, |
|
983 type_suffix, |
|
984 arg_info_get_name (arg))) |
|
985 goto io_lose; |
|
986 break; |
|
987 case ARG_OUT: |
|
988 if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error, |
|
989 type_str, |
|
990 type_suffix, |
|
991 arg_info_get_name (arg))) |
|
992 goto io_lose; |
|
993 break; |
|
994 case ARG_INVALID: |
|
995 break; |
|
996 } |
|
997 } |
|
998 |
|
999 return TRUE; |
|
1000 io_lose: |
|
1001 return FALSE; |
|
1002 } |
|
1003 |
|
1004 #define MAP_FUNDAMENTAL(NAME) \ |
|
1005 case G_TYPE_ ## NAME: \ |
|
1006 return g_strdup ("G_TYPE_" #NAME); |
|
1007 #define MAP_KNOWN(NAME) \ |
|
1008 if (gtype == NAME) \ |
|
1009 return g_strdup (#NAME) |
|
1010 static char * |
|
1011 dbus_g_type_get_lookup_function (GType gtype) |
|
1012 { |
|
1013 char *type_lookup; |
|
1014 switch (gtype) |
|
1015 { |
|
1016 MAP_FUNDAMENTAL(CHAR); |
|
1017 MAP_FUNDAMENTAL(UCHAR); |
|
1018 MAP_FUNDAMENTAL(BOOLEAN); |
|
1019 MAP_FUNDAMENTAL(LONG); |
|
1020 MAP_FUNDAMENTAL(ULONG); |
|
1021 MAP_FUNDAMENTAL(INT); |
|
1022 MAP_FUNDAMENTAL(UINT); |
|
1023 MAP_FUNDAMENTAL(INT64); |
|
1024 MAP_FUNDAMENTAL(UINT64); |
|
1025 MAP_FUNDAMENTAL(FLOAT); |
|
1026 MAP_FUNDAMENTAL(DOUBLE); |
|
1027 MAP_FUNDAMENTAL(STRING); |
|
1028 } |
|
1029 if (dbus_g_type_is_collection (gtype)) |
|
1030 { |
|
1031 GType elt_gtype; |
|
1032 char *sublookup; |
|
1033 |
|
1034 elt_gtype = dbus_g_type_get_collection_specialization (gtype); |
|
1035 sublookup = dbus_g_type_get_lookup_function (elt_gtype); |
|
1036 g_assert (sublookup); |
|
1037 |
|
1038 if (_dbus_g_type_is_fixed (elt_gtype)) |
|
1039 { |
|
1040 type_lookup = g_strdup_printf ("dbus_g_type_get_collection " |
|
1041 "(\"GArray\", %s)", sublookup); |
|
1042 } |
|
1043 else |
|
1044 { |
|
1045 type_lookup = g_strdup_printf ("dbus_g_type_get_collection " |
|
1046 "(\"GPtrArray\", %s)", sublookup); |
|
1047 } |
|
1048 |
|
1049 g_free (sublookup); |
|
1050 |
|
1051 return type_lookup; |
|
1052 } |
|
1053 else if (dbus_g_type_is_map (gtype)) |
|
1054 { |
|
1055 GType key_gtype; |
|
1056 char *key_lookup; |
|
1057 GType value_gtype; |
|
1058 char *value_lookup; |
|
1059 |
|
1060 key_gtype = dbus_g_type_get_map_key_specialization (gtype); |
|
1061 value_gtype = dbus_g_type_get_map_value_specialization (gtype); |
|
1062 key_lookup = dbus_g_type_get_lookup_function (key_gtype); |
|
1063 g_assert (key_lookup); |
|
1064 value_lookup = dbus_g_type_get_lookup_function (value_gtype); |
|
1065 g_assert (value_lookup); |
|
1066 type_lookup = g_strdup_printf ("dbus_g_type_get_map (\"GHashTable\", %s, %s)", |
|
1067 key_lookup, value_lookup); |
|
1068 g_free (key_lookup); |
|
1069 g_free (value_lookup); |
|
1070 return type_lookup; |
|
1071 } |
|
1072 else if (dbus_g_type_is_struct (gtype)) |
|
1073 { |
|
1074 GType value_gtype; |
|
1075 GString *string; |
|
1076 char *value_lookup = NULL; |
|
1077 guint size, i; |
|
1078 |
|
1079 string = g_string_new ("dbus_g_type_get_struct (\"GValueArray\""); |
|
1080 |
|
1081 size = dbus_g_type_get_struct_size (gtype); |
|
1082 for (i=0; i < size; i++) |
|
1083 { |
|
1084 value_gtype = dbus_g_type_get_struct_member_type(gtype, i); |
|
1085 value_lookup = dbus_g_type_get_lookup_function (value_gtype); |
|
1086 g_assert (value_lookup); |
|
1087 g_string_append_printf (string, ", %s", value_lookup); |
|
1088 g_free (value_lookup); |
|
1089 } |
|
1090 g_string_append (string, ", G_TYPE_INVALID)"); |
|
1091 return g_string_free (string, FALSE); |
|
1092 } |
|
1093 |
|
1094 MAP_KNOWN(G_TYPE_VALUE); |
|
1095 MAP_KNOWN(G_TYPE_STRV); |
|
1096 MAP_KNOWN(G_TYPE_VALUE_ARRAY); |
|
1097 MAP_KNOWN(DBUS_TYPE_G_PROXY); |
|
1098 MAP_KNOWN(DBUS_TYPE_G_OBJECT_PATH); |
|
1099 return NULL; |
|
1100 } |
|
1101 #undef MAP_FUNDAMENTAL |
|
1102 #undef MAP_KNOWN |
|
1103 |
|
1104 static gboolean |
|
1105 write_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, int direction, GError **error) |
|
1106 { |
|
1107 GSList *args; |
|
1108 |
|
1109 for (args = method_info_get_args (method); args; args = args->next) |
|
1110 { |
|
1111 ArgInfo *arg; |
|
1112 GType gtype; |
|
1113 char *type_lookup; |
|
1114 |
|
1115 arg = args->data; |
|
1116 |
|
1117 if (direction != arg_info_get_direction (arg)) |
|
1118 continue; |
|
1119 |
|
1120 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1121 g_assert (gtype != G_TYPE_INVALID); |
|
1122 type_lookup = dbus_g_type_get_lookup_function (gtype); |
|
1123 g_assert (type_lookup != NULL); |
|
1124 |
|
1125 switch (direction) |
|
1126 { |
|
1127 |
|
1128 case ARG_IN: |
|
1129 if (!write_printf_to_iochannel ("%s, IN_%s, ", channel, error, |
|
1130 type_lookup, |
|
1131 arg_info_get_name (arg))) |
|
1132 goto io_lose; |
|
1133 break; |
|
1134 case ARG_OUT: |
|
1135 if (!write_printf_to_iochannel ("%s, OUT_%s, ", channel, error, |
|
1136 type_lookup, |
|
1137 arg_info_get_name (arg))) |
|
1138 goto io_lose; |
|
1139 break; |
|
1140 case ARG_INVALID: |
|
1141 break; |
|
1142 } |
|
1143 g_free (type_lookup); |
|
1144 } |
|
1145 |
|
1146 return TRUE; |
|
1147 io_lose: |
|
1148 return FALSE; |
|
1149 } |
|
1150 |
|
1151 static gboolean |
|
1152 check_supported_parameters (MethodInfo *method) |
|
1153 { |
|
1154 GSList *args; |
|
1155 |
|
1156 for (args = method_info_get_args (method); args; args = args->next) |
|
1157 { |
|
1158 ArgInfo *arg; |
|
1159 GType gtype; |
|
1160 |
|
1161 arg = args->data; |
|
1162 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1163 if (gtype == G_TYPE_INVALID) |
|
1164 return FALSE; |
|
1165 } |
|
1166 return TRUE; |
|
1167 } |
|
1168 |
|
1169 static gboolean |
|
1170 write_untyped_out_args (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, GError **error) |
|
1171 { |
|
1172 GSList *args; |
|
1173 |
|
1174 for (args = method_info_get_args (method); args; args = args->next) |
|
1175 { |
|
1176 ArgInfo *arg; |
|
1177 |
|
1178 arg = args->data; |
|
1179 if (arg_info_get_direction (arg) != ARG_OUT) |
|
1180 continue; |
|
1181 |
|
1182 if (!write_printf_to_iochannel ("OUT_%s, ", channel, error, |
|
1183 arg_info_get_name (arg))) |
|
1184 goto io_lose; |
|
1185 } |
|
1186 |
|
1187 return TRUE; |
|
1188 io_lose: |
|
1189 return FALSE; |
|
1190 } |
|
1191 |
|
1192 static gboolean |
|
1193 write_formal_declarations_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error) |
|
1194 { |
|
1195 GSList *args; |
|
1196 |
|
1197 for (args = method_info_get_args (method); args; args = args->next) |
|
1198 { |
|
1199 ArgInfo *arg; |
|
1200 GType gtype; |
|
1201 const char *type_str, *type_suffix; |
|
1202 int dir; |
|
1203 |
|
1204 arg = args->data; |
|
1205 |
|
1206 dir = arg_info_get_direction (arg); |
|
1207 |
|
1208 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1209 type_str = dbus_g_type_get_c_name (gtype); |
|
1210 |
|
1211 if (!type_str) |
|
1212 { |
|
1213 g_set_error (error, |
|
1214 DBUS_BINDING_TOOL_ERROR, |
|
1215 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, |
|
1216 _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""), |
|
1217 arg_info_get_type (arg), |
|
1218 method_info_get_name (method), |
|
1219 interface_info_get_name (iface)); |
|
1220 return FALSE; |
|
1221 } |
|
1222 |
|
1223 /* Variants are special...*/ |
|
1224 if (gtype == G_TYPE_VALUE) |
|
1225 { |
|
1226 if (direction == ARG_IN) |
|
1227 type_suffix = "*"; |
|
1228 else |
|
1229 type_suffix = ""; |
|
1230 } |
|
1231 else if ((g_type_is_a (gtype, G_TYPE_BOXED) |
|
1232 || g_type_is_a (gtype, G_TYPE_OBJECT) |
|
1233 || g_type_is_a (gtype, G_TYPE_POINTER))) |
|
1234 type_suffix = "*"; |
|
1235 else |
|
1236 type_suffix = ""; |
|
1237 |
|
1238 if (direction != dir) |
|
1239 continue; |
|
1240 |
|
1241 switch (dir) |
|
1242 { |
|
1243 case ARG_IN: |
|
1244 if (!write_printf_to_iochannel (" %s%s IN_%s;\n", channel, error, |
|
1245 type_str, type_suffix, |
|
1246 arg_info_get_name (arg))) |
|
1247 goto io_lose; |
|
1248 break; |
|
1249 case ARG_OUT: |
|
1250 if (!write_printf_to_iochannel (" %s%s OUT_%s;\n", channel, error, |
|
1251 type_str, type_suffix, |
|
1252 arg_info_get_name (arg))) |
|
1253 goto io_lose; |
|
1254 break; |
|
1255 case ARG_INVALID: |
|
1256 break; |
|
1257 } |
|
1258 } |
|
1259 return TRUE; |
|
1260 io_lose: |
|
1261 return FALSE; |
|
1262 } |
|
1263 |
|
1264 static gboolean |
|
1265 write_formal_parameters_for_direction (InterfaceInfo *iface, MethodInfo *method, int dir, GIOChannel *channel, GError **error) |
|
1266 { |
|
1267 GSList *args; |
|
1268 |
|
1269 for (args = method_info_get_args (method); args; args = args->next) |
|
1270 { |
|
1271 ArgInfo *arg; |
|
1272 const char *type_str; |
|
1273 const char *type_suffix; |
|
1274 GType gtype; |
|
1275 int direction; |
|
1276 |
|
1277 arg = args->data; |
|
1278 |
|
1279 direction = arg_info_get_direction (arg); |
|
1280 if (dir != direction) continue; |
|
1281 |
|
1282 WRITE_OR_LOSE (", "); |
|
1283 |
|
1284 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1285 type_str = dbus_g_type_get_c_name (gtype); |
|
1286 /* Variants are special...*/ |
|
1287 if (gtype == G_TYPE_VALUE) |
|
1288 { |
|
1289 if (direction == ARG_IN) |
|
1290 type_suffix = "*"; |
|
1291 else |
|
1292 type_suffix = ""; |
|
1293 } |
|
1294 else if ((g_type_is_a (gtype, G_TYPE_BOXED) |
|
1295 || g_type_is_a (gtype, G_TYPE_OBJECT) |
|
1296 || g_type_is_a (gtype, G_TYPE_POINTER))) |
|
1297 type_suffix = "*"; |
|
1298 else |
|
1299 type_suffix = ""; |
|
1300 |
|
1301 if (!type_str) |
|
1302 { |
|
1303 g_set_error (error, |
|
1304 DBUS_BINDING_TOOL_ERROR, |
|
1305 DBUS_BINDING_TOOL_ERROR_UNSUPPORTED_CONVERSION, |
|
1306 _("Unsupported conversion from D-BUS type signature \"%s\" to glib C type in method \"%s\" of interface \"%s\""), |
|
1307 arg_info_get_type (arg), |
|
1308 method_info_get_name (method), |
|
1309 interface_info_get_name (iface)); |
|
1310 return FALSE; |
|
1311 } |
|
1312 |
|
1313 switch (direction) |
|
1314 { |
|
1315 case ARG_IN: |
|
1316 if (!write_printf_to_iochannel ("const %s%s IN_%s", channel, error, |
|
1317 type_str, |
|
1318 type_suffix, |
|
1319 arg_info_get_name (arg))) |
|
1320 goto io_lose; |
|
1321 break; |
|
1322 case ARG_OUT: |
|
1323 if (!write_printf_to_iochannel ("%s%s* OUT_%s", channel, error, |
|
1324 type_str, |
|
1325 type_suffix, |
|
1326 arg_info_get_name (arg))) |
|
1327 goto io_lose; |
|
1328 break; |
|
1329 case ARG_INVALID: |
|
1330 break; |
|
1331 } |
|
1332 } |
|
1333 return TRUE; |
|
1334 io_lose: |
|
1335 return FALSE; |
|
1336 } |
|
1337 |
|
1338 static gboolean |
|
1339 write_typed_args_for_direction (InterfaceInfo *iface, MethodInfo *method, GIOChannel *channel, const int direction, GError **error) |
|
1340 { |
|
1341 GSList *args; |
|
1342 |
|
1343 for (args = method_info_get_args (method); args; args = args->next) |
|
1344 { |
|
1345 ArgInfo *arg; |
|
1346 int dir; |
|
1347 GType gtype; |
|
1348 const char *type_lookup; |
|
1349 |
|
1350 arg = args->data; |
|
1351 |
|
1352 dir = arg_info_get_direction (arg); |
|
1353 |
|
1354 if (dir != direction) |
|
1355 continue; |
|
1356 |
|
1357 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1358 type_lookup = dbus_g_type_get_lookup_function (gtype); |
|
1359 |
|
1360 if (!write_printf_to_iochannel ("%s, &%s_%s, ", channel, error, type_lookup, direction == ARG_IN ? "IN" : "OUT", arg_info_get_name (arg))) |
|
1361 goto io_lose; |
|
1362 } |
|
1363 return TRUE; |
|
1364 io_lose: |
|
1365 return FALSE; |
|
1366 } |
|
1367 |
|
1368 static gboolean |
|
1369 write_async_method_client (GIOChannel *channel, InterfaceInfo *interface, MethodInfo *method, GError **error) |
|
1370 { |
|
1371 char *method_name, *iface_prefix; |
|
1372 const char *interface_c_name; |
|
1373 |
|
1374 iface_prefix = iface_to_c_prefix (interface_info_get_name (interface)); |
|
1375 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL); |
|
1376 if (interface_c_name == NULL) |
|
1377 { |
|
1378 interface_c_name = (const char *) iface_prefix; |
|
1379 } |
|
1380 |
|
1381 method_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL)); |
|
1382 if (method_name == NULL) |
|
1383 { |
|
1384 method_name = compute_client_method_name (interface_c_name, method); |
|
1385 } |
|
1386 g_free(iface_prefix); |
|
1387 |
|
1388 /* Write the typedef for the client callback */ |
|
1389 if (!write_printf_to_iochannel ("typedef void (*%s_reply) (DBusGProxy *proxy, ", channel, error, method_name)) |
|
1390 goto io_lose; |
|
1391 { |
|
1392 GSList *args; |
|
1393 for (args = method_info_get_args (method); args; args = args->next) |
|
1394 { |
|
1395 ArgInfo *arg; |
|
1396 const char *type_suffix, *type_str; |
|
1397 GType gtype; |
|
1398 |
|
1399 arg = args->data; |
|
1400 |
|
1401 if (arg_info_get_direction (arg) != ARG_OUT) |
|
1402 continue; |
|
1403 gtype = _dbus_gtype_from_signature (arg_info_get_type (arg), TRUE); |
|
1404 if (gtype != G_TYPE_VALUE && (g_type_is_a (gtype, G_TYPE_BOXED) |
|
1405 || g_type_is_a (gtype, G_TYPE_OBJECT) |
|
1406 || g_type_is_a (gtype, G_TYPE_POINTER))) |
|
1407 type_suffix = "*"; |
|
1408 else |
|
1409 type_suffix = ""; |
|
1410 type_str = dbus_g_type_get_c_name (_dbus_gtype_from_signature (arg_info_get_type (arg), TRUE)); |
|
1411 if (!write_printf_to_iochannel ("%s %sOUT_%s, ", channel, error, type_str, type_suffix, arg_info_get_name (arg))) |
|
1412 goto io_lose; |
|
1413 } |
|
1414 } |
|
1415 WRITE_OR_LOSE ("GError *error, gpointer userdata);\n\n"); |
|
1416 |
|
1417 |
|
1418 /* Write the callback when the call returns */ |
|
1419 WRITE_OR_LOSE ("static void\n"); |
|
1420 if (!write_printf_to_iochannel ("%s_async_callback (DBusGProxy *proxy, DBusGProxyCall *call, void *user_data)\n", channel, error, method_name)) |
|
1421 goto io_lose; |
|
1422 WRITE_OR_LOSE ("{\n"); |
|
1423 WRITE_OR_LOSE (" DBusGAsyncData *data = (DBusGAsyncData*) user_data;\n GError *error = NULL;\n"); |
|
1424 if (!write_formal_declarations_for_direction (interface, method, channel, ARG_OUT, error)) |
|
1425 goto io_lose; |
|
1426 /* TODO: handle return boolean of end_call */ |
|
1427 WRITE_OR_LOSE (" dbus_g_proxy_end_call (proxy, call, &error, "); |
|
1428 if (!write_typed_args_for_direction (interface, method, channel, ARG_OUT, error)) |
|
1429 goto io_lose; |
|
1430 WRITE_OR_LOSE("G_TYPE_INVALID);\n"); |
|
1431 if (!write_printf_to_iochannel (" (*(%s_reply)data->cb) (proxy, ", channel, error, method_name)) |
|
1432 goto io_lose; |
|
1433 if (!write_untyped_out_args (interface, method, channel, error)) |
|
1434 goto io_lose; |
|
1435 WRITE_OR_LOSE ("error, data->userdata);\n"); |
|
1436 WRITE_OR_LOSE (" return;\n}\n\n"); |
|
1437 |
|
1438 |
|
1439 /* Write the main wrapper function */ |
|
1440 WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\nDBusGProxyCall*\n"); |
|
1441 if (!write_printf_to_iochannel ("%s_async (DBusGProxy *proxy", channel, error, |
|
1442 method_name)) |
|
1443 goto io_lose; |
|
1444 if (!write_formal_parameters_for_direction (interface, method, ARG_IN, channel, error)) |
|
1445 goto io_lose; |
|
1446 |
|
1447 if (!write_printf_to_iochannel (", %s_reply callback, gpointer userdata)\n\n", channel, error, method_name)) |
|
1448 goto io_lose; |
|
1449 |
|
1450 WRITE_OR_LOSE ("{\n"); |
|
1451 WRITE_OR_LOSE (" DBusGAsyncData *stuff;\n stuff = g_new (DBusGAsyncData, 1);\n stuff->cb = G_CALLBACK (callback);\n stuff->userdata = userdata;\n"); |
|
1452 if (!write_printf_to_iochannel (" return dbus_g_proxy_begin_call (proxy, \"%s\", %s_async_callback, stuff, g_free, ", channel, error, method_info_get_name (method), method_name)) |
|
1453 goto io_lose; |
|
1454 if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) |
|
1455 goto io_lose; |
|
1456 WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n"); |
|
1457 |
|
1458 g_free (method_name); |
|
1459 return TRUE; |
|
1460 io_lose: |
|
1461 g_free (method_name); |
|
1462 return FALSE; |
|
1463 } |
|
1464 |
|
1465 static gboolean |
|
1466 generate_client_glue_list (GSList *list, DBusBindingToolCData *data, GError **error) |
|
1467 { |
|
1468 GSList *tmp; |
|
1469 |
|
1470 tmp = list; |
|
1471 while (tmp != NULL) |
|
1472 { |
|
1473 if (!generate_client_glue (tmp->data, data, error)) |
|
1474 return FALSE; |
|
1475 tmp = tmp->next; |
|
1476 } |
|
1477 return TRUE; |
|
1478 } |
|
1479 |
|
1480 static gboolean |
|
1481 generate_client_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error) |
|
1482 { |
|
1483 if (base_info_get_type (base) == INFO_TYPE_NODE) |
|
1484 { |
|
1485 if (!generate_client_glue_list (node_info_get_nodes ((NodeInfo *) base), |
|
1486 data, error)) |
|
1487 return FALSE; |
|
1488 if (!generate_client_glue_list (node_info_get_interfaces ((NodeInfo *) base), |
|
1489 data, error)) |
|
1490 return FALSE; |
|
1491 } |
|
1492 else |
|
1493 { |
|
1494 GIOChannel *channel; |
|
1495 InterfaceInfo *interface; |
|
1496 GSList *methods; |
|
1497 GSList *tmp; |
|
1498 char *iface_prefix; |
|
1499 const char *interface_c_name; |
|
1500 |
|
1501 channel = data->channel; |
|
1502 |
|
1503 interface = (InterfaceInfo *) base; |
|
1504 |
|
1505 methods = interface_info_get_methods (interface); |
|
1506 |
|
1507 iface_prefix = iface_to_c_prefix (interface_info_get_name (interface)); |
|
1508 interface_c_name = interface_info_get_annotation (interface, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL); |
|
1509 if (interface_c_name == NULL) |
|
1510 { |
|
1511 interface_c_name = (const char *) iface_prefix; |
|
1512 } |
|
1513 |
|
1514 if (!write_printf_to_iochannel ("#ifndef DBUS_GLIB_CLIENT_WRAPPERS_%s\n" |
|
1515 "#define DBUS_GLIB_CLIENT_WRAPPERS_%s\n\n", |
|
1516 channel, error, |
|
1517 iface_prefix, iface_prefix)) |
|
1518 { |
|
1519 g_free (iface_prefix); |
|
1520 goto io_lose; |
|
1521 } |
|
1522 |
|
1523 for (tmp = methods; tmp != NULL; tmp = g_slist_next (tmp)) |
|
1524 { |
|
1525 MethodInfo *method; |
|
1526 char *method_c_name; |
|
1527 gboolean is_noreply; |
|
1528 |
|
1529 method = (MethodInfo *) tmp->data; |
|
1530 method_c_name = g_strdup (method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_CLIENT_C_SYMBOL)); |
|
1531 if (method_c_name == NULL) |
|
1532 { |
|
1533 method_c_name = compute_client_method_name (interface_c_name, method); |
|
1534 } |
|
1535 |
|
1536 is_noreply = method_info_get_annotation (method, DBUS_GLIB_ANNOTATION_NOREPLY) != NULL; |
|
1537 |
|
1538 if (data->ignore_unsupported && !check_supported_parameters (method)) |
|
1539 { |
|
1540 g_warning ("Ignoring unsupported signature in method \"%s\" of interface \"%s\"\n", |
|
1541 method_info_get_name (method), |
|
1542 interface_info_get_name (interface)); |
|
1543 continue; |
|
1544 } |
|
1545 |
|
1546 |
|
1547 WRITE_OR_LOSE ("static\n#ifdef G_HAVE_INLINE\ninline\n#endif\ngboolean\n"); |
|
1548 if (!write_printf_to_iochannel ("%s (DBusGProxy *proxy", channel, error, |
|
1549 method_c_name)) |
|
1550 goto io_lose; |
|
1551 g_free (method_c_name); |
|
1552 |
|
1553 if (!write_formal_parameters (interface, method, channel, error)) |
|
1554 goto io_lose; |
|
1555 |
|
1556 WRITE_OR_LOSE (", GError **error)\n\n"); |
|
1557 |
|
1558 WRITE_OR_LOSE ("{\n"); |
|
1559 |
|
1560 if (is_noreply) { |
|
1561 if (!write_printf_to_iochannel (" dbus_g_proxy_call_no_reply (proxy, \"%s\", ", channel, error, |
|
1562 method_info_get_name (method))) |
|
1563 goto io_lose; |
|
1564 |
|
1565 if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) |
|
1566 goto io_lose; |
|
1567 |
|
1568 WRITE_OR_LOSE ("G_TYPE_INVALID, "); |
|
1569 |
|
1570 if (!write_args_for_direction (interface, method, channel, ARG_OUT, error)) |
|
1571 goto io_lose; |
|
1572 |
|
1573 WRITE_OR_LOSE ("G_TYPE_INVALID);\n"); |
|
1574 |
|
1575 WRITE_OR_LOSE (" return TRUE;\n}\n\n"); |
|
1576 } else { |
|
1577 if (!write_printf_to_iochannel (" return dbus_g_proxy_call (proxy, \"%s\", ", channel, error, |
|
1578 method_info_get_name (method))) |
|
1579 goto io_lose; |
|
1580 |
|
1581 WRITE_OR_LOSE ("error, "); |
|
1582 |
|
1583 if (!write_args_for_direction (interface, method, channel, ARG_IN, error)) |
|
1584 goto io_lose; |
|
1585 |
|
1586 WRITE_OR_LOSE ("G_TYPE_INVALID, "); |
|
1587 |
|
1588 if (!write_args_for_direction (interface, method, channel, ARG_OUT, error)) |
|
1589 goto io_lose; |
|
1590 |
|
1591 WRITE_OR_LOSE ("G_TYPE_INVALID);\n}\n\n"); |
|
1592 } |
|
1593 |
|
1594 write_async_method_client (channel, interface, method, error); |
|
1595 } |
|
1596 |
|
1597 if (!write_printf_to_iochannel ("#endif /* defined DBUS_GLIB_CLIENT_WRAPPERS_%s */\n\n", channel, error, iface_prefix)) |
|
1598 { |
|
1599 g_free (iface_prefix); |
|
1600 goto io_lose; |
|
1601 } |
|
1602 |
|
1603 g_free (iface_prefix); |
|
1604 } |
|
1605 return TRUE; |
|
1606 io_lose: |
|
1607 return FALSE; |
|
1608 } |
|
1609 |
|
1610 |
|
1611 gboolean |
|
1612 dbus_binding_tool_output_glib_client (BaseInfo *info, GIOChannel *channel, gboolean ignore_unsupported, GError **error) |
|
1613 { |
|
1614 DBusBindingToolCData data; |
|
1615 gboolean ret; |
|
1616 |
|
1617 memset (&data, 0, sizeof (data)); |
|
1618 |
|
1619 data.channel = channel; |
|
1620 data.ignore_unsupported = ignore_unsupported; |
|
1621 |
|
1622 dbus_g_type_specialized_init (); |
|
1623 _dbus_g_type_specialized_builtins_init (); |
|
1624 |
|
1625 WRITE_OR_LOSE ("/* Generated by dbus-binding-tool; do not edit! */\n\n"); |
|
1626 WRITE_OR_LOSE ("#include <glib/gtypes.h>\n"); |
|
1627 WRITE_OR_LOSE ("#include <glib/gerror.h>\n"); |
|
1628 WRITE_OR_LOSE ("#include <dbus/dbus-glib.h>\n\n"); |
|
1629 WRITE_OR_LOSE ("G_BEGIN_DECLS\n\n"); |
|
1630 |
|
1631 ret = generate_client_glue (info, &data, error); |
|
1632 if (!ret) |
|
1633 goto io_lose; |
|
1634 |
|
1635 WRITE_OR_LOSE ("G_END_DECLS\n"); |
|
1636 |
|
1637 return ret; |
|
1638 io_lose: |
|
1639 return FALSE; |
|
1640 } |