]> git.proxmox.com Git - ceph.git/blob - ceph/src/jaegertracing/thrift/compiler/cpp/src/thrift/generate/t_c_glib_generator.cc
buildsys: switch source download to quincy
[ceph.git] / ceph / src / jaegertracing / thrift / compiler / cpp / src / thrift / generate / t_c_glib_generator.cc
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 *
19 * Contains some contributions under the Thrift Software License.
20 * Please see doc/old-thrift-license.txt in the Thrift distribution for
21 * details.
22 */
23
24 #include <fstream>
25 #include <iostream>
26 #include <stdexcept>
27 #include <string>
28 #include <vector>
29
30 #include <ctype.h>
31
32 #include "thrift/platform.h"
33 #include "thrift/generate/t_oop_generator.h"
34
35 using std::map;
36 using std::ostream;
37 using std::ostringstream;
38 using std::string;
39 using std::stringstream;
40 using std::vector;
41
42 static const string endl = "\n"; // avoid ostream << std::endl flushes
43
44 /* forward declarations */
45 string initial_caps_to_underscores(string name);
46 string underscores_to_initial_caps(string name);
47 string to_upper_case(string name);
48 string to_lower_case(string name);
49
50 /**
51 * C code generator, using glib for C typing.
52 */
53 class t_c_glib_generator : public t_oop_generator {
54 public:
55 /* constructor */
56 t_c_glib_generator(t_program* program,
57 const map<string, string>& parsed_options,
58 const string& option_string)
59 : t_oop_generator(program) {
60 (void)option_string;
61 std::map<std::string, std::string>::const_iterator iter;
62
63 /* set the output directory */
64 this->out_dir_base_ = "gen-c_glib";
65
66 /* no options yet */
67 for( iter = parsed_options.begin(); iter != parsed_options.end(); ++iter) {
68 throw "unknown option c_glib:" + iter->first;
69 }
70
71 /* set the namespace */
72 this->nspace = program_->get_namespace("c_glib");
73
74 if (this->nspace.empty()) {
75 this->nspace = "";
76 this->nspace_u = "";
77 this->nspace_uc = "";
78 this->nspace_lc = "";
79 } else {
80 /* replace dots with underscores */
81 char* tmp = strdup(this->nspace.c_str());
82 for (unsigned int i = 0; i < strlen(tmp); i++) {
83 if (tmp[i] == '.') {
84 tmp[i] = '_';
85 }
86 }
87 this->nspace = string(tmp, strlen(tmp));
88 free(tmp);
89
90 /* clean up the namespace for C.
91 * An input of 'namespace foo' should result in:
92 * - nspace = foo - for thrift objects and typedefs
93 * - nspace_u = Foo - for internal GObject prefixes
94 * - nspace_uc = FOO_ - for macro prefixes
95 * - nspace_lc = foo_ - for filename and method prefixes
96 * The underscores are there since uc and lc strings are used as file and
97 * variable prefixes.
98 */
99 this->nspace_u = initial_caps_to_underscores(this->nspace);
100 this->nspace_uc = to_upper_case(this->nspace_u) + "_";
101 this->nspace_lc = to_lower_case(this->nspace_u) + "_";
102 }
103 }
104
105 /* initialization and destruction */
106 void init_generator() override;
107 void close_generator() override;
108
109 /* generation functions */
110 void generate_typedef(t_typedef* ttypedef) override;
111 void generate_enum(t_enum* tenum) override;
112 void generate_consts(vector<t_const*> consts) override;
113 void generate_struct(t_struct* tstruct) override;
114 void generate_service(t_service* tservice) override;
115 void generate_xception(t_struct* tstruct) override;
116
117 private:
118 /* file streams */
119 ofstream_with_content_based_conditional_update f_types_;
120 ofstream_with_content_based_conditional_update f_types_impl_;
121 ofstream_with_content_based_conditional_update f_header_;
122 ofstream_with_content_based_conditional_update f_service_;
123
124 /* namespace variables */
125 string nspace;
126 string nspace_u;
127 string nspace_uc;
128 string nspace_lc;
129
130 /* helper functions */
131 bool is_complex_type(t_type* ttype);
132 bool is_numeric(t_type* ttype);
133 string type_name(t_type* ttype, bool in_typedef = false, bool is_const = false);
134 string property_type_name(t_type* ttype, bool in_typedef = false, bool is_const = false);
135 string base_type_name(t_type* type);
136 string type_to_enum(t_type* type);
137 string constant_literal(t_type* type, t_const_value* value);
138 string constant_value(string name, t_type* type, t_const_value* value);
139 string constant_value_with_storage(string name, t_type* type, t_const_value* value);
140 string function_signature(t_function* tfunction);
141 string argument_list(t_struct* tstruct);
142 string xception_list(t_struct* tstruct);
143 string declare_field(t_field* tfield,
144 bool init = false,
145 bool pointer = false,
146 bool constant = false,
147 bool reference = false);
148 void declare_local_variable(ostream& out, t_type* ttype, string& base_name, bool for_hash_table);
149 void declore_local_variable_for_write(ostream& out, t_type* ttype, string& base_name);
150
151 /* generation functions */
152 void generate_const_initializer(string name,
153 t_type* type,
154 t_const_value* value,
155 bool top_level = false);
156 void generate_service_helpers(t_service* tservice);
157 void generate_service_client(t_service* tservice);
158 void generate_service_handler(t_service* tservice);
159 void generate_service_processor(t_service* tservice);
160 void generate_service_server(t_service* tservice);
161 void generate_object(t_struct* tstruct);
162 void generate_struct_writer(ostream& out,
163 t_struct* tstruct,
164 string this_name,
165 string this_get = "",
166 bool is_function = true);
167 void generate_struct_reader(ostream& out,
168 t_struct* tstruct,
169 string this_name,
170 string this_get = "",
171 bool is_function = true);
172
173 void generate_serialize_field(ostream& out,
174 t_field* tfield,
175 string prefix,
176 string suffix,
177 int error_ret);
178 void generate_serialize_struct(ostream& out, t_struct* tstruct, string prefix, int error_ret);
179 void generate_serialize_container(ostream& out, t_type* ttype, string prefix, int error_ret);
180 void generate_serialize_map_element(ostream& out,
181 t_map* tmap,
182 string key,
183 string value,
184 int error_ret);
185 void generate_serialize_set_element(ostream& out, t_set* tset, string element, int error_ret);
186 void generate_serialize_list_element(ostream& out,
187 t_list* tlist,
188 string list,
189 string index,
190 int error_ret);
191
192 void generate_deserialize_field(ostream& out,
193 t_field* tfield,
194 string prefix,
195 string suffix,
196 int error_ret,
197 bool allocate = true);
198 void generate_deserialize_struct(ostream& out,
199 t_struct* tstruct,
200 string prefix,
201 int error_ret,
202 bool allocate = true);
203 void generate_deserialize_container(ostream& out, t_type* ttype, string prefix, int error_ret);
204 void generate_deserialize_map_element(ostream& out, t_map* tmap, string prefix, int error_ret);
205 void generate_deserialize_set_element(ostream& out, t_set* tset, string prefix, int error_ret);
206 void generate_deserialize_list_element(ostream& out,
207 t_list* tlist,
208 string prefix,
209 string index,
210 int error_ret);
211
212 string generate_new_hash_from_type(t_type* key, t_type* value);
213 string generate_new_array_from_type(t_type* ttype);
214
215 string generate_free_func_from_type(t_type* ttype);
216 string generate_hash_func_from_type(t_type* ttype);
217 string generate_cmp_func_from_type(t_type* ttype);
218 };
219
220 /**
221 * Prepare for file generation by opening up the necessary file
222 * output streams.
223 */
224 void t_c_glib_generator::init_generator() {
225 /* create output directory */
226 MKDIR(get_out_dir().c_str());
227
228 string program_name_u = initial_caps_to_underscores(program_name_);
229 string program_name_uc = to_upper_case(program_name_u);
230 string program_name_lc = to_lower_case(program_name_u);
231
232 /* create output files */
233 string f_types_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.h";
234 f_types_.open(f_types_name.c_str());
235 string f_types_impl_name = get_out_dir() + this->nspace_lc + program_name_lc + "_types.c";
236 f_types_impl_.open(f_types_impl_name.c_str());
237
238 /* add thrift boilerplate headers */
239 f_types_ << autogen_comment();
240 f_types_impl_ << autogen_comment();
241
242 /* include inclusion guard */
243 f_types_ << "#ifndef " << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << "#define "
244 << this->nspace_uc << program_name_uc << "_TYPES_H" << endl << endl;
245
246 /* include base types */
247 f_types_ << "/* base includes */" << endl << "#include <glib-object.h>" << endl
248 << "#include <thrift/c_glib/thrift_struct.h>" << endl
249 << "#include <thrift/c_glib/protocol/thrift_protocol.h>" << endl;
250
251 /* include other thrift includes */
252 const vector<t_program*>& includes = program_->get_includes();
253 if (!includes.empty()) {
254 f_types_ << "/* other thrift includes */" << endl;
255
256 for (auto include : includes) {
257 const std::string& include_nspace = include->get_namespace("c_glib");
258 std::string include_nspace_prefix =
259 include_nspace.empty() ? "" : initial_caps_to_underscores(include_nspace) + "_";
260
261 f_types_ << "#include \"" << include_nspace_prefix
262 << initial_caps_to_underscores(include->get_name()) << "_types.h\"" << endl;
263 }
264 f_types_ << endl;
265 }
266
267 /* include custom headers */
268 const vector<string>& c_includes = program_->get_c_includes();
269 f_types_ << "/* custom thrift includes */" << endl;
270 for (const auto & c_include : c_includes) {
271 if (c_include[0] == '<') {
272 f_types_ << "#include " << c_include << endl;
273 } else {
274 f_types_ << "#include \"" << c_include << "\"" << endl;
275 }
276 }
277 f_types_ << endl;
278
279 /* include math.h (for "INFINITY") in the implementation file, in case we
280 encounter a struct with a member of type double */
281 f_types_impl_ << endl << "#include <math.h>" << endl;
282
283 // include the types file
284 f_types_impl_ << endl << "#include \"" << this->nspace_lc << program_name_u << "_types.h\""
285 << endl << "#include <thrift/c_glib/thrift.h>" << endl << endl;
286
287 f_types_ << "/* begin types */" << endl << endl;
288 }
289
290 /**
291 * Finish up generation and close all file streams.
292 */
293 void t_c_glib_generator::close_generator() {
294 string program_name_uc = to_upper_case(initial_caps_to_underscores(program_name_));
295
296 /* end the header inclusion guard */
297 f_types_ << "#endif /* " << this->nspace_uc << program_name_uc << "_TYPES_H */" << endl;
298
299 /* close output file */
300 f_types_.close();
301 f_types_impl_.close();
302 }
303
304 /**
305 * Generates a Thrift typedef in C code. For example:
306 *
307 * Thrift:
308 * typedef map<i32,i32> SomeMap
309 *
310 * C:
311 * typedef GHashTable * ThriftSomeMap;
312 */
313 void t_c_glib_generator::generate_typedef(t_typedef* ttypedef) {
314 f_types_ << indent() << "typedef " << type_name(ttypedef->get_type(), true) << " " << this->nspace
315 << ttypedef->get_symbolic() << ";" << endl << endl;
316 }
317
318 /**
319 * Generates a C enumeration. For example:
320 *
321 * Thrift:
322 * enum MyEnum {
323 * ONE = 1,
324 * TWO
325 * }
326 *
327 * C:
328 * enum _ThriftMyEnum {
329 * THRIFT_MY_ENUM_ONE = 1,
330 * THRIFT_MY_ENUM_TWO
331 * };
332 * typedef enum _ThriftMyEnum ThriftMyEnum;
333 */
334 void t_c_glib_generator::generate_enum(t_enum* tenum) {
335 string name = tenum->get_name();
336 string name_uc = to_upper_case(initial_caps_to_underscores(name));
337
338 f_types_ << indent() << "enum _" << this->nspace << name << " {" << endl;
339
340 indent_up();
341
342 vector<t_enum_value*> constants = tenum->get_constants();
343 vector<t_enum_value*>::iterator c_iter;
344 bool first = true;
345
346 /* output each of the enumeration elements */
347 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
348 if (first) {
349 first = false;
350 } else {
351 f_types_ << "," << endl;
352 }
353
354 f_types_ << indent() << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name();
355 f_types_ << " = " << (*c_iter)->get_value();
356 }
357
358 indent_down();
359 f_types_ << endl << "};" << endl << "typedef enum _" << this->nspace << name << " "
360 << this->nspace << name << ";" << endl << endl;
361
362 f_types_ << "/* return the name of the constant */" << endl;
363 f_types_ << "const char *" << endl;
364 f_types_ << "toString_" << name << "(int value); " << endl << endl;
365 ;
366 f_types_impl_ << "/* return the name of the constant */" << endl;
367 f_types_impl_ << "const char *" << endl;
368 f_types_impl_ << "toString_" << name << "(int value) " << endl;
369 f_types_impl_ << "{" << endl;
370 f_types_impl_ << " static __thread char buf[16] = {0};" << endl;
371 f_types_impl_ << " switch(value) {" << endl;
372 std::set<int> done;
373 for (c_iter = constants.begin(); c_iter != constants.end(); ++c_iter) {
374 int value = (*c_iter)->get_value();
375 // Skipping duplicate value
376 if (done.find(value) == done.end()) {
377 done.insert(value);
378 f_types_impl_ << " case " << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name()
379 << ":"
380 << "return \"" << this->nspace_uc << name_uc << "_" << (*c_iter)->get_name()
381 << "\";" << endl;
382 }
383 }
384 f_types_impl_ << " default: g_snprintf(buf, 16, \"%d\", value); return buf;" << endl;
385 f_types_impl_ << " }" << endl;
386 f_types_impl_ << "}" << endl << endl;
387 }
388
389 /**
390 * Generates Thrift constants in C code.
391 */
392 void t_c_glib_generator::generate_consts(vector<t_const*> consts) {
393 f_types_ << "/* constants */" << endl;
394 f_types_impl_ << "/* constants */" << endl;
395
396 vector<t_const*>::iterator c_iter;
397 for (c_iter = consts.begin(); c_iter != consts.end(); ++c_iter) {
398 string name = (*c_iter)->get_name();
399 string name_uc = to_upper_case(name);
400 string name_lc = to_lower_case(name);
401 t_type* type = (*c_iter)->get_type();
402 t_const_value* value = (*c_iter)->get_value();
403
404 if (is_complex_type(type)) {
405 f_types_ << type_name(type) << indent() << this->nspace_lc << name_lc
406 << "_constant();" << endl;
407 }
408
409 f_types_ << indent() << "#define " << this->nspace_uc << name_uc << " "
410 << constant_value(name_lc, type, value) << endl;
411
412 generate_const_initializer(name_lc, type, value, true);
413 }
414
415 f_types_ << endl;
416 f_types_impl_ << endl;
417 }
418
419 /**
420 * Generate Thrift structs in C code, as GObjects. Example:
421 *
422 * Thrift:
423 * struct Bonk
424 * {
425 * 1: string message,
426 * 2: i32 type
427 * }
428 *
429 * C GObject instance header:
430 * struct _ThriftBonk
431 * {
432 * GObject parent;
433 *
434 * gchar * message;
435 * gint32 type;
436 * };
437 * typedef struct _ThriftBonk ThriftBonk
438 * // ... additional GObject boilerplate ...
439 */
440 void t_c_glib_generator::generate_struct(t_struct* tstruct) {
441 f_types_ << "/* struct " << tstruct->get_name() << " */" << endl;
442 generate_object(tstruct);
443 }
444
445 /**
446 * Generate C code to represent Thrift services. Creates a new GObject
447 * which can be used to access the service.
448 */
449 void t_c_glib_generator::generate_service(t_service* tservice) {
450 string svcname_u = initial_caps_to_underscores(tservice->get_name());
451 string svcname_uc = this->nspace_uc + to_upper_case(svcname_u);
452 string filename = this->nspace_lc + to_lower_case(svcname_u);
453
454 // make output files
455 string f_header_name = get_out_dir() + filename + ".h";
456 f_header_.open(f_header_name.c_str());
457
458 string program_name_u = initial_caps_to_underscores(program_name_);
459 string program_name_lc = to_lower_case(program_name_u);
460
461 // add header file boilerplate
462 f_header_ << autogen_comment();
463
464 // add an inclusion guard
465 f_header_ << "#ifndef " << svcname_uc << "_H" << endl << "#define " << svcname_uc << "_H" << endl
466 << endl;
467
468 // add standard includes
469 f_header_ << "#include <thrift/c_glib/processor/thrift_dispatch_processor.h>" << endl << endl;
470 f_header_ << "#include \"" << this->nspace_lc << program_name_lc << "_types.h\"" << endl;
471
472 // if we are inheriting from another service, include its header
473 t_service* extends_service = tservice->get_extends();
474 if (extends_service != NULL) {
475 f_header_ << "#include \"" << this->nspace_lc
476 << to_lower_case(initial_caps_to_underscores(extends_service->get_name())) << ".h\""
477 << endl;
478 }
479 f_header_ << endl;
480
481 // create the service implementation
482 string f_service_name = get_out_dir() + filename + ".c";
483 f_service_.open(f_service_name.c_str());
484
485 // add the boilerplace header
486 f_service_ << autogen_comment();
487
488 // include the headers
489 f_service_ << "#include <string.h>" << endl << "#include <thrift/c_glib/thrift.h>" << endl
490 << "#include <thrift/c_glib/thrift_application_exception.h>" << endl << "#include \""
491 << filename << ".h\"" << endl << endl;
492
493 // generate the service-helper classes
494 generate_service_helpers(tservice);
495
496 // generate the client objects
497 generate_service_client(tservice);
498
499 // generate the server objects
500 generate_service_server(tservice);
501
502 // end the header inclusion guard
503 f_header_ << "#endif /* " << svcname_uc << "_H */" << endl;
504
505 // close the files
506 f_service_.close();
507 f_header_.close();
508 }
509
510 /**
511 *
512 */
513 void t_c_glib_generator::generate_xception(t_struct* tstruct) {
514 string name = tstruct->get_name();
515 string name_u = initial_caps_to_underscores(name);
516 string name_lc = to_lower_case(name_u);
517 string name_uc = to_upper_case(name_u);
518
519 generate_object(tstruct);
520
521 f_types_ << "/* exception */" << endl
522 << "typedef enum" << endl
523 << "{" << endl;
524 indent_up();
525 f_types_ << indent() << this->nspace_uc << name_uc << "_ERROR_CODE" << endl;
526 indent_down();
527 f_types_ << "} " << this->nspace << name << "Error;" << endl
528 << endl
529 << "GQuark " << this->nspace_lc << name_lc
530 << "_error_quark (void);" << endl
531 << "#define " << this->nspace_uc << name_uc << "_ERROR ("
532 << this->nspace_lc << name_lc << "_error_quark())" << endl
533 << endl
534 << endl;
535
536 f_types_impl_ << "/* define the GError domain for exceptions */" << endl << "#define "
537 << this->nspace_uc << name_uc << "_ERROR_DOMAIN \"" << this->nspace_lc << name_lc
538 << "_error_quark\"" << endl << "GQuark" << endl << this->nspace_lc << name_lc
539 << "_error_quark (void)" << endl << "{" << endl
540 << " return g_quark_from_static_string (" << this->nspace_uc << name_uc
541 << "_ERROR_DOMAIN);" << endl << "}" << endl << endl;
542 }
543
544 /********************
545 * HELPER FUNCTIONS *
546 ********************/
547
548 /**
549 * Returns true if ttype is not a primitive.
550 */
551 bool t_c_glib_generator::is_complex_type(t_type* ttype) {
552 ttype = get_true_type(ttype);
553
554 return ttype->is_container() || ttype->is_struct() || ttype->is_xception();
555 }
556
557 bool t_c_glib_generator::is_numeric(t_type* ttype) {
558 return ttype->is_enum() || (ttype->is_base_type() && !ttype->is_string());
559 }
560
561 /**
562 * Maps a Thrift t_type to a C type.
563 */
564 string t_c_glib_generator::type_name(t_type* ttype, bool in_typedef, bool is_const) {
565 if (ttype->is_base_type()) {
566 string bname = base_type_name(ttype);
567
568 if (is_const) {
569 return "const " + bname;
570 } else {
571 return bname;
572 }
573 }
574
575 if (ttype->is_container()) {
576 string cname;
577
578 t_container* tcontainer = (t_container*)ttype;
579 if (tcontainer->has_cpp_name()) {
580 cname = tcontainer->get_cpp_name();
581 } else if (ttype->is_map()) {
582 cname = "GHashTable";
583 } else if (ttype->is_set()) {
584 // since a set requires unique elements, use a GHashTable, and
585 // populate the keys and values with the same data, using keys for
586 // the actual writes and reads.
587 // TODO: discuss whether or not to implement TSet, THashSet or GHashSet
588 cname = "GHashTable";
589 } else if (ttype->is_list()) {
590 t_type* etype = get_true_type(((t_list*)ttype)->get_elem_type());
591 if (etype->is_void()) {
592 throw std::runtime_error("compiler error: list element type cannot be void");
593 }
594 // TODO: investigate other implementations besides GPtrArray
595 cname = is_numeric(etype) ? "GArray" : "GPtrArray";
596 }
597
598 /* Omit the dereference operator if we are aliasing this type within a
599 typedef, to allow the type to be used more naturally in client code;
600 otherwise, include it */
601 if (!in_typedef) {
602 cname += " *";
603 }
604
605 if (is_const) {
606 return "const " + cname;
607 } else {
608 return cname;
609 }
610 }
611
612 // check for a namespace
613 t_program* tprogram = ttype->get_program();
614 string pname = (tprogram ? tprogram->get_namespace("c_glib") : "") + ttype->get_name();
615
616 if (is_complex_type(ttype)) {
617 pname += " *";
618 }
619
620 if (is_const) {
621 return "const " + pname;
622 } else {
623 return pname;
624 }
625 }
626
627 /**
628 * Maps a Thrift primitive to the type needed to hold its value when used as an
629 * object property.
630 *
631 * This method is needed because all integer properties of width less than 64
632 * bits map to the same type, gint, as opposed to their width-specific type
633 * (gint8, gint16 or gint32).
634 */
635 string t_c_glib_generator::property_type_name(t_type* ttype, bool in_typedef, bool is_const) {
636 string result;
637
638 if (ttype->is_base_type()) {
639 switch (((t_base_type*)ttype)->get_base()) {
640 case t_base_type::TYPE_I8:
641 case t_base_type::TYPE_I16:
642 case t_base_type::TYPE_I32:
643 if (is_const) {
644 result = "const gint";
645 } else {
646 result = "gint";
647 }
648 break;
649
650 default:
651 result = type_name(ttype, in_typedef, is_const);
652 }
653 } else {
654 result = type_name(ttype, in_typedef, is_const);
655 }
656
657 return result;
658 }
659
660 /**
661 * Maps a Thrift primitive to a C primitive.
662 */
663 string t_c_glib_generator::base_type_name(t_type* type) {
664 if (type->is_enum()) {
665 return type_name(type);
666 }
667 if (!type->is_base_type()) {
668 throw std::invalid_argument("Only base types are suppported.");
669 }
670 t_base_type* base_type = reinterpret_cast<t_base_type*>(type);
671 t_base_type::t_base tbase = base_type->get_base();
672 switch (tbase) {
673 case t_base_type::TYPE_VOID:
674 return "void";
675 case t_base_type::TYPE_STRING:
676 if (base_type->is_binary()) {
677 return "GByteArray *";
678 } else {
679 return "gchar *";
680 }
681 case t_base_type::TYPE_BOOL:
682 return "gboolean";
683 case t_base_type::TYPE_I8:
684 return "gint8";
685 case t_base_type::TYPE_I16:
686 return "gint16";
687 case t_base_type::TYPE_I32:
688 return "gint32";
689 case t_base_type::TYPE_I64:
690 return "gint64";
691 case t_base_type::TYPE_DOUBLE:
692 return "gdouble";
693 default:
694 throw std::logic_error("compiler error: no C base type name for base type "
695 + t_base_type::t_base_name(tbase));
696 }
697 }
698
699 /**
700 * Returns a member of the ThriftType C enumeration in thrift_protocol.h
701 * for a Thrift type.
702 */
703 string t_c_glib_generator::type_to_enum(t_type* type) {
704 type = get_true_type(type);
705
706 if (type->is_base_type()) {
707 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
708
709 switch (tbase) {
710 case t_base_type::TYPE_VOID:
711 throw "NO T_VOID CONSTRUCT";
712 case t_base_type::TYPE_STRING:
713 return "T_STRING";
714 case t_base_type::TYPE_BOOL:
715 return "T_BOOL";
716 case t_base_type::TYPE_I8:
717 return "T_BYTE";
718 case t_base_type::TYPE_I16:
719 return "T_I16";
720 case t_base_type::TYPE_I32:
721 return "T_I32";
722 case t_base_type::TYPE_I64:
723 return "T_I64";
724 case t_base_type::TYPE_DOUBLE:
725 return "T_DOUBLE";
726 }
727 } else if (type->is_enum()) {
728 return "T_I32";
729 } else if (type->is_struct()) {
730 return "T_STRUCT";
731 } else if (type->is_xception()) {
732 return "T_STRUCT";
733 } else if (type->is_map()) {
734 return "T_MAP";
735 } else if (type->is_set()) {
736 return "T_SET";
737 } else if (type->is_list()) {
738 return "T_LIST";
739 }
740
741 throw "INVALID TYPE IN type_to_enum: " + type->get_name();
742 }
743
744 /**
745 * Returns a Thrift constant formatted as a literal for inclusion in C code.
746 */
747 string t_c_glib_generator::constant_literal(t_type* type, t_const_value* value) {
748 ostringstream render;
749
750 if (type->is_base_type()) {
751 /* primitives */
752 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
753
754 switch (tbase) {
755 case t_base_type::TYPE_STRING:
756 render << "\"" + value->get_string() + "\"";
757 break;
758 case t_base_type::TYPE_BOOL:
759 render << ((value->get_integer() != 0) ? "TRUE" : "FALSE");
760 break;
761 case t_base_type::TYPE_I8:
762 case t_base_type::TYPE_I16:
763 case t_base_type::TYPE_I32:
764 case t_base_type::TYPE_I64:
765 render << value->get_integer();
766 break;
767 case t_base_type::TYPE_DOUBLE:
768 render << value->get_double();
769 break;
770 default:
771 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
772 }
773 } else {
774 t_const_value::t_const_value_type value_type = value->get_type();
775
776 switch (value_type) {
777 case t_const_value::CV_IDENTIFIER:
778 render << value->get_integer();
779 break;
780 case t_const_value::CV_LIST:
781 render << "{ ";
782 {
783 t_type* elem_type = ((t_list*)type)->get_elem_type();
784 const vector<t_const_value*>& list = value->get_list();
785 vector<t_const_value*>::const_iterator list_iter;
786
787 if (list.size() > 0) {
788 list_iter = list.begin();
789 render << constant_literal(elem_type, *list_iter);
790
791 while (++list_iter != list.end()) {
792 render << ", " << constant_literal(elem_type, *list_iter);
793 }
794 }
795 }
796 render << " }";
797 break;
798 case t_const_value::CV_MAP:
799 default:
800 render << "NULL /* not supported */";
801 }
802 }
803
804 return render.str();
805 }
806
807 /**
808 * Returns C code that represents a Thrift constant.
809 */
810 string t_c_glib_generator::constant_value(string name, t_type* type, t_const_value* value) {
811 ostringstream render;
812
813 if (type->is_base_type()) {
814 /* primitives */
815 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
816 switch (tbase) {
817 case t_base_type::TYPE_STRING:
818 render << "g_strdup (\"" + value->get_string() + "\")";
819 break;
820 case t_base_type::TYPE_BOOL:
821 render << ((value->get_integer() != 0) ? 1 : 0);
822 break;
823 case t_base_type::TYPE_I8:
824 case t_base_type::TYPE_I16:
825 case t_base_type::TYPE_I32:
826 render << value->get_integer();
827 break;
828 case t_base_type::TYPE_I64:
829 render << "G_GINT64_CONSTANT (" << value->get_integer() << ")";
830 break;
831 case t_base_type::TYPE_DOUBLE:
832 if (value->get_type() == t_const_value::CV_INTEGER) {
833 render << value->get_integer();
834 } else {
835 render << value->get_double();
836 }
837 break;
838 default:
839 throw "compiler error: no const of base type " + t_base_type::t_base_name(tbase);
840 }
841 } else if (type->is_enum()) {
842 render << "(" << type_name(type) << ")" << value->get_integer();
843 } else if (is_complex_type(type)) {
844 render << "(" << this->nspace_lc << to_lower_case(name) << "_constant())";
845 } else {
846 render << "NULL /* not supported */";
847 }
848
849 return render.str();
850 }
851
852 /**
853 * Renders a function signature of the form 'type name(args)'
854 *
855 * @param tfunction Function definition
856 * @return String of rendered function definition
857 */
858 string t_c_glib_generator::function_signature(t_function* tfunction) {
859 t_type* ttype = tfunction->get_returntype();
860 t_struct* arglist = tfunction->get_arglist();
861 t_struct* xlist = tfunction->get_xceptions();
862 string fname = initial_caps_to_underscores(tfunction->get_name());
863
864 bool has_return = !ttype->is_void();
865 bool has_args = arglist->get_members().size() == 0;
866 bool has_xceptions = xlist->get_members().size() == 0;
867 return "gboolean " + this->nspace_lc + fname + " (" + this->nspace + service_name_ + "If * iface"
868 + (has_return ? ", " + type_name(ttype) + "* _return" : "")
869 + (has_args ? "" : (", " + argument_list(arglist)))
870 + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError ** error)";
871 }
872
873 /**
874 * Renders a field list
875 *
876 * @param tstruct The struct definition
877 * @return Comma sepearated list of all field names in that struct
878 */
879 string t_c_glib_generator::argument_list(t_struct* tstruct) {
880 string result = "";
881
882 const vector<t_field*>& fields = tstruct->get_members();
883 vector<t_field*>::const_iterator f_iter;
884 bool first = true;
885 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
886 if (first) {
887 first = false;
888 } else {
889 result += ", ";
890 }
891 result += type_name((*f_iter)->get_type(), false, true) + " " + (*f_iter)->get_name();
892 }
893 return result;
894 }
895
896 /**
897 * Renders mutable exception lists
898 *
899 * @param tstruct The struct definition
900 * @return Comma sepearated list of all field names in that struct
901 */
902 string t_c_glib_generator::xception_list(t_struct* tstruct) {
903 string result = "";
904
905 const vector<t_field*>& fields = tstruct->get_members();
906 vector<t_field*>::const_iterator f_iter;
907 bool first = true;
908 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
909 if (first) {
910 first = false;
911 } else {
912 result += ", ";
913 }
914 result += type_name((*f_iter)->get_type(), false, false) + "* " + (*f_iter)->get_name();
915 }
916 return result;
917 }
918
919 /**
920 * Declares a field, including any necessary initialization.
921 */
922 string t_c_glib_generator::declare_field(t_field* tfield,
923 bool init,
924 bool pointer,
925 bool constant,
926 bool reference) {
927 string result = "";
928 if (constant) {
929 result += "const ";
930 }
931 result += type_name(tfield->get_type());
932 if (pointer) {
933 result += "*";
934 }
935 if (reference) {
936 result += "*";
937 }
938 result += " " + tfield->get_name();
939 if (init) {
940 t_type* type = get_true_type(tfield->get_type());
941
942 if (type->is_base_type()) {
943 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
944 switch (tbase) {
945 case t_base_type::TYPE_VOID:
946 break;
947 case t_base_type::TYPE_BOOL:
948 case t_base_type::TYPE_I8:
949 case t_base_type::TYPE_I16:
950 case t_base_type::TYPE_I32:
951 case t_base_type::TYPE_I64:
952 result += " = 0";
953 break;
954 case t_base_type::TYPE_DOUBLE:
955 result += " = (gdouble) 0";
956 break;
957 case t_base_type::TYPE_STRING:
958 result += " = NULL";
959 break;
960 default:
961 throw "compiler error: no C intializer for base type " + t_base_type::t_base_name(tbase);
962 }
963 } else if (type->is_enum()) {
964 result += " = (" + type_name(type) + ") 0";
965 } else if (type->is_struct() || type->is_container()) {
966 result += " = NULL";
967 }
968 }
969
970 if (!reference) {
971 result += ";";
972 }
973
974 return result;
975 }
976
977 string t_c_glib_generator::constant_value_with_storage(string fname,
978 t_type* etype,
979 t_const_value* value) {
980 ostringstream render;
981 if (is_numeric(etype)) {
982 render << " " << type_name(etype) << " *" << fname << " = "
983 << "g_new (" << base_type_name(etype) << ", 1);" << endl
984 << " *" << fname << " = " << constant_value(fname, (t_type*)etype, value) << ";"
985 << endl;
986 } else {
987 render << " " << type_name(etype) << " " << fname << " = "
988 << constant_value(fname, (t_type*)etype, value) << ";" << endl;
989 }
990 return render.str();
991 }
992
993 /**
994 * Generates C code that initializes complex constants.
995 */
996 void t_c_glib_generator::generate_const_initializer(string name,
997 t_type* type,
998 t_const_value* value,
999 bool top_level) {
1000 string name_u = initial_caps_to_underscores(name);
1001 string name_lc = to_lower_case(name_u);
1002 string type_u = initial_caps_to_underscores(type->get_name());
1003 string type_uc = to_upper_case(type_u);
1004 string maybe_static = top_level ? "" : "static ";
1005
1006 if (type->is_struct() || type->is_xception()) {
1007 const vector<t_field*>& fields = ((t_struct*)type)->get_members();
1008 vector<t_field*>::const_iterator f_iter;
1009 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
1010 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
1011 ostringstream initializers;
1012
1013 // initialize any constants that may be referenced by this initializer
1014 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1015 t_type* field_type = NULL;
1016 string field_name = "";
1017
1018 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1019 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
1020 field_type = (*f_iter)->get_type();
1021 field_name = (*f_iter)->get_name();
1022 break;
1023 }
1024 }
1025 if (field_type == NULL) {
1026 throw "type error: " + type->get_name() + " has no field "
1027 + v_iter->first->get_string();
1028 }
1029 field_name = tmp(field_name);
1030
1031 generate_const_initializer(name + "_constant_" + field_name,
1032 field_type,
1033 v_iter->second);
1034 initializers << " constant->" << v_iter->first->get_string() << " = "
1035 << constant_value(name + "_constant_" + field_name,
1036 field_type,
1037 v_iter->second) << ";" << endl
1038 << " constant->__isset_" << v_iter->first->get_string()
1039 << " = TRUE;" << endl;
1040 }
1041
1042 // implement the initializer
1043 f_types_impl_ << maybe_static << this->nspace << type->get_name() << " *"
1044 << endl
1045 << this->nspace_lc << name_lc << "_constant (void)" << endl;
1046 scope_up(f_types_impl_);
1047 f_types_impl_ << indent() << "static " << this->nspace << type->get_name()
1048 << " *constant = NULL;" << endl
1049 << indent() << "if (constant == NULL)" << endl;
1050 scope_up(f_types_impl_);
1051 f_types_impl_ << indent() << "constant = g_object_new (" << this->nspace_uc
1052 << "TYPE_" << type_uc << ", NULL);" << endl
1053 << initializers.str();
1054 scope_down(f_types_impl_);
1055
1056 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1057 t_type* field_type = NULL;
1058 string field_name = "";
1059
1060 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
1061 if ((*f_iter)->get_name() == v_iter->first->get_string()) {
1062 field_type = (*f_iter)->get_type();
1063 field_name = (*f_iter)->get_name();
1064 break;
1065 }
1066 }
1067 if (field_type == NULL) {
1068 throw "type error: " + type->get_name() + " has no field "
1069 + v_iter->first->get_string();
1070 }
1071 field_name = tmp(field_name);
1072 }
1073
1074 f_types_impl_ << indent() << "return constant;" << endl;
1075 scope_down(f_types_impl_);
1076 f_types_impl_ << endl;
1077 } else if (type->is_list()) {
1078 string list_type = "GPtrArray *";
1079 string free_func
1080 = generate_free_func_from_type(reinterpret_cast<t_list*>(type)->get_elem_type());
1081 string list_initializer = "g_ptr_array_new_with_free_func (" + free_func + ");";
1082 string list_appender = "g_ptr_array_add";
1083 bool list_variable = false;
1084
1085 t_type* etype = ((t_list*)type)->get_elem_type();
1086 const vector<t_const_value*>& val = value->get_list();
1087 vector<t_const_value*>::const_iterator v_iter;
1088 ostringstream initializers;
1089 ostringstream appenders;
1090
1091 list_initializer = generate_new_array_from_type(etype);
1092 if (etype->is_base_type()) {
1093 t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
1094 switch (tbase) {
1095 case t_base_type::TYPE_VOID:
1096 throw "compiler error: cannot determine array type";
1097 case t_base_type::TYPE_BOOL:
1098 case t_base_type::TYPE_I8:
1099 case t_base_type::TYPE_I16:
1100 case t_base_type::TYPE_I32:
1101 case t_base_type::TYPE_I64:
1102 case t_base_type::TYPE_DOUBLE:
1103 list_type = "GArray *";
1104 list_appender = "g_array_append_val";
1105 list_variable = true;
1106 break;
1107 case t_base_type::TYPE_STRING:
1108 break;
1109 default:
1110 throw "compiler error: no array info for type";
1111 }
1112 } else if (etype->is_enum()) {
1113 list_type = "GArray *";
1114 list_appender = "g_array_append_val";
1115 list_variable = true;
1116 }
1117
1118 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1119 string fname = tmp(name);
1120
1121 generate_const_initializer(fname, etype, (*v_iter));
1122 if (list_variable) {
1123 initializers << " " << type_name(etype) << " " << fname << " = "
1124 << constant_value(fname, (t_type*)etype, (*v_iter)) << ";"
1125 << endl;
1126 appenders << " " << list_appender << "(constant, " << fname << ");"
1127 << endl;
1128 } else {
1129 appenders << " " << list_appender << "(constant, "
1130 << constant_value(fname, (t_type*)etype, (*v_iter)) << ");"
1131 << endl;
1132 }
1133 }
1134
1135 f_types_impl_ << maybe_static << list_type << endl
1136 << this->nspace_lc << name_lc << "_constant (void)" << endl;
1137 scope_up(f_types_impl_);
1138 f_types_impl_ << indent() << "static " << list_type << " constant = NULL;"
1139 << endl
1140 << indent() << "if (constant == NULL)" << endl;
1141 scope_up(f_types_impl_);
1142 if (!initializers.str().empty()) {
1143 f_types_impl_ << initializers.str()
1144 << endl;
1145 }
1146 f_types_impl_ << indent() << "constant = " << list_initializer << endl
1147 << appenders.str();
1148 scope_down(f_types_impl_);
1149 f_types_impl_ << indent() << "return constant;" << endl;
1150 scope_down(f_types_impl_);
1151 f_types_impl_ << endl;
1152 } else if (type->is_set()) {
1153 t_type* etype = ((t_set*)type)->get_elem_type();
1154 const vector<t_const_value*>& val = value->get_list();
1155 vector<t_const_value*>::const_iterator v_iter;
1156 ostringstream initializers;
1157 ostringstream appenders;
1158
1159 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1160 string fname = tmp(name);
1161 string ptr = is_numeric(etype) ? "*" : "";
1162 generate_const_initializer(fname, etype, (*v_iter));
1163 initializers << constant_value_with_storage(fname, (t_type*)etype, *v_iter);
1164 appenders << " g_hash_table_insert (constant, " << fname << ", 0);" << endl;
1165 }
1166
1167 f_types_impl_ << maybe_static << "GHashTable *" << endl
1168 << this->nspace_lc << name_lc << "_constant (void)" << endl;
1169 scope_up(f_types_impl_);
1170 f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl
1171 << indent() << "if (constant == NULL)" << endl;
1172 scope_up(f_types_impl_);
1173 f_types_impl_ << initializers.str() << endl
1174 << indent() << "constant = " << generate_new_hash_from_type(etype, NULL) << endl
1175 << appenders.str();
1176 scope_down(f_types_impl_);
1177 f_types_impl_ << indent() << "return constant;" << endl;
1178 scope_down(f_types_impl_);
1179 f_types_impl_ << endl;
1180 } else if (type->is_map()) {
1181 t_type* ktype = ((t_map*)type)->get_key_type();
1182 t_type* vtype = ((t_map*)type)->get_val_type();
1183 const map<t_const_value*, t_const_value*, t_const_value::value_compare>& val = value->get_map();
1184 map<t_const_value*, t_const_value*, t_const_value::value_compare>::const_iterator v_iter;
1185 ostringstream initializers;
1186 ostringstream appenders;
1187
1188 for (v_iter = val.begin(); v_iter != val.end(); ++v_iter) {
1189 string fname = tmp(name);
1190 string kname = fname + "key";
1191 string vname = fname + "val";
1192 generate_const_initializer(kname, ktype, v_iter->first);
1193 generate_const_initializer(vname, vtype, v_iter->second);
1194
1195 initializers << constant_value_with_storage(kname, (t_type*)ktype, v_iter->first);
1196 initializers << constant_value_with_storage(vname, (t_type*)vtype, v_iter->second);
1197 appenders << " g_hash_table_insert (constant, " << kname << ", " << vname << ");" << endl;
1198 }
1199
1200 f_types_impl_ << maybe_static << "GHashTable *" << endl
1201 << this->nspace_lc << name_lc << "_constant (void)" << endl;
1202 scope_up(f_types_impl_);
1203 f_types_impl_ << indent() << "static GHashTable *constant = NULL;" << endl
1204 << indent() << "if (constant == NULL)" << endl;
1205 scope_up(f_types_impl_);
1206 f_types_impl_ << initializers.str() << endl
1207 << indent() << "constant = " << generate_new_hash_from_type(ktype, vtype) << endl
1208 << appenders.str();
1209 scope_down(f_types_impl_);
1210 f_types_impl_ << indent() << "return constant;" << endl;
1211 scope_down(f_types_impl_);
1212 f_types_impl_ << endl;
1213 }
1214 }
1215
1216 /**
1217 * Generates helper classes for a service, consisting of a ThriftStruct subclass
1218 * for the arguments to and the result from each method.
1219 *
1220 * @param tservice The service for which to generate helper classes
1221 */
1222 void t_c_glib_generator::generate_service_helpers(t_service* tservice) {
1223 vector<t_function*> functions = tservice->get_functions();
1224 vector<t_function*>::iterator function_iter;
1225
1226 // Iterate through the service's methods
1227 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
1228 string function_name = (*function_iter)->get_name();
1229 t_struct* arg_list = (*function_iter)->get_arglist();
1230 string arg_list_name_orig = arg_list->get_name();
1231
1232 // Generate the arguments class
1233 arg_list->set_name(tservice->get_name() + underscores_to_initial_caps(function_name) + "Args");
1234 generate_struct(arg_list);
1235
1236 arg_list->set_name(arg_list_name_orig);
1237
1238 // Generate the result class
1239 if (!(*function_iter)->is_oneway()) {
1240 t_struct result(program_,
1241 tservice->get_name() + underscores_to_initial_caps(function_name) + "Result");
1242 t_field success((*function_iter)->get_returntype(), "success", 0);
1243 success.set_req(t_field::T_OPTIONAL);
1244 if (!(*function_iter)->get_returntype()->is_void()) {
1245 result.append(&success);
1246 }
1247
1248 t_struct* xs = (*function_iter)->get_xceptions();
1249 const vector<t_field*>& fields = xs->get_members();
1250 vector<t_field*>::const_iterator field_iter;
1251 for (field_iter = fields.begin(); field_iter != fields.end(); ++field_iter) {
1252 (*field_iter)->set_req(t_field::T_OPTIONAL);
1253 result.append(*field_iter);
1254 }
1255
1256 generate_struct(&result);
1257 }
1258 }
1259 }
1260
1261 /**
1262 * Generates C code that represents a Thrift service client.
1263 */
1264 void t_c_glib_generator::generate_service_client(t_service* tservice) {
1265 /* get some C friendly service names */
1266 string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
1267 string service_name_uc = to_upper_case(service_name_lc);
1268
1269 string parent_service_name;
1270 string parent_service_name_lc;
1271 string parent_service_name_uc;
1272
1273 string parent_class_name = "GObject";
1274 string parent_type_name = "G_TYPE_OBJECT";
1275
1276 // The service this service extends, or NULL if it extends no
1277 // service
1278 t_service* extends_service = tservice->get_extends();
1279 if (extends_service) {
1280 // The name of the parent service
1281 parent_service_name = extends_service->get_name();
1282 parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
1283 parent_service_name_uc = to_upper_case(parent_service_name_lc);
1284
1285 // The names of the client class' parent class and type
1286 parent_class_name = this->nspace + parent_service_name + "Client";
1287 parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_CLIENT";
1288 }
1289
1290 // The base service (the topmost in the "extends" hierarchy), on
1291 // whose client class the "input_protocol" and "output_protocol"
1292 // properties are defined
1293 t_service* base_service = tservice;
1294 while (base_service->get_extends()) {
1295 base_service = base_service->get_extends();
1296 }
1297
1298 string base_service_name = base_service->get_name();
1299 string base_service_name_lc = to_lower_case(initial_caps_to_underscores(base_service_name));
1300 string base_service_name_uc = to_upper_case(base_service_name_lc);
1301
1302 // Generate the client interface dummy object in the header.
1303 f_header_ << "/* " << service_name_ << " service interface */" << endl << "typedef struct _"
1304 << this->nspace << service_name_ << "If " << this->nspace << service_name_ << "If; "
1305 << " /* dummy object */" << endl << endl;
1306
1307 // Generate the client interface object in the header.
1308 f_header_ << "struct _" << this->nspace << service_name_ << "IfInterface" << endl << "{" << endl
1309 << " GTypeInterface parent;" << endl << endl;
1310
1311 /* write out the functions for this interface */
1312 indent_up();
1313 vector<t_function*> functions = tservice->get_functions();
1314 vector<t_function*>::const_iterator f_iter;
1315 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1316 /* make the function name C friendly */
1317 string funname = initial_caps_to_underscores((*f_iter)->get_name());
1318 t_type* ttype = (*f_iter)->get_returntype();
1319 t_struct* arglist = (*f_iter)->get_arglist();
1320 t_struct* xlist = (*f_iter)->get_xceptions();
1321 bool has_return = !ttype->is_void();
1322 bool has_args = arglist->get_members().size() == 0;
1323 bool has_xceptions = xlist->get_members().size() == 0;
1324
1325 string params = "(" + this->nspace + service_name_ + "If *iface"
1326 + (has_return ? ", " + type_name(ttype) + "* _return" : "")
1327 + (has_args ? "" : (", " + argument_list(arglist)))
1328 + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
1329
1330 indent(f_header_) << "gboolean (*" << funname << ") " << params << ";" << endl;
1331 }
1332 indent_down();
1333
1334 f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "IfInterface "
1335 << this->nspace << service_name_ << "IfInterface;" << endl << endl;
1336
1337 // generate all the interface boilerplate
1338 f_header_ << "GType " << this->nspace_lc << service_name_lc << "_if_get_type (void);" << endl
1339 << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_IF "
1340 << "(" << this->nspace_lc << service_name_lc << "_if_get_type())" << endl << "#define "
1341 << this->nspace_uc << service_name_uc << "_IF(obj) "
1342 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
1343 << service_name_uc << "_IF, " << this->nspace << service_name_ << "If))" << endl
1344 << "#define " << this->nspace_uc << "IS_" << service_name_uc << "_IF(obj) "
1345 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
1346 << service_name_uc << "_IF))" << endl << "#define " << this->nspace_uc
1347 << service_name_uc << "_IF_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), "
1348 << this->nspace_uc << "TYPE_" << service_name_uc << "_IF, " << this->nspace
1349 << service_name_ << "IfInterface))" << endl << endl;
1350
1351 // write out all the interface function prototypes
1352 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1353 /* make the function name C friendly */
1354 string funname = initial_caps_to_underscores((*f_iter)->get_name());
1355 t_type* ttype = (*f_iter)->get_returntype();
1356 t_struct* arglist = (*f_iter)->get_arglist();
1357 t_struct* xlist = (*f_iter)->get_xceptions();
1358 bool has_return = !ttype->is_void();
1359 bool has_args = arglist->get_members().size() == 0;
1360 bool has_xceptions = xlist->get_members().size() == 0;
1361
1362 string params = "(" + this->nspace + service_name_ + "If *iface"
1363 + (has_return ? ", " + type_name(ttype) + "* _return" : "")
1364 + (has_args ? "" : (", " + argument_list(arglist)))
1365 + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
1366
1367 f_header_ << "gboolean " << this->nspace_lc << service_name_lc << "_if_" << funname << " "
1368 << params << ";" << endl;
1369 }
1370 f_header_ << endl;
1371
1372 // Generate the client object instance definition in the header.
1373 f_header_ << "/* " << service_name_ << " service client */" << endl << "struct _" << this->nspace
1374 << service_name_ << "Client" << endl << "{" << endl << " " << parent_class_name
1375 << " parent;" << endl;
1376 if (!extends_service) {
1377 // Define "input_protocol" and "output_protocol" properties only
1378 // for base services; child service-client classes will inherit
1379 // these
1380 f_header_ << endl << " ThriftProtocol *input_protocol;" << endl
1381 << " ThriftProtocol *output_protocol;" << endl;
1382 }
1383 f_header_ << "};" << endl << "typedef struct _" << this->nspace << service_name_ << "Client "
1384 << this->nspace << service_name_ << "Client;" << endl << endl;
1385
1386 // Generate the class definition in the header.
1387 f_header_ << "struct _" << this->nspace << service_name_ << "ClientClass" << endl << "{" << endl
1388 << " " << parent_class_name << "Class parent;" << endl << "};" << endl
1389 << "typedef struct _" << this->nspace << service_name_ << "ClientClass " << this->nspace
1390 << service_name_ << "ClientClass;" << endl << endl;
1391
1392 // Create all the GObject boilerplate
1393 f_header_ << "GType " << this->nspace_lc << service_name_lc << "_client_get_type (void);" << endl
1394 << "#define " << this->nspace_uc << "TYPE_" << service_name_uc << "_CLIENT "
1395 << "(" << this->nspace_lc << service_name_lc << "_client_get_type())" << endl
1396 << "#define " << this->nspace_uc << service_name_uc << "_CLIENT(obj) "
1397 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
1398 << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "Client))" << endl
1399 << "#define " << this->nspace_uc << service_name_uc << "_CLIENT_CLASS(c) "
1400 << "(G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
1401 << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))" << endl << "#define "
1402 << this->nspace_uc << service_name_uc << "_IS_CLIENT(obj) "
1403 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
1404 << service_name_uc << "_CLIENT))" << endl << "#define " << this->nspace_uc
1405 << service_name_uc << "_IS_CLIENT_CLASS(c) "
1406 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
1407 << "_CLIENT))" << endl << "#define " << this->nspace_uc << service_name_uc
1408 << "_CLIENT_GET_CLASS(obj) "
1409 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
1410 << service_name_uc << "_CLIENT, " << this->nspace << service_name_ << "ClientClass))"
1411 << endl << endl;
1412
1413 /* write out the function prototypes */
1414 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1415 /* make the function name C friendly */
1416 string funname = to_lower_case(initial_caps_to_underscores((*f_iter)->get_name()));
1417
1418 t_function service_function((*f_iter)->get_returntype(),
1419 service_name_lc + string("_client_") + funname,
1420 (*f_iter)->get_arglist(),
1421 (*f_iter)->get_xceptions());
1422 indent(f_header_) << function_signature(&service_function) << ";" << endl;
1423
1424 t_function send_function(g_type_void,
1425 service_name_lc + string("_client_send_") + funname,
1426 (*f_iter)->get_arglist());
1427 indent(f_header_) << function_signature(&send_function) << ";" << endl;
1428
1429 // implement recv if not a oneway service
1430 if (!(*f_iter)->is_oneway()) {
1431 t_struct noargs(program_);
1432 t_function recv_function((*f_iter)->get_returntype(),
1433 service_name_lc + string("_client_recv_") + funname,
1434 &noargs,
1435 (*f_iter)->get_xceptions());
1436 indent(f_header_) << function_signature(&recv_function) << ";" << endl;
1437 }
1438 }
1439
1440 /* write out the get/set function prototypes */
1441 f_header_ << "void " + service_name_lc + "_client_set_property (GObject *object, guint "
1442 "property_id, const GValue *value, GParamSpec *pspec);"
1443 << endl;
1444 f_header_ << "void " + service_name_lc + "_client_get_property (GObject *object, guint "
1445 "property_id, GValue *value, GParamSpec *pspec);"
1446 << endl;
1447
1448 f_header_ << endl;
1449 // end of header code
1450
1451 // Generate interface method implementations
1452 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1453 /* make the function name C friendly */
1454 string funname = initial_caps_to_underscores((*f_iter)->get_name());
1455 t_type* ttype = (*f_iter)->get_returntype();
1456 t_struct* arglist = (*f_iter)->get_arglist();
1457 t_struct* xlist = (*f_iter)->get_xceptions();
1458 bool has_return = !ttype->is_void();
1459 bool has_args = arglist->get_members().size() == 0;
1460 bool has_xceptions = xlist->get_members().size() == 0;
1461
1462 string params = "(" + this->nspace + service_name_ + "If *iface"
1463 + (has_return ? ", " + type_name(ttype) + "* _return" : "")
1464 + (has_args ? "" : (", " + argument_list(arglist)))
1465 + (has_xceptions ? "" : (", " + xception_list(xlist))) + ", GError **error)";
1466
1467 string params_without_type = string("iface, ") + (has_return ? "_return, " : "");
1468
1469 const vector<t_field*>& fields = arglist->get_members();
1470 vector<t_field*>::const_iterator f_iter_field;
1471 for (f_iter_field = fields.begin(); f_iter_field != fields.end(); ++f_iter_field) {
1472 params_without_type += (*f_iter_field)->get_name();
1473 params_without_type += ", ";
1474 }
1475
1476 const vector<t_field*>& xceptions = xlist->get_members();
1477 vector<t_field*>::const_iterator x_iter;
1478 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1479 params_without_type += (*x_iter)->get_name();
1480 params_without_type += ", ";
1481 }
1482
1483 f_service_ << "gboolean" << endl << this->nspace_lc << service_name_lc << "_if_" << funname
1484 << " " << params << endl << "{" << endl << " return " << this->nspace_uc
1485 << service_name_uc << "_IF_GET_INTERFACE (iface)->" << funname << " ("
1486 << params_without_type << "error);" << endl << "}" << endl << endl;
1487 }
1488
1489 // Generate interface boilerplate
1490 f_service_ << "GType" << endl << this->nspace_lc << service_name_lc << "_if_get_type (void)"
1491 << endl << "{" << endl << " static GType type = 0;" << endl << " if (type == 0)"
1492 << endl << " {" << endl << " static const GTypeInfo type_info =" << endl << " {"
1493 << endl << " sizeof (" << this->nspace << service_name_ << "IfInterface)," << endl
1494 << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */" << endl
1495 << " NULL, /* class_init */" << endl << " NULL, /* class_finalize */"
1496 << endl << " NULL, /* class_data */" << endl
1497 << " 0, /* instance_size */" << endl << " 0, /* n_preallocs */"
1498 << endl << " NULL, /* instance_init */" << endl
1499 << " NULL /* value_table */" << endl << " };" << endl
1500 << " type = g_type_register_static (G_TYPE_INTERFACE," << endl
1501 << " \"" << this->nspace << service_name_ << "If\","
1502 << endl << " &type_info, 0);" << endl << " }"
1503 << endl << " return type;" << endl << "}" << endl << endl;
1504
1505 // Generate client boilerplate
1506 f_service_ << "static void " << endl << this->nspace_lc << service_name_lc
1507 << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);"
1508 << endl << endl << "G_DEFINE_TYPE_WITH_CODE (" << this->nspace << service_name_
1509 << "Client, " << this->nspace_lc << service_name_lc << "_client," << endl
1510 << " " << parent_type_name << ", " << endl
1511 << " G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_"
1512 << service_name_uc << "_IF," << endl
1513 << " " << this->nspace_lc
1514 << service_name_lc << "_if_interface_init))" << endl << endl;
1515
1516 // Generate property-related code only for base services---child
1517 // service-client classes have only properties inherited from their
1518 // parent class
1519 if (!extends_service) {
1520 // Generate client properties
1521 f_service_ << "enum _" << this->nspace << service_name_ << "ClientProperties" << endl << "{"
1522 << endl << " PROP_0," << endl << " PROP_" << this->nspace_uc << service_name_uc
1523 << "_CLIENT_INPUT_PROTOCOL," << endl << " PROP_" << this->nspace_uc
1524 << service_name_uc << "_CLIENT_OUTPUT_PROTOCOL" << endl << "};" << endl << endl;
1525
1526 // generate property setter
1527 f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_set_property ("
1528 << "GObject *object, guint property_id, const GValue *value, "
1529 << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace
1530 << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc
1531 << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl
1532 << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_"
1533 << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl
1534 << " client->input_protocol = g_value_get_object (value);" << endl
1535 << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc
1536 << "_CLIENT_OUTPUT_PROTOCOL:" << endl
1537 << " client->output_protocol = g_value_get_object (value);" << endl
1538 << " break;" << endl << " }" << endl << "}" << endl << endl;
1539
1540 // generate property getter
1541 f_service_ << "void" << endl << this->nspace_lc << service_name_lc << "_client_get_property ("
1542 << "GObject *object, guint property_id, GValue *value, "
1543 << "GParamSpec *pspec)" << endl << "{" << endl << " " << this->nspace
1544 << service_name_ << "Client *client = " << this->nspace_uc << service_name_uc
1545 << "_CLIENT (object);" << endl << endl << " THRIFT_UNUSED_VAR (pspec);" << endl
1546 << endl << " switch (property_id)" << endl << " {" << endl << " case PROP_"
1547 << this->nspace_uc << service_name_uc << "_CLIENT_INPUT_PROTOCOL:" << endl
1548 << " g_value_set_object (value, client->input_protocol);" << endl
1549 << " break;" << endl << " case PROP_" << this->nspace_uc << service_name_uc
1550 << "_CLIENT_OUTPUT_PROTOCOL:" << endl
1551 << " g_value_set_object (value, client->output_protocol);" << endl
1552 << " break;" << endl << " }" << endl << "}" << endl << endl;
1553 }
1554
1555 // Generate client method implementations
1556 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1557 string name = (*f_iter)->get_name();
1558 string funname = initial_caps_to_underscores(name);
1559
1560 // Get the struct of function call params and exceptions
1561 t_struct* arg_struct = (*f_iter)->get_arglist();
1562
1563 // Function for sending
1564 t_function send_function(g_type_void,
1565 service_name_lc + string("_client_send_") + funname,
1566 (*f_iter)->get_arglist());
1567
1568 // Open the send function
1569 indent(f_service_) << function_signature(&send_function) << endl;
1570 scope_up(f_service_);
1571
1572 string reqType = (*f_iter)->is_oneway() ? "T_ONEWAY" : "T_CALL";
1573
1574 // Serialize the request
1575 f_service_ << indent() << "gint32 cseqid = 0;" << endl << indent()
1576 << "ThriftProtocol * protocol = " << this->nspace_uc << base_service_name_uc
1577 << "_CLIENT (iface)->output_protocol;" << endl << endl << indent()
1578 << "if (thrift_protocol_write_message_begin (protocol, \"" << name << "\", "
1579 << reqType << ", cseqid, error) < 0)" << endl << indent() << " return FALSE;"
1580 << endl << endl;
1581
1582 generate_struct_writer(f_service_, arg_struct, "", "", false);
1583
1584 f_service_ << indent() << "if (thrift_protocol_write_message_end (protocol, error) < 0)" << endl
1585 << indent() << " return FALSE;" << endl << indent()
1586 << "if (!thrift_transport_flush (protocol->transport, error))" << endl << indent()
1587 << " return FALSE;" << endl << indent()
1588 << "if (!thrift_transport_write_end (protocol->transport, error))" << endl
1589 << indent() << " return FALSE;" << endl << endl << indent() << "return TRUE;"
1590 << endl;
1591
1592 scope_down(f_service_);
1593 f_service_ << endl;
1594
1595 // Generate recv function only if not an async function
1596 if (!(*f_iter)->is_oneway()) {
1597 t_struct noargs(program_);
1598 t_function recv_function((*f_iter)->get_returntype(),
1599 service_name_lc + string("_client_recv_") + funname,
1600 &noargs,
1601 (*f_iter)->get_xceptions());
1602 // Open function
1603 indent(f_service_) << function_signature(&recv_function) << endl;
1604 scope_up(f_service_);
1605
1606 f_service_ << indent() << "gint32 rseqid;" << endl
1607 << indent() << "gchar * fname = NULL;" << endl
1608 << indent() << "ThriftMessageType mtype;" << endl
1609 << indent() << "ThriftProtocol * protocol = "
1610 << this->nspace_uc << base_service_name_uc
1611 << "_CLIENT (iface)->input_protocol;" << endl
1612 << indent() << "ThriftApplicationException *xception;" << endl
1613 << endl
1614 << indent() << "if (thrift_protocol_read_message_begin "
1615 "(protocol, &fname, &mtype, &rseqid, error) < 0) {" << endl;
1616 indent_up();
1617 f_service_ << indent() << "if (fname) g_free (fname);" << endl
1618 << indent() << "return FALSE;" << endl;
1619 indent_down();
1620 f_service_ << indent() << "}" << endl
1621 << endl
1622 << indent() << "if (mtype == T_EXCEPTION) {" << endl;
1623 indent_up();
1624 f_service_ << indent() << "if (fname) g_free (fname);" << endl
1625 << indent() << "xception = g_object_new "
1626 "(THRIFT_TYPE_APPLICATION_EXCEPTION, NULL);" << endl
1627 << indent() << "thrift_struct_read (THRIFT_STRUCT (xception), "
1628 "protocol, NULL);" << endl
1629 << indent() << "thrift_protocol_read_message_end "
1630 "(protocol, NULL);" << endl
1631 << indent() << "thrift_transport_read_end "
1632 "(protocol->transport, NULL);" << endl
1633 << indent() << "g_set_error (error, "
1634 "THRIFT_APPLICATION_EXCEPTION_ERROR,xception->type, "
1635 "\"application error: %s\", xception->message);" << endl
1636 << indent() << "g_object_unref (xception);" << endl
1637 << indent() << "return FALSE;" << endl;
1638 indent_down();
1639 f_service_ << indent() << "} else if (mtype != T_REPLY) {" << endl;
1640 indent_up();
1641 f_service_ << indent() << "if (fname) g_free (fname);" << endl
1642 << indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
1643 "NULL);" << endl
1644 << indent() << "thrift_protocol_read_message_end (protocol, "
1645 "NULL);" << endl
1646 << indent() << "thrift_transport_read_end ("
1647 "protocol->transport, NULL);" << endl
1648 << indent() << "g_set_error (error, "
1649 "THRIFT_APPLICATION_EXCEPTION_ERROR, "
1650 "THRIFT_APPLICATION_EXCEPTION_ERROR_INVALID_MESSAGE_TYPE, "
1651 "\"invalid message type %d, expected T_REPLY\", mtype);"
1652 << endl
1653 << indent() << "return FALSE;" << endl;
1654 indent_down();
1655 f_service_ << indent() << "} else if (strncmp (fname, \"" << name
1656 << "\", " << name.length() << ") != 0) {" << endl;
1657 indent_up();
1658 f_service_ << indent() << "thrift_protocol_skip (protocol, T_STRUCT, "
1659 "NULL);" << endl
1660 << indent() << "thrift_protocol_read_message_end (protocol,"
1661 "error);" << endl
1662 << indent() << "thrift_transport_read_end ("
1663 "protocol->transport, error);" << endl
1664 << indent() << "g_set_error (error, "
1665 "THRIFT_APPLICATION_EXCEPTION_ERROR, "
1666 "THRIFT_APPLICATION_EXCEPTION_ERROR_WRONG_METHOD_NAME, "
1667 "\"wrong method name %s, expected " << name
1668 << "\", fname);" << endl
1669 << indent() << "if (fname) g_free (fname);" << endl
1670 << indent() << "return FALSE;" << endl;
1671 indent_down();
1672 f_service_ << indent() << "}" << endl
1673 << indent() << "if (fname) g_free (fname);" << endl
1674 << endl;
1675
1676 t_struct* xs = (*f_iter)->get_xceptions();
1677 const std::vector<t_field*>& xceptions = xs->get_members();
1678 vector<t_field*>::const_iterator x_iter;
1679
1680 {
1681 t_struct result(program_, tservice->get_name() + "_" + (*f_iter)->get_name() + "_result");
1682 t_field success((*f_iter)->get_returntype(), "*_return", 0);
1683 if (!(*f_iter)->get_returntype()->is_void()) {
1684 result.append(&success);
1685 }
1686
1687 // add readers for exceptions, dereferencing the pointer.
1688 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
1689 t_field* xception = new t_field((*x_iter)->get_type(),
1690 "*" + (*x_iter)->get_name(),
1691 (*x_iter)->get_key());
1692 result.append(xception);
1693 }
1694
1695 generate_struct_reader(f_service_, &result, "", "", false);
1696 }
1697
1698 f_service_ << indent() << "if (thrift_protocol_read_message_end (protocol, error) < 0)"
1699 << endl << indent() << " return FALSE;" << endl << endl << indent()
1700 << "if (!thrift_transport_read_end (protocol->transport, error))" << endl
1701 << indent() << " return FALSE;" << endl << endl;
1702
1703 // copy over any throw exceptions and return failure
1704 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); x_iter++) {
1705 f_service_ << indent() << "if (*" << (*x_iter)->get_name() << " != NULL)" << endl
1706 << indent() << "{" << endl << indent() << " g_set_error (error, "
1707 << this->nspace_uc
1708 << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name()))
1709 << "_ERROR, " << this->nspace_uc
1710 << to_upper_case(initial_caps_to_underscores((*x_iter)->get_type()->get_name()))
1711 << "_ERROR_CODE, \"" << (*x_iter)->get_type()->get_name() << "\");" << endl
1712 << indent() << " return FALSE;" << endl << indent() << "}" << endl;
1713 }
1714 // Close function
1715 indent(f_service_) << "return TRUE;" << endl;
1716 scope_down(f_service_);
1717 f_service_ << endl;
1718 }
1719
1720 // Open function
1721 t_function service_function((*f_iter)->get_returntype(),
1722 service_name_lc + string("_client_") + funname,
1723 (*f_iter)->get_arglist(),
1724 (*f_iter)->get_xceptions());
1725 indent(f_service_) << function_signature(&service_function) << endl;
1726 scope_up(f_service_);
1727
1728 // wrap each function
1729 f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_send_"
1730 << funname << " (iface";
1731
1732 // Declare the function arguments
1733 const vector<t_field*>& fields = arg_struct->get_members();
1734 vector<t_field*>::const_iterator fld_iter;
1735 for (fld_iter = fields.begin(); fld_iter != fields.end(); ++fld_iter) {
1736 f_service_ << ", " << (*fld_iter)->get_name();
1737 }
1738 f_service_ << ", error))" << endl << indent() << " return FALSE;" << endl;
1739
1740 // if not oneway, implement recv
1741 if (!(*f_iter)->is_oneway()) {
1742 string ret = (*f_iter)->get_returntype()->is_void() ? "" : "_return, ";
1743
1744 const vector<t_field*>& xceptions = (*f_iter)->get_xceptions()->get_members();
1745 vector<t_field*>::const_iterator x_iter;
1746 for (x_iter = xceptions.begin(); x_iter != xceptions.end(); ++x_iter) {
1747 ret += (*x_iter)->get_name();
1748 ret += ", ";
1749 }
1750
1751 f_service_ << indent() << "if (!" << this->nspace_lc << service_name_lc << "_client_recv_"
1752 << funname << " (iface, " << ret << "error))" << endl << indent()
1753 << " return FALSE;" << endl;
1754 }
1755
1756 // return TRUE which means all functions were called OK
1757 indent(f_service_) << "return TRUE;" << endl;
1758 scope_down(f_service_);
1759 f_service_ << endl;
1760 }
1761
1762 // create the interface initializer
1763 f_service_ << "static void" << endl
1764 << this->nspace_lc << service_name_lc << "_if_interface_init ("
1765 << this->nspace << service_name_ << "IfInterface *iface)" << endl;
1766 scope_up(f_service_);
1767 if (functions.size() > 0) {
1768 for (f_iter = functions.begin(); f_iter != functions.end(); ++f_iter) {
1769 /* make the function name C friendly */
1770 string funname = initial_caps_to_underscores((*f_iter)->get_name());
1771
1772 f_service_ << indent() << "iface->" << funname << " = " << this->nspace_lc
1773 << service_name_lc << "_client_" << funname << ";" << endl;
1774 }
1775 }
1776 else {
1777 f_service_ << indent() << "THRIFT_UNUSED_VAR (iface);" << endl;
1778 }
1779 scope_down(f_service_);
1780 f_service_ << endl;
1781
1782 // create the client instance initializer
1783 f_service_ << "static void" << endl
1784 << this->nspace_lc << service_name_lc << "_client_init ("
1785 << this->nspace << service_name_ << "Client *client)" << endl;
1786 scope_up(f_service_);
1787 if (!extends_service) {
1788 f_service_ << indent() << "client->input_protocol = NULL;" << endl
1789 << indent() << "client->output_protocol = NULL;" << endl;
1790 }
1791 else {
1792 f_service_ << indent() << "THRIFT_UNUSED_VAR (client);" << endl;
1793 }
1794 scope_down(f_service_);
1795 f_service_ << endl;
1796
1797 // create the client class initializer
1798 f_service_ << "static void" << endl << this->nspace_lc << service_name_lc
1799 << "_client_class_init (" << this->nspace << service_name_ << "ClientClass *cls)"
1800 << endl << "{" << endl;
1801 if (!extends_service) {
1802 f_service_ << " GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
1803 << " GParamSpec *param_spec;" << endl << endl
1804 << " gobject_class->set_property = " << this->nspace_lc << service_name_lc
1805 << "_client_set_property;" << endl
1806 << " gobject_class->get_property = " << this->nspace_lc << service_name_lc
1807 << "_client_get_property;" << endl << endl
1808 << " param_spec = g_param_spec_object (\"input_protocol\"," << endl
1809 << " \"input protocol (construct)\"," << endl
1810 << " \"Set the client input protocol\"," << endl
1811 << " THRIFT_TYPE_PROTOCOL," << endl
1812 << " G_PARAM_READWRITE);" << endl
1813 << " g_object_class_install_property (gobject_class," << endl
1814 << " PROP_" << this->nspace_uc << service_name_uc
1815 << "_CLIENT_INPUT_PROTOCOL, param_spec);" << endl << endl
1816 << " param_spec = g_param_spec_object (\"output_protocol\"," << endl
1817 << " \"output protocol (construct)\"," << endl
1818 << " \"Set the client output protocol\"," << endl
1819 << " THRIFT_TYPE_PROTOCOL," << endl
1820 << " G_PARAM_READWRITE);" << endl
1821 << " g_object_class_install_property (gobject_class," << endl
1822 << " PROP_" << this->nspace_uc << service_name_uc
1823 << "_CLIENT_OUTPUT_PROTOCOL, param_spec);" << endl;
1824 }
1825 else {
1826 f_service_ << " THRIFT_UNUSED_VAR (cls);" << endl;
1827 }
1828 f_service_ << "}" << endl << endl;
1829 }
1830
1831 /**
1832 * Generates C code that represents a Thrift service handler.
1833 *
1834 * @param tservice The service for which to generate a handler.
1835 */
1836 void t_c_glib_generator::generate_service_handler(t_service* tservice) {
1837 vector<t_function*> functions = tservice->get_functions();
1838 vector<t_function*>::const_iterator function_iter;
1839
1840 string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
1841 string service_name_uc = to_upper_case(service_name_lc);
1842
1843 string service_handler_name = service_name_ + "Handler";
1844
1845 string class_name = this->nspace + service_handler_name;
1846 string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_handler_name);
1847 string class_name_uc = to_upper_case(class_name_lc);
1848
1849 string parent_class_name;
1850 string parent_type_name;
1851
1852 string args_indent;
1853
1854 // The service this service extends, or NULL if it extends no service
1855 t_service* extends_service = tservice->get_extends();
1856
1857 // Determine the name of our parent service (if any) and the handler class'
1858 // parent class name and type
1859 if (extends_service) {
1860 string parent_service_name = extends_service->get_name();
1861 string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
1862 string parent_service_name_uc = to_upper_case(parent_service_name_lc);
1863
1864 parent_class_name = this->nspace + parent_service_name + "Handler";
1865 parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_HANDLER";
1866 } else {
1867 parent_class_name = "GObject";
1868 parent_type_name = "G_TYPE_OBJECT";
1869 }
1870
1871 // Generate the handler class' definition in the header file
1872
1873 // Generate the handler instance definition
1874 f_header_ << "/* " << service_name_ << " handler (abstract base class) */" << endl << "struct _"
1875 << class_name << endl << "{" << endl;
1876 indent_up();
1877 f_header_ << indent() << parent_class_name << " parent;" << endl;
1878 indent_down();
1879 f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl
1880 << endl;
1881
1882 // Generate the handler class definition, including its class members
1883 // (methods)
1884 f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl;
1885 indent_up();
1886 f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl;
1887
1888 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
1889 string method_name = initial_caps_to_underscores((*function_iter)->get_name());
1890 t_type* return_type = (*function_iter)->get_returntype();
1891 t_struct* arg_list = (*function_iter)->get_arglist();
1892 t_struct* x_list = (*function_iter)->get_xceptions();
1893 bool has_return = !return_type->is_void();
1894 bool has_args = arg_list->get_members().size() == 0;
1895 bool has_xceptions = x_list->get_members().size() == 0;
1896
1897 string params = "(" + this->nspace + service_name_ + "If *iface"
1898 + (has_return ? ", " + type_name(return_type) + "* _return" : "")
1899 + (has_args ? "" : (", " + argument_list(arg_list)))
1900 + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";
1901
1902 indent(f_header_) << "gboolean (*" << method_name << ") " << params << ";" << endl;
1903 }
1904 indent_down();
1905
1906 f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name
1907 << "Class;" << endl << endl;
1908
1909 // Generate the remaining header boilerplate
1910 f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define "
1911 << this->nspace_uc << "TYPE_" << service_name_uc << "_HANDLER "
1912 << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc
1913 << "(obj) "
1914 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
1915 << service_name_uc << "_HANDLER, " << class_name << "))" << endl << "#define "
1916 << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER(obj) "
1917 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
1918 << service_name_uc << "_HANDLER))" << endl << "#define " << class_name_uc
1919 << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
1920 << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << "#define "
1921 << this->nspace_uc << "IS_" << service_name_uc << "_HANDLER_CLASS(c) "
1922 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
1923 << "_HANDLER))" << endl << "#define " << this->nspace_uc << service_name_uc
1924 << "_HANDLER_GET_CLASS(obj) "
1925 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
1926 << service_name_uc << "_HANDLER, " << class_name << "Class))" << endl << endl;
1927
1928 // Generate the handler class' method definitions
1929 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
1930 string method_name = initial_caps_to_underscores((*function_iter)->get_name());
1931 t_type* return_type = (*function_iter)->get_returntype();
1932 t_struct* arg_list = (*function_iter)->get_arglist();
1933 t_struct* x_list = (*function_iter)->get_xceptions();
1934 bool has_return = !return_type->is_void();
1935 bool has_args = arg_list->get_members().size() == 0;
1936 bool has_xceptions = x_list->get_members().size() == 0;
1937
1938 string params = "(" + this->nspace + service_name_ + "If *iface"
1939 + (has_return ? ", " + type_name(return_type) + "* _return" : "")
1940 + (has_args ? "" : (", " + argument_list(arg_list)))
1941 + (has_xceptions ? "" : (", " + xception_list(x_list))) + ", GError **error)";
1942
1943 f_header_ << "gboolean " << class_name_lc << "_" << method_name << " " << params << ";" << endl;
1944 }
1945 f_header_ << endl;
1946
1947 // Generate the handler's implementation in the implementation file
1948
1949 // Generate the implementation boilerplate
1950 f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc
1951 << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface);"
1952 << endl << endl;
1953
1954 args_indent = string(25, ' ');
1955 f_service_ << "G_DEFINE_TYPE_WITH_CODE (" << class_name << ", " << endl << args_indent
1956 << class_name_lc << "," << endl << args_indent << parent_type_name << "," << endl
1957 << args_indent << "G_IMPLEMENT_INTERFACE (" << this->nspace_uc << "TYPE_"
1958 << service_name_uc << "_IF," << endl;
1959 args_indent += string(23, ' ');
1960 f_service_ << args_indent << class_name_lc << "_" << service_name_lc << "_if_interface_init))"
1961 << endl << endl;
1962
1963 // Generate the handler method implementations
1964 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
1965 string function_name = (*function_iter)->get_name();
1966 string method_name = initial_caps_to_underscores(function_name);
1967 t_type* return_type = (*function_iter)->get_returntype();
1968 t_struct* arg_list = (*function_iter)->get_arglist();
1969 t_struct* x_list = (*function_iter)->get_xceptions();
1970
1971 const vector<t_field*>& args = arg_list->get_members();
1972 const vector<t_field*>& xceptions = x_list->get_members();
1973
1974 vector<t_field*>::const_iterator field_iter;
1975
1976 t_function implementing_function(return_type,
1977 service_name_lc + "_handler_" + method_name,
1978 arg_list,
1979 x_list,
1980 (*function_iter)->is_oneway());
1981
1982 indent(f_service_) << function_signature(&implementing_function) << endl;
1983 scope_up(f_service_);
1984 f_service_ << indent() << "g_return_val_if_fail (" << this->nspace_uc << "IS_"
1985 << service_name_uc << "_HANDLER (iface), FALSE);" << endl << endl << indent()
1986 << "return " << class_name_uc << "_GET_CLASS (iface)"
1987 << "->" << method_name << " (iface, ";
1988
1989 if (!return_type->is_void()) {
1990 f_service_ << "_return, ";
1991 }
1992 for (field_iter = args.begin(); field_iter != args.end(); ++field_iter) {
1993 f_service_ << (*field_iter)->get_name() << ", ";
1994 }
1995 for (field_iter = xceptions.begin(); field_iter != xceptions.end(); ++field_iter) {
1996 f_service_ << (*field_iter)->get_name() << ", ";
1997 }
1998 f_service_ << "error);" << endl;
1999 scope_down(f_service_);
2000 f_service_ << endl;
2001 }
2002
2003 // Generate the handler interface initializer
2004 f_service_ << "static void" << endl << class_name_lc << "_" << service_name_lc
2005 << "_if_interface_init (" << this->nspace << service_name_ << "IfInterface *iface)"
2006 << endl;
2007 scope_up(f_service_);
2008 if (functions.size() > 0) {
2009 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
2010 string method_name = initial_caps_to_underscores((*function_iter)->get_name());
2011
2012 f_service_ << indent() << "iface->" << method_name << " = " << class_name_lc << "_"
2013 << method_name << ";" << endl;
2014 }
2015 }
2016 else {
2017 f_service_ << "THRIFT_UNUSED_VAR (iface);" << endl;
2018 }
2019 scope_down(f_service_);
2020 f_service_ << endl;
2021
2022 // Generate the handler instance initializer
2023 f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)"
2024 << endl;
2025 scope_up(f_service_);
2026 f_service_ << indent() << "THRIFT_UNUSED_VAR (self);" << endl;
2027 scope_down(f_service_);
2028 f_service_ << endl;
2029
2030 // Generate the handler class initializer
2031 f_service_ << "static void" << endl
2032 << class_name_lc << "_class_init (" << class_name << "Class *cls)"
2033 << endl;
2034 scope_up(f_service_);
2035 if (functions.size() > 0) {
2036 for (function_iter = functions.begin();
2037 function_iter != functions.end();
2038 ++function_iter) {
2039 string function_name = (*function_iter)->get_name();
2040 string method_name = initial_caps_to_underscores(function_name);
2041
2042 // All methods are pure virtual and must be implemented by subclasses
2043 f_service_ << indent() << "cls->" << method_name << " = NULL;" << endl;
2044 }
2045 }
2046 else {
2047 f_service_ << indent() << "THRIFT_UNUSED_VAR (cls);" << endl;
2048 }
2049 scope_down(f_service_);
2050 f_service_ << endl;
2051 }
2052
2053 /**
2054 * Generates C code that represents a Thrift service processor.
2055 *
2056 * @param tservice The service for which to generate a processor
2057 */
2058 void t_c_glib_generator::generate_service_processor(t_service* tservice) {
2059 vector<t_function*> functions = tservice->get_functions();
2060 vector<t_function*>::const_iterator function_iter;
2061
2062 string service_name_lc = to_lower_case(initial_caps_to_underscores(service_name_));
2063 string service_name_uc = to_upper_case(service_name_lc);
2064
2065 string service_processor_name = service_name_ + "Processor";
2066
2067 string class_name = this->nspace + service_processor_name;
2068 string class_name_lc = this->nspace_lc + initial_caps_to_underscores(service_processor_name);
2069 string class_name_uc = to_upper_case(class_name_lc);
2070
2071 string parent_class_name;
2072 string parent_type_name;
2073
2074 string handler_class_name = this->nspace + service_name_ + "Handler";
2075 string handler_class_name_lc = initial_caps_to_underscores(handler_class_name);
2076
2077 string process_function_type_name = class_name + "ProcessFunction";
2078 string process_function_def_type_name =
2079 class_name_lc + "_process_function_def";
2080
2081 string function_name;
2082 string args_indent;
2083
2084 // The service this service extends, or NULL if it extends no service
2085 t_service* extends_service = tservice->get_extends();
2086
2087 // Determine the name of our parent service (if any) and the
2088 // processor class' parent class name and type
2089 if (extends_service) {
2090 string parent_service_name = extends_service->get_name();
2091 string parent_service_name_lc = to_lower_case(initial_caps_to_underscores(parent_service_name));
2092 string parent_service_name_uc = to_upper_case(parent_service_name_lc);
2093
2094 parent_class_name = this->nspace + parent_service_name + "Processor";
2095 parent_type_name = this->nspace_uc + "TYPE_" + parent_service_name_uc + "_PROCESSOR";
2096 } else {
2097 parent_class_name = "ThriftDispatchProcessor";
2098 parent_type_name = "THRIFT_TYPE_DISPATCH_PROCESSOR";
2099 }
2100
2101 // Generate the processor class' definition in the header file
2102
2103 // Generate the processor instance definition
2104 f_header_ << "/* " << service_name_ << " processor */" << endl << "struct _" << class_name << endl
2105 << "{" << endl;
2106 indent_up();
2107 f_header_ << indent() << parent_class_name << " parent;" << endl << endl << indent()
2108 << "/* protected */" << endl << indent()
2109 << this->nspace + service_name_ + "Handler *handler;" << endl << indent()
2110 << "GHashTable *process_map;" << endl;
2111 indent_down();
2112 f_header_ << "};" << endl << "typedef struct _" << class_name << " " << class_name << ";" << endl
2113 << endl;
2114
2115 // Generate the processor class definition
2116 f_header_ << "struct _" << class_name << "Class" << endl << "{" << endl;
2117 indent_up();
2118 f_header_ << indent() << parent_class_name << "Class parent;" << endl << endl << indent()
2119 << "/* protected */" << endl << indent()
2120 << "gboolean (*dispatch_call) (ThriftDispatchProcessor *processor," << endl;
2121 args_indent = indent() + string(27, ' ');
2122 f_header_ << args_indent << "ThriftProtocol *in," << endl << args_indent << "ThriftProtocol *out,"
2123 << endl << args_indent << "gchar *fname," << endl << args_indent << "gint32 seqid,"
2124 << endl << args_indent << "GError **error);" << endl;
2125 indent_down();
2126 f_header_ << "};" << endl << "typedef struct _" << class_name << "Class " << class_name
2127 << "Class;" << endl << endl;
2128
2129 // Generate the remaining header boilerplate
2130 f_header_ << "GType " << class_name_lc << "_get_type (void);" << endl << "#define "
2131 << this->nspace_uc << "TYPE_" << service_name_uc << "_PROCESSOR "
2132 << "(" << class_name_lc << "_get_type())" << endl << "#define " << class_name_uc
2133 << "(obj) "
2134 << "(G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_"
2135 << service_name_uc << "_PROCESSOR, " << class_name << "))" << endl << "#define "
2136 << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR(obj) "
2137 << "(G_TYPE_CHECK_INSTANCE_TYPE ((obj), " << this->nspace_uc << "TYPE_"
2138 << service_name_uc << "_PROCESSOR))" << endl << "#define " << class_name_uc
2139 << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "TYPE_"
2140 << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << "#define "
2141 << this->nspace_uc << "IS_" << service_name_uc << "_PROCESSOR_CLASS(c) "
2142 << "(G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc << "TYPE_" << service_name_uc
2143 << "_PROCESSOR))" << endl << "#define " << this->nspace_uc << service_name_uc
2144 << "_PROCESSOR_GET_CLASS(obj) "
2145 << "(G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
2146 << service_name_uc << "_PROCESSOR, " << class_name << "Class))" << endl << endl;
2147
2148 // Generate the processor's implementation in the implementation file
2149
2150 // Generate the processor's properties enum
2151 f_service_ << "enum _" << class_name << "Properties" << endl << "{" << endl;
2152 indent_up();
2153 f_service_ << indent() << "PROP_" << class_name_uc << "_0," << endl << indent() << "PROP_"
2154 << class_name_uc << "_HANDLER" << endl;
2155 indent_down();
2156 f_service_ << "};" << endl << endl;
2157
2158 // Generate the implementation boilerplate
2159 args_indent = string(15, ' ');
2160 f_service_ << "G_DEFINE_TYPE (" << class_name << "," << endl << args_indent << class_name_lc
2161 << "," << endl << args_indent << parent_type_name << ")" << endl << endl;
2162
2163 // Generate the processor's processing-function type
2164 args_indent = string(process_function_type_name.length() + 23, ' ');
2165 f_service_ << "typedef gboolean (* " << process_function_type_name << ") ("
2166 << class_name << " *, " << endl
2167 << args_indent << "gint32," << endl
2168 << args_indent << "ThriftProtocol *," << endl
2169 << args_indent << "ThriftProtocol *," << endl
2170 << args_indent << "GError **);" << endl
2171 << endl;
2172
2173 // Generate the processor's processing-function-definition type
2174 f_service_ << "typedef struct" << endl
2175 << "{" << endl;
2176 indent_up();
2177 f_service_ << indent() << "gchar *name;" << endl
2178 << indent() << process_function_type_name << " function;" << endl;
2179 indent_down();
2180 f_service_ << "} " << process_function_def_type_name << ";" << endl
2181 << endl;
2182
2183 // Generate forward declarations of the processor's processing functions so we
2184 // can refer to them in the processing-function-definition struct below and
2185 // keep all of the processor's declarations in one place
2186 for (function_iter = functions.begin();
2187 function_iter != functions.end();
2188 ++function_iter) {
2189 function_name = class_name_lc + "_process_"
2190 + initial_caps_to_underscores((*function_iter)->get_name());
2191
2192 args_indent = string(function_name.length() + 2, ' ');
2193 f_service_ << "static gboolean" << endl
2194 << function_name << " ("
2195 << class_name << " *," << endl
2196 << args_indent << "gint32," << endl
2197 << args_indent << "ThriftProtocol *," << endl
2198 << args_indent << "ThriftProtocol *," << endl
2199 << args_indent << "GError **);" << endl;
2200 }
2201 f_service_ << endl;
2202
2203 // Generate the processor's processing-function definitions, if the service
2204 // defines any methods
2205 if (functions.size() > 0) {
2206 f_service_ << indent() << "static " << process_function_def_type_name
2207 << endl
2208 << indent() << class_name_lc << "_process_function_defs["
2209 << functions.size() << "] = {" << endl;
2210 indent_up();
2211 for (function_iter = functions.begin();
2212 function_iter != functions.end();
2213 ++function_iter) {
2214 string service_function_name = (*function_iter)->get_name();
2215 string process_function_name = class_name_lc + "_process_"
2216 + initial_caps_to_underscores(service_function_name);
2217
2218 f_service_ << indent() << "{" << endl;
2219 indent_up();
2220 f_service_ << indent() << "\"" << service_function_name << "\"," << endl
2221 << indent() << process_function_name << endl;
2222 indent_down();
2223 f_service_ << indent() << "}"
2224 << (function_iter == --functions.end() ? "" : ",") << endl;
2225 }
2226 indent_down();
2227 f_service_ << indent() << "};" << endl
2228 << endl;
2229 }
2230
2231 // Generate the processor's processing functions
2232 for (function_iter = functions.begin(); function_iter != functions.end(); ++function_iter) {
2233 string service_function_name = (*function_iter)->get_name();
2234 string service_function_name_ic = underscores_to_initial_caps(service_function_name);
2235 string service_function_name_lc = initial_caps_to_underscores(service_function_name);
2236 string service_function_name_uc = to_upper_case(service_function_name_lc);
2237
2238 t_type* return_type = (*function_iter)->get_returntype();
2239 bool has_return_value = !return_type->is_void();
2240
2241 t_struct* arg_list = (*function_iter)->get_arglist();
2242 const vector<t_field*>& args = arg_list->get_members();
2243 vector<t_field*>::const_iterator arg_iter;
2244
2245 const vector<t_field*>& xceptions = (*function_iter)->get_xceptions()->get_members();
2246 vector<t_field*>::const_iterator xception_iter;
2247
2248 string args_class_name = this->nspace + service_name_ + service_function_name_ic + "Args";
2249 string args_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_"
2250 + service_function_name_uc + "_ARGS";
2251
2252 string result_class_name = this->nspace + service_name_ + service_function_name_ic + "Result";
2253 string result_class_type = this->nspace_uc + "TYPE_" + service_name_uc + "_"
2254 + service_function_name_uc + "_RESULT";
2255
2256 string handler_function_name = handler_class_name_lc + "_" + service_function_name_lc;
2257
2258 function_name = class_name_lc + "_process_"
2259 + initial_caps_to_underscores(service_function_name);
2260
2261 args_indent = string(function_name.length() + 2, ' ');
2262 f_service_ << "static gboolean" << endl << function_name << " (" << class_name << " *self,"
2263 << endl << args_indent << "gint32 sequence_id," << endl << args_indent
2264 << "ThriftProtocol *input_protocol," << endl << args_indent
2265 << "ThriftProtocol *output_protocol," << endl << args_indent << "GError **error)"
2266 << endl;
2267 scope_up(f_service_);
2268 f_service_ << indent() << "gboolean result = TRUE;" << endl
2269 << indent() << "ThriftTransport * transport;" << endl
2270 << indent() << "ThriftApplicationException *xception;" << endl
2271 << indent() << args_class_name + " * args =" << endl;
2272 indent_up();
2273 f_service_ << indent() << "g_object_new (" << args_class_type << ", NULL);" << endl << endl;
2274 indent_down();
2275 if ((*function_iter)->is_oneway()) {
2276 f_service_ << indent() << "THRIFT_UNUSED_VAR (sequence_id);" << endl << indent()
2277 << "THRIFT_UNUSED_VAR (output_protocol);" << endl << endl;
2278 }
2279 f_service_ << indent() << "g_object_get (input_protocol, \"transport\", "
2280 << "&transport, NULL);" << endl << endl;
2281
2282 // Read the method's arguments from the caller
2283 f_service_ << indent() << "if ((thrift_struct_read (THRIFT_STRUCT (args), "
2284 << "input_protocol, error) != -1) &&" << endl << indent()
2285 << " (thrift_protocol_read_message_end (input_protocol, "
2286 << "error) != -1) &&" << endl << indent()
2287 << " (thrift_transport_read_end (transport, error) != FALSE))" << endl;
2288 scope_up(f_service_);
2289
2290 for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
2291 f_service_ << indent() << property_type_name((*arg_iter)->get_type()) << " "
2292 << (*arg_iter)->get_name() << ";" << endl;
2293 }
2294 for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
2295 f_service_ << indent() << type_name((*xception_iter)->get_type()) << " "
2296 << initial_caps_to_underscores((*xception_iter)->get_name()) << " = NULL;" << endl;
2297 }
2298 if (has_return_value) {
2299 f_service_ << indent() << property_type_name(return_type) << " return_value;" << endl;
2300 }
2301 if (!(*function_iter)->is_oneway()) {
2302 f_service_ << indent() << result_class_name << " * result_struct;" << endl;
2303 }
2304 f_service_ << endl;
2305
2306 if (args.size() > 0) {
2307 f_service_ << indent() << "g_object_get (args," << endl;
2308 args_indent = indent() + string(14, ' ');
2309 for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
2310 string arg_name = (*arg_iter)->get_name();
2311
2312 f_service_ << args_indent << "\"" << arg_name << "\", &" << arg_name << "," << endl;
2313 }
2314 f_service_ << args_indent << "NULL);" << endl << endl;
2315 }
2316
2317 if (!(*function_iter)->is_oneway()) {
2318 f_service_ << indent() << "g_object_unref (transport);" << endl << indent()
2319 << "g_object_get (output_protocol, \"transport\", "
2320 << "&transport, NULL);" << endl << endl << indent()
2321 << "result_struct = g_object_new (" << result_class_type << ", NULL);" << endl;
2322 if (has_return_value) {
2323 f_service_ << indent() << "g_object_get (result_struct, "
2324 "\"success\", &return_value, NULL);" << endl;
2325 }
2326 f_service_ << endl;
2327 }
2328
2329 // Pass the arguments to the corresponding method in the handler
2330 f_service_ << indent() << "if (" << handler_function_name << " (" << this->nspace_uc
2331 << service_name_uc << "_IF (self->handler)," << endl;
2332 args_indent = indent() + string(handler_function_name.length() + 6, ' ');
2333 if (has_return_value) {
2334 string return_type_name = type_name(return_type);
2335
2336 f_service_ << args_indent;
2337
2338 // Cast return_value if it was declared as a type other than the return
2339 // value's actual type---this is true for integer values 32 bits or fewer
2340 // in width, for which GLib requires a plain gint type be used when
2341 // storing or retrieving as an object property
2342 if (return_type_name != property_type_name(return_type)) {
2343 if (return_type_name[return_type_name.length() - 1] != '*') {
2344 return_type_name += ' ';
2345 }
2346 return_type_name += '*';
2347
2348 f_service_ << "(" << return_type_name << ")";
2349 }
2350
2351 f_service_ << "&return_value," << endl;
2352 }
2353 for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
2354 f_service_ << args_indent << (*arg_iter)->get_name() << "," << endl;
2355 }
2356 for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
2357 f_service_ << args_indent << "&" << initial_caps_to_underscores((*xception_iter)->get_name())
2358 << "," << endl;
2359 }
2360 f_service_ << args_indent << "error) == TRUE)" << endl;
2361 scope_up(f_service_);
2362
2363 // The handler reported success; return the result, if any, to the caller
2364 if (!(*function_iter)->is_oneway()) {
2365 if (has_return_value) {
2366 f_service_ << indent() << "g_object_set (result_struct, \"success\", ";
2367 if (type_name(return_type) != property_type_name(return_type)) {
2368 // Roundtrip cast to fix the position of sign bit.
2369 f_service_ << "(" << property_type_name(return_type) << ")"
2370 << "(" << type_name(return_type) << ")";
2371 }
2372 f_service_ << "return_value, "
2373 << "NULL);" << endl;
2374
2375 // Deallocate (or unref) return_value
2376 return_type = get_true_type(return_type);
2377 if (return_type->is_base_type()) {
2378 t_base_type* base_type = ((t_base_type*)return_type);
2379
2380 if (base_type->get_base() == t_base_type::TYPE_STRING) {
2381 f_service_ << indent() << "if (return_value != NULL)" << endl;
2382 indent_up();
2383 if (base_type->is_binary()) {
2384 f_service_ << indent() << "g_byte_array_unref (return_value);" << endl;
2385 } else {
2386 f_service_ << indent() << "g_free (return_value);" << endl;
2387 }
2388 indent_down();
2389 }
2390 } else if (return_type->is_container()) {
2391 f_service_ << indent() << "if (return_value != NULL)" << endl;
2392 indent_up();
2393
2394 if (return_type->is_list()) {
2395 t_type* elem_type = ((t_list*)return_type)->get_elem_type();
2396
2397 f_service_ << indent();
2398 if (is_numeric(elem_type)) {
2399 f_service_ << "g_array_unref";
2400 } else {
2401 f_service_ << "g_ptr_array_unref";
2402 }
2403 f_service_ << " (return_value);" << endl;
2404 } else if (return_type->is_map() || return_type->is_set()) {
2405 f_service_ << indent() << "g_hash_table_unref (return_value);" << endl;
2406 }
2407
2408 indent_down();
2409 } else if (return_type->is_struct()) {
2410 f_service_ << indent() << "if (return_value != NULL)" << endl;
2411 indent_up();
2412 f_service_ << indent() << "g_object_unref (return_value);" << endl;
2413 indent_down();
2414 }
2415
2416 f_service_ << endl;
2417 }
2418 f_service_ << indent() << "result =" << endl;
2419 indent_up();
2420 f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
2421 args_indent = indent() + string(39, ' ');
2422 f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
2423 << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent
2424 << "error) != -1) &&" << endl << indent()
2425 << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl;
2426 args_indent = indent() + string(23, ' ');
2427 f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
2428 << endl;
2429 indent_down();
2430 }
2431 scope_down(f_service_);
2432 f_service_ << indent() << "else" << endl;
2433 scope_up(f_service_);
2434
2435 // The handler reported failure; check to see if an application-defined
2436 // exception was raised and if so, return it to the caller
2437 f_service_ << indent();
2438 if (xceptions.size() > 0) {
2439 for (xception_iter = xceptions.begin(); xception_iter != xceptions.end(); ++xception_iter) {
2440 f_service_ << "if (" << initial_caps_to_underscores((*xception_iter)->get_name())
2441 << " != NULL)" << endl;
2442 scope_up(f_service_);
2443 f_service_ << indent() << "g_object_set (result_struct," << endl;
2444 args_indent = indent() + string(14, ' ');
2445 f_service_ << args_indent << "\"" << (*xception_iter)->get_name() << "\", "
2446 << (*xception_iter)->get_name() << "," << endl << args_indent << "NULL);" << endl
2447 << endl;
2448 f_service_ << indent() << "result =" << endl;
2449 indent_up();
2450 f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
2451 args_indent = indent() + string(39, ' ');
2452 f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
2453 << "T_REPLY," << endl << args_indent << "sequence_id," << endl << args_indent
2454 << "error) != -1) &&" << endl << indent()
2455 << " (thrift_struct_write (THRIFT_STRUCT (result_struct)," << endl;
2456 args_indent = indent() + string(23, ' ');
2457 f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
2458 << endl;
2459 indent_down();
2460 scope_down(f_service_);
2461 f_service_ << indent() << "else" << endl;
2462 }
2463
2464 scope_up(f_service_);
2465 f_service_ << indent();
2466 }
2467
2468 // If the handler reported failure but raised no application-defined
2469 // exception, return a Thrift application exception with the information
2470 // returned via GLib's own error-reporting mechanism
2471 f_service_ << "if (*error == NULL)" << endl;
2472 indent_up();
2473 f_service_ << indent() << "g_warning (\"" << service_name_ << "."
2474 << (*function_iter)->get_name() << " implementation returned FALSE \"" << endl
2475 << indent() << string(11, ' ') << "\"but did not set an error\");" << endl << endl;
2476 indent_down();
2477 f_service_ << indent() << "xception =" << endl;
2478 indent_up();
2479 f_service_ << indent() << "g_object_new (THRIFT_TYPE_APPLICATION_EXCEPTION," << endl;
2480 args_indent = indent() + string(14, ' ');
2481 f_service_ << args_indent << "\"type\", *error != NULL ? (*error)->code :" << endl
2482 << args_indent << string(11, ' ') << "THRIFT_APPLICATION_EXCEPTION_ERROR_UNKNOWN,"
2483 << endl << args_indent << "\"message\", *error != NULL ? (*error)->message : NULL,"
2484 << endl << args_indent << "NULL);" << endl;
2485 indent_down();
2486 f_service_ << indent() << "g_clear_error (error);" << endl << endl << indent()
2487 << "result =" << endl;
2488 indent_up();
2489 f_service_ << indent() << "((thrift_protocol_write_message_begin (output_protocol," << endl;
2490 args_indent = indent() + string(39, ' ');
2491 f_service_ << args_indent << "\"" << service_function_name << "\"," << endl << args_indent
2492 << "T_EXCEPTION," << endl << args_indent << "sequence_id," << endl << args_indent
2493 << "error) != -1) &&" << endl << indent()
2494 << " (thrift_struct_write (THRIFT_STRUCT (xception)," << endl;
2495 args_indent = indent() + string(23, ' ');
2496 f_service_ << args_indent << "output_protocol," << endl << args_indent << "error) != -1));"
2497 << endl;
2498 indent_down();
2499 f_service_ << endl << indent() << "g_object_unref (xception);" << endl;
2500
2501 if (xceptions.size() > 0) {
2502 scope_down(f_service_);
2503 }
2504 scope_down(f_service_);
2505 f_service_ << endl;
2506
2507 // Dellocate or unref retrieved argument values as necessary
2508 for (arg_iter = args.begin(); arg_iter != args.end(); ++arg_iter) {
2509 string arg_name = (*arg_iter)->get_name();
2510 t_type* arg_type = get_true_type((*arg_iter)->get_type());
2511
2512 if (arg_type->is_base_type()) {
2513 t_base_type* base_type = ((t_base_type*)arg_type);
2514
2515 if (base_type->get_base() == t_base_type::TYPE_STRING) {
2516 f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
2517 indent_up();
2518 if (base_type->is_binary()) {
2519 f_service_ << indent() << "g_byte_array_unref (" << arg_name << ");" << endl;
2520 } else {
2521 f_service_ << indent() << "g_free (" << arg_name << ");" << endl;
2522 }
2523 indent_down();
2524 }
2525 } else if (arg_type->is_container()) {
2526 f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
2527 indent_up();
2528
2529 if (arg_type->is_list()) {
2530 t_type* elem_type = ((t_list*)arg_type)->get_elem_type();
2531
2532 f_service_ << indent();
2533 if (is_numeric(elem_type)) {
2534 f_service_ << "g_array_unref";
2535 } else {
2536 f_service_ << "g_ptr_array_unref";
2537 }
2538 f_service_ << " (" << arg_name << ");" << endl;
2539 } else if (arg_type->is_map() || arg_type->is_set()) {
2540 f_service_ << indent() << "g_hash_table_unref (" << arg_name << ");" << endl;
2541 }
2542
2543 indent_down();
2544 } else if (arg_type->is_struct()) {
2545 f_service_ << indent() << "if (" << arg_name << " != NULL)" << endl;
2546 indent_up();
2547 f_service_ << indent() << "g_object_unref (" << arg_name << ");" << endl;
2548 indent_down();
2549 }
2550 }
2551
2552 if (!(*function_iter)->is_oneway()) {
2553 f_service_ << indent() << "g_object_unref (result_struct);" << endl << endl << indent()
2554 << "if (result == TRUE)" << endl;
2555 indent_up();
2556 f_service_ << indent() << "result =" << endl;
2557 indent_up();
2558 f_service_ << indent() << "((thrift_protocol_write_message_end "
2559 << "(output_protocol, error) != -1) &&" << endl << indent()
2560 << " (thrift_transport_write_end (transport, error) "
2561 << "!= FALSE) &&" << endl << indent()
2562 << " (thrift_transport_flush (transport, error) "
2563 << "!= FALSE));" << endl;
2564 indent_down();
2565 indent_down();
2566 }
2567 scope_down(f_service_);
2568 f_service_ << indent() << "else" << endl;
2569 indent_up();
2570 f_service_ << indent() << "result = FALSE;" << endl;
2571 indent_down();
2572
2573 f_service_ << endl << indent() << "g_object_unref (transport);" << endl << indent()
2574 << "g_object_unref (args);" << endl << endl << indent() << "return result;" << endl;
2575 scope_down(f_service_);
2576
2577 f_service_ << endl;
2578 }
2579
2580 // Generate the processor's dispatch_call implementation
2581 function_name = class_name_lc + "_dispatch_call";
2582 args_indent = indent() + string(function_name.length() + 2, ' ');
2583 f_service_ << "static gboolean" << endl << function_name
2584 << " (ThriftDispatchProcessor *dispatch_processor," << endl << args_indent
2585 << "ThriftProtocol *input_protocol," << endl << args_indent
2586 << "ThriftProtocol *output_protocol," << endl << args_indent << "gchar *method_name,"
2587 << endl << args_indent << "gint32 sequence_id," << endl << args_indent
2588 << "GError **error)" << endl;
2589 scope_up(f_service_);
2590 f_service_ << indent() << class_name_lc << "_process_function_def *"
2591 << "process_function_def;" << endl;
2592 f_service_ << indent() << "gboolean dispatch_result = FALSE;" << endl << endl << indent()
2593 << class_name << " *self = " << class_name_uc << " (dispatch_processor);" << endl;
2594 f_service_ << indent() << parent_class_name << "Class "
2595 "*parent_class =" << endl;
2596 indent_up();
2597 f_service_ << indent() << "g_type_class_peek_parent (" << class_name_uc << "_GET_CLASS (self));"
2598 << endl;
2599 indent_down();
2600 f_service_ << endl
2601 << indent() << "process_function_def = "
2602 << "g_hash_table_lookup (self->process_map, method_name);" << endl
2603 << indent() << "if (process_function_def != NULL)" << endl;
2604 scope_up(f_service_);
2605 args_indent = indent() + string(53, ' ');
2606 f_service_ << indent() << "g_free (method_name);" << endl
2607 << indent() << "dispatch_result = "
2608 << "(*process_function_def->function) (self," << endl
2609 << args_indent << "sequence_id," << endl
2610 << args_indent << "input_protocol," << endl
2611 << args_indent << "output_protocol," << endl
2612 << args_indent << "error);" << endl;
2613 scope_down(f_service_);
2614 f_service_ << indent() << "else" << endl;
2615 scope_up(f_service_);
2616
2617 // Method name not recognized; chain up to our parent processor---note the
2618 // top-most implementation of this method, in ThriftDispatchProcessor itself,
2619 // will return an application exception to the caller if no class in the
2620 // hierarchy recognizes the method name
2621 f_service_ << indent() << "dispatch_result = parent_class->dispatch_call "
2622 "(dispatch_processor," << endl;
2623 args_indent = indent() + string(47, ' ');
2624 f_service_ << args_indent << "input_protocol," << endl << args_indent << "output_protocol,"
2625 << endl << args_indent << "method_name," << endl << args_indent << "sequence_id,"
2626 << endl << args_indent << "error);" << endl;
2627 scope_down(f_service_);
2628 f_service_ << endl << indent() << "return dispatch_result;" << endl;
2629 scope_down(f_service_);
2630 f_service_ << endl;
2631
2632 // Generate the processor's property setter
2633 function_name = class_name_lc + "_set_property";
2634 args_indent = string(function_name.length() + 2, ' ');
2635 f_service_ << "static void" << endl << function_name << " (GObject *object," << endl
2636 << args_indent << "guint property_id," << endl << args_indent << "const GValue *value,"
2637 << endl << args_indent << "GParamSpec *pspec)" << endl;
2638 scope_up(f_service_);
2639 f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
2640 << endl << indent() << "switch (property_id)" << endl;
2641 scope_up(f_service_);
2642 f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl;
2643 indent_up();
2644 f_service_ << indent() << "if (self->handler != NULL)" << endl;
2645 indent_up();
2646 f_service_ << indent() << "g_object_unref (self->handler);" << endl;
2647 indent_down();
2648 f_service_ << indent() << "self->handler = g_value_get_object (value);" << endl << indent()
2649 << "g_object_ref (self->handler);" << endl;
2650 if (extends_service) {
2651 // Chain up to set the handler in every superclass as well
2652 f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)->"
2653 << endl;
2654 indent_up();
2655 f_service_ << indent() << "set_property (object, property_id, value, pspec);" << endl;
2656 indent_down();
2657 }
2658 f_service_ << indent() << "break;" << endl;
2659 indent_down();
2660 f_service_ << indent() << "default:" << endl;
2661 indent_up();
2662 f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2663 << endl << indent() << "break;" << endl;
2664 indent_down();
2665 scope_down(f_service_);
2666 scope_down(f_service_);
2667 f_service_ << endl;
2668
2669 // Generate processor's property getter
2670 function_name = class_name_lc + "_get_property";
2671 args_indent = string(function_name.length() + 2, ' ');
2672 f_service_ << "static void" << endl << function_name << " (GObject *object," << endl
2673 << args_indent << "guint property_id," << endl << args_indent << "GValue *value,"
2674 << endl << args_indent << "GParamSpec *pspec)" << endl;
2675 scope_up(f_service_);
2676 f_service_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
2677 << endl << indent() << "switch (property_id)" << endl;
2678 scope_up(f_service_);
2679 f_service_ << indent() << "case PROP_" << class_name_uc << "_HANDLER:" << endl;
2680 indent_up();
2681 f_service_ << indent() << "g_value_set_object (value, self->handler);" << endl << indent()
2682 << "break;" << endl;
2683 indent_down();
2684 f_service_ << indent() << "default:" << endl;
2685 indent_up();
2686 f_service_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2687 << endl << indent() << "break;" << endl;
2688 indent_down();
2689 scope_down(f_service_);
2690 scope_down(f_service_);
2691 f_service_ << endl;
2692
2693 // Generator the processor's dispose function
2694 f_service_ << "static void" << endl << class_name_lc << "_dispose (GObject *gobject)" << endl;
2695 scope_up(f_service_);
2696 f_service_ << indent() << class_name << " *self = " << class_name_uc << " (gobject);" << endl
2697 << endl << indent() << "if (self->handler != NULL)" << endl;
2698 scope_up(f_service_);
2699 f_service_ << indent() << "g_object_unref (self->handler);" << endl << indent()
2700 << "self->handler = NULL;" << endl;
2701 scope_down(f_service_);
2702 f_service_ << endl << indent() << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
2703 "->dispose (gobject);"
2704 << endl;
2705 scope_down(f_service_);
2706 f_service_ << endl;
2707
2708 // Generate processor finalize function
2709 f_service_ << "static void" << endl << class_name_lc << "_finalize (GObject *gobject)" << endl;
2710 scope_up(f_service_);
2711 f_service_ << indent() << this->nspace << service_name_ << "Processor *self = " << this->nspace_uc
2712 << service_name_uc << "_PROCESSOR (gobject);" << endl << endl << indent()
2713 << "thrift_safe_hash_table_destroy (self->process_map);" << endl << endl << indent()
2714 << "G_OBJECT_CLASS (" << class_name_lc << "_parent_class)"
2715 "->finalize (gobject);" << endl;
2716 scope_down(f_service_);
2717 f_service_ << endl;
2718
2719 // Generate processor instance initializer
2720 f_service_ << "static void" << endl << class_name_lc << "_init (" << class_name << " *self)"
2721 << endl;
2722 scope_up(f_service_);
2723 if (functions.size() > 0) {
2724 f_service_ << indent() << "guint index;" << endl
2725 << endl;
2726 }
2727 f_service_ << indent() << "self->handler = NULL;" << endl << indent()
2728 << "self->process_map = "
2729 "g_hash_table_new (g_str_hash, g_str_equal);" << endl;
2730 if (functions.size() > 0) {
2731 args_indent = string(21, ' ');
2732 f_service_ << endl
2733 << indent() << "for (index = 0; index < "
2734 << functions.size() << "; index += 1)" << endl;
2735 indent_up();
2736 f_service_ << indent() << "g_hash_table_insert (self->process_map," << endl
2737 << indent() << args_indent
2738 << class_name_lc << "_process_function_defs[index].name," << endl
2739 << indent() << args_indent
2740 << "&" << class_name_lc << "_process_function_defs[index]" << ");"
2741 << endl;
2742 indent_down();
2743 }
2744 scope_down(f_service_);
2745 f_service_ << endl;
2746
2747 // Generate processor class initializer
2748 f_service_ << "static void" << endl << class_name_lc << "_class_init (" << class_name
2749 << "Class *cls)" << endl;
2750 scope_up(f_service_);
2751 f_service_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
2752 << indent() << "ThriftDispatchProcessorClass *dispatch_processor_class =" << endl;
2753 indent_up();
2754 f_service_ << indent() << "THRIFT_DISPATCH_PROCESSOR_CLASS (cls);" << endl;
2755 indent_down();
2756 f_service_ << indent() << "GParamSpec *param_spec;" << endl << endl << indent()
2757 << "gobject_class->dispose = " << class_name_lc << "_dispose;" << endl << indent()
2758 << "gobject_class->finalize = " << class_name_lc << "_finalize;" << endl << indent()
2759 << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl
2760 << indent() << "gobject_class->get_property = " << class_name_lc << "_get_property;"
2761 << endl << endl << indent()
2762 << "dispatch_processor_class->dispatch_call = " << class_name_lc << "_dispatch_call;"
2763 << endl << indent() << "cls->dispatch_call = " << class_name_lc << "_dispatch_call;"
2764 << endl << endl << indent() << "param_spec = g_param_spec_object (\"handler\","
2765 << endl;
2766 args_indent = indent() + string(34, ' ');
2767 f_service_ << args_indent << "\"Service handler implementation\"," << endl << args_indent
2768 << "\"The service handler implementation \"" << endl << args_indent
2769 << "\"to which method calls are dispatched.\"," << endl << args_indent
2770 << this->nspace_uc + "TYPE_" + service_name_uc + "_HANDLER," << endl << args_indent
2771 << "G_PARAM_READWRITE);" << endl;
2772 f_service_ << indent() << "g_object_class_install_property (gobject_class," << endl;
2773 args_indent = indent() + string(33, ' ');
2774 f_service_ << args_indent << "PROP_" << class_name_uc << "_HANDLER," << endl << args_indent
2775 << "param_spec);" << endl;
2776 scope_down(f_service_);
2777 }
2778
2779 /**
2780 * Generates C code that represents a Thrift service server.
2781 */
2782 void t_c_glib_generator::generate_service_server(t_service* tservice) {
2783 (void)tservice;
2784 // Generate the service's handler class
2785 generate_service_handler(tservice);
2786
2787 // Generate the service's processor class
2788 generate_service_processor(tservice);
2789 }
2790
2791 /**
2792 * Generates C code to represent a THrift structure as a GObject.
2793 */
2794 void t_c_glib_generator::generate_object(t_struct* tstruct) {
2795 string name = tstruct->get_name();
2796 string name_u = initial_caps_to_underscores(name);
2797 string name_uc = to_upper_case(name_u);
2798
2799 string class_name = this->nspace + name;
2800 string class_name_lc = this->nspace_lc + initial_caps_to_underscores(name);
2801 string class_name_uc = to_upper_case(class_name_lc);
2802
2803 string function_name;
2804 string args_indent;
2805
2806 // write the instance definition
2807 f_types_ << "struct _" << this->nspace << name << endl << "{ " << endl
2808 << " ThriftStruct parent; " << endl << endl << " /* public */" << endl;
2809
2810 // for each field, add a member variable
2811 vector<t_field*>::const_iterator m_iter;
2812 const vector<t_field*>& members = tstruct->get_members();
2813 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2814 t_type* t = get_true_type((*m_iter)->get_type());
2815 f_types_ << " " << type_name(t) << " " << (*m_iter)->get_name() << ";" << endl;
2816 if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
2817 f_types_ << " gboolean __isset_" << (*m_iter)->get_name() << ";" << endl;
2818 }
2819 }
2820
2821 // close the structure definition and create a typedef
2822 f_types_ << "};" << endl << "typedef struct _" << this->nspace << name << " " << this->nspace
2823 << name << ";" << endl << endl;
2824
2825 // write the class definition
2826 f_types_ << "struct _" << this->nspace << name << "Class" << endl << "{" << endl
2827 << " ThriftStructClass parent;" << endl << "};" << endl << "typedef struct _"
2828 << this->nspace << name << "Class " << this->nspace << name << "Class;" << endl << endl;
2829
2830 // write the standard GObject boilerplate
2831 f_types_ << "GType " << this->nspace_lc << name_u << "_get_type (void);" << endl << "#define "
2832 << this->nspace_uc << "TYPE_" << name_uc << " (" << this->nspace_lc << name_u
2833 << "_get_type())" << endl << "#define " << this->nspace_uc << name_uc
2834 << "(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), " << this->nspace_uc << "TYPE_" << name_uc
2835 << ", " << this->nspace << name << "))" << endl << "#define " << this->nspace_uc
2836 << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_CAST ((c), " << this->nspace_uc << "_TYPE_"
2837 << name_uc << ", " << this->nspace << name << "Class))" << endl << "#define "
2838 << this->nspace_uc << "IS_" << name_uc << "(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), "
2839 << this->nspace_uc << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc
2840 << "IS_" << name_uc << "_CLASS(c) (G_TYPE_CHECK_CLASS_TYPE ((c), " << this->nspace_uc
2841 << "TYPE_" << name_uc << "))" << endl << "#define " << this->nspace_uc << name_uc
2842 << "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " << this->nspace_uc << "TYPE_"
2843 << name_uc << ", " << this->nspace << name << "Class))" << endl << endl;
2844
2845 // start writing the object implementation .c file
2846
2847 // generate properties enum
2848 if (members.size() > 0) {
2849 f_types_impl_ << "enum _" << class_name << "Properties" << endl << "{" << endl;
2850 indent_up();
2851 f_types_impl_ << indent() << "PROP_" << class_name_uc << "_0";
2852 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2853 string member_name_uc
2854 = to_upper_case(to_lower_case(initial_caps_to_underscores((*m_iter)->get_name())));
2855
2856 f_types_impl_ << "," << endl << indent() << "PROP_" << class_name_uc << "_" << member_name_uc;
2857 }
2858 f_types_impl_ << endl;
2859 indent_down();
2860 f_types_impl_ << "};" << endl << endl;
2861 }
2862
2863 // generate struct I/O methods
2864 string this_get = this->nspace + name + " * this_object = " + this->nspace_uc + name_uc
2865 + "(object);";
2866 generate_struct_reader(f_types_impl_, tstruct, "this_object->", this_get);
2867 generate_struct_writer(f_types_impl_, tstruct, "this_object->", this_get);
2868
2869 // generate property setter and getter
2870 if (members.size() > 0) {
2871 // generate property setter
2872 function_name = class_name_lc + "_set_property";
2873 args_indent = string(function_name.length() + 2, ' ');
2874 f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl
2875 << args_indent << "guint property_id," << endl << args_indent
2876 << "const GValue *value," << endl << args_indent << "GParamSpec *pspec)" << endl;
2877 scope_up(f_types_impl_);
2878 f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
2879 << endl << indent() << "switch (property_id)" << endl;
2880 scope_up(f_types_impl_);
2881 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
2882 t_field* member = (*m_iter);
2883 string member_name = member->get_name();
2884 string member_name_uc
2885 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
2886 t_type* member_type = get_true_type(member->get_type());
2887
2888 string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
2889
2890 f_types_impl_ << indent() << "case " << property_identifier + ":" << endl;
2891 indent_up();
2892
2893 if (member_type->is_base_type()) {
2894 t_base_type* base_type = ((t_base_type*)member_type);
2895 string assign_function_name;
2896
2897 if (base_type->get_base() == t_base_type::TYPE_STRING) {
2898 string release_function_name;
2899
2900 f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
2901 indent_up();
2902
2903 if (base_type->is_binary()) {
2904 release_function_name = "g_byte_array_unref";
2905 assign_function_name = "g_value_dup_boxed";
2906 } else {
2907 release_function_name = "g_free";
2908 assign_function_name = "g_value_dup_string";
2909 }
2910
2911 f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");"
2912 << endl;
2913 indent_down();
2914 } else {
2915 switch (base_type->get_base()) {
2916 case t_base_type::TYPE_BOOL:
2917 assign_function_name = "g_value_get_boolean";
2918 break;
2919
2920 case t_base_type::TYPE_I8:
2921 case t_base_type::TYPE_I16:
2922 case t_base_type::TYPE_I32:
2923 assign_function_name = "g_value_get_int";
2924 break;
2925
2926 case t_base_type::TYPE_I64:
2927 assign_function_name = "g_value_get_int64";
2928 break;
2929
2930 case t_base_type::TYPE_DOUBLE:
2931 assign_function_name = "g_value_get_double";
2932 break;
2933
2934 default:
2935 throw "compiler error: "
2936 "unrecognized base type \"" + base_type->get_name() + "\" "
2937 "for struct member \""
2938 + member_name + "\"";
2939 break;
2940 }
2941 }
2942
2943 f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name
2944 << " (value);" << endl;
2945 } else if (member_type->is_enum()) {
2946 f_types_impl_ << indent() << "self->" << member_name << " = g_value_get_int (value);"
2947 << endl;
2948 } else if (member_type->is_container()) {
2949 string release_function_name;
2950 string assign_function_name;
2951
2952 if (member_type->is_list()) {
2953 t_type* elem_type = ((t_list*)member_type)->get_elem_type();
2954
2955 // Lists of base types other than strings are represented as GArrays;
2956 // all others as GPtrArrays
2957 if (is_numeric(elem_type)) {
2958 release_function_name = "g_array_unref";
2959 } else {
2960 release_function_name = "g_ptr_array_unref";
2961 }
2962
2963 assign_function_name = "g_value_dup_boxed";
2964 } else if (member_type->is_set() || member_type->is_map()) {
2965 release_function_name = "g_hash_table_unref";
2966 assign_function_name = "g_value_dup_boxed";
2967 }
2968
2969 f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
2970 indent_up();
2971 f_types_impl_ << indent() << release_function_name << " (self->" << member_name << ");"
2972 << endl;
2973 indent_down();
2974 f_types_impl_ << indent() << "self->" << member_name << " = " << assign_function_name
2975 << " (value);" << endl;
2976 } else if (member_type->is_struct() || member_type->is_xception()) {
2977 f_types_impl_ << indent() << "if (self->" << member_name << " != NULL)" << endl;
2978 indent_up();
2979 f_types_impl_ << indent() << "g_object_unref (self->" << member_name << ");" << endl;
2980 indent_down();
2981 f_types_impl_ << indent() << "self->" << member_name << " = g_value_dup_object (value);"
2982 << endl;
2983 }
2984
2985 if (member->get_req() != t_field::T_REQUIRED) {
2986 f_types_impl_ << indent() << "self->__isset_" << member_name << " = TRUE;" << endl;
2987 }
2988
2989 f_types_impl_ << indent() << "break;" << endl << endl;
2990 indent_down();
2991 }
2992 f_types_impl_ << indent() << "default:" << endl;
2993 indent_up();
2994 f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
2995 << endl << indent() << "break;" << endl;
2996 indent_down();
2997 scope_down(f_types_impl_);
2998 scope_down(f_types_impl_);
2999 f_types_impl_ << endl;
3000
3001 // generate property getter
3002 function_name = class_name_lc + "_get_property";
3003 args_indent = string(function_name.length() + 2, ' ');
3004 f_types_impl_ << "static void" << endl << function_name << " (GObject *object," << endl
3005 << args_indent << "guint property_id," << endl << args_indent << "GValue *value,"
3006 << endl << args_indent << "GParamSpec *pspec)" << endl;
3007 scope_up(f_types_impl_);
3008 f_types_impl_ << indent() << class_name << " *self = " << class_name_uc << " (object);" << endl
3009 << endl << indent() << "switch (property_id)" << endl;
3010 scope_up(f_types_impl_);
3011 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3012 t_field* member = (*m_iter);
3013 string member_name = (*m_iter)->get_name();
3014 string member_name_uc
3015 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
3016 t_type* member_type = get_true_type(member->get_type());
3017
3018 string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
3019
3020 string setter_function_name;
3021
3022 if (member_type->is_base_type()) {
3023 t_base_type* base_type = ((t_base_type*)member_type);
3024
3025 switch (base_type->get_base()) {
3026 case t_base_type::TYPE_BOOL:
3027 setter_function_name = "g_value_set_boolean";
3028 break;
3029
3030 case t_base_type::TYPE_I8:
3031 case t_base_type::TYPE_I16:
3032 case t_base_type::TYPE_I32:
3033 setter_function_name = "g_value_set_int";
3034 break;
3035
3036 case t_base_type::TYPE_I64:
3037 setter_function_name = "g_value_set_int64";
3038 break;
3039
3040 case t_base_type::TYPE_DOUBLE:
3041 setter_function_name = "g_value_set_double";
3042 break;
3043
3044 case t_base_type::TYPE_STRING:
3045 if (base_type->is_binary()) {
3046 setter_function_name = "g_value_set_boxed";
3047 } else {
3048 setter_function_name = "g_value_set_string";
3049 }
3050 break;
3051
3052 default:
3053 throw "compiler error: "
3054 "unrecognized base type \"" + base_type->get_name() + "\" "
3055 "for struct member \""
3056 + member_name + "\"";
3057 break;
3058 }
3059 } else if (member_type->is_enum()) {
3060 setter_function_name = "g_value_set_int";
3061 } else if (member_type->is_struct() || member_type->is_xception()) {
3062 setter_function_name = "g_value_set_object";
3063 } else if (member_type->is_container()) {
3064 setter_function_name = "g_value_set_boxed";
3065 } else {
3066 throw "compiler error: "
3067 "unrecognized type for struct member \"" + member_name + "\"";
3068 }
3069
3070 f_types_impl_ << indent() << "case " << property_identifier + ":" << endl;
3071 indent_up();
3072 f_types_impl_ << indent() << setter_function_name << " (value, self->" << member_name << ");"
3073 << endl << indent() << "break;" << endl << endl;
3074 indent_down();
3075 }
3076 f_types_impl_ << indent() << "default:" << endl;
3077 indent_up();
3078 f_types_impl_ << indent() << "G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);"
3079 << endl << indent() << "break;" << endl;
3080 indent_down();
3081 scope_down(f_types_impl_);
3082 scope_down(f_types_impl_);
3083 f_types_impl_ << endl;
3084 }
3085
3086 // generate the instance init function
3087
3088 f_types_impl_ << "static void " << endl << this->nspace_lc << name_u << "_instance_init ("
3089 << this->nspace << name << " * object)" << endl << "{" << endl;
3090 indent_up();
3091
3092 // generate default-value structures for container-type members
3093 bool constant_declaration_output = false;
3094 bool string_list_constant_output = false;
3095 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3096 t_field* member = *m_iter;
3097 t_const_value* member_value = member->get_value();
3098
3099 if (member_value != NULL) {
3100 string member_name = member->get_name();
3101 t_type* member_type = get_true_type(member->get_type());
3102
3103 if (member_type->is_list()) {
3104 const vector<t_const_value*>& list = member_value->get_list();
3105 t_type* elem_type = ((t_list*)member_type)->get_elem_type();
3106
3107 // Generate an array with the list literal
3108 indent(f_types_impl_) << "static " << type_name(elem_type, false, true) << " __default_"
3109 << member_name << "[" << list.size() << "] = " << endl;
3110 indent_up();
3111 f_types_impl_ << indent() << constant_literal(member_type, member_value) << ";" << endl;
3112 indent_down();
3113
3114 constant_declaration_output = true;
3115
3116 // If we are generating values for a pointer array (i.e. a list of
3117 // strings), set a flag so we know to also declare an index variable to
3118 // use in pre-populating the array
3119 if (elem_type->is_string()) {
3120 string_list_constant_output = true;
3121 }
3122 }
3123
3124 // TODO: Handle container types other than list
3125 }
3126 }
3127 if (constant_declaration_output) {
3128 if (string_list_constant_output) {
3129 indent(f_types_impl_) << "unsigned int list_index;" << endl;
3130 }
3131
3132 f_types_impl_ << endl;
3133 }
3134
3135 // satisfy compilers with -Wall turned on
3136 indent(f_types_impl_) << "/* satisfy -Wall */" << endl << indent()
3137 << "THRIFT_UNUSED_VAR (object);" << endl;
3138
3139 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3140 t_type* member_type = (*m_iter)->get_type();
3141 t_type* t = get_true_type(member_type);
3142 if (t->is_base_type()) {
3143 string dval = " = ";
3144 if (t->is_enum()) {
3145 dval += "(" + type_name(t) + ")";
3146 }
3147 t_const_value* cv = (*m_iter)->get_value();
3148 if (cv != NULL) {
3149 dval += constant_value("", t, cv);
3150 } else {
3151 dval += t->is_string() ? "NULL" : "0";
3152 }
3153 indent(f_types_impl_) << "object->" << (*m_iter)->get_name() << dval << ";" << endl;
3154 } else if (t->is_struct()) {
3155 string name = (*m_iter)->get_name();
3156 t_program* type_program = member_type->get_program();
3157 string type_nspace = type_program ? type_program->get_namespace("c_glib") : "";
3158 string type_nspace_prefix =
3159 type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_";
3160 string type_name_uc = to_upper_case(initial_caps_to_underscores(member_type->get_name()));
3161 indent(f_types_impl_) << "object->" << name << " = g_object_new ("
3162 << to_upper_case(type_nspace_prefix) << "TYPE_" << type_name_uc
3163 << ", NULL);" << endl;
3164 } else if (t->is_xception()) {
3165 string name = (*m_iter)->get_name();
3166 indent(f_types_impl_) << "object->" << name << " = NULL;" << endl;
3167 } else if (t->is_container()) {
3168 string name = (*m_iter)->get_name();
3169 string init_function;
3170 t_type* etype = NULL;
3171
3172 if (t->is_map()) {
3173 t_type* key = ((t_map*)t)->get_key_type();
3174 t_type* value = ((t_map*)t)->get_val_type();
3175 init_function = generate_new_hash_from_type(key, value);
3176 } else if (t->is_set()) {
3177 etype = ((t_set*)t)->get_elem_type();
3178 init_function = generate_new_hash_from_type(etype, NULL);
3179 } else if (t->is_list()) {
3180 etype = ((t_list*)t)->get_elem_type();
3181 init_function = generate_new_array_from_type(etype);
3182 }
3183
3184 indent(f_types_impl_) << "object->" << name << " = " << init_function << endl;
3185
3186 // Pre-populate the container with the specified default values, if any
3187 if ((*m_iter)->get_value()) {
3188 t_const_value* member_value = (*m_iter)->get_value();
3189
3190 if (t->is_list()) {
3191 const vector<t_const_value*>& list = member_value->get_list();
3192
3193 if (is_numeric(etype)) {
3194 indent(f_types_impl_) <<
3195 "g_array_append_vals (object->" << name << ", &__default_" <<
3196 name << ", " << list.size() << ");" << endl;
3197 }
3198 else {
3199 indent(f_types_impl_) <<
3200 "for (list_index = 0; list_index < " << list.size() << "; " <<
3201 "list_index += 1)" << endl;
3202 indent_up();
3203 indent(f_types_impl_) <<
3204 "g_ptr_array_add (object->" << name << "," << endl <<
3205 indent() << string(17, ' ') << "g_strdup (__default_" <<
3206 name << "[list_index]));" << endl;
3207 indent_down();
3208 }
3209 }
3210
3211 // TODO: Handle container types other than list
3212 }
3213 }
3214
3215 /* if not required, initialize the __isset variable */
3216 if ((*m_iter)->get_req() != t_field::T_REQUIRED) {
3217 indent(f_types_impl_) << "object->__isset_" << (*m_iter)->get_name() << " = FALSE;" << endl;
3218 }
3219 }
3220
3221 indent_down();
3222 f_types_impl_ << "}" << endl << endl;
3223
3224 /* create the destructor */
3225 f_types_impl_ << "static void " << endl << this->nspace_lc << name_u
3226 << "_finalize (GObject *object)" << endl << "{" << endl;
3227 indent_up();
3228
3229 f_types_impl_ << indent() << this->nspace << name << " *tobject = " << this->nspace_uc << name_uc
3230 << " (object);" << endl << endl;
3231
3232 f_types_impl_ << indent() << "/* satisfy -Wall in case we don't use tobject */" << endl
3233 << indent() << "THRIFT_UNUSED_VAR (tobject);" << endl;
3234
3235 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3236 t_type* t = get_true_type((*m_iter)->get_type());
3237 if (t->is_container()) {
3238 string name = (*m_iter)->get_name();
3239 if (t->is_map() || t->is_set()) {
3240 f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
3241 f_types_impl_ << indent() << "{" << endl;
3242 indent_up();
3243 f_types_impl_ << indent() << "g_hash_table_destroy (tobject->" << name << ");" << endl;
3244 f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
3245 indent_down();
3246 f_types_impl_ << indent() << "}" << endl;
3247 } else if (t->is_list()) {
3248 t_type* etype = ((t_list*)t)->get_elem_type();
3249 string destructor_function = "g_ptr_array_unref";
3250
3251 if (etype->is_base_type()) {
3252 t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
3253 switch (tbase) {
3254 case t_base_type::TYPE_VOID:
3255 throw "compiler error: cannot determine array type";
3256 case t_base_type::TYPE_BOOL:
3257 case t_base_type::TYPE_I8:
3258 case t_base_type::TYPE_I16:
3259 case t_base_type::TYPE_I32:
3260 case t_base_type::TYPE_I64:
3261 case t_base_type::TYPE_DOUBLE:
3262 destructor_function = "g_array_unref";
3263 break;
3264 case t_base_type::TYPE_STRING:
3265 break;
3266 default:
3267 throw "compiler error: no array info for type";
3268 }
3269 } else if (etype->is_enum()) {
3270 destructor_function = "g_array_unref";
3271 }
3272
3273 f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
3274 f_types_impl_ << indent() << "{" << endl;
3275 indent_up();
3276 f_types_impl_ << indent() << destructor_function << " (tobject->" << name << ");" << endl;
3277 f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
3278 indent_down();
3279 f_types_impl_ << indent() << "}" << endl;
3280 }
3281 } else if (t->is_struct() || t->is_xception()) {
3282 string name = (*m_iter)->get_name();
3283 // TODO: g_clear_object needs glib >= 2.28
3284 // f_types_impl_ << indent() << "g_clear_object (&(tobject->" << name << "));" << endl;
3285 // does g_object_unref the trick?
3286 f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
3287 f_types_impl_ << indent() << "{" << endl;
3288 indent_up();
3289 f_types_impl_ << indent() << "g_object_unref(tobject->" << name << ");" << endl;
3290 f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
3291 indent_down();
3292 f_types_impl_ << indent() << "}" << endl;
3293 } else if (t->is_string()) {
3294 string name = (*m_iter)->get_name();
3295 f_types_impl_ << indent() << "if (tobject->" << name << " != NULL)" << endl;
3296 f_types_impl_ << indent() << "{" << endl;
3297 indent_up();
3298 f_types_impl_ << indent() << generate_free_func_from_type(t) << "(tobject->" << name << ");"
3299 << endl;
3300 f_types_impl_ << indent() << "tobject->" << name << " = NULL;" << endl;
3301 indent_down();
3302 f_types_impl_ << indent() << "}" << endl;
3303 }
3304 }
3305
3306 indent_down();
3307 f_types_impl_ << "}" << endl << endl;
3308
3309 // generate the class init function
3310
3311 f_types_impl_ << "static void" << endl << class_name_lc << "_class_init (" << class_name
3312 << "Class * cls)" << endl;
3313 scope_up(f_types_impl_);
3314
3315 f_types_impl_ << indent() << "GObjectClass *gobject_class = G_OBJECT_CLASS (cls);" << endl
3316 << indent() << "ThriftStructClass *struct_class = "
3317 << "THRIFT_STRUCT_CLASS (cls);" << endl << endl << indent()
3318 << "struct_class->read = " << class_name_lc << "_read;" << endl << indent()
3319 << "struct_class->write = " << class_name_lc << "_write;" << endl << endl
3320 << indent() << "gobject_class->finalize = " << class_name_lc << "_finalize;"
3321 << endl;
3322 if (members.size() > 0) {
3323 f_types_impl_ << indent() << "gobject_class->get_property = " << class_name_lc
3324 << "_get_property;" << endl << indent()
3325 << "gobject_class->set_property = " << class_name_lc << "_set_property;" << endl;
3326
3327 // install a property for each member
3328 for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
3329 t_field* member = (*m_iter);
3330 string member_name = member->get_name();
3331 string member_name_uc
3332 = to_upper_case(to_lower_case(initial_caps_to_underscores(member_name)));
3333 t_type* member_type = get_true_type(member->get_type());
3334 t_const_value* member_value = member->get_value();
3335
3336 string property_identifier = "PROP_" + class_name_uc + "_" + member_name_uc;
3337
3338 f_types_impl_ << endl << indent() << "g_object_class_install_property" << endl;
3339 indent_up();
3340 args_indent = indent() + ' ';
3341 f_types_impl_ << indent() << "(gobject_class," << endl << args_indent << property_identifier
3342 << "," << endl << args_indent;
3343
3344 if (member_type->is_base_type()) {
3345 t_base_type::t_base base_type = ((t_base_type*)member_type)->get_base();
3346
3347 if (base_type == t_base_type::TYPE_STRING) {
3348 if (((t_base_type*)member_type)->is_binary()) {
3349 args_indent += string(20, ' ');
3350 f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
3351 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3352 << "G_TYPE_BYTE_ARRAY," << endl << args_indent << "G_PARAM_READWRITE));"
3353 << endl;
3354 } else {
3355 args_indent += string(21, ' ');
3356 f_types_impl_ << "g_param_spec_string (\"" << member_name << "\"," << endl
3357 << args_indent << "NULL," << endl << args_indent << "NULL," << endl
3358 << args_indent
3359 << ((member_value != NULL) ? "\"" + member_value->get_string() + "\""
3360 : "NULL") << "," << endl << args_indent
3361 << "G_PARAM_READWRITE));" << endl;
3362 }
3363 } else if (base_type == t_base_type::TYPE_BOOL) {
3364 args_indent += string(22, ' ');
3365 f_types_impl_ << "g_param_spec_boolean (\"" << member_name << "\"," << endl << args_indent
3366 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3367 << (((member_value != NULL) && (member_value->get_integer() != 0))
3368 ? "TRUE"
3369 : "FALSE") << "," << endl << args_indent << "G_PARAM_READWRITE));"
3370 << endl;
3371 } else if ((base_type == t_base_type::TYPE_I8) || (base_type == t_base_type::TYPE_I16)
3372 || (base_type == t_base_type::TYPE_I32) || (base_type == t_base_type::TYPE_I64)
3373 || (base_type == t_base_type::TYPE_DOUBLE)) {
3374 string param_spec_function_name = "g_param_spec_int";
3375 string min_value;
3376 string max_value;
3377 ostringstream default_value;
3378
3379 switch (base_type) {
3380 case t_base_type::TYPE_I8:
3381 min_value = "G_MININT8";
3382 max_value = "G_MAXINT8";
3383 break;
3384
3385 case t_base_type::TYPE_I16:
3386 min_value = "G_MININT16";
3387 max_value = "G_MAXINT16";
3388 break;
3389
3390 case t_base_type::TYPE_I32:
3391 min_value = "G_MININT32";
3392 max_value = "G_MAXINT32";
3393 break;
3394
3395 case t_base_type::TYPE_I64:
3396 param_spec_function_name = "g_param_spec_int64";
3397 min_value = "G_MININT64";
3398 max_value = "G_MAXINT64";
3399 break;
3400
3401 case t_base_type::TYPE_DOUBLE:
3402 param_spec_function_name = "g_param_spec_double";
3403 min_value = "-INFINITY";
3404 max_value = "INFINITY";
3405 break;
3406
3407 default:
3408 throw "compiler error: "
3409 "unrecognized base type \"" + member_type->get_name() + "\" "
3410 "for struct member \""
3411 + member_name + "\"";
3412 break;
3413 }
3414
3415 if (member_value != NULL) {
3416 default_value << (base_type == t_base_type::TYPE_DOUBLE ? member_value->get_double()
3417 : member_value->get_integer());
3418 } else {
3419 default_value << "0";
3420 }
3421
3422 args_indent += string(param_spec_function_name.length() + 2, ' ');
3423 f_types_impl_ << param_spec_function_name << " (\"" << member_name << "\"," << endl
3424 << args_indent << "NULL," << endl << args_indent << "NULL," << endl
3425 << args_indent << min_value << "," << endl << args_indent << max_value
3426 << "," << endl << args_indent << default_value.str() << "," << endl
3427 << args_indent << "G_PARAM_READWRITE));" << endl;
3428 }
3429
3430 indent_down();
3431 } else if (member_type->is_enum()) {
3432 t_enum_value* enum_min_value = ((t_enum*)member_type)->get_min_value();
3433 t_enum_value* enum_max_value = ((t_enum*)member_type)->get_max_value();
3434 int min_value = (enum_min_value != NULL) ? enum_min_value->get_value() : 0;
3435 int max_value = (enum_max_value != NULL) ? enum_max_value->get_value() : 0;
3436
3437 args_indent += string(18, ' ');
3438 f_types_impl_ << "g_param_spec_int (\"" << member_name << "\"," << endl << args_indent
3439 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3440 << min_value << "," << endl << args_indent << max_value << "," << endl
3441 << args_indent << min_value << "," << endl << args_indent
3442 << "G_PARAM_READWRITE));" << endl;
3443 indent_down();
3444 } else if (member_type->is_struct() || member_type->is_xception()) {
3445 t_program* type_program = member_type->get_program();
3446 string type_nspace = type_program ? type_program->get_namespace("c_glib") : "";
3447 string type_nspace_prefix =
3448 type_nspace.empty() ? "" : initial_caps_to_underscores(type_nspace) + "_";
3449
3450 string param_type = to_upper_case(type_nspace_prefix) + "TYPE_"
3451 + to_upper_case(initial_caps_to_underscores(member_type->get_name()));
3452
3453 args_indent += string(20, ' ');
3454 f_types_impl_ << "g_param_spec_object (\"" << member_name << "\"," << endl << args_indent
3455 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3456 << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl;
3457 indent_down();
3458 } else if (member_type->is_list()) {
3459 t_type* elem_type = ((t_list*)member_type)->get_elem_type();
3460 string param_type;
3461
3462 if (elem_type->is_base_type() && !elem_type->is_string()) {
3463 param_type = "G_TYPE_ARRAY";
3464 } else {
3465 param_type = "G_TYPE_PTR_ARRAY";
3466 }
3467
3468 args_indent += string(20, ' ');
3469 f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
3470 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3471 << param_type << "," << endl << args_indent << "G_PARAM_READWRITE));" << endl;
3472 indent_down();
3473 } else if (member_type->is_set() || member_type->is_map()) {
3474 args_indent += string(20, ' ');
3475 f_types_impl_ << "g_param_spec_boxed (\"" << member_name << "\"," << endl << args_indent
3476 << "NULL," << endl << args_indent << "NULL," << endl << args_indent
3477 << "G_TYPE_HASH_TABLE," << endl << args_indent << "G_PARAM_READWRITE));"
3478 << endl;
3479 indent_down();
3480 }
3481 }
3482 }
3483 scope_down(f_types_impl_);
3484 f_types_impl_ << endl;
3485
3486 f_types_impl_ << "GType" << endl << this->nspace_lc << name_u << "_get_type (void)" << endl << "{"
3487 << endl << " static GType type = 0;" << endl << endl << " if (type == 0) " << endl
3488 << " {" << endl << " static const GTypeInfo type_info = " << endl << " {"
3489 << endl << " sizeof (" << this->nspace << name << "Class)," << endl
3490 << " NULL, /* base_init */" << endl << " NULL, /* base_finalize */"
3491 << endl << " (GClassInitFunc) " << this->nspace_lc << name_u << "_class_init,"
3492 << endl << " NULL, /* class_finalize */" << endl
3493 << " NULL, /* class_data */" << endl << " sizeof (" << this->nspace
3494 << name << ")," << endl << " 0, /* n_preallocs */" << endl
3495 << " (GInstanceInitFunc) " << this->nspace_lc << name_u << "_instance_init,"
3496 << endl << " NULL, /* value_table */" << endl << " };" << endl << endl
3497 << " type = g_type_register_static (THRIFT_TYPE_STRUCT, " << endl
3498 << " \"" << this->nspace << name << "Type\","
3499 << endl << " &type_info, 0);" << endl << " }"
3500 << endl << endl << " return type;" << endl << "}" << endl << endl;
3501 }
3502
3503 /**
3504 * Generates functions to write Thrift structures to a stream.
3505 */
3506 void t_c_glib_generator::generate_struct_writer(ostream& out,
3507 t_struct* tstruct,
3508 string this_name,
3509 string this_get,
3510 bool is_function) {
3511 string name = tstruct->get_name();
3512 string name_u = initial_caps_to_underscores(name);
3513 string name_uc = to_upper_case(name_u);
3514
3515 const vector<t_field*>& fields = tstruct->get_members();
3516 vector<t_field*>::const_iterator f_iter;
3517 int error_ret = 0;
3518
3519 if (is_function) {
3520 error_ret = -1;
3521 indent(out) << "static gint32" << endl << this->nspace_lc << name_u
3522 << "_write (ThriftStruct *object, ThriftProtocol *protocol, GError **error)"
3523 << endl;
3524 }
3525 indent(out) << "{" << endl;
3526 indent_up();
3527
3528 out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << endl;
3529
3530 indent(out) << this_get << endl;
3531 // satisfy -Wall in the case of an empty struct
3532 if (!this_get.empty()) {
3533 indent(out) << "THRIFT_UNUSED_VAR (this_object);" << endl;
3534 }
3535
3536 out << indent() << "if ((ret = thrift_protocol_write_struct_begin (protocol, \"" << name
3537 << "\", error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl
3538 << indent() << "xfer += ret;" << endl;
3539
3540 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3541 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
3542 indent(out) << "if (this_object->__isset_" << (*f_iter)->get_name() << " == TRUE) {" << endl;
3543 indent_up();
3544 }
3545
3546 out << indent() << "if ((ret = thrift_protocol_write_field_begin (protocol, "
3547 << "\"" << (*f_iter)->get_name() << "\", " << type_to_enum((*f_iter)->get_type()) << ", "
3548 << (*f_iter)->get_key() << ", error)) < 0)" << endl << indent() << " return " << error_ret
3549 << ";" << endl << indent() << "xfer += ret;" << endl;
3550 generate_serialize_field(out, *f_iter, this_name, "", error_ret);
3551 out << indent() << "if ((ret = thrift_protocol_write_field_end (protocol, error)) < 0)" << endl
3552 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;"
3553 << endl;
3554
3555 if ((*f_iter)->get_req() == t_field::T_OPTIONAL) {
3556 indent_down();
3557 indent(out) << "}" << endl;
3558 }
3559 }
3560
3561 // write the struct map
3562 out << indent() << "if ((ret = thrift_protocol_write_field_stop (protocol, error)) < 0)" << endl
3563 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
3564 << indent() << "if ((ret = thrift_protocol_write_struct_end (protocol, error)) < 0)" << endl
3565 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
3566 << endl;
3567
3568 if (is_function) {
3569 indent(out) << "return xfer;" << endl;
3570 }
3571
3572 indent_down();
3573 indent(out) << "}" << endl << endl;
3574 }
3575
3576 /**
3577 * Generates code to read Thrift structures from a stream.
3578 */
3579 void t_c_glib_generator::generate_struct_reader(ostream& out,
3580 t_struct* tstruct,
3581 string this_name,
3582 string this_get,
3583 bool is_function) {
3584 string name = tstruct->get_name();
3585 string name_u = initial_caps_to_underscores(name);
3586 string name_uc = to_upper_case(name_u);
3587 int error_ret = 0;
3588 const vector<t_field*>& fields = tstruct->get_members();
3589 vector<t_field*>::const_iterator f_iter;
3590
3591 if (is_function) {
3592 error_ret = -1;
3593 indent(out) << "/* reads a " << name_u << " object */" << endl << "static gint32" << endl
3594 << this->nspace_lc << name_u
3595 << "_read (ThriftStruct *object, ThriftProtocol *protocol, GError **error)" << endl;
3596 }
3597
3598 indent(out) << "{" << endl;
3599 indent_up();
3600
3601 // declare stack temp variables
3602 out << indent() << "gint32 ret;" << endl << indent() << "gint32 xfer = 0;" << endl << indent()
3603 << "gchar *name = NULL;" << endl << indent() << "ThriftType ftype;" << endl << indent()
3604 << "gint16 fid;" << endl << indent() << "guint32 len = 0;" << endl << indent()
3605 << "gpointer data = NULL;" << endl << indent() << this_get << endl;
3606
3607 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3608 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
3609 indent(out) << "gboolean isset_" << (*f_iter)->get_name() << " = FALSE;" << endl;
3610 }
3611 }
3612
3613 out << endl;
3614
3615 // satisfy -Wall in case we don't use some variables
3616 out << indent() << "/* satisfy -Wall in case these aren't used */" << endl << indent()
3617 << "THRIFT_UNUSED_VAR (len);" << endl << indent() << "THRIFT_UNUSED_VAR (data);" << endl;
3618
3619 if (!this_get.empty()) {
3620 out << indent() << "THRIFT_UNUSED_VAR (this_object);" << endl;
3621 }
3622 out << endl;
3623
3624 // read the beginning of the structure marker
3625 out << indent() << "/* read the struct begin marker */" << endl << indent()
3626 << "if ((ret = thrift_protocol_read_struct_begin (protocol, &name, error)) < 0)" << endl
3627 << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl << indent()
3628 << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent()
3629 << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent()
3630 << "name = NULL;" << endl << endl;
3631
3632 // read the struct fields
3633 out << indent() << "/* read the struct fields */" << endl << indent() << "while (1)" << endl;
3634 scope_up(out);
3635
3636 // read beginning field marker
3637 out << indent() << "/* read the beginning of a field */" << endl << indent()
3638 << "if ((ret = thrift_protocol_read_field_begin (protocol, &name, &ftype, &fid, error)) < 0)"
3639 << endl << indent() << "{" << endl << indent() << " if (name) g_free (name);" << endl
3640 << indent() << " return " << error_ret << ";" << endl << indent() << "}" << endl << indent()
3641 << "xfer += ret;" << endl << indent() << "if (name) g_free (name);" << endl << indent()
3642 << "name = NULL;" << endl << endl;
3643
3644 // check for field STOP marker
3645 out << indent() << "/* break if we get a STOP field */" << endl << indent()
3646 << "if (ftype == T_STOP)" << endl << indent() << "{" << endl << indent() << " break;" << endl
3647 << indent() << "}" << endl << endl;
3648
3649 // switch depending on the field type
3650 indent(out) << "switch (fid)" << endl;
3651
3652 // start switch
3653 scope_up(out);
3654
3655 // generate deserialization code for known types
3656 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3657 indent(out) << "case " << (*f_iter)->get_key() << ":" << endl;
3658 indent_up();
3659 indent(out) << "if (ftype == " << type_to_enum((*f_iter)->get_type()) << ")" << endl;
3660 indent(out) << "{" << endl;
3661
3662 indent_up();
3663 // generate deserialize field
3664 generate_deserialize_field(out, *f_iter, this_name, "", error_ret, false);
3665 indent_down();
3666
3667 out << indent() << "} else {" << endl << indent()
3668 << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent()
3669 << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl
3670 << indent() << "}" << endl << indent() << "break;" << endl;
3671 indent_down();
3672 }
3673
3674 // create the default case
3675 out << indent() << "default:" << endl << indent()
3676 << " if ((ret = thrift_protocol_skip (protocol, ftype, error)) < 0)" << endl << indent()
3677 << " return " << error_ret << ";" << endl << indent() << " xfer += ret;" << endl
3678 << indent() << " break;" << endl;
3679
3680 // end switch
3681 scope_down(out);
3682
3683 // read field end marker
3684 out << indent() << "if ((ret = thrift_protocol_read_field_end (protocol, error)) < 0)" << endl
3685 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl;
3686
3687 // end while loop
3688 scope_down(out);
3689 out << endl;
3690
3691 // read the end of the structure
3692 out << indent() << "if ((ret = thrift_protocol_read_struct_end (protocol, error)) < 0)" << endl
3693 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
3694 << endl;
3695
3696 // if a required field is missing, throw an error
3697 for (f_iter = fields.begin(); f_iter != fields.end(); ++f_iter) {
3698 if ((*f_iter)->get_req() == t_field::T_REQUIRED) {
3699 out << indent() << "if (!isset_" << (*f_iter)->get_name() << ")" << endl << indent() << "{"
3700 << endl << indent() << " g_set_error (error, THRIFT_PROTOCOL_ERROR," << endl << indent()
3701 << " THRIFT_PROTOCOL_ERROR_INVALID_DATA," << endl << indent()
3702 << " \"missing field\");" << endl << indent() << " return -1;" << endl
3703 << indent() << "}" << endl << endl;
3704 }
3705 }
3706
3707 if (is_function) {
3708 indent(out) << "return xfer;" << endl;
3709 }
3710
3711 // end the function/structure
3712 indent_down();
3713 indent(out) << "}" << endl << endl;
3714 }
3715
3716 void t_c_glib_generator::generate_serialize_field(ostream& out,
3717 t_field* tfield,
3718 string prefix,
3719 string suffix,
3720 int error_ret) {
3721 t_type* type = get_true_type(tfield->get_type());
3722 string name = prefix + tfield->get_name() + suffix;
3723
3724 if (type->is_void()) {
3725 throw "CANNOT GENERATE SERIALIZE CODE FOR void TYPE: " + name;
3726 }
3727
3728 if (type->is_struct() || type->is_xception()) {
3729 generate_serialize_struct(out, (t_struct*)type, name, error_ret);
3730 } else if (type->is_container()) {
3731 generate_serialize_container(out, type, name, error_ret);
3732 } else if (type->is_base_type() || type->is_enum()) {
3733 indent(out) << "if ((ret = thrift_protocol_write_";
3734
3735 if (type->is_base_type()) {
3736 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
3737 switch (tbase) {
3738 case t_base_type::TYPE_VOID:
3739 throw "compiler error: cannot serialize void field in a struct: " + name;
3740 break;
3741 case t_base_type::TYPE_BOOL:
3742 out << "bool (protocol, " << name;
3743 break;
3744 case t_base_type::TYPE_I8:
3745 out << "byte (protocol, " << name;
3746 break;
3747 case t_base_type::TYPE_I16:
3748 out << "i16 (protocol, " << name;
3749 break;
3750 case t_base_type::TYPE_I32:
3751 out << "i32 (protocol, " << name;
3752 break;
3753 case t_base_type::TYPE_I64:
3754 out << "i64 (protocol, " << name;
3755 break;
3756 case t_base_type::TYPE_DOUBLE:
3757 out << "double (protocol, " << name;
3758 break;
3759 case t_base_type::TYPE_STRING:
3760 if (type->is_binary()) {
3761 out << "binary (protocol, " << name << " ? ((GByteArray *) " << name << ")->data : NULL, "
3762 << name << " ? ((GByteArray *) " << name << ")->len : 0";
3763 } else {
3764 out << "string (protocol, " << name;
3765 }
3766 break;
3767 default:
3768 throw "compiler error: no C writer for base type " + t_base_type::t_base_name(tbase) + name;
3769 }
3770 } else {
3771 out << "i32 (protocol, (gint32) " << name;
3772 }
3773 out << ", error)) < 0)" << endl
3774 << indent() << " return " << error_ret << ";" << endl
3775 << indent() << "xfer += ret;" << endl << endl;
3776 } else {
3777 throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + name + "' TYPE '"
3778 + type_name(type));
3779 }
3780 }
3781
3782 void t_c_glib_generator::generate_serialize_struct(ostream& out,
3783 t_struct* tstruct,
3784 string prefix,
3785 int error_ret) {
3786 (void)tstruct;
3787 out << indent() << "if ((ret = thrift_struct_write (THRIFT_STRUCT (" << prefix
3788 << "), protocol, error)) < 0)" << endl << indent() << " return " << error_ret << ";" << endl
3789 << indent() << "xfer += ret;" << endl << endl;
3790 }
3791
3792 void t_c_glib_generator::generate_serialize_container(ostream& out,
3793 t_type* ttype,
3794 string prefix,
3795 int error_ret) {
3796 scope_up(out);
3797
3798 if (ttype->is_map()) {
3799 t_type* tkey = ((t_map*)ttype)->get_key_type();
3800 t_type* tval = ((t_map*)ttype)->get_val_type();
3801 string tkey_name = type_name(tkey);
3802 string tval_name = type_name(tval);
3803 string tkey_ptr;
3804 string tval_ptr;
3805 string keyname = tmp("key");
3806 string valname = tmp("val");
3807
3808 declore_local_variable_for_write(out, tkey, keyname);
3809 declore_local_variable_for_write(out, tval, valname);
3810
3811 /* If either the key or value type is a typedef, find its underlying type so
3812 we can correctly determine how to generate a pointer to it */
3813 tkey = get_true_type(tkey);
3814 tval = get_true_type(tval);
3815
3816 tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
3817 tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
3818
3819 /*
3820 * Some ugliness here. To maximize backwards compatibility, we
3821 * avoid using GHashTableIter and instead get a GList of all keys,
3822 * then copy it into a array on the stack, and free it.
3823 * This is because we may exit early before we get a chance to free the
3824 * GList.
3825 */
3826 out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl
3827 << indent() << tkey_name << tkey_ptr << "* keys;" << endl
3828 << indent() << "int i = 0, key_count;" << endl
3829 << endl
3830 << indent() << "if ((ret = thrift_protocol_write_map_begin (protocol, "
3831 << type_to_enum(tkey) << ", " << type_to_enum(tval) << ", " << prefix << " ? "
3832 << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0"
3833 << ", error)) < 0)" << endl;
3834 indent_up();
3835 out << indent() << "return " << error_ret << ";" << endl;
3836 indent_down();
3837 out << indent() << "xfer += ret;" << endl
3838 << indent() << "if (" << prefix << ")" << endl
3839 << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix
3840 << ", thrift_hash_table_get_keys, &key_list);" << endl
3841 << indent() << "key_count = g_list_length (key_list);" << endl
3842 << indent() << "keys = g_newa (" << tkey_name << tkey_ptr
3843 << ", key_count);" << endl
3844 << indent() << "for (iter = g_list_first (key_list); iter; "
3845 "iter = iter->next)" << endl;
3846 indent_up();
3847 out << indent() << "keys[i++] = (" << tkey_name << tkey_ptr
3848 << ") iter->data;" << endl;
3849 indent_down();
3850 out << indent() << "g_list_free (key_list);" << endl
3851 << endl
3852 << indent() << "for (i = 0; i < key_count; ++i)" << endl;
3853 scope_up(out);
3854 out << indent() << keyname << " = keys[i];" << endl
3855 << indent() << valname << " = (" << tval_name << tval_ptr
3856 << ") g_hash_table_lookup (((GHashTable *) " << prefix
3857 << "), (gpointer) " << keyname << ");" << endl
3858 << endl;
3859 generate_serialize_map_element(out,
3860 (t_map*)ttype,
3861 tkey_ptr + " " + keyname,
3862 tval_ptr + " " + valname,
3863 error_ret);
3864 scope_down(out);
3865 out << indent() << "if ((ret = thrift_protocol_write_map_end (protocol, "
3866 "error)) < 0)" << endl;
3867 indent_up();
3868 out << indent() << "return " << error_ret << ";" << endl;
3869 indent_down();
3870 out << indent() << "xfer += ret;" << endl;
3871 } else if (ttype->is_set()) {
3872 t_type* telem = ((t_set*)ttype)->get_elem_type();
3873 string telem_name = type_name(telem);
3874 string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
3875 out << indent() << "GList *key_list = NULL, *iter = NULL;" << endl
3876 << indent() << telem_name << telem_ptr << "* keys;" << endl
3877 << indent() << "int i = 0, key_count;" << endl
3878 << indent() << telem_name << telem_ptr << " elem;" << endl
3879 << indent() << "gpointer value;" << endl
3880 << indent() << "THRIFT_UNUSED_VAR (value);" << endl
3881 << endl
3882 << indent() << "if ((ret = thrift_protocol_write_set_begin (protocol, "
3883 << type_to_enum(telem) << ", " << prefix << " ? "
3884 << "(gint32) g_hash_table_size ((GHashTable *) " << prefix << ") : 0"
3885 << ", error)) < 0)" << endl;
3886 indent_up();
3887 out << indent() << "return " << error_ret << ";" << endl;
3888 indent_down();
3889 out << indent() << "xfer += ret;" << endl
3890 << indent() << "if (" << prefix << ")" << endl
3891 << indent() << " g_hash_table_foreach ((GHashTable *) " << prefix
3892 << ", thrift_hash_table_get_keys, &key_list);" << endl
3893 << indent() << "key_count = g_list_length (key_list);" << endl
3894 << indent() << "keys = g_newa (" << telem_name << telem_ptr
3895 << ", key_count);" << endl
3896 << indent() << "for (iter = g_list_first (key_list); iter; "
3897 "iter = iter->next)" << endl;
3898 indent_up();
3899 out << indent() << "keys[i++] = (" << telem_name << telem_ptr
3900 << ") iter->data;" << endl;
3901 indent_down();
3902 out << indent() << "g_list_free (key_list);" << endl
3903 << endl
3904 << indent() << "for (i = 0; i < key_count; ++i)" << endl;
3905 scope_up(out);
3906 out << indent() << "elem = keys[i];" << endl
3907 << indent() << "value = (gpointer) g_hash_table_lookup "
3908 "(((GHashTable *) " << prefix << "), (gpointer) elem);" << endl
3909 << endl;
3910 generate_serialize_set_element(out,
3911 (t_set*)ttype,
3912 telem_ptr + "elem",
3913 error_ret);
3914 scope_down(out);
3915 out << indent() << "if ((ret = thrift_protocol_write_set_end (protocol, "
3916 "error)) < 0)" << endl;
3917 indent_up();
3918 out << indent() << "return " << error_ret << ";" << endl;
3919 indent_down();
3920 out << indent() << "xfer += ret;" << endl;
3921 } else if (ttype->is_list()) {
3922 string length = "(" + prefix + " ? " + prefix + "->len : 0)";
3923 string i = tmp("i");
3924 out << indent() << "guint " << i << ";" << endl
3925 << endl
3926 << indent() << "if ((ret = thrift_protocol_write_list_begin (protocol, "
3927 << type_to_enum(((t_list*)ttype)->get_elem_type()) << ", (gint32) "
3928 << length << ", error)) < 0)" << endl;
3929 indent_up();
3930 out << indent() << "return " << error_ret << ";" << endl;
3931 indent_down();
3932 out << indent() << "xfer += ret;" << endl
3933 << indent() << "for (" << i << " = 0; " << i << " < " << length << "; "
3934 << i << "++)" << endl;
3935 scope_up(out);
3936 generate_serialize_list_element(out, (t_list*)ttype, prefix, i, error_ret);
3937 scope_down(out);
3938 out << indent() << "if ((ret = thrift_protocol_write_list_end (protocol, "
3939 "error)) < 0)" << endl;
3940 indent_up();
3941 out << indent() << "return " << error_ret << ";" << endl;
3942 indent_down();
3943 out << indent() << "xfer += ret;" << endl;
3944 }
3945
3946 scope_down(out);
3947 }
3948
3949 void t_c_glib_generator::generate_serialize_map_element(ostream& out,
3950 t_map* tmap,
3951 string key,
3952 string value,
3953 int error_ret) {
3954 t_field kfield(tmap->get_key_type(), key);
3955 generate_serialize_field(out, &kfield, "", "", error_ret);
3956
3957 t_field vfield(tmap->get_val_type(), value);
3958 generate_serialize_field(out, &vfield, "", "", error_ret);
3959 }
3960
3961 void t_c_glib_generator::generate_serialize_set_element(ostream& out,
3962 t_set* tset,
3963 string element,
3964 int error_ret) {
3965 t_field efield(tset->get_elem_type(), element);
3966 generate_serialize_field(out, &efield, "", "", error_ret);
3967 }
3968
3969 void t_c_glib_generator::generate_serialize_list_element(ostream& out,
3970 t_list* tlist,
3971 string list,
3972 string index,
3973 int error_ret) {
3974 t_type* ttype = get_true_type(tlist->get_elem_type());
3975
3976 // cast to non-const
3977 string cast = "";
3978 string name = "g_ptr_array_index ((GPtrArray *) " + list + ", " + index + ")";
3979
3980 if (ttype->is_void()) {
3981 throw std::runtime_error("compiler error: list element type cannot be void");
3982 } else if (is_numeric(ttype)) {
3983 name = "g_array_index (" + list + ", " + base_type_name(ttype) + ", " + index + ")";
3984 } else if (ttype->is_string()) {
3985 cast = "(gchar*)";
3986 } else if (ttype->is_map() || ttype->is_set()) {
3987 cast = "(GHashTable*)";
3988 } else if (ttype->is_list()) {
3989 t_type* etype = ((t_list*)ttype)->get_elem_type();
3990 if (etype->is_void()) {
3991 throw std::runtime_error("compiler error: list element type cannot be void");
3992 }
3993 cast = is_numeric(etype) ? "(GArray*)" : "(GPtrArray*)";
3994 }
3995
3996 t_field efield(ttype, "(" + cast + name + ")");
3997 generate_serialize_field(out, &efield, "", "", error_ret);
3998 }
3999
4000 /* deserializes a field of any type. */
4001 void t_c_glib_generator::generate_deserialize_field(ostream& out,
4002 t_field* tfield,
4003 string prefix,
4004 string suffix,
4005 int error_ret,
4006 bool allocate) {
4007 t_type* type = get_true_type(tfield->get_type());
4008
4009 if (type->is_void()) {
4010 throw std::runtime_error("CANNOT GENERATE DESERIALIZE CODE FOR void TYPE: " + prefix
4011 + tfield->get_name());
4012 }
4013
4014 string name = prefix + tfield->get_name() + suffix;
4015
4016 if (type->is_struct() || type->is_xception()) {
4017 generate_deserialize_struct(out, (t_struct*)type, name, error_ret, allocate);
4018 } else if (type->is_container()) {
4019 generate_deserialize_container(out, type, name, error_ret);
4020 } else if (type->is_base_type()) {
4021 t_base_type::t_base tbase = ((t_base_type*)type)->get_base();
4022 if (tbase == t_base_type::TYPE_STRING) {
4023 indent(out) << "if (" << name << " != NULL)" << endl << indent() << "{" << endl;
4024 indent_up();
4025 indent(out) << "g_free(" << name << ");" << endl << indent() << name << " = NULL;" << endl;
4026 indent_down();
4027 indent(out) << "}" << endl << endl;
4028 }
4029 indent(out) << "if ((ret = thrift_protocol_read_";
4030
4031 switch (tbase) {
4032 case t_base_type::TYPE_VOID:
4033 throw "compiler error: cannot serialize void field in a struct: " + name;
4034 break;
4035 case t_base_type::TYPE_STRING:
4036 if (type->is_binary()) {
4037 out << "binary (protocol, &data, &len";
4038 } else {
4039 out << "string (protocol, &" << name;
4040 }
4041 break;
4042 case t_base_type::TYPE_BOOL:
4043 out << "bool (protocol, &" << name;
4044 break;
4045 case t_base_type::TYPE_I8:
4046 out << "byte (protocol, &" << name;
4047 break;
4048 case t_base_type::TYPE_I16:
4049 out << "i16 (protocol, &" << name;
4050 break;
4051 case t_base_type::TYPE_I32:
4052 out << "i32 (protocol, &" << name;
4053 break;
4054 case t_base_type::TYPE_I64:
4055 out << "i64 (protocol, &" << name;
4056 break;
4057 case t_base_type::TYPE_DOUBLE:
4058 out << "double (protocol, &" << name;
4059 break;
4060 default:
4061 throw "compiler error: no C reader for base type " + t_base_type::t_base_name(tbase) + name;
4062 }
4063 out << ", error)) < 0)" << endl;
4064 out << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;"
4065 << endl;
4066
4067 // load the byte array with the data
4068 if (tbase == t_base_type::TYPE_STRING && type->is_binary()) {
4069 indent(out) << name << " = g_byte_array_new();" << endl;
4070 indent(out) << "g_byte_array_append (" << name << ", (guint8 *) data, (guint) len);" << endl;
4071 indent(out) << "g_free (data);" << endl;
4072 }
4073 } else if (type->is_enum()) {
4074 string t = tmp("ecast");
4075 out << indent() << "gint32 " << t << ";" << endl << indent()
4076 << "if ((ret = thrift_protocol_read_i32 (protocol, &" << t << ", error)) < 0)" << endl
4077 << indent() << " return " << error_ret << ";" << endl << indent() << "xfer += ret;" << endl
4078 << indent() << name << " = (" << type_name(type) << ")" << t << ";" << endl;
4079 } else {
4080 throw std::logic_error("DO NOT KNOW HOW TO SERIALIZE FIELD '" + tfield->get_name() + "' TYPE '"
4081 + type_name(type));
4082 }
4083
4084 // if the type is not required and this is a thrift struct (no prefix),
4085 // set the isset variable. if the type is required, then set the
4086 // local variable indicating the value was set, so that we can do // validation later.
4087 if (prefix != "" && tfield->get_req() != t_field::T_REQUIRED) {
4088 indent(out) << prefix << "__isset_" << tfield->get_name() << suffix << " = TRUE;" << endl;
4089 } else if (prefix != "" && tfield->get_req() == t_field::T_REQUIRED) {
4090 indent(out) << "isset_" << tfield->get_name() << " = TRUE;" << endl;
4091 }
4092 }
4093
4094 void t_c_glib_generator::generate_deserialize_struct(ostream& out,
4095 t_struct* tstruct,
4096 string prefix,
4097 int error_ret,
4098 bool allocate) {
4099 string name_uc = to_upper_case(initial_caps_to_underscores(tstruct->get_name()));
4100 if (tstruct->is_xception()) {
4101 out << indent() << "/* This struct is an exception */" << endl;
4102 allocate = true;
4103 }
4104
4105 if (allocate) {
4106 out << indent() << "if ( " << prefix << " != NULL)" << endl << indent() << "{" << endl;
4107 indent_up();
4108 out << indent() << "g_object_unref (" << prefix << ");" << endl;
4109 indent_down();
4110 out << indent() << "}" << endl << indent() << prefix << " = g_object_new (" << this->nspace_uc
4111 << "TYPE_" << name_uc << ", NULL);" << endl;
4112 }
4113 out << indent() << "if ((ret = thrift_struct_read (THRIFT_STRUCT (" << prefix
4114 << "), protocol, error)) < 0)" << endl << indent() << "{" << endl;
4115 indent_up();
4116 if (allocate) {
4117 indent(out) << "g_object_unref (" << prefix << ");" << endl;
4118 if (tstruct->is_xception()) {
4119 indent(out) << prefix << " = NULL;" << endl;
4120 }
4121 }
4122 out << indent() << "return " << error_ret << ";" << endl;
4123 indent_down();
4124 out << indent() << "}" << endl << indent() << "xfer += ret;" << endl;
4125 }
4126
4127 void t_c_glib_generator::generate_deserialize_container(ostream& out,
4128 t_type* ttype,
4129 string prefix,
4130 int error_ret) {
4131 scope_up(out);
4132
4133 if (ttype->is_map()) {
4134 out << indent() << "guint32 size;" << endl
4135 << indent() << "guint32 i;" << endl
4136 << indent() << "ThriftType key_type;" << endl
4137 << indent() << "ThriftType value_type;" << endl
4138 << endl
4139 << indent() << "/* read the map begin marker */" << endl
4140 << indent() << "if ((ret = thrift_protocol_read_map_begin (protocol, "
4141 "&key_type, &value_type, &size, error)) < 0)" << endl;
4142 indent_up();
4143 out << indent() << "return " << error_ret << ";" << endl;
4144 indent_down();
4145 out << indent() << "xfer += ret;" << endl
4146 << endl;
4147
4148 // iterate over map elements
4149 out << indent() << "/* iterate through each of the map's fields */" << endl
4150 << indent() << "for (i = 0; i < size; i++)" << endl;
4151 scope_up(out);
4152 generate_deserialize_map_element(out, (t_map*)ttype, prefix, error_ret);
4153 scope_down(out);
4154 out << endl;
4155
4156 // read map end
4157 out << indent() << "/* read the map end marker */" << endl
4158 << indent() << "if ((ret = thrift_protocol_read_map_end (protocol, "
4159 "error)) < 0)" << endl;
4160 indent_up();
4161 out << indent() << "return " << error_ret << ";" << endl;
4162 indent_down();
4163 out << indent() << "xfer += ret;" << endl;
4164 } else if (ttype->is_set()) {
4165 out << indent() << "guint32 size;" << endl
4166 << indent() << "guint32 i;" << endl
4167 << indent() << "ThriftType element_type;" << endl
4168 << endl
4169 << indent() << "if ((ret = thrift_protocol_read_set_begin (protocol, "
4170 "&element_type, &size, error)) < 0)" << endl;
4171 indent_up();
4172 out << indent() << "return " << error_ret << ";" << endl;
4173 indent_down();
4174 out << indent() << "xfer += ret;" << endl
4175 << endl;
4176
4177 // iterate over the elements
4178 out << indent() << "/* iterate through the set elements */" << endl
4179 << indent() << "for (i = 0; i < size; ++i)" << endl;
4180 scope_up(out);
4181 generate_deserialize_set_element(out, (t_set*)ttype, prefix, error_ret);
4182 scope_down(out);
4183
4184 // read set end
4185 out << indent() << "if ((ret = thrift_protocol_read_set_end (protocol, "
4186 "error)) < 0)" << endl;
4187 indent_up();
4188 out << indent() << "return " << error_ret << ";" << endl;
4189 indent_down();
4190 out << indent() << "xfer += ret;" << endl
4191 << endl;
4192 } else if (ttype->is_list()) {
4193 out << indent() << "guint32 size;" << endl
4194 << indent() << "guint32 i;" << endl
4195 << indent() << "ThriftType element_type;" << endl
4196 << endl
4197 << indent() << "if ((ret = thrift_protocol_read_list_begin (protocol, "
4198 "&element_type,&size, error)) < 0)" << endl;
4199 indent_up();
4200 out << indent() << "return " << error_ret << ";" << endl;
4201 indent_down();
4202 out << indent() << "xfer += ret;" << endl
4203 << endl;
4204
4205 // iterate over the elements
4206 out << indent() << "/* iterate through list elements */" << endl
4207 << indent() << "for (i = 0; i < size; i++)" << endl;
4208 scope_up(out);
4209 generate_deserialize_list_element(out,
4210 (t_list*)ttype,
4211 prefix,
4212 "i",
4213 error_ret);
4214 scope_down(out);
4215
4216 // read list end
4217 out << indent() << "if ((ret = thrift_protocol_read_list_end (protocol, "
4218 "error)) < 0)" << endl;
4219 indent_up();
4220 out << indent() << "return " << error_ret << ";" << endl;
4221 indent_down();
4222 out << indent() << "xfer += ret;" << endl;
4223 }
4224
4225 scope_down(out);
4226 }
4227
4228 void t_c_glib_generator::declare_local_variable(ostream& out, t_type* ttype, string& name, bool for_hash_table) {
4229 string tname = type_name(ttype);
4230
4231 /* If the given type is a typedef, find its underlying type so we
4232 can correctly determine how to generate a pointer to it */
4233 ttype = get_true_type(ttype);
4234 string ptr = !is_numeric(ttype) ? "" : "*";
4235
4236 if (ttype->is_map()) {
4237 t_map* tmap = (t_map*)ttype;
4238 out << indent() << tname << ptr << " " << name << " = "
4239 << generate_new_hash_from_type(tmap->get_key_type(), tmap->get_val_type()) << endl;
4240 } else if (ttype->is_list()) {
4241 t_list* tlist = (t_list*)ttype;
4242 out << indent() << tname << ptr << " " << name << " = "
4243 << generate_new_array_from_type(tlist->get_elem_type()) << endl;
4244 } else if (for_hash_table && ttype->is_enum()) {
4245 out << indent() << tname << " " << name << ";" << endl;
4246 } else {
4247 out << indent() << tname << ptr << " " << name
4248 << (ptr != "" ? " = g_new (" + tname + ", 1)" : " = NULL") << ";" << endl;
4249 }
4250 }
4251
4252 void t_c_glib_generator::declore_local_variable_for_write(ostream& out,
4253 t_type* ttype,
4254 string& name) {
4255 string tname = type_name(ttype);
4256 ttype = get_true_type(ttype);
4257 string ptr = ttype->is_string() || !ttype->is_base_type() ? " " : "* ";
4258 string init_val = ttype->is_enum() ? "" : " = NULL";
4259 out << indent() << tname << ptr << name << init_val << ";" << endl;
4260 }
4261
4262 void t_c_glib_generator::generate_deserialize_map_element(ostream& out,
4263 t_map* tmap,
4264 string prefix,
4265 int error_ret) {
4266 t_type* tkey = tmap->get_key_type();
4267 t_type* tval = tmap->get_val_type();
4268 string keyname = tmp("key");
4269 string valname = tmp("val");
4270
4271 declare_local_variable(out, tkey, keyname, true);
4272 declare_local_variable(out, tval, valname, true);
4273
4274 /* If either the key or value type is a typedef, find its underlying
4275 type so we can correctly determine how to generate a pointer to
4276 it */
4277 tkey = get_true_type(tkey);
4278 tval = get_true_type(tval);
4279
4280 string tkey_ptr = tkey->is_string() || !tkey->is_base_type() ? "" : "*";
4281 string tval_ptr = tval->is_string() || !tval->is_base_type() ? "" : "*";
4282
4283 // deserialize the fields of the map element
4284 t_field fkey(tkey, tkey_ptr + keyname);
4285 generate_deserialize_field(out, &fkey, "", "", error_ret);
4286 t_field fval(tval, tval_ptr + valname);
4287 generate_deserialize_field(out, &fval, "", "", error_ret);
4288
4289 indent(out) << "if (" << prefix << " && " << keyname << ")" << endl;
4290 indent_up();
4291 indent(out) << "g_hash_table_insert ((GHashTable *)" << prefix << ", (gpointer) " << keyname
4292 << ", (gpointer) " << valname << ");" << endl;
4293 indent_down();
4294 }
4295
4296 void t_c_glib_generator::generate_deserialize_set_element(ostream& out,
4297 t_set* tset,
4298 string prefix,
4299 int error_ret) {
4300 t_type* telem = tset->get_elem_type();
4301 string elem = tmp("_elem");
4302 string telem_ptr = telem->is_string() || !telem->is_base_type() ? "" : "*";
4303
4304 declare_local_variable(out, telem, elem, true);
4305
4306 t_field felem(telem, telem_ptr + elem);
4307 generate_deserialize_field(out, &felem, "", "", error_ret);
4308
4309 indent(out) << "if (" << prefix << " && " << elem << ")" << endl;
4310 indent_up();
4311 indent(out) << "g_hash_table_insert ((GHashTable *) " << prefix << ", (gpointer) " << elem
4312 << ", (gpointer) " << elem << ");" << endl;
4313 indent_down();
4314 }
4315
4316 void t_c_glib_generator::generate_deserialize_list_element(ostream& out,
4317 t_list* tlist,
4318 string prefix,
4319 string index,
4320 int error_ret) {
4321 (void)index;
4322 t_type* ttype = get_true_type(tlist->get_elem_type());
4323 string elem = tmp("_elem");
4324 string telem_ptr = !is_numeric(ttype) ? "" : "*";
4325
4326 declare_local_variable(out, ttype, elem, false);
4327
4328 t_field felem(ttype, telem_ptr + elem);
4329 generate_deserialize_field(out, &felem, "", "", error_ret);
4330
4331 if (ttype->is_void()) {
4332 throw std::runtime_error("compiler error: list element type cannot be void");
4333 } else if (is_numeric(ttype)) {
4334 indent(out) << "g_array_append_vals (" << prefix << ", " << elem << ", 1);" << endl;
4335 } else {
4336 indent(out) << "g_ptr_array_add (" << prefix << ", " << elem << ");" << endl;
4337 }
4338 }
4339
4340 string t_c_glib_generator::generate_free_func_from_type(t_type* ttype) {
4341 if (ttype == NULL)
4342 return "NULL";
4343
4344 if (ttype->is_base_type()) {
4345 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
4346 switch (tbase) {
4347 case t_base_type::TYPE_VOID:
4348 throw "compiler error: cannot determine hash type";
4349 break;
4350 case t_base_type::TYPE_BOOL:
4351 case t_base_type::TYPE_I8:
4352 case t_base_type::TYPE_I16:
4353 case t_base_type::TYPE_I32:
4354 case t_base_type::TYPE_I64:
4355 case t_base_type::TYPE_DOUBLE:
4356 return "g_free";
4357 case t_base_type::TYPE_STRING:
4358 if (((t_base_type*)ttype)->is_binary()) {
4359 return "thrift_string_free";
4360 }
4361 return "g_free";
4362 default:
4363 throw "compiler error: no hash table info for type";
4364 }
4365 } else if (ttype->is_enum()) {
4366 return "NULL";
4367 } else if (ttype->is_map() || ttype->is_set()) {
4368 return "(GDestroyNotify) thrift_safe_hash_table_destroy";
4369 } else if (ttype->is_struct()) {
4370 return "g_object_unref";
4371 } else if (ttype->is_list()) {
4372 t_type* etype = ((t_list*)ttype)->get_elem_type();
4373 if (etype->is_base_type()) {
4374 t_base_type::t_base tbase = ((t_base_type*)etype)->get_base();
4375 switch (tbase) {
4376 case t_base_type::TYPE_VOID:
4377 throw "compiler error: cannot determine array type";
4378 break;
4379 case t_base_type::TYPE_BOOL:
4380 case t_base_type::TYPE_I8:
4381 case t_base_type::TYPE_I16:
4382 case t_base_type::TYPE_I32:
4383 case t_base_type::TYPE_I64:
4384 case t_base_type::TYPE_DOUBLE:
4385 return "(GDestroyNotify) g_array_unref";
4386 case t_base_type::TYPE_STRING:
4387 return "(GDestroyNotify) g_ptr_array_unref";
4388 default:
4389 throw "compiler error: no array info for type";
4390 }
4391 } else if (etype->is_container() || etype->is_struct()) {
4392 return "(GDestroyNotify) g_ptr_array_unref";
4393 ;
4394 } else if (etype->is_enum()) {
4395 return "(GDestroyNotify) g_array_unref";
4396 }
4397 printf("Type not expected inside the array: %s\n", etype->get_name().c_str());
4398 throw "Type not expected inside array";
4399 } else if (ttype->is_typedef()) {
4400 return generate_free_func_from_type(((t_typedef*)ttype)->get_type());
4401 }
4402 printf("Type not expected: %s\n", ttype->get_name().c_str());
4403 throw "Type not expected";
4404 }
4405
4406 string t_c_glib_generator::generate_hash_func_from_type(t_type* ttype) {
4407 if (ttype == NULL)
4408 return "NULL";
4409
4410 if (ttype->is_base_type()) {
4411 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
4412 switch (tbase) {
4413 case t_base_type::TYPE_VOID:
4414 throw "compiler error: cannot determine hash type";
4415 break;
4416 case t_base_type::TYPE_BOOL:
4417 return "thrift_boolean_hash";
4418 case t_base_type::TYPE_I8:
4419 return "thrift_int8_hash";
4420 case t_base_type::TYPE_I16:
4421 return "thrift_int16_hash";
4422 case t_base_type::TYPE_I32:
4423 return "g_int_hash";
4424 case t_base_type::TYPE_I64:
4425 return "g_int64_hash";
4426 case t_base_type::TYPE_DOUBLE:
4427 return "g_double_hash";
4428 case t_base_type::TYPE_STRING:
4429 return "g_str_hash";
4430 default:
4431 throw "compiler error: no hash table info for type";
4432 }
4433 } else if (ttype->is_enum()) {
4434 return "g_direct_hash";
4435 } else if (ttype->is_container() || ttype->is_struct()) {
4436 return "g_direct_hash";
4437 } else if (ttype->is_typedef()) {
4438 return generate_hash_func_from_type(((t_typedef*)ttype)->get_type());
4439 }
4440 printf("Type not expected: %s\n", ttype->get_name().c_str());
4441 throw "Type not expected";
4442 }
4443
4444 string t_c_glib_generator::generate_cmp_func_from_type(t_type* ttype) {
4445 if (ttype == NULL)
4446 return "NULL";
4447
4448 if (ttype->is_base_type()) {
4449 t_base_type::t_base tbase = ((t_base_type*)ttype)->get_base();
4450 switch (tbase) {
4451 case t_base_type::TYPE_VOID:
4452 throw "compiler error: cannot determine hash type";
4453 break;
4454 case t_base_type::TYPE_BOOL:
4455 return "thrift_boolean_equal";
4456 case t_base_type::TYPE_I8:
4457 return "thrift_int8_equal";
4458 case t_base_type::TYPE_I16:
4459 return "thrift_int16_equal";
4460 case t_base_type::TYPE_I32:
4461 return "g_int_equal";
4462 case t_base_type::TYPE_I64:
4463 return "g_int64_equal";
4464 case t_base_type::TYPE_DOUBLE:
4465 return "g_double_equal";
4466 case t_base_type::TYPE_STRING:
4467 return "g_str_equal";
4468 default:
4469 throw "compiler error: no hash table info for type";
4470 }
4471 } else if (ttype->is_enum()) {
4472 return "g_direct_equal";
4473 } else if (ttype->is_container() || ttype->is_struct()) {
4474 return "g_direct_equal";
4475 } else if (ttype->is_typedef()) {
4476 return generate_cmp_func_from_type(((t_typedef*)ttype)->get_type());
4477 }
4478 printf("Type not expected: %s\n", ttype->get_name().c_str());
4479 throw "Type not expected";
4480 }
4481
4482 string t_c_glib_generator::generate_new_hash_from_type(t_type* key, t_type* value) {
4483 string hash_func = generate_hash_func_from_type(key);
4484 string cmp_func = generate_cmp_func_from_type(key);
4485 string key_free_func = generate_free_func_from_type(key);
4486 string value_free_func = generate_free_func_from_type(value);
4487
4488 return "g_hash_table_new_full (" + hash_func + ", " + cmp_func + ", " + key_free_func + ", "
4489 + value_free_func + ");";
4490 }
4491
4492 string t_c_glib_generator::generate_new_array_from_type(t_type* ttype) {
4493 if (ttype->is_void()) {
4494 throw std::runtime_error("compiler error: cannot determine array type");
4495 } else if (is_numeric(ttype)) {
4496 return "g_array_new (0, 1, sizeof (" + base_type_name(ttype) + "));";
4497 } else {
4498 string free_func = generate_free_func_from_type(ttype);
4499 return "g_ptr_array_new_with_free_func (" + free_func + ");";
4500 }
4501 }
4502
4503 /***************************************
4504 * UTILITY FUNCTIONS *
4505 ***************************************/
4506
4507 /**
4508 * Upper case a string.
4509 */
4510 string to_upper_case(string name) {
4511 string s(name);
4512 std::transform(s.begin(), s.end(), s.begin(), ::toupper);
4513 return s;
4514 }
4515
4516 /**
4517 * Lower case a string.
4518 */
4519 string to_lower_case(string name) {
4520 string s(name);
4521 std::transform(s.begin(), s.end(), s.begin(), ::tolower);
4522 return s;
4523 }
4524
4525 /**
4526 * Makes a string friendly to C code standards by lowercasing and adding
4527 * underscores, with the exception of the first character. For example:
4528 *
4529 * Input: "ZomgCamelCase"
4530 * Output: "zomg_camel_case"
4531 */
4532 string initial_caps_to_underscores(string name) {
4533 string ret;
4534 const char* tmp = name.c_str();
4535 int pos = 0;
4536
4537 /* the first character isn't underscored if uppercase, just lowercased */
4538 ret += tolower(tmp[pos]);
4539 pos++;
4540 for (unsigned int i = pos; i < name.length(); i++) {
4541 char lc = tolower(tmp[i]);
4542 if (lc != tmp[i]) {
4543 ret += '_';
4544 }
4545 ret += lc;
4546 }
4547
4548 return ret;
4549 }
4550
4551 /**
4552 * Performs the reverse operation of initial_caps_to_underscores: The first
4553 * character of the string is made uppercase, along with each character that
4554 * follows an underscore (which is removed). Useful for converting Thrift
4555 * service-method names into GObject-style class names.
4556 *
4557 * Input: "zomg_camel_case"
4558 * Output: "ZomgCamelCase"
4559 */
4560 string underscores_to_initial_caps(string name) {
4561 string ret;
4562 const char* tmp = name.c_str();
4563 bool uppercase_next = true;
4564
4565 for (unsigned int i = 0; i < name.length(); i++) {
4566 char c = tmp[i];
4567 if (c == '_') {
4568 uppercase_next = true;
4569 } else {
4570 if (uppercase_next) {
4571 ret += toupper(c);
4572 uppercase_next = false;
4573 } else {
4574 ret += c;
4575 }
4576 }
4577 }
4578
4579 return ret;
4580 }
4581
4582 /* register this generator with the main program */
4583 THRIFT_REGISTER_GENERATOR(c_glib, "C, using GLib", "")