1 // idlcomp/languages/c++/server.cc -- C++ server-side stubs
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // This software is provided 'as-is', without any express or implied warranty.
6 // In no event will the authors or contributors be held liable for any damages
7 // arising from the use of this software.
9 // Permission is hereby granted to everyone, free of charge, to use, copy,
10 // modify, prepare derivative works of, publish, distribute, perform,
11 // sublicense, and/or sell copies of the Software, provided that the above
12 // copyright notice and disclaimer of warranty be included in all copies or
13 // substantial portions of this software.
25 static void output_ifaceptrs(Class *cla, ostream &f)
27 f << "// " << *cla->get_fq_name()->flatten("::") << "\n"
28 "// This is a C++ server class mixin generated by idlc.\n"
29 "// Do not modify this file directly.\n"
30 "// This file provides data and methods used by the object system\n"
31 "// to connect this class to its interface(s). Include it inside\n"
32 "// the class definition as \"public:\", and call the init_iface()\n"
33 "// method from your constructor(s).\n\n";
36 Interface *conc = cla->concrete_iface;
37 assert(conc->get_num_chains() > 0);
39 f << "struct IDL_ifaceptr {\n\t";
41 for (int i = 0; i < conc->get_num_chains(); i++) {
42 Interface *iface = conc->get_chain_head(i);
44 // Skip the "fake" aggregation interface on the first chain.
46 iface = *iface->supers_begin();
48 cpp_output_name(f, iface, "_i_");
49 f << " p" << i << ";\n\t";
52 f << **cla->name << " *priv;\n"
57 static void output_classptr(Class *cla, Interface *iface, ostream &f)
59 int chain = cla->concrete_iface->super_to_chain(iface);
61 f << "static " << **cla->name << " *classptr(";
62 cpp_output_name(f, iface);
65 "\tif (ref && static_cast<const void *>(ref._ptr->info) ==\n"
66 "\t static_cast<const void *>(&IDL_info.p" << chain << "))\n"
68 "\t\tuintptr_t ptr = reinterpret_cast<uintptr_t>(ref._ptr);\n"
69 "\t\tptr -= " << chain * target->pointer_size << ";\n"
70 "\t\treturn reinterpret_cast<IDL_ifaceptr *>(ref._ptr)->priv;\n"
76 static void output_convfunc(Class *cla, Interface *iface, ostream &f)
80 cpp_output_name(f, iface);
86 cpp_output_name(f, iface);
88 int chain = cla->concrete_iface->super_to_chain(iface);
90 f << "(reinterpret_cast< ";
91 cpp_output_name(f, iface, "_i_");
92 f << " *>(&IDL_ref.p" << chain << "));\n"
96 static void output_info_type(Class *cla, ostream &f)
98 Interface *conc = cla->concrete_iface;
99 f << "struct IDL_info_type {\n";
101 for (int i = 0; i < conc->get_num_chains(); i++) {
102 Interface *iface = conc->get_chain_head(i);
104 // Skip the "fake" aggregation interface on the first chain.
106 iface = *iface->supers_begin();
109 cpp_output_name(f, iface, "_i_");
110 f << "::info_type p" << i << ";\n";
114 "static IDL_info_type IDL_info;\n\n";
117 static void output_mixin(Class *cla, string &filename)
121 f.open(filename.c_str());
123 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
124 filename.c_str(), strerror(errno));
129 output_ifaceptrs(cla, f);
130 output_info_type(cla, f);
132 f << "// The classptr method(s) can be used to get a class pointer from\n"
133 "// an interface reference. If the interface reference does\n"
134 "// not refer to an instance of the class, it returns NULL.\n\n";
136 for (Class::ifaces_iterator i = cla->ifaces_begin();
137 i != cla->ifaces_end(); ++i)
139 output_classptr(cla, *i, f);
142 f << "// Used by auto-generated stubs which know that the interface is of\n"
143 "// the proper class. Do not call this from user code.\n\n"
144 "static " << **cla->name << " *_classptr_internal(void *ptr)\n"
146 "\tIDL_ifaceptr *wrap = static_cast<IDL_ifaceptr *>(ptr);\n"
147 "\treturn wrap->priv;\n"
150 f << "IDL_ifaceptr IDL_ref;\n\n";
152 f << "// The implicit conversion function(s) below can be used to convert\n"
153 "// a class reference to an interface reference. Note that if you\n"
154 "// have a pointer, rather than a reference, you will need to dereference\n"
155 "// it prior to casting to the desired interface type.\n\n";
157 for (Class::ifaces_iterator i = cla->ifaces_begin();
158 i != cla->ifaces_end(); ++i)
160 output_convfunc(cla, *i, f);
163 f << "// This method must be called prior to using any interface references\n"
164 << "// to this object. If a method is called through an interface pointer\n"
165 << "// before this is done, a memory fault is likely.\n\n"
166 << "void init_iface()\n"
168 << "\tIDL_ref.priv = this;\n"
172 struct callback_data {
177 static void output_method_wrapper(Class *cla, Interface *iface,
178 Method *meth, Class::MethodInfo *mi,
179 bool copy, ostream &f)
181 const String *implname_idlns, *implname_scope;
184 implname_idlns = mi->implname->flatten("_IDLNS_");
185 implname_scope = mi->implname->flatten("::");
187 implname_idlns = implname_scope = meth->name;
191 Indent indent = { 1, implname_idlns->length() + 6 };
198 f << *implname_idlns << "(void *_this";
200 for (Method::entries_iterator i = meth->entries_begin();
201 i != meth->entries_end(); ++i)
203 f << ",\n" << indent;
204 cpp_output_one_param(f, *i, true, copy);
207 const String *classname = cla->get_fq_name()->flatten("::");
212 int chain = cla->concrete_iface->super_to_chain(iface);
214 f << "\t\t_this = reinterpret_cast<void *>"
215 "(reinterpret_cast<uintptr_t>(_this) - "
216 << chain * target->pointer_size << ");\n";
219 f << "\t\t::" << *classname << " *_ptr = ::" << *classname
220 << "::_classptr_internal(_this);\n"
221 "\t\t_ptr->" << *implname_scope << '(';
223 indent = (Indent){ 2, implname_scope->length() + 7 };
225 for (Method::entries_iterator i = meth->entries_begin();
226 i != meth->entries_end(); ++i)
228 if (i != meth->entries_begin())
229 f << ",\n" << indent;
232 bool copy_this_param = false;
234 Class::ParamInfo *pi = mi->get_param(p);
236 copy_this_param = true;
239 // FIXME: copy non-arrays
243 if (copy_this_param && p->is_array())
251 // Should be static, but GCC won't accept it as a template parameter
252 // even though the template is only used from this file (and thus
253 // won't be instantiated elsewhere (unless some template consolidation
254 // mechanism puts them all in one file or something, but then an
255 // exception could be made for templates with static parameters,
256 // as they can be placed in their original files with no chance
259 void cpp_output_iface_method_wrappers(Interface *super, void *arg)
261 callback_data *data = static_cast<callback_data *>(arg);
263 for (Interface::methods_iterator i = super->methods_begin();
264 i != super->methods_end(); ++i)
267 Class::MethodInfo *mi = data->cla->get_method(m);
269 output_method_wrapper(data->cla, super, m, mi, false, data->f);
271 if (mi && mi->copy_params)
272 output_method_wrapper(data->cla, super, m, mi, true, data->f);
284 void cpp_output_iface_table_entry(Interface *super, void *arg)
286 Context &ctx(*static_cast<Context *>(arg));
288 ctx.f << ctx.indent << "{\n";
289 ctx.indent.indent_level++;
291 ctx.f << ctx.indent << '&';
292 cpp_output_name(ctx.f, super);
294 ctx.f << "_ns::_info,\n"
296 << (ctx.cla->concrete_iface->super_to_chain(super) - ctx.chain) *
297 target->pointer_size << '\n';
299 ctx.indent.indent_level--;
300 ctx.f << ctx.indent << "},\n";
303 void cpp_output_method_table_entries(Interface *super, void *arg)
305 Context &ctx(*static_cast<Context *>(arg));
307 for (Interface::methods_iterator i = super->methods_begin();
308 i != super->methods_end(); ++i)
311 Class::MethodInfo *mi = ctx.cla->get_method(meth);
312 const String *implname;
315 implname = mi->implname->flatten("::");
317 implname = meth->name;
319 ctx.f << ctx.indent << "IDL_Server_"
320 << *ctx.cla->get_fq_name()->flatten("_IDLNS_")
321 << "::" << *implname << ",\n";
325 static void output_info_type_init_rec(Context &ctx)
327 Interface *iface = ctx.cur;
329 ctx.f << ctx.indent << "{ // " << *iface->get_fq_name()->flatten() << '\n';
330 ctx.indent.indent_level++;
332 if (!iface->supers_empty()) {
333 ctx.cur = *iface->supers_begin();
334 output_info_type_init_rec(ctx);
336 // Concrete pointer adjustment
337 ctx.f << ctx.indent << '-'
338 << ctx.chain * target->pointer_size << ",\n";
340 // Pointer to concrete downcast table
341 ctx.f << ctx.indent << "&IDL_info.p0.iface_table.";
343 Interface *iface = *ctx.cla->concrete_iface->supers_begin();
344 ctx.f << *iface->get_fq_name()->flatten("_IDLNS_") << ",\n";
347 // Interface table for downcasts
348 ctx.f << ctx.indent << "{\n";
349 ctx.indent.indent_level++;
351 cpp_output_iface_table_entry(iface, &ctx);
352 iface->for_each_super<cpp_output_iface_table_entry>(&ctx);
354 ctx.f << ctx.indent << "NULL\n";
356 ctx.indent.indent_level--;
357 ctx.f << ctx.indent << "},\n";
361 ctx.f << ctx.indent << "{\n";
362 ctx.indent.indent_level++;
364 cpp_output_method_table_entries(iface, &ctx);
365 iface->for_each_super<cpp_output_method_table_entries>(&ctx);
367 ctx.indent.indent_level--;
368 ctx.f << ctx.indent << "},\n";
370 ctx.indent.indent_level--;
371 ctx.f << ctx.indent << "},\n";
374 static void output_info_type_init(Class *cla, ostream &f)
376 Indent indent = (Indent){1, 0};
378 // The struct name is enclosed in parentheses to disambiguate the
379 // leading :: from being a continuation of the type name.
381 cpp_output_name(f, cla);
382 f << "::IDL_info_type (";
383 cpp_output_name(f, cla);
384 f << "::IDL_info) =\n"
387 Context ctx = { cla, f };
388 ctx.indent.indent_level = 1;
390 for (ctx.chain = 0; ctx.chain < cla->concrete_iface->get_num_chains();
393 ctx.cur = cla->concrete_iface->get_chain_head(ctx.chain);
395 // Skip the "fake" aggregation interface on the first chain.
397 ctx.cur = *ctx.cur->supers_begin();
399 output_info_type_init_rec(ctx);
402 assert(ctx.indent.indent_level == 1);
406 static void output_footer(Class *cla, ostream &f)
408 // Create an arbitrary, unique name to stick the method wrappers in.
409 f << "\n\nnamespace IDL_Server_" << *cla->get_fq_name()->flatten("_IDLNS_")
412 callback_data data = { cla, f };
414 cla->concrete_iface->for_each_super
415 <cpp_output_iface_method_wrappers>(&data);
419 output_info_type_init(cla, f);
421 cpp_output_name(f, cla);
422 f << "::IDL_ifaceptr::IDL_ifaceptr() :";
424 for (int i = 0; i < cla->concrete_iface->get_num_chains(); i++) {
428 f << "\np" << i << "(&IDL_info.p" << i << ")";
435 void CPPBinding::output_server(UserNameSpace *ns, const char *dir)
439 string footer_name(dir);
440 footer_name += "/footer.cc";
443 printf("%s: %s\n", footer_name.c_str(), dir);
445 footer.open(footer_name.c_str());
446 if (!footer.is_open()) {
447 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
448 footer_name.c_str(), strerror(errno));
453 footer << "// This is a C++ server binding generated by idlc.\n"
454 "// Do not modify this file directly.\n"
455 "// Include this file from exactly one file that has access to\n"
456 "// the class and interface declarations (and preferably, with\n"
457 "// access to to inlineable methods as well).";
460 for (list<ClassRef>::iterator i = classes.begin(); i != classes.end(); ++i) {
463 string filename(dir);
465 filename += *cla->get_ns()->get_fq_name()->flatten("/");
467 makepath(filename.c_str(), false);
470 filename += **cla->name;
474 printf("%s: %s\n", filename.c_str(), dir);
476 output_mixin(cla, filename);
477 output_footer(cla, footer);