1 // idlcomp/languages/c++/server.cc -- C++ server-side stubs
3 // This software is copyright (c) 2006 Scott Wood <scott@buserror.net>.
5 // Permission is hereby granted, free of charge, to any person obtaining a copy of
6 // this software and associated documentation files (the "Software"), to deal with
7 // the Software without restriction, including without limitation the rights to
8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9 // of the Software, and to permit persons to whom the Software is furnished to do
10 // so, subject to the following condition:
12 // The above copyright notice and this permission notice shall be
13 // included in all copies or substantial portions of the Software.
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
33 static void output_ifaceptrs(Class *cla, ostream &f)
35 f << "// " << *cla->get_fq_name()->flatten("::") << "\n"
36 "// This is a C++ server class mixin generated by idlc.\n"
37 "// Do not modify this file directly.\n"
38 "// This file provides data and methods used by the object system\n"
39 "// to connect this class to its interface(s). Include it inside\n"
40 "// the class definition as \"public:\", and call the init_iface()\n"
41 "// method from your constructor(s).\n\n";
44 Interface *conc = cla->concrete_iface;
45 assert(conc->get_num_chains() > 0);
47 f << "struct IDL_ifaceptr {\n\t";
49 for (int i = 0; i < conc->get_num_chains(); i++) {
50 Interface *iface = conc->get_chain_head(i);
52 // Skip the "fake" aggregation interface on the first chain.
54 iface = *iface->supers_begin();
56 cpp_output_name(f, iface, "_i_");
57 f << " p" << i << ";\n\t";
60 f << **cla->name << " *priv;\n"
65 static void output_classptr(Class *cla, Interface *iface, ostream &f)
67 int chain = cla->concrete_iface->super_to_chain(iface);
69 f << "static " << **cla->name << " *classptr(";
70 cpp_output_name(f, iface);
73 "\tif (ref && static_cast<const void *>(ref._ptr->info) ==\n"
74 "\t static_cast<const void *>(&IDL_info.p" << chain << "))\n"
76 "\t\tuintptr_t ptr = reinterpret_cast<uintptr_t>(ref._ptr);\n"
77 "\t\tptr -= " << chain * target->pointer_size << ";\n"
78 "\t\treturn reinterpret_cast<IDL_ifaceptr *>(ref._ptr)->priv;\n"
84 static void output_convfunc(Class *cla, Interface *iface, ostream &f)
88 cpp_output_name(f, iface);
94 cpp_output_name(f, iface);
96 int chain = cla->concrete_iface->super_to_chain(iface);
98 f << "(reinterpret_cast< ";
99 cpp_output_name(f, iface, "_i_");
100 f << " *>(&IDL_ref.p" << chain << "));\n"
104 static void output_info_type(Class *cla, ostream &f)
106 Interface *conc = cla->concrete_iface;
107 f << "struct IDL_info_type {\n";
109 for (int i = 0; i < conc->get_num_chains(); i++) {
110 Interface *iface = conc->get_chain_head(i);
112 // Skip the "fake" aggregation interface on the first chain.
114 iface = *iface->supers_begin();
117 cpp_output_name(f, iface, "_i_");
118 f << "::info_type p" << i << ";\n";
122 "static IDL_info_type IDL_info;\n\n";
125 static void output_mixin(Class *cla, string &filename)
129 f.open(filename.c_str());
131 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
132 filename.c_str(), strerror(errno));
137 output_ifaceptrs(cla, f);
138 output_info_type(cla, f);
140 f << "// The classptr method(s) can be used to get a class pointer from\n"
141 "// an interface reference. If the interface reference does\n"
142 "// not refer to an instance of the class, it returns NULL.\n\n";
144 for (Class::ifaces_iterator i = cla->ifaces_begin();
145 i != cla->ifaces_end(); ++i)
147 output_classptr(cla, *i, f);
150 f << "// Used by auto-generated stubs which know that the interface is of\n"
151 "// the proper class. Do not call this from user code.\n\n"
152 "static " << **cla->name << " *_classptr_internal(void *ptr)\n"
154 "\tIDL_ifaceptr *wrap = static_cast<IDL_ifaceptr *>(ptr);\n"
155 "\treturn wrap->priv;\n"
158 f << "IDL_ifaceptr IDL_ref;\n\n";
160 f << "// The implicit conversion function(s) below can be used to convert\n"
161 "// a class reference to an interface reference. Note that if you\n"
162 "// have a pointer, rather than a reference, you will need to dereference\n"
163 "// it prior to casting to the desired interface type.\n\n";
165 for (Class::ifaces_iterator i = cla->ifaces_begin();
166 i != cla->ifaces_end(); ++i)
168 output_convfunc(cla, *i, f);
171 f << "// This method must be called prior to using any interface references\n"
172 << "// to this object. If a method is called through an interface pointer\n"
173 << "// before this is done, a memory fault is likely.\n\n"
174 << "void init_iface()\n"
176 << "\tIDL_ref.priv = this;\n"
180 struct callback_data {
185 static void output_method_wrapper(Class *cla, Interface *iface,
186 Method *meth, Class::MethodInfo *mi,
187 bool copy, ostream &f)
189 const String *implname_idlns, *implname_scope;
192 implname_idlns = mi->implname->flatten("_IDLNS_");
193 implname_scope = mi->implname->flatten("::");
195 implname_idlns = implname_scope = meth->name;
199 Indent indent = { 1, implname_idlns->length() + 6 };
206 f << *implname_idlns << "(void *_this";
208 for (Method::entries_iterator i = meth->entries_begin();
209 i != meth->entries_end(); ++i)
211 f << ",\n" << indent;
212 cpp_output_one_param(f, *i, true, copy);
215 const String *classname = cla->get_fq_name()->flatten("::");
220 int chain = cla->concrete_iface->super_to_chain(iface);
222 f << "\t\t_this = reinterpret_cast<void *>"
223 "(reinterpret_cast<uintptr_t>(_this) - "
224 << chain * target->pointer_size << ");\n";
227 f << "\t\t::" << *classname << " *_ptr = ::" << *classname
228 << "::_classptr_internal(_this);\n"
229 "\t\t_ptr->" << *implname_scope << '(';
231 indent = (Indent){ 2, implname_scope->length() + 7 };
233 for (Method::entries_iterator i = meth->entries_begin();
234 i != meth->entries_end(); ++i)
236 if (i != meth->entries_begin())
237 f << ",\n" << indent;
240 bool copy_this_param = false;
242 Class::ParamInfo *pi = mi->get_param(p);
244 copy_this_param = true;
247 // FIXME: copy non-arrays
251 if (copy_this_param && p->is_array())
259 // Should be static, but GCC won't accept it as a template parameter
260 // even though the template is only used from this file (and thus
261 // won't be instantiated elsewhere (unless some template consolidation
262 // mechanism puts them all in one file or something, but then an
263 // exception could be made for templates with static parameters,
264 // as they can be placed in their original files with no chance
267 void cpp_output_iface_method_wrappers(Interface *super, void *arg)
269 callback_data *data = static_cast<callback_data *>(arg);
271 for (Interface::methods_iterator i = super->methods_begin();
272 i != super->methods_end(); ++i)
275 Class::MethodInfo *mi = data->cla->get_method(m);
277 output_method_wrapper(data->cla, super, m, mi, false, data->f);
279 if (mi && mi->copy_params)
280 output_method_wrapper(data->cla, super, m, mi, true, data->f);
292 void cpp_output_iface_table_entry(Interface *super, void *arg)
294 Context &ctx(*static_cast<Context *>(arg));
296 ctx.f << ctx.indent << "{\n";
297 ctx.indent.indent_level++;
300 cpp_output_name(ctx.f, super);
302 ctx.f << "_ns::_guid.l,\n"
304 << (ctx.cla->concrete_iface->super_to_chain(super) - ctx.chain) *
305 target->pointer_size << '\n';
307 ctx.indent.indent_level--;
308 ctx.f << ctx.indent << "},\n";
311 void cpp_output_method_table_entries(Interface *super, void *arg)
313 Context &ctx(*static_cast<Context *>(arg));
315 for (Interface::methods_iterator i = super->methods_begin();
316 i != super->methods_end(); ++i)
319 Class::MethodInfo *mi = ctx.cla->get_method(meth);
320 const String *implname;
323 implname = mi->implname->flatten("::");
325 implname = meth->name;
327 ctx.f << ctx.indent << "IDL_Server_"
328 << *ctx.cla->get_fq_name()->flatten("_IDLNS_")
329 << "::" << *implname << ",\n";
333 static void output_info_type_init_rec(Context &ctx)
335 Interface *iface = ctx.cur;
337 ctx.f << ctx.indent << "{ // " << *iface->get_fq_name()->flatten() << '\n';
338 ctx.indent.indent_level++;
340 if (!iface->supers_empty()) {
341 ctx.cur = *iface->supers_begin();
342 output_info_type_init_rec(ctx);
344 // Concrete pointer adjustment
345 ctx.f << ctx.indent << '-'
346 << ctx.chain * target->pointer_size << ",\n";
348 // Pointer to concrete downcast table
349 ctx.f << ctx.indent << "&IDL_info.p0.iface_table.";
351 Interface *iface = *ctx.cla->concrete_iface->supers_begin();
352 ctx.f << *iface->get_fq_name()->flatten("_IDLNS_") << ",\n";
355 // Interface table for downcasts
356 ctx.f << ctx.indent << "{\n";
357 ctx.indent.indent_level++;
359 cpp_output_iface_table_entry(iface, &ctx);
360 iface->for_each_super<cpp_output_iface_table_entry>(&ctx);
362 ctx.f << ctx.indent << "NULL\n";
364 ctx.indent.indent_level--;
365 ctx.f << ctx.indent << "},\n";
369 ctx.f << ctx.indent << "{\n";
370 ctx.indent.indent_level++;
372 cpp_output_method_table_entries(iface, &ctx);
373 iface->for_each_super<cpp_output_method_table_entries>(&ctx);
375 ctx.indent.indent_level--;
376 ctx.f << ctx.indent << "},\n";
378 ctx.indent.indent_level--;
379 ctx.f << ctx.indent << "},\n";
382 static void output_info_type_init(Class *cla, ostream &f)
384 Indent indent = (Indent){1, 0};
386 // The struct name is enclosed in parentheses to disambiguate the
387 // leading :: from being a continuation of the type name.
389 cpp_output_name(f, cla);
390 f << "::IDL_info_type (";
391 cpp_output_name(f, cla);
392 f << "::IDL_info) =\n"
395 Context ctx = { cla, f };
396 ctx.indent.indent_level = 1;
398 for (ctx.chain = 0; ctx.chain < cla->concrete_iface->get_num_chains();
401 ctx.cur = cla->concrete_iface->get_chain_head(ctx.chain);
403 // Skip the "fake" aggregation interface on the first chain.
405 ctx.cur = *ctx.cur->supers_begin();
407 output_info_type_init_rec(ctx);
410 assert(ctx.indent.indent_level == 1);
414 static void output_footer(Class *cla, ostream &f)
416 // Create an arbitrary, unique name to stick the method wrappers in.
417 f << "\n\nnamespace IDL_Server_" << *cla->get_fq_name()->flatten("_IDLNS_")
420 callback_data data = { cla, f };
422 cla->concrete_iface->for_each_super
423 <cpp_output_iface_method_wrappers>(&data);
427 output_info_type_init(cla, f);
429 cpp_output_name(f, cla);
430 f << "::IDL_ifaceptr::IDL_ifaceptr() :";
432 for (int i = 0; i < cla->concrete_iface->get_num_chains(); i++) {
436 f << "\np" << i << "(&IDL_info.p" << i << ")";
443 void CPPBinding::output_server(UserNameSpace *ns, const char *dir)
447 string footer_name(dir);
448 footer_name += "/footer.cc";
451 printf("%s: %s\n", footer_name.c_str(), dir);
453 footer.open(footer_name.c_str());
454 if (!footer.is_open()) {
455 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
456 footer_name.c_str(), strerror(errno));
461 footer << "// This is a C++ server binding generated by idlc.\n"
462 "// Do not modify this file directly.\n"
463 "// Include this file from exactly one file that has access to\n"
464 "// the class and interface declarations (and preferably, with\n"
465 "// access to to inlineable methods as well).";
468 for (list<ClassRef>::iterator i = classes.begin(); i != classes.end(); ++i) {
471 string filename(dir);
473 filename += *cla->get_ns()->get_fq_name()->flatten("/");
475 makepath(filename.c_str(), false);
478 filename += **cla->name;
482 printf("%s: %s\n", filename.c_str(), dir);
484 output_mixin(cla, filename);
485 output_footer(cla, footer);