gio-2.0: Fix g_file_mount_enclosing_volume binding
[vala-lang.git] / codegen / valadbusmodule.vala
blobac6007d1bcc93ebc0414bb45f52d4daaa7d1a3c0
1 /* valadbusmodule.vala
3 * Copyright (C) 2008-2009 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 internal 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 public DBusModule (CCodeGenerator codegen, CCodeModule? next) {
49 base (codegen, next);
52 static bool is_string_marshalled_enum (TypeSymbol? symbol) {
53 if (symbol != null && symbol is Enum) {
54 var dbus = symbol.get_attribute ("DBus");
55 return dbus != null && dbus.get_bool ("use_string_marshalling");
57 return false;
60 string get_dbus_value (EnumValue value, string default_value) {
61 var dbus = value.get_attribute ("DBus");
62 if (dbus == null) {
63 return default_value;
66 string dbus_value = dbus.get_string ("value");
67 if (dbus_value == null) {
68 return default_value;
70 return dbus_value;
73 public string? get_dbus_name (TypeSymbol symbol) {
74 var dbus = symbol.get_attribute ("DBus");
75 if (dbus == null) {
76 return null;
79 return dbus.get_string ("name");
82 public string get_dbus_name_for_member (Symbol symbol) {
83 var dbus = symbol.get_attribute ("DBus");
84 if (dbus != null) {
85 return dbus.get_string ("name");
88 return Symbol.lower_case_to_camel_case (symbol.name);
91 bool get_basic_type_info (string signature, out BasicTypeInfo basic_type) {
92 foreach (BasicTypeInfo info in basic_types) {
93 if (info.signature == signature) {
94 basic_type = info;
95 return true;
98 return false;
101 public static string get_type_signature (DataType datatype) {
102 if (is_string_marshalled_enum (datatype.data_type)) {
103 return "s";
104 } else {
105 return datatype.get_type_signature ();
109 public override void visit_enum (Enum en) {
110 base.visit_enum (en);
112 if (is_string_marshalled_enum (en)) {
113 // strcmp
114 source_declarations.add_include ("string.h");
115 source_declarations.add_include ("dbus/dbus-glib.h");
117 source_type_member_definition.append (generate_enum_from_string_function (en));
118 source_type_member_definition.append (generate_enum_to_string_function (en));
122 public override bool generate_enum_declaration (Enum en, CCodeDeclarationSpace decl_space) {
123 if (base.generate_enum_declaration (en, decl_space)) {
124 if (is_string_marshalled_enum (en)) {
125 decl_space.add_type_member_declaration (generate_enum_from_string_function_declaration (en));
126 decl_space.add_type_member_declaration (generate_enum_to_string_function_declaration (en));
128 return true;
130 return false;
133 CCodeExpression? get_array_length (CCodeExpression expr, int dim) {
134 var id = expr as CCodeIdentifier;
135 var ma = expr as CCodeMemberAccess;
136 if (id != null) {
137 return new CCodeIdentifier ("%s_length%d".printf (id.name, dim));
138 } else if (ma != null) {
139 return new CCodeMemberAccess.pointer (ma.inner, "%s_length%d".printf (ma.member_name, dim));
141 return null;
144 CCodeExpression? generate_enum_value_from_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
145 var en = type.type_symbol as Enum;
146 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
148 var from_string_call = new CCodeFunctionCall (new CCodeIdentifier (from_string_name));
149 from_string_call.add_argument (expr);
150 from_string_call.add_argument (new CCodeConstant ("NULL"));
152 return from_string_call;
155 public CCodeFunction generate_enum_from_string_function_declaration (Enum en) {
156 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
158 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
159 from_string_func.add_parameter (new CCodeFormalParameter ("str", "const char*"));
160 from_string_func.add_parameter (new CCodeFormalParameter ("error", "GError**"));
162 return from_string_func;
165 public CCodeFunction generate_enum_from_string_function (Enum en) {
166 var from_string_name = "%s_from_string".printf (en.get_lower_case_cname (null));
168 var from_string_func = new CCodeFunction (from_string_name, en.get_cname ());
169 from_string_func.add_parameter (new CCodeFormalParameter ("str", "const char*"));
170 from_string_func.add_parameter (new CCodeFormalParameter ("error", "GError**"));
172 var from_string_block = new CCodeBlock ();
173 from_string_func.block = from_string_block;
175 var cdecl = new CCodeDeclaration (en.get_cname ());
176 cdecl.add_declarator (new CCodeVariableDeclarator ("value"));
177 from_string_block.add_statement (cdecl);
179 CCodeStatement if_else_if = null;
180 CCodeIfStatement last_statement = null;
181 foreach (EnumValue enum_value in en.get_values ()) {
182 var true_block = new CCodeBlock ();
183 true_block.suppress_newline = true;
184 true_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("value"), new CCodeIdentifier (enum_value.get_cname ()))));
186 string dbus_value = get_dbus_value (enum_value, enum_value.name);
187 var string_comparison = new CCodeFunctionCall (new CCodeIdentifier ("strcmp"));
188 string_comparison.add_argument (new CCodeIdentifier ("str"));
189 string_comparison.add_argument (new CCodeConstant ("\"%s\"".printf (dbus_value)));
190 var stmt = new CCodeIfStatement (new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, string_comparison, new CCodeConstant ("0")), true_block);
192 if (last_statement != null) {
193 last_statement.false_statement = stmt;
194 } else {
195 if_else_if = stmt;
197 last_statement = stmt;
200 var error_block = new CCodeBlock ();
201 error_block.suppress_newline = true;
203 var set_error_call = new CCodeFunctionCall (new CCodeIdentifier ("g_set_error_literal"));
204 set_error_call.add_argument (new CCodeIdentifier ("error"));
205 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR"));
206 set_error_call.add_argument (new CCodeIdentifier ("DBUS_GERROR_INVALID_ARGS"));
207 set_error_call.add_argument (new CCodeConstant ("\"Invalid enumeration value\""));
208 error_block.add_statement (new CCodeExpressionStatement (set_error_call));
210 last_statement.false_statement = error_block;
211 from_string_block.add_statement (if_else_if);
213 from_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("value")));
215 return from_string_func;
218 CCodeExpression read_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, bool transfer = false) {
219 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
221 var cdecl = new CCodeDeclaration (basic_type.cname);
222 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
223 fragment.append (cdecl);
225 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_basic"));
226 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
227 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
228 fragment.append (new CCodeExpressionStatement (iter_call));
230 var temp_result = new CCodeIdentifier (temp_name);
232 if (!transfer
233 && (basic_type.signature == "s"
234 || basic_type.signature == "o"
235 || basic_type.signature == "g")) {
236 var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_strdup"));
237 dup_call.add_argument (temp_result);
238 return dup_call;
239 } else {
240 return temp_result;
244 CCodeExpression read_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression? expr) {
245 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
247 var new_call = new CCodeFunctionCall (new CCodeIdentifier ("g_new"));
248 new_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
249 // add one extra element for NULL-termination
250 new_call.add_argument (new CCodeConstant ("5"));
252 var cdecl = new CCodeDeclaration (array_type.get_cname ());
253 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name, new_call));
254 fragment.append (cdecl);
256 cdecl = new CCodeDeclaration ("int");
257 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_length", new CCodeConstant ("0")));
258 fragment.append (cdecl);
260 cdecl = new CCodeDeclaration ("int");
261 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name + "_size", new CCodeConstant ("4")));
262 fragment.append (cdecl);
264 read_array_dim (fragment, array_type, 1, temp_name, iter_expr, expr);
266 if (array_type.element_type.is_reference_type_or_type_parameter ()) {
267 // NULL terminate array
268 var length = new CCodeIdentifier (temp_name + "_length");
269 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), length);
270 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, new CCodeIdentifier ("NULL"))));
273 return new CCodeIdentifier (temp_name);
276 void read_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, string temp_name, CCodeExpression iter_expr, CCodeExpression? expr) {
277 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
279 var cdecl = new CCodeDeclaration ("int");
280 cdecl.add_declarator (new CCodeVariableDeclarator ("%s_length%d".printf (temp_name, dim), new CCodeConstant ("0")));
281 fragment.append (cdecl);
283 cdecl = new CCodeDeclaration ("DBusMessageIter");
284 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
285 fragment.append (cdecl);
287 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
288 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
289 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
290 fragment.append (new CCodeExpressionStatement (iter_call));
292 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
293 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
295 var cforblock = new CCodeBlock ();
296 var cforfragment = new CCodeFragment ();
297 cforblock.add_statement (cforfragment);
298 var cfor = new CCodeForStatement (iter_call, cforblock);
299 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("%s_length%d".printf (temp_name, dim))));
301 if (dim < array_type.rank) {
302 read_array_dim (cforfragment, array_type, dim + 1, temp_name, new CCodeIdentifier (subiter_name), expr);
304 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
305 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
306 cforfragment.append (new CCodeExpressionStatement (iter_call));
307 } else {
308 var size_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeIdentifier (temp_name + "_size"), new CCodeIdentifier (temp_name + "_length"));
309 var renew_block = new CCodeBlock ();
311 // tmp_size = (2 * tmp_size);
312 var new_size = new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeConstant ("2"), new CCodeIdentifier (temp_name + "_size"));
313 renew_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name + "_size"), new_size)));
315 var renew_call = new CCodeFunctionCall (new CCodeIdentifier ("g_renew"));
316 renew_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
317 renew_call.add_argument (new CCodeIdentifier (temp_name));
318 // add one extra element for NULL-termination
319 renew_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (temp_name + "_size"), new CCodeConstant ("1")));
320 var renew_stmt = new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), renew_call));
321 renew_block.add_statement (renew_stmt);
323 var cif = new CCodeIfStatement (size_check, renew_block);
324 cforfragment.append (cif);
326 var element_access = new CCodeElementAccess (new CCodeIdentifier (temp_name), new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (temp_name + "_length")));
327 var element_expr = read_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), null);
328 cforfragment.append (new CCodeExpressionStatement (new CCodeAssignment (element_access, element_expr)));
331 fragment.append (cfor);
333 if (expr != null) {
334 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (get_array_length (expr, dim), new CCodeIdentifier ("%s_length%d".printf (temp_name, dim)))));
338 CCodeExpression read_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr) {
339 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
340 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
342 var cdecl = new CCodeDeclaration (st.get_cname ());
343 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
344 fragment.append (cdecl);
346 cdecl = new CCodeDeclaration ("DBusMessageIter");
347 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
348 fragment.append (cdecl);
350 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
351 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
352 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
353 fragment.append (new CCodeExpressionStatement (iter_call));
355 foreach (Field f in st.get_fields ()) {
356 if (f.binding != MemberBinding.INSTANCE) {
357 continue;
360 var field_expr = read_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()));
361 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess (new CCodeIdentifier (temp_name), f.get_cname ()), field_expr)));
364 return new CCodeIdentifier (temp_name);
367 CCodeExpression read_value (CCodeFragment fragment, CCodeExpression iter_expr) {
368 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
369 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
371 // 0-initialize struct with struct initializer { 0 }
372 var cvalinit = new CCodeInitializerList ();
373 cvalinit.append (new CCodeConstant ("0"));
375 var cdecl = new CCodeDeclaration ("GValue");
376 cdecl.add_declarator (new CCodeVariableDeclarator.zero (temp_name, cvalinit));
377 fragment.append (cdecl);
379 cdecl = new CCodeDeclaration ("DBusMessageIter");
380 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
381 fragment.append (cdecl);
383 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
384 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
385 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
386 fragment.append (new CCodeExpressionStatement (iter_call));
388 CCodeIfStatement clastif = null;
390 foreach (BasicTypeInfo basic_type in basic_types) {
391 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
392 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
393 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
395 var type_block = new CCodeBlock ();
396 var type_fragment = new CCodeFragment ();
397 type_block.add_statement (type_fragment);
398 var result = read_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name));
400 var value_init = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
401 value_init.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
402 value_init.add_argument (new CCodeIdentifier (basic_type.gtype));
403 type_fragment.append (new CCodeExpressionStatement (value_init));
405 var value_set = new CCodeFunctionCall (new CCodeIdentifier (basic_type.set_value_function));
406 value_set.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
407 value_set.add_argument (result);
408 type_fragment.append (new CCodeExpressionStatement (value_set));
410 var cif = new CCodeIfStatement (type_check, type_block);
411 if (clastif == null) {
412 fragment.append (cif);
413 } else {
414 clastif.false_statement = cif;
417 clastif = cif;
420 return new CCodeIdentifier (temp_name);
423 CCodeExpression read_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr) {
424 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
425 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
426 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
428 var type_args = type.get_type_arguments ();
429 assert (type_args.size == 2);
430 var key_type = type_args.get (0);
431 var value_type = type_args.get (1);
433 var cdecl = new CCodeDeclaration ("GHashTable*");
434 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
435 fragment.append (cdecl);
437 cdecl = new CCodeDeclaration ("DBusMessageIter");
438 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
439 fragment.append (cdecl);
441 cdecl = new CCodeDeclaration ("DBusMessageIter");
442 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
443 fragment.append (cdecl);
445 var hash_table_new = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_new_full"));
446 if (key_type.data_type == string_type.data_type) {
447 hash_table_new.add_argument (new CCodeIdentifier ("g_str_hash"));
448 hash_table_new.add_argument (new CCodeIdentifier ("g_str_equal"));
449 } else {
450 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_hash"));
451 hash_table_new.add_argument (new CCodeIdentifier ("g_direct_equal"));
453 if (key_type.data_type == string_type.data_type) {
454 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
455 } else {
456 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
458 if (value_type.data_type == string_type.data_type) {
459 hash_table_new.add_argument (new CCodeIdentifier ("g_free"));
460 } else {
461 hash_table_new.add_argument (new CCodeIdentifier ("NULL"));
463 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), hash_table_new)));
465 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
466 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
467 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
468 fragment.append (new CCodeExpressionStatement (iter_call));
470 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_get_arg_type"));
471 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
473 var cwhileblock = new CCodeBlock ();
474 var cwhilefragment = new CCodeFragment ();
475 cwhileblock.add_statement (cwhilefragment);
476 var cwhile = new CCodeWhileStatement (iter_call, cwhileblock);
478 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_recurse"));
479 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
480 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
481 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
483 cdecl = new CCodeDeclaration (key_type.get_cname ());
484 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
485 cwhilefragment.append (cdecl);
487 cdecl = new CCodeDeclaration (value_type.get_cname ());
488 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
489 cwhilefragment.append (cdecl);
491 var key_expr = read_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), null);
492 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), key_expr)));
494 var value_expr = read_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), null);
495 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), value_expr)));
497 var hash_table_insert = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_insert"));
498 hash_table_insert.add_argument (new CCodeIdentifier (temp_name));
499 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_key"), key_type));
500 hash_table_insert.add_argument (convert_to_generic_pointer (new CCodeIdentifier ("_value"), value_type));
501 cwhilefragment.append (new CCodeExpressionStatement (hash_table_insert));
503 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
504 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
505 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
507 fragment.append (cwhile);
509 return new CCodeIdentifier (temp_name);
512 public CCodeExpression? read_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression? expr) {
513 BasicTypeInfo basic_type;
514 CCodeExpression result = null;
515 if (is_string_marshalled_enum (type.data_type)) {
516 get_basic_type_info ("s", out basic_type);
517 result = read_basic (fragment, basic_type, iter_expr, true);
518 result = generate_enum_value_from_string (fragment, type as EnumValueType, result);
519 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
520 result = read_basic (fragment, basic_type, iter_expr);
521 } else if (type is ArrayType) {
522 result = read_array (fragment, (ArrayType) type, iter_expr, expr);
523 } else if (type.data_type is Struct) {
524 var st = (Struct) type.data_type;
525 if (type.data_type.get_full_name () == "GLib.Value") {
526 result = read_value (fragment, iter_expr);
527 } else {
528 result = read_struct (fragment, st, iter_expr);
530 if (type.nullable) {
531 var csizeof = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
532 csizeof.add_argument (new CCodeIdentifier (st.get_cname ()));
533 var cdup = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
534 cdup.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, result));
535 cdup.add_argument (csizeof);
536 result = cdup;
538 } else if (type is ObjectType) {
539 if (type.data_type.get_full_name () == "GLib.HashTable") {
540 result = read_hash_table (fragment, (ObjectType) type, iter_expr);
542 } else {
543 Report.error (type.source_reference, "D-Bus deserialization of type `%s' is not supported".printf (type.to_string ()));
544 return null;
547 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_next"));
548 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
549 fragment.append (new CCodeExpressionStatement (iter_call));
551 return result;
554 CCodeExpression? generate_enum_value_to_string (CCodeFragment fragment, EnumValueType type, CCodeExpression? expr) {
555 var en = type.type_symbol as Enum;
556 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
558 var to_string_call = new CCodeFunctionCall (new CCodeIdentifier (to_string_name));
559 to_string_call.add_argument (expr);
561 return to_string_call;
564 public CCodeFunction generate_enum_to_string_function_declaration (Enum en) {
565 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
567 var to_string_func = new CCodeFunction (to_string_name, "const char*");
568 to_string_func.add_parameter (new CCodeFormalParameter ("value", en.get_cname ()));
570 return to_string_func;
573 public CCodeFunction generate_enum_to_string_function (Enum en) {
574 var to_string_name = "%s_to_string".printf (en.get_lower_case_cname (null));
576 var to_string_func = new CCodeFunction (to_string_name, "const char*");
577 to_string_func.add_parameter (new CCodeFormalParameter ("value", en.get_cname ()));
579 var to_string_block = new CCodeBlock ();
580 to_string_func.block = to_string_block;
582 var cdecl = new CCodeDeclaration ("const char *");
583 cdecl.add_declarator (new CCodeVariableDeclarator ("str"));
584 to_string_block.add_statement (cdecl);
586 var cswitch = new CCodeSwitchStatement (new CCodeIdentifier ("value"));
587 foreach (EnumValue enum_value in en.get_values ()) {
588 string dbus_value = get_dbus_value (enum_value, enum_value.name);
589 cswitch.add_statement (new CCodeCaseStatement (new CCodeIdentifier (enum_value.get_cname ())));
590 cswitch.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("str"), new CCodeConstant ("\"%s\"".printf (dbus_value)))));
591 cswitch.add_statement (new CCodeBreakStatement ());
593 to_string_block.add_statement (cswitch);
595 to_string_block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("str")));
597 return to_string_func;
600 void write_basic (CCodeFragment fragment, BasicTypeInfo basic_type, CCodeExpression iter_expr, CCodeExpression expr) {
601 string temp_name = "_tmp%d_".printf (next_temp_var_id++);
603 var cdecl = new CCodeDeclaration (basic_type.cname);
604 cdecl.add_declarator (new CCodeVariableDeclarator (temp_name));
605 fragment.append (cdecl);
607 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (temp_name), expr)));
609 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_append_basic"));
610 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
611 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_" + basic_type.type_name));
612 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_name)));
613 fragment.append (new CCodeExpressionStatement (iter_call));
616 void write_array (CCodeFragment fragment, ArrayType array_type, CCodeExpression iter_expr, CCodeExpression array_expr) {
617 string array_iter_name = "_tmp%d_".printf (next_temp_var_id++);
619 var cdecl = new CCodeDeclaration (array_type.get_cname ());
620 cdecl.add_declarator (new CCodeVariableDeclarator (array_iter_name));
621 fragment.append (cdecl);
623 fragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (array_iter_name), array_expr)));
625 write_array_dim (fragment, array_type, 1, iter_expr, array_expr, new CCodeIdentifier (array_iter_name));
628 void write_array_dim (CCodeFragment fragment, ArrayType array_type, int dim, CCodeExpression iter_expr, CCodeExpression array_expr, CCodeExpression array_iter_expr) {
629 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
630 string index_name = "_tmp%d_".printf (next_temp_var_id++);
632 var cdecl = new CCodeDeclaration ("DBusMessageIter");
633 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
634 fragment.append (cdecl);
636 cdecl = new CCodeDeclaration ("int");
637 cdecl.add_declarator (new CCodeVariableDeclarator (index_name));
638 fragment.append (cdecl);
640 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
641 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
642 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
643 iter_call.add_argument (new CCodeConstant ("\"%s%s\"".printf (string.nfill (array_type.rank - dim, 'a'), get_type_signature (array_type.element_type))));
644 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
645 fragment.append (new CCodeExpressionStatement (iter_call));
647 var cforblock = new CCodeBlock ();
648 var cforfragment = new CCodeFragment ();
649 cforblock.add_statement (cforfragment);
650 var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (index_name), get_array_length (array_expr, dim)), cforblock);
651 cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (index_name), new CCodeConstant ("0")));
652 cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier (index_name)));
654 if (dim < array_type.rank) {
655 write_array_dim (cforfragment, array_type, dim + 1, new CCodeIdentifier (subiter_name), array_expr, array_iter_expr);
656 } else {
657 var element_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, array_iter_expr);
658 write_expression (cforfragment, array_type.element_type, new CCodeIdentifier (subiter_name), element_expr);
660 var array_iter_incr = new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, array_iter_expr);
661 cforfragment.append (new CCodeExpressionStatement (array_iter_incr));
663 fragment.append (cfor);
665 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
666 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
667 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
668 fragment.append (new CCodeExpressionStatement (iter_call));
671 void write_struct (CCodeFragment fragment, Struct st, CCodeExpression iter_expr, CCodeExpression struct_expr) {
672 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
674 var cdecl = new CCodeDeclaration ("DBusMessageIter");
675 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
676 fragment.append (cdecl);
678 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
679 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
680 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_STRUCT"));
681 iter_call.add_argument (new CCodeConstant ("NULL"));
682 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
683 fragment.append (new CCodeExpressionStatement (iter_call));
685 foreach (Field f in st.get_fields ()) {
686 if (f.binding != MemberBinding.INSTANCE) {
687 continue;
690 write_expression (fragment, f.field_type, new CCodeIdentifier (subiter_name), new CCodeMemberAccess (struct_expr, f.get_cname ()));
693 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
694 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
695 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
696 fragment.append (new CCodeExpressionStatement (iter_call));
699 void write_value (CCodeFragment fragment, CCodeExpression iter_expr, CCodeExpression expr) {
700 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
702 var cdecl = new CCodeDeclaration ("DBusMessageIter");
703 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
704 fragment.append (cdecl);
706 CCodeIfStatement clastif = null;
708 foreach (BasicTypeInfo basic_type in basic_types) {
709 // ensure that there is only one case per GType
710 if (basic_type.get_value_function == null) {
711 continue;
714 var type_call = new CCodeFunctionCall (new CCodeIdentifier ("G_VALUE_TYPE"));
715 type_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
716 var type_check = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, type_call, new CCodeIdentifier (basic_type.gtype));
718 var type_block = new CCodeBlock ();
719 var type_fragment = new CCodeFragment ();
720 type_block.add_statement (type_fragment);
722 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
723 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
724 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_VARIANT"));
725 iter_call.add_argument (new CCodeConstant ("\"%s\"".printf (basic_type.signature)));
726 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
727 type_fragment.append (new CCodeExpressionStatement (iter_call));
729 var value_get = new CCodeFunctionCall (new CCodeIdentifier (basic_type.get_value_function));
730 value_get.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, expr));
732 write_basic (type_fragment, basic_type, new CCodeIdentifier (subiter_name), value_get);
734 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
735 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
736 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
737 type_fragment.append (new CCodeExpressionStatement (iter_call));
739 var cif = new CCodeIfStatement (type_check, type_block);
740 if (clastif == null) {
741 fragment.append (cif);
742 } else {
743 clastif.false_statement = cif;
746 clastif = cif;
750 void write_hash_table (CCodeFragment fragment, ObjectType type, CCodeExpression iter_expr, CCodeExpression hash_table_expr) {
751 string subiter_name = "_tmp%d_".printf (next_temp_var_id++);
752 string entryiter_name = "_tmp%d_".printf (next_temp_var_id++);
753 string tableiter_name = "_tmp%d_".printf (next_temp_var_id++);
754 string key_name = "_tmp%d_".printf (next_temp_var_id++);
755 string value_name = "_tmp%d_".printf (next_temp_var_id++);
757 var type_args = type.get_type_arguments ();
758 assert (type_args.size == 2);
759 var key_type = type_args.get (0);
760 var value_type = type_args.get (1);
762 var iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
763 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, iter_expr));
764 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_ARRAY"));
765 iter_call.add_argument (new CCodeConstant ("\"{%s%s}\"".printf (get_type_signature (key_type), get_type_signature (value_type))));
766 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
767 fragment.append (new CCodeExpressionStatement (iter_call));
769 var cdecl = new CCodeDeclaration ("DBusMessageIter");
770 cdecl.add_declarator (new CCodeVariableDeclarator (subiter_name));
771 cdecl.add_declarator (new CCodeVariableDeclarator (entryiter_name));
772 fragment.append (cdecl);
774 cdecl = new CCodeDeclaration ("GHashTableIter");
775 cdecl.add_declarator (new CCodeVariableDeclarator (tableiter_name));
776 fragment.append (cdecl);
778 cdecl = new CCodeDeclaration ("gpointer");
779 cdecl.add_declarator (new CCodeVariableDeclarator (key_name));
780 cdecl.add_declarator (new CCodeVariableDeclarator (value_name));
781 fragment.append (cdecl);
783 var iter_init_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_init"));
784 iter_init_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
785 iter_init_call.add_argument (hash_table_expr);
786 fragment.append (new CCodeExpressionStatement (iter_init_call));
788 var iter_next_call = new CCodeFunctionCall (new CCodeIdentifier ("g_hash_table_iter_next"));
789 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (tableiter_name)));
790 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (key_name)));
791 iter_next_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (value_name)));
793 var cwhileblock = new CCodeBlock ();
794 var cwhilefragment = new CCodeFragment ();
795 cwhileblock.add_statement (cwhilefragment);
796 var cwhile = new CCodeWhileStatement (iter_next_call, cwhileblock);
798 cdecl = new CCodeDeclaration (key_type.get_cname ());
799 cdecl.add_declarator (new CCodeVariableDeclarator ("_key"));
800 cwhilefragment.append (cdecl);
802 cdecl = new CCodeDeclaration (value_type.get_cname ());
803 cdecl.add_declarator (new CCodeVariableDeclarator ("_value"));
804 cwhilefragment.append (cdecl);
806 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_open_container"));
807 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
808 iter_call.add_argument (new CCodeIdentifier ("DBUS_TYPE_DICT_ENTRY"));
809 iter_call.add_argument (new CCodeConstant ("NULL"));
810 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
811 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
813 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_key"), convert_from_generic_pointer (new CCodeIdentifier (key_name), key_type))));
814 cwhilefragment.append (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("_value"), convert_from_generic_pointer (new CCodeIdentifier (value_name), value_type))));
816 write_expression (cwhilefragment, key_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_key"));
817 write_expression (cwhilefragment, value_type, new CCodeIdentifier (entryiter_name), new CCodeIdentifier ("_value"));
819 iter_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_message_iter_close_container"));
820 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (subiter_name)));
821 iter_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (entryiter_name)));
822 cwhilefragment.append (new CCodeExpressionStatement (iter_call));
824 fragment.append (cwhile);
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 fragment.append (new CCodeExpressionStatement (iter_call));
832 public void write_expression (CCodeFragment fragment, DataType type, CCodeExpression iter_expr, CCodeExpression expr) {
833 BasicTypeInfo basic_type;
834 if (is_string_marshalled_enum (type.data_type)) {
835 get_basic_type_info ("s", out basic_type);
836 var result = generate_enum_value_to_string (fragment, type as EnumValueType, expr);
837 write_basic (fragment, basic_type, iter_expr, result);
838 } else if (get_basic_type_info (get_type_signature (type), out basic_type)) {
839 write_basic (fragment, basic_type, iter_expr, expr);
840 } else if (type is ArrayType) {
841 write_array (fragment, (ArrayType) type, iter_expr, expr);
842 } else if (type.data_type is Struct) {
843 var st_expr = expr;
844 if (type.nullable) {
845 st_expr = new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, st_expr);
847 if (type.data_type.get_full_name () == "GLib.Value") {
848 write_value (fragment, iter_expr, st_expr);
849 } else {
850 write_struct (fragment, (Struct) type.data_type, iter_expr, st_expr);
852 } else if (type is ObjectType) {
853 if (type.data_type.get_full_name () == "GLib.HashTable") {
854 write_hash_table (fragment, (ObjectType) type, iter_expr, expr);
856 } else {
857 Report.error (type.source_reference, "D-Bus serialization of type `%s' is not supported".printf (type.to_string ()));