Initial commit based on .zip from Glenn Schmottlach.
[dbus-cxx-async.git] / tools / xml2cpp.cpp
blob253b6dc77935aacf654846423f6be955a7610c76
1 /*
3 * D-Bus++ - C++ bindings for D-Bus
5 * Copyright (C) 2005-2009 Paolo Durante <shackan@gmail.com>
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
29 #include <cctype>
30 #include <cstdlib>
31 #include <cstring>
32 #include <string>
33 #include <map>
34 #include <iostream>
35 #include <fstream>
36 #include <sstream>
37 #include <algorithm>
39 #include "xml.h"
41 using namespace std;
42 using namespace DBus;
44 static const char *header =
45 "\n/*"
46 "\n * This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!"
47 "\n */"
48 "\n"
49 "\n";
51 static const char *dbus_includes =
52 "\n#include <dbus-c++/dbus.h>"
53 "\n#include <memory>"
54 "\n";
56 typedef map<string,string> TypeCache;
58 void usage(const char *argv0)
60 cerr << endl << "Usage: " << argv0 << " <xmlfile> [ --proxy=<outfile.h> ] [ --adaptor=<outfile.h> ]"
61 << endl;
62 exit(-1);
65 void split_file(const string& filename, string& base, string& ext)
67 base.clear();
68 ext.clear();
69 size_t found = filename.find_last_of(".");
70 base = filename.substr(0, found);
71 if ( found != string::npos )
73 ext = filename.substr(found+1);
77 void underscorize(string &str)
79 for (unsigned int i = 0; i < str.length(); ++i)
81 if (!isalpha(str[i]) && !isdigit(str[i])) str[i] = '_';
85 int char_to_atomic_type(char t)
87 if (strchr("ybnqiuxtdsgavre", t))
88 return t;
90 return 0;
93 const char *atomic_type_to_string(char t)
95 static struct { char type; const char *name; } atos[] =
97 { 'y', "uint8_t" },
98 { 'b', "bool" },
99 { 'n', "int16_t" },
100 { 'q', "uint16_t" },
101 { 'i', "int32_t" },
102 { 'u', "uint32_t" },
103 { 'x', "int64_t" },
104 { 't', "uint64_t" },
105 { 'd', "double" },
106 { 's', "std::string" },
107 { 'o', "::DBus::Path" },
108 { 'g', "::DBus::Signature" },
109 { 'v', "::DBus::Variant" },
110 { '\0', "" }
112 int i;
114 for (i = 0; atos[i].type; ++i)
116 if (atos[i].type == t) break;
118 return atos[i].name;
121 bool is_atomic_type(const string &type)
123 return type.length() == 1 && char_to_atomic_type(type[0]) != 0;
126 void parse_signature(const string &signature, string &type, unsigned int &i)
128 for (; i < signature.length(); ++i)
130 switch (signature[i])
132 case 'a':
134 switch (signature[++i])
136 case '{':
138 type += "std::map< ";
140 const char *atom = atomic_type_to_string(signature[++i]);
141 if (!atom)
143 cerr << "invalid signature" << endl;
144 exit(-1);
146 type += atom;
147 type += ", ";
148 ++i;
150 parse_signature(signature, type, i);
151 type += " >";
153 break;
155 case '(':
157 type += "std::vector< ::DBus::Struct< ";
159 parse_signature(signature, type, ++i);
161 if (signature[i] != ')')
163 cerr << "invalid signature \"" << signature << "\"" << endl;
164 exit(-1);
167 type += " > >";
169 if((i+1) < signature.length() &&
170 signature[i+1] != ')' && signature[i+1] != '}')
172 type += ", ";
174 break;
176 default:
178 type += "std::vector< ";
179 const char* atom = atomic_type_to_string(signature[i]);
180 if(!atom)
182 cerr << "invalid signature \"" << signature << "\"" << endl;
183 exit(-1);
185 type += atom;
187 type += " >";
189 if((i+1) < signature.length() &&
190 signature[i+1] != ')' && signature[i+1] != '}')
192 type += ", ";
194 break;
197 break;
199 case '(':
201 type += "::DBus::Struct< ";
202 ++i;
203 parse_signature(signature, type, i);
204 type += " >";
205 if((i+1) < signature.length() &&
206 signature[i+1] != ')' && signature[i+1] != '}')
208 type += ", ";
210 continue;
212 case ')':
213 case '}':
215 return;
217 default:
219 const char *atom = atomic_type_to_string(signature[i]);
220 if (!atom)
222 cerr << "invalid signature" << endl;
223 exit(-1);
225 type += atom;
227 if (signature[i+1] != ')' && signature[i+1] != '}' && i+1 < signature.length())
229 type += ", ";
231 break;
237 string signature_to_type(const string &signature)
239 string type;
240 unsigned int i = 0;
241 parse_signature(signature, type, i);
242 return type;
245 void generate_proxy(Xml::Document &doc, const char *filename)
247 cerr << "writing " << filename << endl;
249 ofstream file(filename);
250 if (file.bad())
252 cerr << "unable to write file " << filename << endl;
253 exit(-1);
256 file << header;
257 string filestring;
258 string file_ext;
259 split_file(filename, filestring, file_ext);
260 underscorize(filestring);
261 std::transform(filestring.begin(), filestring.end(), filestring.begin(), ::toupper);
262 transform(file_ext.begin(), file_ext.end(), file_ext.begin(), ::toupper);
264 string cond_comp = "DBUSXXX_" + filestring + "_PROXY_MARSHAL_" + file_ext;
266 file << "#ifndef " << cond_comp << endl;
267 file << "#define " << cond_comp << endl;
269 file << dbus_includes;
271 Xml::Node &root = *(doc.root);
272 Xml::Nodes interfaces = root["interface"];
274 for (Xml::Nodes::iterator ifi = interfaces.begin(); ifi != interfaces.end(); ++ifi)
276 Xml::Node &iface = **ifi;
277 Xml::Nodes anns = iface["annotation"];
278 Xml::Nodes methods = iface["method"];
279 Xml::Nodes signals = iface["signal"];
280 Xml::Nodes properties = iface["property"];
281 Xml::Nodes ms;
282 ms.insert(ms.end(), methods.begin(), methods.end());
283 ms.insert(ms.end(), signals.begin(), signals.end());
285 unsigned int i = 0;
287 bool iface_ann_extra = false;
289 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
291 Xml::Node &ann = **ni;
292 if (ann.get("name") == "org.freedesktop.DBus.Cxx.ExtraInfo")
293 if (ann.get("value") == "proxy" || ann.get("value") == "both")
294 iface_ann_extra = true;
297 string iface_name = iface.get("name");
298 if (iface_name == "org.freedesktop.DBus.Introspectable"
299 || iface_name == "org.freedesktop.DBus.Properties")
301 cerr << "skipping interface " << iface_name << endl;
302 continue;
305 istringstream ss(iface_name);
306 string nspace;
307 unsigned int nspaces = 0;
309 file << endl;
311 while (ss.str().find('.', ss.tellg()) != string::npos)
313 getline(ss, nspace, '.');
315 file << "namespace " << nspace << " {" << endl;
317 ++nspaces;
320 string iface_class;
322 getline(ss, iface_class);
324 iface_class += "_proxy";
326 cerr << "generating code for interface " << iface_name << "..." << endl;
328 file
329 << endl << "class " << iface_class
330 << endl << " : virtual public ::DBus::CallbackTarget, public ::DBus::InterfaceProxy"
331 << endl << "{"
332 << endl << "public:"
333 << endl
334 << endl << " " << iface_class << "()"
335 << endl << " : ::DBus::CallbackTarget()"
336 << endl << " , ::DBus::InterfaceProxy(\"" << iface_name << "\") {"
337 << endl;
339 for (Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
341 Xml::Node &signal = **si;
343 string marshname = "_" + signal.get("name") + "_stub";
345 file << " connect_signal("
346 << iface_class << ", " << signal.get("name") << ", "
347 << "_" << signal.get("name") << "_stub);" << endl;
350 file << " }" << endl;
352 file
353 << endl << " // Context of the response to a received pending call"
354 << endl << " class CallContext : public ::DBus::CallInfo"
355 << endl << " {"
356 << endl << " public:"
357 << endl
358 << endl << " " << iface_class << " &iface;"
359 << endl << " void *data;"
360 << endl
361 << endl << " CallContext(" << iface_class << " &ifc, ::DBus::PendingCall &call, void *ptr)"
362 << endl << " : ::DBus::CallInfo(ifc.object().conn(), call), iface(ifc), data(ptr) {}"
363 << endl
364 << endl << " private:"
365 << endl
366 << endl << " // Not implemented to prevent copy-construction"
367 << endl << " CallContext(const CallContext &);"
368 << endl << " };"
369 << endl;
371 for (Xml::Nodes::iterator pi = properties.begin ();
372 pi != properties.end (); ++pi)
374 Xml::Node & property = **pi;
375 string prop_name = property.get ("name");
376 string property_access = property.get ("access");
377 if (property_access == "read" || property_access == "readwrite")
379 file
380 << endl << "public:"
381 << endl << " // DBus property: getter method"
382 << endl << " const " << signature_to_type(property.get("type")) << " " << prop_name << "() {"
383 << endl << " ::DBus::CallMessage call;"
384 << endl << " call.member(\"Get\"); call.interface(\"org.freedesktop.DBus.Properties\");"
385 << endl << " ::DBus::MessageIter wi = call.writer(); "
386 << endl << " const std::string interface_name = \"" << iface_name << "\";"
387 << endl << " const std::string property_name = \"" << prop_name << "\";"
388 << endl << " wi << interface_name;"
389 << endl << " wi << property_name;"
390 << endl << " ::DBus::Message ret = this->invoke_method(call);"
391 << endl << " ::DBus::MessageIter ri = ret.reader();"
392 << endl << " ::DBus::Variant argout; "
393 << endl << " ri >> argout;"
394 << endl << " return argout;"
395 << endl << " };"
396 << endl;
399 if (property_access == "write" || property_access == "readwrite")
401 file
402 << endl << "public:"
403 << endl << " // DBus property: setter method"
404 << endl << " void " << prop_name << "( const "<< signature_to_type(property.get("type")) << " &input" << ") {"
405 << endl << " ::DBus::CallMessage call;"
406 << endl << " call.member(\"Set\"); call.interface(\"org.freedesktop.DBus.Properties\");"
407 << endl << " ::DBus::MessageIter wi = call.writer();"
408 << endl << " ::DBus::Variant value;"
409 << endl << " ::DBus::MessageIter vi = value.writer();"
410 << endl << " vi << input;"
411 << endl << " const std::string interface_name = \"" << iface_name << "\";"
412 << endl << " const std::string property_name = \"" << prop_name << "\";"
413 << endl << " wi << interface_name;"
414 << endl << " wi << property_name;"
415 << endl << " wi << value;"
416 << endl << " ::DBus::Message ret = this->invoke_method(call);"
417 << endl << " };"
418 << endl;
422 for (Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
424 Xml::Node &method = **mi;
425 Xml::Nodes anns = method["annotation"];
426 Xml::Nodes args = method["arg"];
427 Xml::Nodes args_in = args.select("direction","in");
428 Xml::Nodes args_out = args.select("direction","out");
430 string method_name = method.get("name");
432 bool ann_extra = iface_ann_extra;
434 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
436 Xml::Node &ann = **ni;
437 string ann_name = ann.get("name");
438 string ann_value = ann.get("value");
440 if (ann_name == "org.freedesktop.DBus.Cxx.ExtraInfo")
441 if (ann_value == "proxy" || ann_value == "both")
442 ann_extra = true;
444 cerr << "method \"" << method_name << "\" annotated with \"" << ann_name << "\"" << endl;
447 file
448 << endl << "private:"
449 << endl
450 << endl << " // Class member function binding for \"" << method_name << "\""
451 << endl << " template < class Delegate >"
452 << endl << " struct _" << method_name << "_memBind {"
453 << endl << " typedef void (Delegate::*Method)("
454 << endl;
456 i = 0;
457 for (Xml::Nodes::iterator ai = args_out.begin(); ai != args_out.end(); ++ai, ++i)
459 Xml::Node &arg = **ai;
460 file << " const " << signature_to_type(arg.get("type")) << " &, " << endl;
463 file << " CallContext&);"
464 << endl
465 << endl << " Delegate* delegate;"
466 << endl << " Method method;"
467 << endl << " void* data;"
468 << endl << " _" << method_name << "_memBind(Delegate* del, Method meth, void* ptr)"
469 << endl << " : delegate(del), method(meth), data(ptr) {}"
470 << endl << " };"
471 << endl;
473 file
474 << endl
475 << endl << " // Stub for \"" << method_name << "\" member function callback"
476 << endl << " template < class Delegate >"
477 << endl << " void _" << method_name << "_memStub(::DBus::PendingCall &call) {"
478 << endl << " _" << method_name << "_memBind<Delegate>* bind = static_cast<_" << method_name << "_memBind<Delegate>*>(call.data());"
479 << endl << " CallContext ret(*this, call, bind->data);";
481 i = 0;
482 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
484 Xml::Node &arg = **ao;
485 file << endl << " " << signature_to_type(arg.get("type")) << " "
486 << "argout" << i << ";";
489 file
490 << endl << " if (!ret.error()) {"
491 << endl << " ::DBus::MessageIter ri = ret.msg().reader();";
493 i = 0;
494 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
496 file << endl << " ri >> " << "argout" << i << ";";
499 file
500 << endl << " }"
501 << endl << " (bind->delegate->*bind->method)(";
502 i = 0;
503 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
505 file << "argout" << i << ", ";
507 file << "ret);"
508 << endl << " delete bind;"
509 << endl << " }"
510 << endl;
512 file
513 << endl << "public:"
514 << endl
515 << endl << " // \"" << method_name << "\" asynchronous call with member function callback"
516 << endl << " template < class Delegate >"
517 << endl << " ::DBus::PendingCall " << method_name << "_async("
518 << endl;
520 i = 0;
521 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
523 Xml::Node &arg = **ai;
524 file << " const " << signature_to_type(arg.get("type")) << "& ";
526 file << "argin" << i << "," << endl;
529 file << " Delegate* delegate,"
530 << endl << " typename _" << method_name << "_memBind<Delegate>::Method method,"
531 << endl << " void* data,"
532 << endl << " int timeout = -1) {"
533 << endl << " ::DBus::CallMessage call;"
534 << endl << " ::DBus::MessageIter wi = call.writer();"
535 << endl;
537 i = 0;
538 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
540 file << " wi << " << "argin" << i << ";" << endl;
543 file << " call.member(\"" << method.get("name") << "\");"
544 << endl << " ::DBus::PendingCallSlot slot;"
545 << endl << " slot = new ::DBus::CallbackNoReturn<" << iface_class << ", ::DBus::PendingCall &>("
546 << endl << " this, &" << iface_class << "::_" << method_name << "_memStub<Delegate>);"
547 << endl << " std::auto_ptr<_" << method_name << "_memBind<Delegate> > binding(new _" << method_name << "_memBind<Delegate>(delegate, method, data));"
548 << endl << " ::DBus::PendingCall async = invoke_method_async(call, slot, binding.get(), timeout);"
549 << endl << " binding.release();"
550 << endl << " return async;"
551 << endl << " }"
552 << endl;
554 if (args_out.size() == 0 || args_out.size() > 1)
556 file << endl << " void ";
558 else if (args_out.size() == 1)
560 file << endl << " " << signature_to_type(args_out.front()->get("type")) << " ";
563 file << method_name << "(";
565 i = 0;
566 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
568 Xml::Node &arg = **ai;
569 file << "const " << signature_to_type(arg.get("type")) << "& " << "argin" << i << ", ";
572 if (args_out.size() > 1)
574 i = 0;
575 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
577 Xml::Node &arg = **ao;
578 file << signature_to_type(arg.get("type")) << "& " << "argout" << i << ", ";
582 if (ann_extra)
584 file << "::DBus::CallInfo &info, ";
587 file << "int timeout = -1) {"
588 << endl << " ::DBus::CallMessage call;"
589 << endl;
591 if (args_in.size() > 0)
593 file << " ::DBus::MessageIter wi = call.writer();" << endl;
596 i = 0;
597 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
599 file << " wi << argin" << i << ";" << endl;
602 file << " call.member(\"" << method_name << "\");"
603 << endl << " ::DBus::Message ret = invoke_method(call, timeout);"
604 << endl;
606 if (ann_extra)
608 file << " info = ::DBus::CallInfo(object().conn(), ret);" << endl;
611 if (args_out.size() > 0)
613 file << " ::DBus::MessageIter ri = ret.reader();" << endl;
616 if (args_out.size() == 1)
618 file << " " << signature_to_type(args_out.front()->get("type")) << " argout;"
619 << endl << " ri >> argout;"
620 << endl << " return argout;"
621 << endl;
623 else if (args_out.size() > 1)
625 i = 0;
626 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
628 file << " ri >> argout" << i << ";" << endl;
631 file << " }" << endl;
634 for (Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
636 Xml::Node &signal = **si;
637 Xml::Nodes args = signal["arg"];
638 std::string name = signal.get("name");
640 file
641 << endl << "private:"
642 << endl << " // DBus signal: reimplement this method to receive the \"" << name << "\" signal"
643 << endl << " virtual void " << name << "(";
645 i = 0;
646 for (Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++i)
648 Xml::Node &arg = **ai;
649 std::string name = arg.get("name");
651 if (ai != args.begin())
652 file << ", ";
654 file << "const " << signature_to_type(arg.get("type")) << " &";
656 if (name.length())
657 file << name;
659 file << ") {}" << endl;
662 for (Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
664 Xml::Node &signal = **si;
665 Xml::Nodes args = signal["arg"];
667 file
668 << endl << "private:"
669 << endl << " void _" << signal.get("name") << "_stub(const ::DBus::SignalMessage &sig) {" << endl;
671 if (args.size() > 0)
673 file << " ::DBus::MessageIter ri = sig.reader();" << endl;
676 i = 0;
677 for (Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++i)
679 Xml::Node &arg = **ai;
680 file << " " << signature_to_type(arg.get("type"))
681 << " arg" << i << ";" << " ri >> " << "arg" << i << ";" << endl;
684 file << " " << signal.get("name") << "(";
686 i = 0;
687 for (Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai, ++i)
689 file << "arg" << i;
691 if (ai+1 != args.end())
692 file << ", ";
695 file << ");" << endl
696 << " }" << endl;
698 file << "};" << endl;
700 file << endl;
701 for (i = 0; i < nspaces; ++i)
703 file << "} ";
705 file << endl;
707 file << "#endif//" << cond_comp << endl;
709 file.close();
712 void generate_adaptor(Xml::Document &doc, const char *filename)
714 cerr << "writing " << filename << endl;
716 ofstream file(filename);
717 if (file.bad())
719 cerr << "unable to write file " << filename << endl;
720 exit(-1);
723 file << header;
724 string filestring;
725 string file_ext;
726 split_file(filename, filestring, file_ext);
727 underscorize(filestring);
728 transform(filestring.begin(), filestring.end(), filestring.begin(), ::toupper);
729 transform(file_ext.begin(), file_ext.end(), file_ext.begin(), ::toupper);
731 string cond_comp = "DBUSXX_" + filestring + "_ADAPTOR_MARSHAL_" + file_ext;
733 file << "#ifndef " << cond_comp << endl;
734 file << "#define " << cond_comp << endl;
736 file << dbus_includes;
738 Xml::Node &root = *(doc.root);
739 Xml::Nodes interfaces = root["interface"];
741 for (Xml::Nodes::iterator ifi = interfaces.begin(); ifi != interfaces.end(); ++ifi)
743 Xml::Node &iface = **ifi;
744 Xml::Nodes anns = iface["annotation"];
745 Xml::Nodes methods = iface["method"];
746 Xml::Nodes signals = iface["signal"];
747 Xml::Nodes properties = iface["property"];
748 Xml::Nodes ms;
749 ms.insert(ms.end(), methods.begin(), methods.end());
750 ms.insert(ms.end(), signals.begin(), signals.end());
752 unsigned int i = 0;
753 bool iface_ann_extra = false;
754 bool iface_ann_async = false;
756 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
758 Xml::Node &ann = **ni;
760 string ann_name = ann.get("name");
761 string ann_value = ann.get("value");
763 if (ann_name == "org.freedesktop.DBus.Cxx.Async")
764 if (ann_value == "adaptor" || ann_value == "both")
765 iface_ann_async = true;
767 if (ann_name == "org.freedesktop.DBus.Cxx.ExtraInfo")
768 if (ann_value == "adaptor" || ann_value == "both")
769 iface_ann_extra = true;
772 string iface_name = iface.get("name");
773 if (iface_name == "org.freedesktop.DBus.Introspectable"
774 || iface_name == "org.freedesktop.DBus.Properties")
776 cerr << "skipping interface " << iface_name << endl;
777 continue;
780 istringstream ss(iface_name);
781 string nspace;
782 unsigned int nspaces = 0;
784 file << endl;
786 while (ss.str().find('.', ss.tellg()) != string::npos)
788 getline(ss, nspace, '.');
790 file << "namespace " << nspace << " {" << endl;
792 ++nspaces;
795 string iface_class;
797 getline(ss, iface_class);
799 iface_class += "_adaptor";
801 cerr << "generating code for interface " << iface_name << "..." << endl;
803 file
804 << endl << "class " << iface_class
805 << endl << ": virtual public ::DBus::CallbackTarget, public ::DBus::InterfaceAdaptor"
806 << endl << "{"
807 << endl << "public:"
808 << endl
809 << endl << " " << iface_class << "()"
810 << endl << " : ::DBus::CallbackTarget()"
811 << endl << " , ::DBus::InterfaceAdaptor(\"" << iface_name << "\")"
812 << endl << " {"
813 << endl;
815 for (Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi)
817 Xml::Node &property = **pi;
819 file << " bind_property("
820 << property.get("name") << ", "
821 << "\"" << property.get("type") << "\", "
822 << (property.get("access").find("read") != string::npos
823 ? "true"
824 : "false")
825 << ", "
826 << (property.get("access").find("write") != string::npos
827 ? "true"
828 : "false")
829 << ");" << endl;
832 for (Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
834 Xml::Node &method = **mi;
836 Xml::Nodes anns = method["annotation"];
837 string method_name = method.get("name");
839 bool ann_async = iface_ann_async;
840 bool ann_extra = iface_ann_extra;
842 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
844 Xml::Node &ann = **ni;
845 string ann_name = ann.get("name");
846 string ann_value = ann.get("value");
848 if (ann_name == "org.freedesktop.DBus.Cxx.Async")
849 if (ann_value == "adaptor" || ann_value == "both")
850 ann_async = true;
852 if (ann_name == "org.freedesktop.DBus.Cxx.ExtraInfo")
853 if (ann_value == "adaptor" || ann_value == "both")
854 ann_extra = true;
857 if (ann_async)
859 file << " register_async(" << iface_class << ", " << method_name
860 << ", _" << method_name << "_stub);" << endl;
862 else
864 file << " register_method(" << iface_class << ", " << method_name
865 << ", _" << method_name << "_stub);" << endl;
869 file << " }" << endl;
871 file
872 << endl << " ::DBus::IntrospectedInterface *const introspect() const {"
873 << endl;
875 for (Xml::Nodes::iterator mi = ms.begin(); mi != ms.end(); ++mi)
877 Xml::Node &method = **mi;
878 Xml::Nodes args = method["arg"];
880 string method_name = method.get("name");
882 file
883 << endl << " static ::DBus::IntrospectedArgument " << method_name << "_args[] = "
884 << endl << " {"
885 << endl;
887 for (Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai)
889 Xml::Node &arg = **ai;
891 file << " { ";
893 if (arg.get("name").length())
895 file << "\"" << arg.get("name") << "\", ";
897 else
899 file << "0, ";
901 file << "\"" << arg.get("type") << "\", "
902 << (arg.get("direction") == "in" ? "true" : "false")
903 << " }," << endl;
905 file << " { 0, 0, 0 }"
906 << endl << " };"
907 << endl;
910 file
911 << endl << " static ::DBus::IntrospectedMethod " << iface_class << "_methods[] = "
912 << endl << " {"
913 << endl;
915 for (Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
917 Xml::Node &method = **mi;
919 string method_name = method.get("name");
921 file << " { \"" << method_name << "\", " << method_name << "_args }," << endl;
924 file << " { 0, 0 }"
925 << endl << " };"
926 << endl;
928 file
929 << endl << " static ::DBus::IntrospectedMethod " << iface_class << "_signals[] = "
930 << endl << " {"
931 << endl;
933 for (Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
935 Xml::Node &method = **si;
937 string method_name = method.get("name");
939 file << " { \"" << method_name << "\", " << method_name << "_args }," << endl;
942 file << " { 0, 0 }"
943 << endl << " };"
944 << endl;
946 file
947 << endl << " static ::DBus::IntrospectedProperty " << iface_class << "_properties[] = "
948 << endl << " {"
949 << endl;
951 for (Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi)
953 Xml::Node &property = **pi;
955 file << " { "
956 << "\"" << property.get("name") << "\", "
957 << "\"" << property.get("type") << "\", "
958 << (property.get("access").find("read") != string::npos
959 ? "true"
960 : "false")
961 << ", "
962 << (property.get("access").find("write") != string::npos
963 ? "true"
964 : "false")
965 << " }," << endl;
968 file << " { 0, 0, 0, 0 }"
969 << endl << " };"
970 << endl;
972 file
973 << endl << " static ::DBus::IntrospectedInterface " << iface_class << "_interface = "
974 << endl << " {"
975 << endl << " \"" << iface_name << "\","
976 << endl << " " << iface_class << "_methods,"
977 << endl << " " << iface_class << "_signals,"
978 << endl << " " << iface_class << "_properties"
979 << endl << " };"
980 << endl << " return &" << iface_class << "_interface;"
981 << endl << " }"
982 << endl;
984 for (Xml::Nodes::iterator pi = properties.begin(); pi != properties.end(); ++pi)
986 Xml::Node &property = **pi;
987 string name = property.get("name");
988 string type = property.get("type");
989 string type_name = signature_to_type(type);
991 file
992 << endl << "public:"
993 << endl << " // DBus property: set it with " << name << "(value) and read it back with " << name << "()"
994 << endl << " ::DBus::PropertyAdaptor< " << type_name << " > " << name << ";"
995 << endl;
998 for (Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si)
1000 Xml::Node &signal = **si;
1001 Xml::Nodes args = signal["arg"];
1002 std::string name = signal.get("name");
1004 file
1005 << endl << "public:"
1006 << endl << " // DBus signal: use " << name << "(args) to broadcast this signal"
1007 << endl << " void " << name << "(";
1009 i = 0;
1010 for (Xml::Nodes::iterator a = args.begin(); a != args.end(); ++a, ++i)
1012 Xml::Node &arg = **a;
1014 file << "const " << signature_to_type(arg.get("type")) << "& arg" << i+1;
1016 if (i+1 != args.size())
1017 file << ", ";
1019 file << ") {"
1020 << endl << " ::DBus::SignalMessage sig(\"" << signal.get("name") <<"\");"
1021 << endl;
1023 if (args.size() > 0)
1025 file << " ::DBus::MessageIter wi = sig.writer();" << endl;
1027 for (unsigned int i = 0; i < args.size(); ++i)
1029 file << " wi << arg" << i+1 << ";" << endl;
1033 file << " emit_signal(sig);"
1034 << endl << " }"
1035 << endl;
1038 // See if there are any annotated methods
1039 bool async_method_exists = iface_ann_async;
1040 for (Xml::Nodes::iterator mi = methods.begin();
1041 !async_method_exists && (mi != methods.end()); ++mi)
1043 Xml::Node &method = **mi;
1044 Xml::Nodes anns = method["annotation"];
1046 string method_name = method.get("name");
1048 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
1050 Xml::Node &ann = **ni;
1051 string ann_name = ann.get("name");
1052 string ann_value = ann.get("value");
1054 if (ann_name == "org.freedesktop.DBus.Cxx.Async")
1055 if (ann_value == "adaptor" || ann_value == "both")
1057 async_method_exists = true;
1058 break;
1063 // If at least one asynchronous method exists then ...
1064 if ( async_method_exists )
1066 file
1067 << endl
1068 << endl << " class _BaseContext"
1069 << endl << " {"
1070 << endl << " public:"
1071 << endl << " _BaseContext(" << iface_class << " &ifc, const ::DBus::Message &msg)"
1072 << endl << " : iface(ifc), _msg(msg), _replied(false) {}"
1073 << endl << " virtual ~_BaseContext() {}"
1074 << endl
1075 << endl << " bool hasReplied() const { return _replied; }"
1076 << endl << " " << iface_class << " &iface;"
1077 << endl
1078 << endl << " void send_error(const char *name, const char *description) {"
1079 << endl << " if ( !hasReplied() ) {"
1080 << endl << " ::DBus::ErrorMessage msg(_msg, name, description);"
1081 << endl << " iface.object().conn().send(msg);"
1082 << endl << " setReplied(true);"
1083 << endl << " } else {"
1084 << endl << " throw ::DBus::ErrorFailed(ERROR_MSG_MULTIPLE_REPLIES());"
1085 << endl << " }"
1086 << endl << " }"
1087 << endl
1088 << endl << " void send_error(const ::DBus::Error &error) {"
1089 << endl << " if ( !hasReplied() ) {"
1090 << endl << " ::DBus::ErrorMessage msg(_msg, error.name(), error.description());"
1091 << endl << " iface.object().conn().send(msg);"
1092 << endl << " setReplied(true);"
1093 << endl << " } else {"
1094 << endl << " throw ::DBus::ErrorFailed(ERROR_MSG_MULTIPLE_REPLIES());"
1095 << endl << " }"
1096 << endl << " }"
1097 << endl
1098 << endl << " protected:"
1099 << endl << " void setReplied(bool replied) { _replied = replied; }"
1100 << endl << " static const char* ERROR_MSG_MULTIPLE_REPLIES()"
1101 << endl << " { return \"The application tried to send multiple replies\"; }"
1102 << endl << " static const char* ERROR_MSG_OBJ_DESTROYED_BEFORE_COMPLETING_REQUEST()"
1103 << endl << " { return \"Object was destroyed before completing the request\"; }"
1104 << endl << " ::DBus::Message _msg;"
1105 << endl
1106 << endl << " private:"
1107 << endl << " // Unsupported copy constructor"
1108 << endl << " _BaseContext(const _BaseContext&);"
1109 << endl
1110 << endl << " bool _replied;"
1111 << endl << " };"
1112 << endl;
1115 for (Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi)
1117 Xml::Node &method = **mi;
1118 Xml::Nodes anns = method["annotation"];
1119 Xml::Nodes args = method["arg"];
1120 Xml::Nodes args_in = args.select("direction","in");
1121 Xml::Nodes args_out = args.select("direction","out");
1123 string method_name = method.get("name");
1125 bool ann_async = iface_ann_async;
1126 bool ann_extra = iface_ann_extra;
1128 for (Xml::Nodes::iterator ni = anns.begin(); ni != anns.end(); ++ni)
1130 Xml::Node &ann = **ni;
1131 string ann_name = ann.get("name");
1132 string ann_value = ann.get("value");
1134 if (ann_name == "org.freedesktop.DBus.Cxx.Async")
1135 if (ann_value == "adaptor" || ann_value == "both")
1136 ann_async = true;
1138 if (ann_name == "org.freedesktop.DBus.Cxx.ExtraInfo")
1139 if (ann_value == "adaptor" || ann_value == "both")
1140 ann_extra = true;
1143 if (ann_async)
1145 file
1146 << endl << "public:"
1147 << endl
1148 << endl << " class _" << method_name << "_context : public _BaseContext"
1149 << endl << " {"
1150 << endl;
1151 #if 0
1152 << endl << " struct Args {"
1153 << endl;
1154 #ifdef SAVE_SERVER_ARGSIN
1155 i = 0;
1156 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1158 Xml::Node &arg = **ai;
1159 file << " const " << signature_to_type(arg.get("type"));
1161 string arg_name = arg.get("name");
1162 if (arg_name.length())
1163 file << " " << arg_name << ";" << endl;
1164 else
1165 file << " argin" << i << ";" << endl;
1167 #endif
1168 i = 0;
1169 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
1171 Xml::Node &arg = **ao;
1172 file << " " << signature_to_type(arg.get("type"));
1174 string arg_name = arg.get("name");
1175 if (arg_name.length())
1176 file << " " << arg_name << ";" << endl;
1177 else
1178 file << " argout" << i << ";" << endl;
1181 file << " } args;"
1182 << endl
1183 #endif
1184 file
1185 << endl << " private:"
1186 << endl
1187 << endl << " // Unsupported copy-constructor"
1188 << endl << " _" << method_name << "_context(const _" << method_name << "_context &);"
1189 << endl
1190 << endl << " public:"
1191 << endl
1192 << endl << " _" << method_name << "_context(" << iface_class << " &ifc, const ::DBus::Message &msg)"
1193 << endl;
1195 if ( ann_extra )
1197 file << " : _BaseContext(ifc, msg), callInfo(ifc.object().conn(), msg) {}" << endl;
1199 else
1201 file << " : _BaseContext(ifc, msg) {}" << endl;
1204 file
1205 << endl
1206 << endl << " ~_" << method_name << "_context() {"
1207 << endl << " if (!hasReplied()) {"
1208 << endl << " send_error(::DBus::ErrorNoReply(ERROR_MSG_OBJ_DESTROYED_BEFORE_COMPLETING_REQUEST()));"
1209 << endl << " }"
1210 << endl << " }"
1211 << endl;
1213 if ( ann_extra )
1215 file << " ::DBus::CallInfo callInfo;" << endl;
1218 file
1219 << endl << " void send_reply(";
1221 i = 0;
1222 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
1224 if (ao != args_out.begin()) file << ", ";
1226 Xml::Node &arg = **ao;
1227 file << signature_to_type(arg.get("type")) << " argout" << i;
1231 file << ") {"
1232 << endl << " if (!hasReplied()) {"
1233 << endl << " ::DBus::CallMessage &call = static_cast< ::DBus::CallMessage &>(_msg);"
1234 << endl << " ::DBus::ReturnMessage reply(call);"
1235 << endl << " ::DBus::MessageIter wi = reply.writer();"
1236 << endl;
1238 i = 0;
1239 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
1241 file << " wi << argout" << i << ";" << endl;
1244 file << " iface.object().conn().send(reply);"
1245 << endl << " setReplied(true);"
1246 << endl << " } else {"
1247 << endl << " throw ::DBus::ErrorFailed(ERROR_MSG_MULTIPLE_REPLIES());"
1248 << endl << " }"
1249 << endl << " }"
1250 << endl << " };"
1251 << endl
1252 << endl << " typedef ::DBus::RefPtr<_" << method_name << "_context> " << method_name << "_ctxref;"
1253 << endl;
1255 file
1256 << endl << "public:"
1257 << endl << " // DBus method: reimplement this function in your server class to offer the desired behaviour"
1258 << endl << " virtual void " << method_name << "(";
1260 i = 0;
1261 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1263 if (ai != args_in.begin())
1264 file << ", ";
1266 Xml::Node &arg = **ai;
1267 file << "const " << signature_to_type(arg.get("type")) << " &";
1269 string arg_name = arg.get("name");
1270 if (arg_name.length())
1271 file << arg_name;
1274 if (!args_in.empty())
1275 file << ", ";
1277 file << method_name << "_ctxref) = 0;" << endl;
1279 file
1280 << endl << "private:"
1281 << endl
1282 << endl << " void _" << method_name << "_stub(const ::DBus::CallMessage &call) {"
1283 << endl << " ::DBus::MessageIter ri = call.reader();"
1284 << endl << " " << method_name << "_ctxref ctx = new _" << method_name << "_context(*this, call);"
1285 << endl;
1287 i = 0;
1288 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1290 Xml::Node &arg = **ai;
1292 string arg_name = arg.get("name");
1294 #ifdef SAVE_SERVER_ARGSIN
1295 if (arg_name.length())
1296 file << " ri >> const_cast< " << signature_to_type(arg.get("type"))
1297 << " &>(ctx->args." << arg_name << ");" << endl;
1298 else
1299 file << " ri >> const_cast< " << signature_to_type(arg.get("type"))
1300 << " &>(ctx->args.argin" << i << ");" << endl;
1301 #else
1302 file << " " << signature_to_type(arg.get("type")) << " argin" << i << "; ri >> argin" << i << ";" << endl;
1303 #endif
1306 file << " " << method_name << "(";
1307 i = 0;
1308 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1310 Xml::Node &arg = **ai;
1312 string arg_name = arg.get("name");
1314 if (ai != args_in.begin())
1315 file << ", ";
1317 #ifdef SAVE_SERVER_ARGSIN
1318 if (arg_name.length())
1319 file << "ctx->args." << arg_name;
1320 else
1321 file << "ctx->args.argin" << i;
1322 #else
1323 file << "argin" << i;
1324 #endif
1326 if ( 0 < args_in.size() )
1327 file << ", ctx);" << endl;
1328 else
1329 file << "ctx);" << endl;
1331 file << " }" << endl;
1333 else
1335 file
1336 << endl << "public:"
1337 << endl << " // DBus method: reimplement this function in your server class to offer the desired behaviour"
1338 << endl << " virtual ";
1340 if (args_out.size() == 0 || args_out.size() > 1)
1342 file << "void ";
1344 else if (args_out.size() == 1)
1346 file << signature_to_type(args_out.front()->get("type")) << " ";
1349 file << method_name << "(";
1351 i = 0;
1352 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1354 Xml::Node &arg = **ai;
1355 file << "const " << signature_to_type(arg.get("type")) << " &";
1357 if (i+1 != args_in.size() || args_out.size() > 1 || ann_extra)
1358 file << ", ";
1361 if (args_out.size() > 1)
1363 unsigned int i = 0;
1364 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
1366 Xml::Node &arg = **ao;
1367 file << signature_to_type(arg.get("type")) << " &";
1369 string arg_name = arg.get("name");
1370 if (arg_name.length())
1371 file << arg_name;
1373 if (i+1 != args_out.size() || ann_extra)
1374 file << ", ";
1377 if (ann_extra)
1379 file << "::DBus::CallInfo &info";
1381 file << ") = 0;" << endl;
1383 file
1384 << endl << "private:"
1385 << endl
1386 << endl << " ::DBus::Message _" << method_name << "_stub(const ::DBus::CallMessage &call) {"
1387 << endl << " ::DBus::MessageIter ri = call.reader();"
1388 << endl;
1390 unsigned int i = 1;
1391 for (Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i)
1393 Xml::Node &arg = **ai;
1394 file << " " << signature_to_type(arg.get("type")) << " argin" << i << ";"
1395 << " ri >> argin" << i << ";" << endl;
1398 if (args_out.size() == 0)
1400 file << " ";
1402 else if (args_out.size() == 1)
1404 file << " " << signature_to_type(args_out.front()->get("type")) << " argout1 = ";
1406 else
1408 unsigned int i = 1;
1409 for (Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i)
1411 Xml::Node &arg = **ao;
1412 file << " " << signature_to_type(arg.get("type")) << " argout" << i << ";" << endl;
1414 file << " ";
1417 if (ann_extra)
1419 file << "::DBus::CallInfo info(object().conn(), call);" << endl;
1422 file << " " << method_name << "(";
1424 for (unsigned int i = 0; i < args_in.size(); ++i)
1426 file << "argin" << i+1;
1428 if (i+1 != args_in.size() || args_out.size() > 1 || ann_extra)
1429 file << ", ";
1432 if (args_out.size() > 1)
1433 for (unsigned int i = 0; i < args_out.size(); ++i)
1435 file << "argout" << i+1;
1437 if (i+1 != args_out.size() || ann_extra)
1438 file << ", ";
1440 if (ann_extra)
1442 file << "info";
1444 file << ");" << endl;
1446 file << " ::DBus::ReturnMessage reply(call);" << endl;
1448 if (args_out.size() > 0)
1450 file << " ::DBus::MessageIter wi = reply.writer();" << endl;
1452 for (unsigned int i = 0; i < args_out.size(); ++i)
1454 file << " wi << argout" << i+1 << ";" << endl;
1458 file << " return reply;" << endl
1459 << " }" << endl;
1462 file << "};" << endl;
1464 file << endl;
1465 for (unsigned int i = 0; i < nspaces; ++i)
1467 file << "} ";
1469 file << endl;
1471 file << "#endif//" << cond_comp << endl;
1473 file.close();
1476 int main(int argc, char ** argv)
1478 if (argc < 2)
1480 usage(argv[0]);
1483 bool proxy_mode, adaptor_mode;
1484 char *proxy, *adaptor;
1486 proxy_mode = false;
1487 proxy = 0;
1489 adaptor_mode = false;
1490 adaptor = 0;
1492 for (int a = 1; a < argc; ++a)
1494 if (!std::strncmp(argv[a], "--proxy=", 8))
1496 proxy_mode = true;
1497 proxy = argv[a] +8;
1499 else
1500 if (!std::strncmp(argv[a], "--adaptor=", 10))
1502 adaptor_mode = true;
1503 adaptor = argv[a] +10;
1507 if (!proxy_mode && !adaptor_mode) usage(argv[0]);
1509 ifstream xmlfile(argv[1]);
1511 if (xmlfile.bad())
1513 cerr << "unable to open file " << argv[1] << endl;
1514 return -1;
1517 Xml::Document doc;
1521 xmlfile >> doc;
1522 //cout << doc.to_xml();
1524 catch(Xml::Error &e)
1526 cerr << "error parsing " << argv[1] << ": " << e.what() << endl;
1527 return -1;
1530 if (!doc.root)
1532 cerr << "empty document" << endl;
1533 return -1;
1536 if (proxy_mode) generate_proxy(doc, proxy);
1537 if (adaptor_mode) generate_adaptor(doc, adaptor);
1539 return 0;