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 conditions:
12 // * Redistributions of source code must retain the above copyright notice,
13 // this list of conditions and the following disclaimers.
15 // * Redistributions in binary form must reproduce the above copyright notice,
16 // this list of conditions and the following disclaimers in the
17 // documentation and/or other materials provided with the distribution.
19 // * The names of the Software's authors and/or contributors
20 // may not be used to endorse or promote products derived from
21 // this Software without specific prior written permission.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
41 static void output_ifaceptrs(Class *cla, ostream &f)
43 f << "// " << *cla->get_fq_name()->flatten("::") << "\n"
44 "// This is a C++ server class mixin generated by idlc.\n"
45 "// Do not modify this file directly.\n"
46 "// This file provides data and methods used by the object system\n"
47 "// to connect this class to its interface(s). Include it inside\n"
48 "// the class definition as \"public:\", and call the init_iface()\n"
49 "// method from your constructor(s).\n\n";
52 Interface *conc = cla->concrete_iface;
53 assert(conc->get_num_chains() > 0);
55 f << "struct IDL_ifaceptr {\n\t";
57 for (int i = 0; i < conc->get_num_chains(); i++) {
58 Interface *iface = conc->get_chain_head(i);
60 // Skip the "fake" aggregation interface on the first chain.
62 iface = *iface->supers_begin();
64 cpp_output_name(f, iface, "_i_");
65 f << " p" << i << ";\n\t";
68 f << **cla->name << " *priv;\n"
73 static void output_classptr(Class *cla, Interface *iface, ostream &f)
75 int chain = cla->concrete_iface->super_to_chain(iface);
77 f << "static " << **cla->name << " *classptr(";
78 cpp_output_name(f, iface);
81 "\tif (ref && static_cast<const void *>(ref._ptr->info) ==\n"
82 "\t static_cast<const void *>(&IDL_info.p" << chain << "))\n"
84 "\t\tuintptr_t ptr = reinterpret_cast<uintptr_t>(ref._ptr);\n"
85 "\t\tptr -= " << chain * target->pointer_size << ";\n"
86 "\t\treturn reinterpret_cast<IDL_ifaceptr *>(ref._ptr)->priv;\n"
92 static void output_convfunc(Class *cla, Interface *iface, ostream &f)
96 cpp_output_name(f, iface);
102 cpp_output_name(f, iface);
104 int chain = cla->concrete_iface->super_to_chain(iface);
106 f << "(reinterpret_cast< ";
107 cpp_output_name(f, iface, "_i_");
108 f << " *>(&IDL_ref.p" << chain << "));\n"
112 static void output_info_type(Class *cla, ostream &f)
114 Interface *conc = cla->concrete_iface;
115 f << "struct IDL_info_type {\n";
117 for (int i = 0; i < conc->get_num_chains(); i++) {
118 Interface *iface = conc->get_chain_head(i);
120 // Skip the "fake" aggregation interface on the first chain.
122 iface = *iface->supers_begin();
125 cpp_output_name(f, iface, "_i_");
126 f << "::info_type p" << i << ";\n";
130 "static IDL_info_type IDL_info;\n\n";
133 static void output_mixin(Class *cla, string &filename)
137 f.open(filename.c_str());
139 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
140 filename.c_str(), strerror(errno));
145 output_ifaceptrs(cla, f);
146 output_info_type(cla, f);
148 f << "// The classptr method(s) can be used to get a class pointer from\n"
149 "// an interface reference. If the interface reference does\n"
150 "// not refer to an instance of the class, it returns NULL.\n\n";
152 for (Class::ifaces_iterator i = cla->ifaces_begin();
153 i != cla->ifaces_end(); ++i)
155 output_classptr(cla, *i, f);
158 f << "// Used by auto-generated stubs which know that the interface is of\n"
159 "// the proper class. Do not call this from user code.\n\n"
160 "static " << **cla->name << " *_classptr_internal(void *ptr)\n"
162 "\tIDL_ifaceptr *wrap = static_cast<IDL_ifaceptr *>(ptr);\n"
163 "\treturn wrap->priv;\n"
166 f << "IDL_ifaceptr IDL_ref;\n\n";
168 f << "// The implicit conversion function(s) below can be used to convert\n"
169 "// a class reference to an interface reference. Note that if you\n"
170 "// have a pointer, rather than a reference, you will need to dereference\n"
171 "// it prior to casting to the desired interface type.\n\n";
173 for (Class::ifaces_iterator i = cla->ifaces_begin();
174 i != cla->ifaces_end(); ++i)
176 output_convfunc(cla, *i, f);
179 f << "// This method must be called prior to using any interface references\n"
180 << "// to this object. If a method is called through an interface pointer\n"
181 << "// before this is done, a memory fault is likely.\n\n"
182 << "void init_iface()\n"
184 << "\tIDL_ref.priv = this;\n"
188 struct callback_data {
193 static void output_method_wrapper(Class *cla, Interface *iface,
194 Method *meth, Class::MethodInfo *mi,
195 bool copy, ostream &f)
197 const String *implname_idlns, *implname_scope;
200 implname_idlns = mi->implname->flatten("_IDLNS_");
201 implname_scope = mi->implname->flatten("::");
203 implname_idlns = implname_scope = meth->name;
207 Indent indent = { 1, implname_idlns->length() + 6 };
214 f << *implname_idlns << "(void *_this";
216 for (Method::entries_iterator i = meth->entries_begin();
217 i != meth->entries_end(); ++i)
219 f << ",\n" << indent;
220 cpp_output_one_param(f, *i, true, copy);
223 const String *classname = cla->get_fq_name()->flatten("::");
228 int chain = cla->concrete_iface->super_to_chain(iface);
230 f << "\t\t_this = reinterpret_cast<void *>"
231 "(reinterpret_cast<uintptr_t>(_this) - "
232 << chain * target->pointer_size << ");\n";
235 f << "\t\t::" << *classname << " *_ptr = ::" << *classname
236 << "::_classptr_internal(_this);\n"
237 "\t\t_ptr->" << *implname_scope << '(';
239 indent = (Indent){ 2, implname_scope->length() + 7 };
241 for (Method::entries_iterator i = meth->entries_begin();
242 i != meth->entries_end(); ++i)
244 if (i != meth->entries_begin())
245 f << ",\n" << indent;
248 bool copy_this_param = false;
250 Class::ParamInfo *pi = mi->get_param(p);
252 copy_this_param = true;
255 // FIXME: copy non-arrays
259 if (copy_this_param && p->is_array())
267 // Should be static, but GCC won't accept it as a template parameter
268 // even though the template is only used from this file (and thus
269 // won't be instantiated elsewhere (unless some template consolidation
270 // mechanism puts them all in one file or something, but then an
271 // exception could be made for templates with static parameters,
272 // as they can be placed in their original files with no chance
275 void cpp_output_iface_method_wrappers(Interface *super, void *arg)
277 callback_data *data = static_cast<callback_data *>(arg);
279 for (Interface::methods_iterator i = super->methods_begin();
280 i != super->methods_end(); ++i)
283 Class::MethodInfo *mi = data->cla->get_method(m);
285 output_method_wrapper(data->cla, super, m, mi, false, data->f);
287 if (mi && mi->copy_params)
288 output_method_wrapper(data->cla, super, m, mi, true, data->f);
300 void cpp_output_iface_table_entry(Interface *super, void *arg)
302 Context &ctx(*static_cast<Context *>(arg));
304 ctx.f << ctx.indent << "{\n";
305 ctx.indent.indent_level++;
308 cpp_output_name(ctx.f, super);
310 ctx.f << "_ns::_guid.l,\n"
312 << (ctx.cla->concrete_iface->super_to_chain(super) - ctx.chain) *
313 target->pointer_size << '\n';
315 ctx.indent.indent_level--;
316 ctx.f << ctx.indent << "},\n";
319 void cpp_output_method_table_entries(Interface *super, void *arg)
321 Context &ctx(*static_cast<Context *>(arg));
323 for (Interface::methods_iterator i = super->methods_begin();
324 i != super->methods_end(); ++i)
327 Class::MethodInfo *mi = ctx.cla->get_method(meth);
328 const String *implname;
331 implname = mi->implname->flatten("::");
333 implname = meth->name;
335 ctx.f << ctx.indent << "IDL_Server_"
336 << *ctx.cla->get_fq_name()->flatten("_IDLNS_")
337 << "::" << *implname << ",\n";
341 static void output_info_type_init_rec(Context &ctx)
343 Interface *iface = ctx.cur;
345 ctx.f << ctx.indent << "{ // " << *iface->get_fq_name()->flatten() << '\n';
346 ctx.indent.indent_level++;
348 if (!iface->supers_empty()) {
349 ctx.cur = *iface->supers_begin();
350 output_info_type_init_rec(ctx);
352 // Concrete pointer adjustment
353 ctx.f << ctx.indent << '-'
354 << ctx.chain * target->pointer_size << ",\n";
356 // Pointer to concrete downcast table
357 ctx.f << ctx.indent << "&IDL_info.p0.iface_table.";
359 Interface *iface = *ctx.cla->concrete_iface->supers_begin();
360 ctx.f << *iface->get_fq_name()->flatten("_IDLNS_") << ",\n";
363 // Interface table for downcasts
364 ctx.f << ctx.indent << "{\n";
365 ctx.indent.indent_level++;
367 cpp_output_iface_table_entry(iface, &ctx);
368 iface->for_each_super<cpp_output_iface_table_entry>(&ctx);
370 ctx.f << ctx.indent << "NULL\n";
372 ctx.indent.indent_level--;
373 ctx.f << ctx.indent << "},\n";
377 ctx.f << ctx.indent << "{\n";
378 ctx.indent.indent_level++;
380 cpp_output_method_table_entries(iface, &ctx);
381 iface->for_each_super<cpp_output_method_table_entries>(&ctx);
383 ctx.indent.indent_level--;
384 ctx.f << ctx.indent << "},\n";
386 ctx.indent.indent_level--;
387 ctx.f << ctx.indent << "},\n";
390 static void output_info_type_init(Class *cla, ostream &f)
392 Indent indent = (Indent){1, 0};
394 // The struct name is enclosed in parentheses to disambiguate the
395 // leading :: from being a continuation of the type name.
397 cpp_output_name(f, cla);
398 f << "::IDL_info_type (";
399 cpp_output_name(f, cla);
400 f << "::IDL_info) =\n"
403 Context ctx = { cla, f };
404 ctx.indent.indent_level = 1;
406 for (ctx.chain = 0; ctx.chain < cla->concrete_iface->get_num_chains();
409 ctx.cur = cla->concrete_iface->get_chain_head(ctx.chain);
411 // Skip the "fake" aggregation interface on the first chain.
413 ctx.cur = *ctx.cur->supers_begin();
415 output_info_type_init_rec(ctx);
418 assert(ctx.indent.indent_level == 1);
422 static void output_footer(Class *cla, ostream &f)
424 // Create an arbitrary, unique name to stick the method wrappers in.
425 f << "\n\nnamespace IDL_Server_" << *cla->get_fq_name()->flatten("_IDLNS_")
428 callback_data data = { cla, f };
430 cla->concrete_iface->for_each_super
431 <cpp_output_iface_method_wrappers>(&data);
435 output_info_type_init(cla, f);
437 cpp_output_name(f, cla);
438 f << "::IDL_ifaceptr::IDL_ifaceptr() :";
440 for (int i = 0; i < cla->concrete_iface->get_num_chains(); i++) {
444 f << "\np" << i << "(&IDL_info.p" << i << ")";
451 void CPPBinding::output_server(UserNameSpace *ns, const char *dir)
455 string footer_name(dir);
456 footer_name += "/footer.cc";
459 printf("%s: %s\n", footer_name.c_str(), dir);
461 footer.open(footer_name.c_str());
462 if (!footer.is_open()) {
463 fprintf(stderr, "Could not create output file \"%s\": %s.\n",
464 footer_name.c_str(), strerror(errno));
469 footer << "// This is a C++ server binding generated by idlc.\n"
470 "// Do not modify this file directly.\n"
471 "// Include this file from exactly one file that has access to\n"
472 "// the class and interface declarations (and preferably, with\n"
473 "// access to to inlineable methods as well).";
476 for (list<ClassRef>::iterator i = classes.begin(); i != classes.end(); ++i) {
479 string filename(dir);
481 filename += *cla->get_ns()->get_fq_name()->flatten("/");
483 makepath(filename.c_str(), false);
486 filename += **cla->name;
490 printf("%s: %s\n", filename.c_str(), dir);
492 output_mixin(cla, filename);
493 output_footer(cla, footer);