codegen: Drop unnecessary comma expressions when boxing values
[vala-lang.git] / codegen / valadbusmodule.vala
blob8c658f49bd6aa8063ab03a805b07feff875cb651
1 /* valadbusmodule.vala
3 * Copyright (C) 2008-2010 Jürg Billeter
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 public class Vala.DBusModule : GAsyncModule {
24 struct BasicTypeInfo {
25 public weak string signature;
26 public weak string type_name;
27 public weak string cname;
28 public weak string gtype;
29 public weak string? get_value_function;
30 public weak string set_value_function;
33 const BasicTypeInfo[] basic_types = {
34 { "y", "BYTE", "guint8", "G_TYPE_UCHAR", "g_value_get_uchar", "g_value_set_uchar" },
35 { "b", "BOOLEAN", "dbus_bool_t", "G_TYPE_BOOLEAN", "g_value_get_boolean", "g_value_set_boolean" },
36 { "n", "INT16", "dbus_int16_t", "G_TYPE_INT", null, "g_value_set_int" },
37 { "q", "UINT16", "dbus_uint16_t", "G_TYPE_UINT", null, "g_value_set_uint" },
38 { "i", "INT32", "dbus_int32_t", "G_TYPE_INT", "g_value_get_int", "g_value_set_int" },
39 { "u", "UINT32", "dbus_uint32_t", "G_TYPE_UINT", "g_value_get_uint", "g_value_set_uint" },
40 { "x", "INT64", "dbus_int64_t", "G_TYPE_INT64", "g_value_get_int64", "g_value_set_int64" },
41 { "t", "UINT64", "dbus_uint64_t", "G_TYPE_UINT64", "g_value_get_uint64", "g_value_set_uint64" },
42 { "d", "DOUBLE", "double", "G_TYPE_DOUBLE", "g_value_get_double", "g_value_set_double" },
43 { "s", "STRING", "const char*", "G_TYPE_STRING", "g_value_get_string", "g_value_take_string" },
44 { "o", "OBJECT_PATH", "const char*", "G_TYPE_STRING", null, "g_value_take_string" },
45 { "g", "SIGNATURE", "const char*", "G_TYPE_STRING", null, "g_value_take_string" }
48 static bool is_string_marshalled_enum (TypeSymbol? symbol) {
49 if (symbol != null && symbol is Enum) {
50 var dbus = symbol.get_attribute ("DBus");
51 return dbus != null && dbus.get_bool ("use_string_marshalling");
53 return false;
56 string get_dbus_value (EnumValue value, string default_value) {
57 var dbus = value.get_attribute ("DBus");
58 if (dbus == null) {
59 return default_value;
62 string dbus_value = dbus.get_string ("value");
63 if (dbus_value == null) {
64 return default_value;
66 return dbus_value;
69 public static string? get_dbus_name (TypeSymbol symbol) {
70 var dbus = symbol.get_attribute ("DBus");
71 if (dbus == null) {
72 return null;
75 return dbus.get_string ("name");
78 public static string get_dbus_name_for_member (Symbol symbol) {
79 var dbus = symbol.get_attribute ("DBus");
80 if (dbus != null && dbus.has_argument ("name")) {
81 return dbus.get_string ("name");
84 return Symbol.lower_case_to_camel_case (symbol.name);
87 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
88 foreach (BasicTypeInfo info in basic_types) {
89 if (info.signature == signature) {
90 basic_type = info;
91 return true;
94 return false;
97 public static string? get_type_signature (DataType datatype) {
98 var array_type = datatype as ArrayType;
100 if (array_type != null) {
101 string element_type_signature = get_type_signature (array_type.element_type);
103 if (element_type_signature == null) {
104 return null;
107 return string.nfill (array_type.rank, 'a') + element_type_signature;
108 } else if (is_string_marshalled_enum (datatype.data_type)) {
109 return "s";
110 } else if (datatype.data_type != null) {
111 string sig = null;
113 var ccode = datatype.data_type.get_attribute ("CCode");
114 if (ccode != null) {
115 sig = ccode.get_string ("type_signature");
118 var st = datatype.data_type as Struct;
119 var en = datatype.data_type as Enum;
120 if (sig == null && st != null) {
121 var str = new StringBuilder ();
122 str.append_c ('(');
123 foreach (Field f in st.get_fields ()) {
124 if (f.binding == MemberBinding.INSTANCE) {
125 str.append (get_type_signature (f.variable_type));
128 str.append_c (')');
129 sig = str.str;
130 } else if (sig == null && en != null) {
131 if (en.is_flags) {
132 return "u";
133 } else {
134 return "i";
138 var type_args = datatype.get_type_arguments ();
139 if (sig != null && "%s" in sig && type_args.size > 0) {
140 string element_sig = "";
141 foreach (DataType type_arg in type_args) {
142 var s = get_type_signature (type_arg);
143 if (s != null) {
144 element_sig += s;
148 sig = sig.printf (element_sig);
151 return sig;
152 } else {
153 return null;
157 public override void visit_enum (Enum en) {
158 base.visit_enum (en);
160 if (is_string_marshalled_enum (en)) {
161 // strcmp
162 cfile.add_include ("string.h");
163 cfile.add_include ("dbus/dbus-glib.h");
165 cfile.add_function (generate_enum_from_string_function (en));
166 cfile.add_function (generate_enum_to_string_function (en));
170 public override bool generate_enum_declaration (Enum en, CCodeFile decl_space) {
171 if (base.generate_enum_declaration (en, decl_space)) {
172 if (is_string_marshalled_enum (en)) {
173 decl_space.add_function_declaration (generate_enum_from_string_function_declaration (en));
174 decl_space.add_function_declaration (generate_enum_to_string_function_declaration (en));
176 return true;
178 return false;
181 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
182 var id = expr as CCodeIdentifier;
183 var ma = expr as CCodeMemberAccess;
184 if (id != null) {
185 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
186 } else if (ma != null) {
187 if (ma.is_pointer) {
188 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
189 } else {
190 return new CCodeMemberAccess (ma.inner, "%s_length%d".printf (ma.member_name, dim));
192 } else {
193 // must be NULL-terminated
194 var len_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strv_length"));
195 len_call.add_argument (expr);
196 return len_call;
200 CCodeExpression? generate_enum_value_from_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
201 var en = type.type_symbol as Enum;
202 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
204 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
205 from_string_call.add_argument (expr);
206 from_string_call.add_argument (new CCodeConstant ("NULL"));
208 return from_string_call;
211 public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
212 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
214 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
215 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
216 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
218 return from_string_func;
221 public CCodeFunction generate_enum_from_string_function (Enum en) {
222 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
224 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
225 from_string_func.add_parameter (new CCodeParameter ("str", "const char*"));
226 from_string_func.add_parameter (new CCodeParameter ("error", "GError**"));
228 var from_string_block = new CCodeBlock ();
229 from_string_func.block = from_string_block;
231 var cdecl = new CCodeDeclaration (en.get_cname ());
232 cdecl.add_declarator (new CCodeVariableDeclarator.zero ("value", new CCodeConstant ("0")));
233 from_string_block.add_statement (cdecl);
235 CCodeStatement if_else_if = null;
236 CCodeIfStatement last_statement = null;
237 foreach (EnumValue enum_value in en.get_values ()) {
238 var true_block = new CCodeBlock ();
239 true_block.suppress_newline = true;
240 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("value"), new CCodeIdentifier (enum_value.get_cname ()))));
242 string dbus_value = get_dbus_value (enum_value, enum_value.name);
243 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
244 string_comparison.add_argument (new CCodeIdentifier ("str"));
245 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
246 var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0")), true_block);
248 if (last_statement != null) {
249 last_statement.false_statement = stmt;
250 } else {
251 if_else_if = stmt;
253 last_statement = stmt;
256 var error_block = new CCodeBlock ();
257 error_block.suppress_newline = true;
259 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error"));
260 set_error_call.add_argument (new CCodeIdentifier ("error"));
261 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
262 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_INVALID_ARGS"));
263 set_error_call.add_argument (new CCodeConstant ("\"%s\""));
264 set_error_call.add_argument (new CCodeConstant ("\"Invalid enumeration value\""));
265 error_block.add_statement (new CCodeExpressionStatement (set_error_call));
267 last_statement.false_statement = error_block;
268 from_string_block.add_statement (if_else_if);
270 from_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
272 return from_string_func;
275 CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, bool transfer = false) {
276 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
278 var cdecl = new CCodeDeclaration (basic_type.cname);
279 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
280 fragment.append (cdecl);
282 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
283 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
284 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
285 fragment.append (new CCodeExpressionStatement (iter_call));
287 var temp_result = new CCodeIdentifier (temp_name);
289 if (!transfer
290 && (basic_type.signature == "s"
291 || basic_type.signature == "o"
292 || basic_type.signature == "g")) {
293 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
294 dup_call.add_argument (temp_result);
295 return dup_call;
296 } else {
297 return temp_result;
301 CCodeExpression read_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression? expr) {
302 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
304 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
305 new_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
306 // add one extra element for NULL-termination
307 new_call.add_argument (new CCodeConstant ("5"));
309 var cdecl = new CCodeDeclaration (array_type.get_cname ());
310 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, new_call));
311 fragment.append (cdecl);
313 cdecl = new CCodeDeclaration ("int");
314 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
315 fragment.append (cdecl);
317 cdecl = new CCodeDeclaration ("int");
318 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
319 fragment.append (cdecl);
321 read_array_dim (fragment, array_type, 1, temp_name, iter_expr, expr);
323 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
324 // NULL terminate array
325 var length = new CCodeIdentifier (temp_name + "_length");
326 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
327 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, new CCodeIdentifier ("NULL"))));
330 return new CCodeIdentifier (temp_name);
333 void read_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, string temp_name, CCodeExpression iter_expr, CCodeExpression? expr) {
334 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
336 var cdecl = new CCodeDeclaration ("int");
337 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
338 fragment.append (cdecl);
340 cdecl = new CCodeDeclaration ("DBusMessageIter");
341 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
342 fragment.append (cdecl);
344 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
345 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
346 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
347 fragment.append (new CCodeExpressionStatement (iter_call));
349 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
350 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
352 var cforblock = new CCodeBlock ();
353 var cforfragment = new CCodeFragment ();
354 cforblock.add_statement (cforfragment);
355 var cfor = new CCodeForStatement (iter_call, cforblock);
356 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim))));
358 if (dim < array_type.rank) {
359 read_array_dim (cforfragment, array_type, dim + 1, temp_name, new CCodeIdentifier (subiter_name), expr);
361 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
362 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
363 cforfragment.append (new CCodeExpressionStatement (iter_call));
364 } else {
365 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
366 var renew_block = new CCodeBlock ();
368 // tmp_size = (2 * tmp_size);
369 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
370 renew_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name + "_size"), new_size)));
372 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
373 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
374 renew_call.add_argument (new CCodeIdentifier (temp_name));
375 // add one extra element for NULL-termination
376 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
377 var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
378 renew_block.add_statement (renew_stmt);
380 var cif = new CCodeIfStatement (size_check, renew_block);
381 cforfragment.append (cif);
383 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
384 var element_expr = read_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), null);
385 cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, element_expr)));
388 fragment.append (cfor);
390 if (expr != null) {
391 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)))));
395 CCodeExpression read_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr) {
396 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
397 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
399 var cdecl = new CCodeDeclaration (st.get_cname ());
400 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
401 fragment.append (cdecl);
403 cdecl = new CCodeDeclaration ("DBusMessageIter");
404 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
405 fragment.append (cdecl);
407 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
408 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
409 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
410 fragment.append (new CCodeExpressionStatement (iter_call));
412 foreach (Field f in st.get_fields ()) {
413 if (f.binding != MemberBinding.INSTANCE) {
414 continue;
417 var field_expr = read_expression (fragment, f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
418 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), field_expr)));
421 return new CCodeIdentifier (temp_name);
424 CCodeExpression read_value (CCodeFragment fragment, CCodeExpression iter_expr) {
425 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
426 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
428 // 0-initialize struct with struct initializer { 0 }
429 var cvalinit = new CCodeInitializerList ();
430 cvalinit.append (new CCodeConstant ("0"));
432 var cdecl = new CCodeDeclaration ("GValue");
433 cdecl.add_declarator (new CCodeVariableDeclarator.zero (temp_name, cvalinit));
434 fragment.append (cdecl);
436 cdecl = new CCodeDeclaration ("DBusMessageIter");
437 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
438 fragment.append (cdecl);
440 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
441 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
442 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
443 fragment.append (new CCodeExpressionStatement (iter_call));
445 CCodeIfStatement clastif = null;
447 foreach (BasicTypeInfo basic_type in basic_types) {
448 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
449 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
450 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
452 var type_block = new CCodeBlock ();
453 var type_fragment = new CCodeFragment ();
454 type_block.add_statement (type_fragment);
455 var result = read_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name));
457 var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
458 value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
459 value_init.add_argument (new CCodeIdentifier (basic_type.gtype));
460 type_fragment.append (new CCodeExpressionStatement (value_init));
462 var value_set = new CCodeFunctionCall (new CCodeIdentifier (basic_type.set_value_function));
463 value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
464 value_set.add_argument (result);
465 type_fragment.append (new CCodeExpressionStatement (value_set));
467 var cif = new CCodeIfStatement (type_check, type_block);
468 if (clastif == null) {
469 fragment.append (cif);
470 } else {
471 clastif.false_statement = cif;
474 clastif = cif;
477 // handle string arrays
478 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
479 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
480 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
482 type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_element_type"));
483 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
484 var element_type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_STRING"));
486 type_check = new CCodeBinaryExpression (CCodeBinaryOperator.AND, type_check, element_type_check);
488 var type_block = new CCodeBlock ();
489 var type_fragment = new CCodeFragment ();
490 type_block.add_statement (type_fragment);
491 var result = read_array (type_fragment, new ArrayType (string_type, 1, null), new CCodeIdentifier (subiter_name), null);
493 var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
494 value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
495 value_init.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
496 type_fragment.append (new CCodeExpressionStatement (value_init));
498 var value_set = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
499 value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
500 value_set.add_argument (result);
501 type_fragment.append (new CCodeExpressionStatement (value_set));
503 var cif = new CCodeIfStatement (type_check, type_block);
504 if (clastif == null) {
505 fragment.append (cif);
506 } else {
507 clastif.false_statement = cif;
510 clastif = cif;
512 return new CCodeIdentifier (temp_name);
515 CCodeExpression read_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr) {
516 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
517 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
518 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
520 var type_args = type.get_type_arguments ();
521 assert (type_args.size == 2);
522 var key_type = type_args.get (0);
523 var value_type = type_args.get (1);
525 var cdecl = new CCodeDeclaration ("GHashTable*");
526 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
527 fragment.append (cdecl);
529 cdecl = new CCodeDeclaration ("DBusMessageIter");
530 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
531 fragment.append (cdecl);
533 cdecl = new CCodeDeclaration ("DBusMessageIter");
534 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
535 fragment.append (cdecl);
537 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
538 if (key_type.data_type == string_type.data_type) {
539 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
540 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
541 } else {
542 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
543 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
545 if (key_type.data_type == string_type.data_type) {
546 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
547 } else {
548 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
550 if (value_type.data_type == string_type.data_type) {
551 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
552 } else {
553 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
555 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
557 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
558 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
559 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
560 fragment.append (new CCodeExpressionStatement (iter_call));
562 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
563 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
565 var cwhileblock = new CCodeBlock ();
566 var cwhilefragment = new CCodeFragment ();
567 cwhileblock.add_statement (cwhilefragment);
568 var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
570 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
571 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
572 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
573 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
575 cdecl = new CCodeDeclaration (key_type.get_cname ());
576 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
577 cwhilefragment.append (cdecl);
579 cdecl = new CCodeDeclaration (value_type.get_cname ());
580 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
581 cwhilefragment.append (cdecl);
583 var key_expr = read_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), null);
584 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), key_expr)));
586 var value_expr = read_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), null);
587 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), value_expr)));
589 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
590 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
591 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_key"), key_type));
592 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_value"), value_type));
593 cwhilefragment.append (new CCodeExpressionStatement (hash_table_insert));
595 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
596 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
597 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
599 fragment.append (cwhile);
601 return new CCodeIdentifier (temp_name);
604 public CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
605 BasicTypeInfo basic_type;
606 CCodeExpression result = null;
607 if (is_string_marshalled_enum (type.data_type)) {
608 get_basic_type_info ("s", out basic_type);
609 result = read_basic (fragment, basic_type, iter_expr, true);
610 result = generate_enum_value_from_string (fragment, type as EnumValueType, result);
611 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
612 result = read_basic (fragment, basic_type, iter_expr);
613 } else if (type is ArrayType) {
614 result = read_array (fragment, (ArrayType) type, iter_expr, expr);
615 } else if (type.data_type is Struct) {
616 var st = (Struct) type.data_type;
617 if (type.data_type.get_full_name () == "GLib.Value") {
618 result = read_value (fragment, iter_expr);
619 } else {
620 result = read_struct (fragment, st, iter_expr);
622 if (type.nullable) {
623 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
624 csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
625 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
626 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
627 cdup.add_argument (csizeof);
628 result = cdup;
630 } else if (type is ObjectType) {
631 if (type.data_type.get_full_name () == "GLib.HashTable") {
632 result = read_hash_table (fragment, (ObjectType) type, iter_expr);
634 } else {
635 Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
636 return null;
639 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
640 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
641 fragment.append (new CCodeExpressionStatement (iter_call));
643 return result;
646 CCodeExpression? generate_enum_value_to_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
647 var en = type.type_symbol as Enum;
648 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
650 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
651 to_string_call.add_argument (expr);
653 return to_string_call;
656 public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
657 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
659 var to_string_func = new CCodeFunction (to_string_name, "const char*");
660 to_string_func.add_parameter (new CCodeParameter ("value", en.get_cname ()));
662 return to_string_func;
665 public CCodeFunction generate_enum_to_string_function (Enum en) {
666 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
668 var to_string_func = new CCodeFunction (to_string_name, "const char*");
669 to_string_func.add_parameter (new CCodeParameter ("value", en.get_cname ()));
671 var to_string_block = new CCodeBlock ();
672 to_string_func.block = to_string_block;
674 var cdecl = new CCodeDeclaration ("const char *");
675 cdecl.add_declarator (new CCodeVariableDeclarator ("str"));
676 to_string_block.add_statement (cdecl);
678 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("value"));
679 foreach (EnumValue enum_value in en.get_values ()) {
680 string dbus_value = get_dbus_value (enum_value, enum_value.name);
681 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value.get_cname ())));
682 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)))));
683 cswitch.add_statement (new CCodeBreakStatement ());
685 to_string_block.add_statement (cswitch);
687 to_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("str")));
689 return to_string_func;
692 void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
693 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
695 var cdecl = new CCodeDeclaration (basic_type.cname);
696 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
697 fragment.append (cdecl);
699 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
701 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
702 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
703 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
704 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
705 fragment.append (new CCodeExpressionStatement (iter_call));
708 void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
709 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
711 var cdecl = new CCodeDeclaration (array_type.get_cname ());
712 cdecl.add_declarator (new CCodeVariableDeclarator (array_iter_name));
713 fragment.append (cdecl);
715 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (array_iter_name), array_expr)));
717 write_array_dim (fragment, array_type, 1, iter_expr, array_expr, new CCodeIdentifier (array_iter_name));
720 void write_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, CCodeExpression iter_expr, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
721 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
722 string index_name = "_tmp%d_".printf (next_temp_var_id++);
724 var cdecl = new CCodeDeclaration ("DBusMessageIter");
725 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
726 fragment.append (cdecl);
728 cdecl = new CCodeDeclaration ("int");
729 cdecl.add_declarator (new CCodeVariableDeclarator (index_name));
730 fragment.append (cdecl);
732 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
733 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
734 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
735 iter_call.add_argument (new CCodeConstant ("\"%s%s\"".printf (string.nfill (array_type.rank - dim, 'a'), get_type_signature (array_type.element_type))));
736 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
737 fragment.append (new CCodeExpressionStatement (iter_call));
739 var cforblock = new CCodeBlock ();
740 var cforfragment = new CCodeFragment ();
741 cforblock.add_statement (cforfragment);
742 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim)), cforblock);
743 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0")));
744 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name)));
746 if (dim < array_type.rank) {
747 write_array_dim (cforfragment, array_type, dim + 1, new CCodeIdentifier (subiter_name), array_expr, array_iter_expr);
748 } else {
749 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
750 write_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), element_expr);
752 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
753 cforfragment.append (new CCodeExpressionStatement (array_iter_incr));
755 fragment.append (cfor);
757 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
758 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
759 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
760 fragment.append (new CCodeExpressionStatement (iter_call));
763 void write_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr, CCodeExpression struct_expr) {
764 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
766 var cdecl = new CCodeDeclaration ("DBusMessageIter");
767 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
768 fragment.append (cdecl);
770 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
771 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
772 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRUCT"));
773 iter_call.add_argument (new CCodeConstant ("NULL"));
774 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
775 fragment.append (new CCodeExpressionStatement (iter_call));
777 foreach (Field f in st.get_fields ()) {
778 if (f.binding != MemberBinding.INSTANCE) {
779 continue;
782 write_expression (fragment, f.variable_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (struct_expr, f.get_cname ()));
785 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
786 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
787 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
788 fragment.append (new CCodeExpressionStatement (iter_call));
791 void write_value (CCodeFragment fragment, CCodeExpression iter_expr, CCodeExpression expr) {
792 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
794 var cdecl = new CCodeDeclaration ("DBusMessageIter");
795 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
796 fragment.append (cdecl);
798 CCodeIfStatement clastif = null;
800 foreach (BasicTypeInfo basic_type in basic_types) {
801 // ensure that there is only one case per GType
802 if (basic_type.get_value_function == null) {
803 continue;
806 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
807 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
808 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier (basic_type.gtype));
810 var type_block = new CCodeBlock ();
811 var type_fragment = new CCodeFragment ();
812 type_block.add_statement (type_fragment);
814 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
815 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
816 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
817 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (basic_type.signature)));
818 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
819 type_fragment.append (new CCodeExpressionStatement (iter_call));
821 var value_get = new CCodeFunctionCall (new CCodeIdentifier (basic_type.get_value_function));
822 value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
824 write_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name), value_get);
826 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
827 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
828 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
829 type_fragment.append (new CCodeExpressionStatement (iter_call));
831 var cif = new CCodeIfStatement (type_check, type_block);
832 if (clastif == null) {
833 fragment.append (cif);
834 } else {
835 clastif.false_statement = cif;
838 clastif = cif;
841 // handle string arrays
842 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
843 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
844 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("G_TYPE_STRV"));
846 var type_block = new CCodeBlock ();
847 var type_fragment = new CCodeFragment ();
848 type_block.add_statement (type_fragment);
850 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
851 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
852 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
853 iter_call.add_argument (new CCodeConstant ("\"as\""));
854 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
855 type_fragment.append (new CCodeExpressionStatement (iter_call));
857 var value_get = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_boxed"));
858 value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
860 write_array (type_fragment, new ArrayType (string_type, 1, null), new CCodeIdentifier (subiter_name), value_get);
862 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
863 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
864 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
865 type_fragment.append (new CCodeExpressionStatement (iter_call));
867 var cif = new CCodeIfStatement (type_check, type_block);
868 if (clastif == null) {
869 fragment.append (cif);
870 } else {
871 clastif.false_statement = cif;
874 clastif = cif;
877 void write_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr, CCodeExpression hash_table_expr) {
878 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
879 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
880 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
881 string key_name = "_tmp%d_".printf (next_temp_var_id++);
882 string value_name = "_tmp%d_".printf (next_temp_var_id++);
884 var type_args = type.get_type_arguments ();
885 assert (type_args.size == 2);
886 var key_type = type_args.get (0);
887 var value_type = type_args.get (1);
889 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
890 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
891 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
892 iter_call.add_argument (new CCodeConstant ("\"{%s%s}\"".printf (get_type_signature (key_type), get_type_signature (value_type))));
893 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
894 fragment.append (new CCodeExpressionStatement (iter_call));
896 var cdecl = new CCodeDeclaration ("DBusMessageIter");
897 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
898 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
899 fragment.append (cdecl);
901 cdecl = new CCodeDeclaration ("GHashTableIter");
902 cdecl.add_declarator (new CCodeVariableDeclarator (tableiter_name));
903 fragment.append (cdecl);
905 cdecl = new CCodeDeclaration ("gpointer");
906 cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
907 cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
908 fragment.append (cdecl);
910 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
911 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
912 iter_init_call.add_argument (hash_table_expr);
913 fragment.append (new CCodeExpressionStatement (iter_init_call));
915 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
916 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
917 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
918 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
920 var cwhileblock = new CCodeBlock ();
921 var cwhilefragment = new CCodeFragment ();
922 cwhileblock.add_statement (cwhilefragment);
923 var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
925 cdecl = new CCodeDeclaration (key_type.get_cname ());
926 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
927 cwhilefragment.append (cdecl);
929 cdecl = new CCodeDeclaration (value_type.get_cname ());
930 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
931 cwhilefragment.append (cdecl);
933 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
934 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
935 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
936 iter_call.add_argument (new CCodeConstant ("NULL"));
937 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
938 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
940 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type))));
941 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type))));
943 write_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_key"));
944 write_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_value"));
946 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
947 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
948 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
949 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
951 fragment.append (cwhile);
953 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
954 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
955 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
956 fragment.append (new CCodeExpressionStatement (iter_call));
959 public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
960 BasicTypeInfo basic_type;
961 if (is_string_marshalled_enum (type.data_type)) {
962 get_basic_type_info ("s", out basic_type);
963 var result = generate_enum_value_to_string (fragment, type as EnumValueType, expr);
964 write_basic (fragment, basic_type, iter_expr, result);
965 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
966 write_basic (fragment, basic_type, iter_expr, expr);
967 } else if (type is ArrayType) {
968 write_array (fragment, (ArrayType) type, iter_expr, expr);
969 } else if (type.data_type is Struct) {
970 var st_expr = expr;
971 if (type.nullable) {
972 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
974 if (type.data_type.get_full_name () == "GLib.Value") {
975 write_value (fragment, iter_expr, st_expr);
976 } else {
977 write_struct (fragment, (Struct) type.data_type, iter_expr, st_expr);
979 } else if (type is ObjectType) {
980 if (type.data_type.get_full_name () == "GLib.HashTable") {
981 write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
983 } else {
984 Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));
988 public void add_dbus_helpers () {
989 if (cfile.add_declaration ("_vala_dbus_register_object")) {
990 return;
993 cfile.add_include ("dbus/dbus.h");
994 cfile.add_include ("dbus/dbus-glib.h");
995 cfile.add_include ("dbus/dbus-glib-lowlevel.h");
997 var dbusvtable = new CCodeStruct ("_DBusObjectVTable");
998 dbusvtable.add_field ("void", "(*register_object) (DBusConnection*, const char*, void*)");
999 cfile.add_type_definition (dbusvtable);
1001 cfile.add_type_declaration (new CCodeTypeDefinition ("struct _DBusObjectVTable", new CCodeVariableDeclarator ("_DBusObjectVTable")));
1003 var cfunc = new CCodeFunction ("_vala_dbus_register_object", "void");
1004 cfunc.add_parameter (new CCodeParameter ("connection", "DBusConnection*"));
1005 cfunc.add_parameter (new CCodeParameter ("path", "const char*"));
1006 cfunc.add_parameter (new CCodeParameter ("object", "void*"));
1008 cfunc.modifiers |= CCodeModifiers.STATIC;
1009 cfile.add_function_declaration (cfunc);
1011 var block = new CCodeBlock ();
1012 cfunc.block = block;
1014 var cdecl = new CCodeDeclaration ("const _DBusObjectVTable *");
1015 cdecl.add_declarator (new CCodeVariableDeclarator ("vtable"));
1016 block.add_statement (cdecl);
1018 var quark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
1019 quark.add_argument (new CCodeConstant ("\"DBusObjectVTable\""));
1021 var get_qdata = new CCodeFunctionCall (new CCodeIdentifier ("g_type_get_qdata"));
1022 get_qdata.add_argument (new CCodeIdentifier ("G_TYPE_FROM_INSTANCE (object)"));
1023 get_qdata.add_argument (quark);
1025 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("vtable"), get_qdata)));
1027 var cregister = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("vtable"), "register_object"));
1028 cregister.add_argument (new CCodeIdentifier ("connection"));
1029 cregister.add_argument (new CCodeIdentifier ("path"));
1030 cregister.add_argument (new CCodeIdentifier ("object"));
1032 var ifblock = new CCodeBlock ();
1033 ifblock.add_statement (new CCodeExpressionStatement (cregister));
1035 var elseblock = new CCodeBlock ();
1037 var warn = new CCodeFunctionCall (new CCodeIdentifier ("g_warning"));
1038 warn.add_argument (new CCodeConstant ("\"Object does not implement any D-Bus interface\""));
1040 elseblock.add_statement (new CCodeExpressionStatement(warn));
1042 block.add_statement (new CCodeIfStatement (new CCodeIdentifier ("vtable"), ifblock, elseblock));
1044 cfile.add_function (cfunc);
1046 // unregister function
1047 cfunc = new CCodeFunction ("_vala_dbus_unregister_object", "void");
1048 cfunc.add_parameter (new CCodeParameter ("connection", "gpointer"));
1049 cfunc.add_parameter (new CCodeParameter ("object", "GObject*"));
1051 cfunc.modifiers |= CCodeModifiers.STATIC;
1052 cfile.add_function_declaration (cfunc);
1054 block = new CCodeBlock ();
1055 cfunc.block = block;
1057 cdecl = new CCodeDeclaration ("char*");
1058 cdecl.add_declarator (new CCodeVariableDeclarator ("path"));
1059 block.add_statement (cdecl);
1061 var path = new CCodeFunctionCall (new CCodeIdentifier ("g_object_steal_data"));
1062 path.add_argument (new CCodeCastExpression (new CCodeIdentifier ("object"), "GObject*"));
1063 path.add_argument (new CCodeConstant ("\"dbus_object_path\""));
1064 block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("path"), path)));
1066 var unregister_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_connection_unregister_object_path"));
1067 unregister_call.add_argument (new CCodeIdentifier ("connection"));
1068 unregister_call.add_argument (new CCodeIdentifier ("path"));
1069 block.add_statement (new CCodeExpressionStatement (unregister_call));
1071 var path_free = new CCodeFunctionCall (new CCodeIdentifier ("g_free"));
1072 path_free.add_argument (new CCodeIdentifier ("path"));
1073 block.add_statement (new CCodeExpressionStatement (path_free));
1075 cfile.add_function (cfunc);