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
44 static const char *header
=
46 "\n * This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT!"
51 static const char *dbus_includes
=
52 "\n#include <dbus-c++/dbus.h>"
56 typedef map
<string
,string
> TypeCache
;
58 void usage(const char *argv0
)
60 cerr
<< endl
<< "Usage: " << argv0
<< " <xmlfile> [ --proxy=<outfile.h> ] [ --adaptor=<outfile.h> ]"
65 void split_file(const string
& filename
, string
& base
, string
& ext
)
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
))
93 const char *atomic_type_to_string(char t
)
95 static struct { char type
; const char *name
; } atos
[] =
106 { 's', "std::string" },
107 { 'o', "::DBus::Path" },
108 { 'g', "::DBus::Signature" },
109 { 'v', "::DBus::Variant" },
114 for (i
= 0; atos
[i
].type
; ++i
)
116 if (atos
[i
].type
== t
) break;
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
])
134 switch (signature
[++i
])
138 type
+= "std::map< ";
140 const char *atom
= atomic_type_to_string(signature
[++i
]);
143 cerr
<< "invalid signature" << endl
;
150 parse_signature(signature
, type
, i
);
157 type
+= "std::vector< ::DBus::Struct< ";
159 parse_signature(signature
, type
, ++i
);
161 if (signature
[i
] != ')')
163 cerr
<< "invalid signature \"" << signature
<< "\"" << endl
;
169 if((i
+1) < signature
.length() &&
170 signature
[i
+1] != ')' && signature
[i
+1] != '}')
178 type
+= "std::vector< ";
179 const char* atom
= atomic_type_to_string(signature
[i
]);
182 cerr
<< "invalid signature \"" << signature
<< "\"" << endl
;
189 if((i
+1) < signature
.length() &&
190 signature
[i
+1] != ')' && signature
[i
+1] != '}')
201 type
+= "::DBus::Struct< ";
203 parse_signature(signature
, type
, i
);
205 if((i
+1) < signature
.length() &&
206 signature
[i
+1] != ')' && signature
[i
+1] != '}')
219 const char *atom
= atomic_type_to_string(signature
[i
]);
222 cerr
<< "invalid signature" << endl
;
227 if (signature
[i
+1] != ')' && signature
[i
+1] != '}' && i
+1 < signature
.length())
237 string
signature_to_type(const string
&signature
)
241 parse_signature(signature
, type
, i
);
245 void generate_proxy(Xml::Document
&doc
, const char *filename
)
247 cerr
<< "writing " << filename
<< endl
;
249 ofstream
file(filename
);
252 cerr
<< "unable to write file " << filename
<< endl
;
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"];
282 ms
.insert(ms
.end(), methods
.begin(), methods
.end());
283 ms
.insert(ms
.end(), signals
.begin(), signals
.end());
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
;
305 istringstream
ss(iface_name
);
307 unsigned int nspaces
= 0;
311 while (ss
.str().find('.', ss
.tellg()) != string::npos
)
313 getline(ss
, nspace
, '.');
315 file
<< "namespace " << nspace
<< " {" << endl
;
322 getline(ss
, iface_class
);
324 iface_class
+= "_proxy";
326 cerr
<< "generating code for interface " << iface_name
<< "..." << endl
;
329 << endl
<< "class " << iface_class
330 << endl
<< " : virtual public ::DBus::CallbackTarget, public ::DBus::InterfaceProxy"
334 << endl
<< " " << iface_class
<< "()"
335 << endl
<< " : ::DBus::CallbackTarget()"
336 << endl
<< " , ::DBus::InterfaceProxy(\"" << iface_name
<< "\") {"
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
;
353 << endl
<< " // Context of the response to a received pending call"
354 << endl
<< " class CallContext : public ::DBus::CallInfo"
356 << endl
<< " public:"
358 << endl
<< " " << iface_class
<< " &iface;"
359 << endl
<< " void *data;"
361 << endl
<< " CallContext(" << iface_class
<< " &ifc, ::DBus::PendingCall &call, void *ptr)"
362 << endl
<< " : ::DBus::CallInfo(ifc.object().conn(), call), iface(ifc), data(ptr) {}"
364 << endl
<< " private:"
366 << endl
<< " // Not implemented to prevent copy-construction"
367 << endl
<< " CallContext(const CallContext &);"
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")
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;"
399 if (property_access
== "write" || property_access
== "readwrite")
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);"
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")
444 cerr
<< "method \"" << method_name
<< "\" annotated with \"" << ann_name
<< "\"" << endl
;
448 << endl
<< "private:"
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)("
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&);"
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) {}"
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);";
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
<< ";";
490 << endl
<< " if (!ret.error()) {"
491 << endl
<< " ::DBus::MessageIter ri = ret.msg().reader();";
494 for (Xml::Nodes::iterator ao
= args_out
.begin(); ao
!= args_out
.end(); ++ao
, ++i
)
496 file
<< endl
<< " ri >> " << "argout" << i
<< ";";
501 << endl
<< " (bind->delegate->*bind->method)(";
503 for (Xml::Nodes::iterator ao
= args_out
.begin(); ao
!= args_out
.end(); ++ao
, ++i
)
505 file
<< "argout" << i
<< ", ";
508 << endl
<< " delete bind;"
515 << endl
<< " // \"" << method_name
<< "\" asynchronous call with member function callback"
516 << endl
<< " template < class Delegate >"
517 << endl
<< " ::DBus::PendingCall " << method_name
<< "_async("
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();"
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;"
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
<< "(";
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)
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
<< ", ";
584 file
<< "::DBus::CallInfo &info, ";
587 file
<< "int timeout = -1) {"
588 << endl
<< " ::DBus::CallMessage call;"
591 if (args_in
.size() > 0)
593 file
<< " ::DBus::MessageIter wi = call.writer();" << endl
;
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);"
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;"
623 else if (args_out
.size() > 1)
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");
641 << endl
<< "private:"
642 << endl
<< " // DBus signal: reimplement this method to receive the \"" << name
<< "\" signal"
643 << endl
<< " virtual void " << name
<< "(";
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())
654 file
<< "const " << signature_to_type(arg
.get("type")) << " &";
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"];
668 << endl
<< "private:"
669 << endl
<< " void _" << signal
.get("name") << "_stub(const ::DBus::SignalMessage &sig) {" << endl
;
673 file
<< " ::DBus::MessageIter ri = sig.reader();" << endl
;
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") << "(";
687 for (Xml::Nodes::iterator ai
= args
.begin(); ai
!= args
.end(); ++ai
, ++i
)
691 if (ai
+1 != args
.end())
698 file
<< "};" << endl
;
701 for (i
= 0; i
< nspaces
; ++i
)
707 file
<< "#endif//" << cond_comp
<< endl
;
712 void generate_adaptor(Xml::Document
&doc
, const char *filename
)
714 cerr
<< "writing " << filename
<< endl
;
716 ofstream
file(filename
);
719 cerr
<< "unable to write file " << filename
<< endl
;
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"];
749 ms
.insert(ms
.end(), methods
.begin(), methods
.end());
750 ms
.insert(ms
.end(), signals
.begin(), signals
.end());
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
;
780 istringstream
ss(iface_name
);
782 unsigned int nspaces
= 0;
786 while (ss
.str().find('.', ss
.tellg()) != string::npos
)
788 getline(ss
, nspace
, '.');
790 file
<< "namespace " << nspace
<< " {" << endl
;
797 getline(ss
, iface_class
);
799 iface_class
+= "_adaptor";
801 cerr
<< "generating code for interface " << iface_name
<< "..." << endl
;
804 << endl
<< "class " << iface_class
805 << endl
<< ": virtual public ::DBus::CallbackTarget, public ::DBus::InterfaceAdaptor"
809 << endl
<< " " << iface_class
<< "()"
810 << endl
<< " : ::DBus::CallbackTarget()"
811 << endl
<< " , ::DBus::InterfaceAdaptor(\"" << iface_name
<< "\")"
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
826 << (property
.get("access").find("write") != string::npos
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")
852 if (ann_name
== "org.freedesktop.DBus.Cxx.ExtraInfo")
853 if (ann_value
== "adaptor" || ann_value
== "both")
859 file
<< " register_async(" << iface_class
<< ", " << method_name
860 << ", _" << method_name
<< "_stub);" << endl
;
864 file
<< " register_method(" << iface_class
<< ", " << method_name
865 << ", _" << method_name
<< "_stub);" << endl
;
869 file
<< " }" << endl
;
872 << endl
<< " ::DBus::IntrospectedInterface *const introspect() const {"
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");
883 << endl
<< " static ::DBus::IntrospectedArgument " << method_name
<< "_args[] = "
887 for (Xml::Nodes::iterator ai
= args
.begin(); ai
!= args
.end(); ++ai
)
889 Xml::Node
&arg
= **ai
;
893 if (arg
.get("name").length())
895 file
<< "\"" << arg
.get("name") << "\", ";
901 file
<< "\"" << arg
.get("type") << "\", "
902 << (arg
.get("direction") == "in" ? "true" : "false")
905 file
<< " { 0, 0, 0 }"
911 << endl
<< " static ::DBus::IntrospectedMethod " << iface_class
<< "_methods[] = "
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
;
929 << endl
<< " static ::DBus::IntrospectedMethod " << iface_class
<< "_signals[] = "
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
;
947 << endl
<< " static ::DBus::IntrospectedProperty " << iface_class
<< "_properties[] = "
951 for (Xml::Nodes::iterator pi
= properties
.begin(); pi
!= properties
.end(); ++pi
)
953 Xml::Node
&property
= **pi
;
956 << "\"" << property
.get("name") << "\", "
957 << "\"" << property
.get("type") << "\", "
958 << (property
.get("access").find("read") != string::npos
962 << (property
.get("access").find("write") != string::npos
968 file
<< " { 0, 0, 0, 0 }"
973 << endl
<< " static ::DBus::IntrospectedInterface " << iface_class
<< "_interface = "
975 << endl
<< " \"" << iface_name
<< "\","
976 << endl
<< " " << iface_class
<< "_methods,"
977 << endl
<< " " << iface_class
<< "_signals,"
978 << endl
<< " " << iface_class
<< "_properties"
980 << endl
<< " return &" << iface_class
<< "_interface;"
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
);
993 << endl
<< " // DBus property: set it with " << name
<< "(value) and read it back with " << name
<< "()"
994 << endl
<< " ::DBus::PropertyAdaptor< " << type_name
<< " > " << name
<< ";"
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");
1005 << endl
<< "public:"
1006 << endl
<< " // DBus signal: use " << name
<< "(args) to broadcast this signal"
1007 << endl
<< " void " << name
<< "(";
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())
1020 << endl
<< " ::DBus::SignalMessage sig(\"" << signal
.get("name") <<"\");"
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);"
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;
1063 // If at least one asynchronous method exists then ...
1064 if ( async_method_exists
)
1068 << endl
<< " class _BaseContext"
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() {}"
1075 << endl
<< " bool hasReplied() const { return _replied; }"
1076 << endl
<< " " << iface_class
<< " &iface;"
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());"
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());"
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;"
1106 << endl
<< " private:"
1107 << endl
<< " // Unsupported copy constructor"
1108 << endl
<< " _BaseContext(const _BaseContext&);"
1110 << endl
<< " bool _replied;"
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")
1138 if (ann_name
== "org.freedesktop.DBus.Cxx.ExtraInfo")
1139 if (ann_value
== "adaptor" || ann_value
== "both")
1146 << endl
<< "public:"
1148 << endl
<< " class _" << method_name
<< "_context : public _BaseContext"
1152 << endl
<< " struct Args {"
1154 #ifdef SAVE_SERVER_ARGSIN
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
;
1165 file
<< " argin" << i
<< ";" << endl
;
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
;
1178 file
<< " argout" << i
<< ";" << endl
;
1185 << endl
<< " private:"
1187 << endl
<< " // Unsupported copy-constructor"
1188 << endl
<< " _" << method_name
<< "_context(const _" << method_name
<< "_context &);"
1190 << endl
<< " public:"
1192 << endl
<< " _" << method_name
<< "_context(" << iface_class
<< " &ifc, const ::DBus::Message &msg)"
1197 file
<< " : _BaseContext(ifc, msg), callInfo(ifc.object().conn(), msg) {}" << endl
;
1201 file
<< " : _BaseContext(ifc, msg) {}" << endl
;
1206 << endl
<< " ~_" << method_name
<< "_context() {"
1207 << endl
<< " if (!hasReplied()) {"
1208 << endl
<< " send_error(::DBus::ErrorNoReply(ERROR_MSG_OBJ_DESTROYED_BEFORE_COMPLETING_REQUEST()));"
1215 file
<< " ::DBus::CallInfo callInfo;" << endl
;
1219 << endl
<< " void send_reply(";
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
;
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();"
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());"
1252 << endl
<< " typedef ::DBus::RefPtr<_" << method_name
<< "_context> " << method_name
<< "_ctxref;"
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
<< "(";
1261 for (Xml::Nodes::iterator ai
= args_in
.begin(); ai
!= args_in
.end(); ++ai
, ++i
)
1263 if (ai
!= args_in
.begin())
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())
1274 if (!args_in
.empty())
1277 file
<< method_name
<< "_ctxref) = 0;" << endl
;
1280 << endl
<< "private:"
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);"
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
;
1299 file
<< " ri >> const_cast< " << signature_to_type(arg
.get("type"))
1300 << " &>(ctx->args.argin" << i
<< ");" << endl
;
1302 file
<< " " << signature_to_type(arg
.get("type")) << " argin" << i
<< "; ri >> argin" << i
<< ";" << endl
;
1306 file
<< " " << method_name
<< "(";
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())
1317 #ifdef SAVE_SERVER_ARGSIN
1318 if (arg_name
.length())
1319 file
<< "ctx->args." << arg_name
;
1321 file
<< "ctx->args.argin" << i
;
1323 file
<< "argin" << i
;
1326 if ( 0 < args_in
.size() )
1327 file
<< ", ctx);" << endl
;
1329 file
<< "ctx);" << endl
;
1331 file
<< " }" << endl
;
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)
1344 else if (args_out
.size() == 1)
1346 file
<< signature_to_type(args_out
.front()->get("type")) << " ";
1349 file
<< method_name
<< "(";
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
)
1361 if (args_out
.size() > 1)
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())
1373 if (i
+1 != args_out
.size() || ann_extra
)
1379 file
<< "::DBus::CallInfo &info";
1381 file
<< ") = 0;" << endl
;
1384 << endl
<< "private:"
1386 << endl
<< " ::DBus::Message _" << method_name
<< "_stub(const ::DBus::CallMessage &call) {"
1387 << endl
<< " ::DBus::MessageIter ri = call.reader();"
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)
1402 else if (args_out
.size() == 1)
1404 file
<< " " << signature_to_type(args_out
.front()->get("type")) << " argout1 = ";
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
;
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
)
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
)
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
1462 file
<< "};" << endl
;
1465 for (unsigned int i
= 0; i
< nspaces
; ++i
)
1471 file
<< "#endif//" << cond_comp
<< endl
;
1476 int main(int argc
, char ** argv
)
1483 bool proxy_mode
, adaptor_mode
;
1484 char *proxy
, *adaptor
;
1489 adaptor_mode
= false;
1492 for (int a
= 1; a
< argc
; ++a
)
1494 if (!std::strncmp(argv
[a
], "--proxy=", 8))
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]);
1513 cerr
<< "unable to open file " << argv
[1] << endl
;
1522 //cout << doc.to_xml();
1524 catch(Xml::Error
&e
)
1526 cerr
<< "error parsing " << argv
[1] << ": " << e
.what() << endl
;
1532 cerr
<< "empty document" << endl
;
1536 if (proxy_mode
) generate_proxy(doc
, proxy
);
1537 if (adaptor_mode
) generate_adaptor(doc
, adaptor
);