diff options
| author | pdurante <pdurante@30a43799-04e7-0310-8b2b-ea0d24f86d0e> | 2006-09-05 13:36:22 +0000 |
|---|---|---|
| committer | pdurante <pdurante@30a43799-04e7-0310-8b2b-ea0d24f86d0e> | 2006-09-05 13:36:22 +0000 |
| commit | acfeb85b879556475d1495c4c5979b1e2aa9ee8e (patch) | |
| tree | 613d5da9a9536e5266342745180ac41d75e2ad7f /tools/xml2cpp.cpp | |
| download | dbus-c++-acfeb85b879556475d1495c4c5979b1e2aa9ee8e.tar.gz | |
imported D-Bus C++ library
git-svn-id: http://dev.openwengo.org/svn/openwengo/wengophone-ng/branches/wengophone-dbus-api/libs/dbus@7382 30a43799-04e7-0310-8b2b-ea0d24f86d0e
Diffstat (limited to 'tools/xml2cpp.cpp')
| -rw-r--r-- | tools/xml2cpp.cpp | 742 |
1 files changed, 742 insertions, 0 deletions
diff --git a/tools/xml2cpp.cpp b/tools/xml2cpp.cpp new file mode 100644 index 0000000..36a2838 --- /dev/null +++ b/tools/xml2cpp.cpp @@ -0,0 +1,742 @@ +/* + * + * D-Bus++ - C++ bindings for DBus + * + * Copyright (C) 2005-2006 Paolo Durante <shackan@gmail.com> + * + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + + +#include "xml2cpp.h" + +#include <dbus/dbus.h> + +#include <string> +#include <map> +#include <iostream> +#include <fstream> +#include <sstream> + +using namespace std; +using namespace DBus; + +static const char* tab = " "; + +static const char* header = "\n\ +/* This file was automatically generated by dbusxx-xml2cpp; DO NOT EDIT! */\n\ +\n\ +"; + +static const char* dbus_includes = "\n\ +#include <dbus-c++/dbus-c++.h>\n\ +\n\ +"; + +typedef map<string,string> TypeCache; + +void usage( const char* argv0 ) +{ + cerr << endl << "Usage: " << argv0 << " <xmlfile> [ --client=<outfile.h> ] [ --adaptor=<outfile.h> ]" + << endl << endl; + exit(-1); +} + +void underscorize( std::string& str ) +{ + for(unsigned int i = 0; i < str.length(); ++i) + { + if(!isalpha(str[i])) str[i] = '_'; + } +} + +std::string stub_name( std::string name ) +{ + underscorize(name); + + return "_" + name + "_stub"; +} + +int char_to_atomic_type( char t ) +{ + if(strchr("ybnqiuxtdsgavre", t)) + return t; + + return DBUS_TYPE_INVALID; +} + +const char* atomic_type_to_string( char t ) +{ + static struct { char type; char* name; } atos[] = + { + { 'y', "DBus::Byte" }, + { 'b', "DBus::Bool" }, + { 'n', "DBus::Int16" }, + { 'q', "DBus::UInt16" }, + { 'i', "DBus::Int32" }, + { 'u', "DBus::UInt32" }, + { 'x', "DBus::Int64" }, + { 't', "DBus::UInt64" }, + { 'd', "DBus::Double" }, + { 's', "DBus::String" }, + { 'o', "DBus::Path" }, + { 'g', "DBus::Signature" }, + { 'v', "DBus::Variant" }, + { '\0', "" } + }; + int i; + + for(i = 0; atos[i].type; ++i) + { + if(atos[i].type == t) break; + } + return atos[i].name; +} + +bool is_atomic_type( const std::string& type ) +{ + return type.length() == 1 && char_to_atomic_type(type[0]) != DBUS_TYPE_INVALID; +} + +void _parse_signature( const std::string& signature, std::string& type, size_t& i ) +{ + for(; i < signature.length(); ++i) + { + switch(signature[i]) + { + case 'a': + { + switch(signature[++i]) + { + case '{': + { + type += "DBus::Dict< "; + + const char* atom = atomic_type_to_string(signature[++i]); + if(!atom) + { + cerr << "invalid signature" << endl; + exit(-1); + } + type += atom; + type += ", "; + ++i; + break; + } + default: + { + type += "DBus::Array< "; + break; + } + } + _parse_signature(signature, type, i); + type += " >"; + continue; + } + case '(': + { + type += "DBus::Struct< "; + ++i; + _parse_signature(signature, type, i); + type += " >"; + continue; + } + case ')': + case '}': + { + return; + } + default: + { + const char* atom = atomic_type_to_string(signature[i]); + if(!atom) + { + cerr << "invalid signature" << endl; + exit(-1); + } + type += atom; + + if(signature[i+1] != ')' && signature[i+1] != '}' && i+1 < signature.length()) + { + type += ", "; + } + break; + } + } + } +} + +std::string signature_to_type( const std::string& signature ) +{ + std::string type; + size_t i = 0; + _parse_signature(signature, type, i); + return type; +} + +void generate_client( Xml::Document& doc, const char* filename ) +{ + cerr << "writing " << filename << endl; + + ofstream file(filename); + if(file.bad()) + { + cerr << "unable to write file " << filename << endl; + exit(-1); + } + + file << header; + std::string filestring = filename; + underscorize(filestring); + + std::string cond_comp = "__dbusxx__" + filestring + "__CLIENT_MARSHAL_H"; + + file << "#ifndef " << cond_comp << endl; + file << "#define " << cond_comp << endl; + + file << dbus_includes; +#if 0 + Xml::Node& root = *(doc.root); + Xml::Nodes interfaces = root["interface"]; + + for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i) + { + Xml::Node& iface = **i; + Xml::Nodes methods = iface["method"]; + Xml::Nodes signals = iface["signal"]; + + std::string ifacename = iface.get("name"); + std::string ifaceclass = ifacename; + underscorize(ifaceclass); + + cerr << "generating code for interface " << ifacename << "..." << endl; + + file << "class " << ifaceclass << " : public DBus::InterfaceProxy" << endl + << "{" << endl + << "public:" << endl + << endl + << tab << ifaceclass << "()" << endl + << tab << ": DBus::InterfaceProxy(\"" << ifacename << "\")" << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + + std::string marshname = "_" + signal.get("name") + "_stub"; + + file << tab << tab << "connect_signal(" << ifaceclass << ", " << marshname << ");" << endl; + } + + file << tab << "}" << endl + << endl; + + for(Xml::Nodes::iterator j = methods.begin(); j != methods.end(); ++j) + { + Xml::Node& method = **j; + std::string methodname = method.get("name"); + std::string marshname = "_" + methodname + "_stub"; + + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + file << endl; + + if(args_out.size() == 1) + { + std::string ret_type = args_out.front()->get("type"); + std::string ret_sig; + + if(is_atomic_type(ret_type)) + { + ret_sig = atomic_type_to_string(ret_type[0]); + } + else + { + } + + file << tab << ret_sig << " " << methodname << "( "; + + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai) + { + Xml::Node& a = **ai; + + file << "const "; + + if(is_atomic_type(a.get("type"))) + { + file << atomic_type_to_string(a.get("type")[0]); + } + else + { + } + + file << "& " << a.get("name") << ( ai+1 != args_in.end() ? ", " : " " ); + } + + file << ")" << endl; + } + else + { + file << tab << "void " << methodname << "( args )" << endl; + } + + file << tab << "{" << endl + << tab << tab << "DBus::CallMessage call;" << endl + << tab << tab << "DBus::MessageIter wi = call.w_iter();" << endl + << endl; + + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai) + { + Xml::Node& arg = **ai; + } + + file << tab << tab << "call.member(\"" << methodname << "\");" << endl + << tab << tab << "DBus::Message ret = invoke_method(call);" << endl + << tab << tab << "DBus::MessageIter ri = ret.r_iter();" << endl + << endl; + + file << tab << "}" << endl + << endl; + + } + + file << "};" << endl + << endl; + } +#endif + file << "#endif//" << cond_comp << endl; + + file.close(); +} + +void generate_adaptor( Xml::Document& doc, const char* filename ) +{ + cerr << "writing " << filename << endl; + + ofstream file(filename); + if(file.bad()) + { + cerr << "unable to write file " << filename << endl; + exit(-1); + } + + file << header; + std::string filestring = filename; + underscorize(filestring); + + std::string cond_comp = "__dbusxx__" + filestring + "__ADAPTOR_MARSHAL_H"; + + file << "#ifndef " << cond_comp << endl + << "#define " << cond_comp << endl; + + file << dbus_includes; + + Xml::Node& root = *(doc.root); + Xml::Nodes interfaces = root["interface"]; + + for(Xml::Nodes::iterator i = interfaces.begin(); i != interfaces.end(); ++i) + { + Xml::Node& iface = **i; + Xml::Nodes methods = iface["method"]; + Xml::Nodes signals = iface["signal"]; + Xml::Nodes ms; + ms.insert(ms.end(), methods.begin(), methods.end()); + ms.insert(ms.end(), signals.begin(), signals.end()); + + std::string ifacename = iface.get("name"); + if(ifacename.find("org.freedesktop.DBus") == 0) + { + cerr << "skipping interface " << ifacename << endl; + continue; + } + + std::istringstream ss(ifacename); + string nspace; + size_t nspaces = 0; + + while(ss.str().find('.', ss.tellg()) != string::npos) + { + getline(ss, nspace, '.'); + + file << "namespace " << nspace << " {" << endl; + + ++nspaces; + } + file << endl; + + std::string ifaceclass; + + getline(ss, ifaceclass); + + cerr << "generating code for interface " << ifacename << "..." << endl; + + file << "class " << ifaceclass << " : public DBus::InterfaceAdaptor" << endl + << "{" << endl + << "public:" << endl + << endl + << tab << ifaceclass << "()" << endl + << tab << ": DBus::InterfaceAdaptor(\"" << ifacename << "\")" << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + + file << tab << tab << "register_method(" + << ifaceclass << ", " << method.get("name") << ", "<< stub_name(method.get("name")) + << ");" << endl; + } + + file << tab << "}" << endl + << endl; + + file << tab << "DBus::IntrospectedInterface* const introspect() const " << endl + << tab << "{" << endl; + + for(Xml::Nodes::iterator mi = ms.begin(); mi != ms.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + + file << tab << tab << "static DBus::IntrospectedArgument " << method.get("name") << "_args[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator ai = args.begin(); ai != args.end(); ++ai) + { + Xml::Node& arg = **ai; + + file << tab << tab << tab << "{ "; + + if(arg.get("name").length()) + { + file << "\"" << arg.get("name") << "\", "; + } + else + { + file << "0, "; + } + file << "\"" << arg.get("type") << "\", " + << ( arg.get("direction") == "in" ? "true" : "false" ) + << " }," << endl; + } + file << tab << tab << tab << "{ 0, 0, 0 }" << endl + << tab << tab << "};" << endl; + } + + file << tab << tab << "static DBus::IntrospectedMethod " << ifaceclass << "_methods[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + + file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl; + } + + file << tab << tab << tab << "{ 0, 0 }" << endl + << tab << tab << "};" << endl; + + file << tab << tab << "static DBus::IntrospectedMethod " << ifaceclass << "_signals[] = " << endl + << tab << tab << "{" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& method = **si; + + file << tab << tab << tab << "{ \"" << method.get("name") << "\", " << method.get("name") << "_args }," << endl; + } + + file << tab << tab << tab << "{ 0, 0 }" << endl + << tab << tab << "};" << endl; + + file << tab << tab << "static DBus::IntrospectedInterface " << ifaceclass << "_interface = " << endl + << tab << tab << "{" << endl + << tab << tab << tab << "\"" << ifacename << "\"," << endl + << tab << tab << tab << ifaceclass << "_methods," << endl + << tab << tab << tab << ifaceclass << "_signals," << endl + << tab << tab << "};" << endl + << tab << tab << "return &" << ifaceclass << "_interface;" << endl + << tab << "}" << endl + << endl; + + file << "public:" << endl + << endl + << tab << "/* methods exported by this interface," << endl + << tab << " * you will have to implement them in your ObjectAdaptor" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + file << tab << "virtual "; + + if(args_out.size() == 0 || args_out.size() > 1 ) + { + file << "void "; + } + else if(args_out.size() == 1) + { + file << signature_to_type(args_out.front()->get("type")) << " "; + } + + file << method.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << "const " << signature_to_type(arg.get("type")) << "& "; + + std::string arg_name = arg.get("name"); + if(arg_name.length()) + file << arg_name; + + if((i+1 != args_in.size() || args_out.size() > 1)) + file << ", "; + } + + if(args_out.size() > 1) + { + unsigned int i = 0; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + file << signature_to_type(arg.get("type")) << "&"; + + std::string arg_name = arg.get("name"); + if(arg_name.length()) + file << " " << arg_name; + + if(i+1 != args_out.size()) + file << ", "; + } + } + file << " ) = 0;" << endl; + } + + file << endl + << "protected:" << endl + << endl + << tab << "/* signals emitted by this interface" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator si = signals.begin(); si != signals.end(); ++si) + { + Xml::Node& signal = **si; + Xml::Nodes args = signal["arg"]; + + file << tab << "void " << signal.get("name") << "( "; + + unsigned int i = 0; + for(Xml::Nodes::iterator a = args.begin(); a != args.end(); ++a, ++i) + { + Xml::Node& arg = **a; + + file << "const " << signature_to_type(arg.get("type")) << "& arg" << i+1; + + if(i+1 != args.size()) + file << ", "; + } + + file << " )" << endl + << tab << "{" << endl + << tab << tab << "DBus::SignalMessage sig(\"" << signal.get("name") <<"\");" << endl;; + + + if(args.size() > 0) + { + file << tab << tab << "DBus::MessageIter wi = sig.w_iter();" << endl; + + for(unsigned int i = 0; i < args.size(); ++i) + { + file << tab << tab << "wi << arg" << i+1 << ";" << endl; + } + } + + file << tab << tab << "emit_signal(sig);" << endl + << tab << "}" << endl; + } + + file << endl + << "private:" << endl + << endl + << tab << "/* marshalers (to unpack the DBus message before calling the actual interface method)" << endl + << tab << " */" << endl; + + for(Xml::Nodes::iterator mi = methods.begin(); mi != methods.end(); ++mi) + { + Xml::Node& method = **mi; + Xml::Nodes args = method["arg"]; + Xml::Nodes args_in = args.select("direction","in"); + Xml::Nodes args_out = args.select("direction","out"); + + file << tab << "DBus::Message " << stub_name(method.get("name")) << "( const DBus::CallMessage& call )" << endl + << tab << "{" << endl + << tab << tab << "DBus::MessageIter ri = call.r_iter();" << endl + << endl; + + unsigned int i = 1; + for(Xml::Nodes::iterator ai = args_in.begin(); ai != args_in.end(); ++ai, ++i) + { + Xml::Node& arg = **ai; + file << tab << tab << signature_to_type(arg.get("type")) << " argin" << i << ";" + << " ri >> argin" << i << ";" << endl; + } + + if(args_out.size() == 0) + { + file << tab << tab; + } + else if(args_out.size() == 1) + { + file << tab << tab << signature_to_type(args_out.front()->get("type")) << " argout1 = "; + } + else + { + unsigned int i = 1; + for(Xml::Nodes::iterator ao = args_out.begin(); ao != args_out.end(); ++ao, ++i) + { + Xml::Node& arg = **ao; + file << tab << tab << signature_to_type(arg.get("type")) << " argout" << i << ";" << endl; + } + file << tab << tab; + } + + file << method.get("name") << "("; + + for(unsigned int i = 0; i < args_in.size(); ++i) + { + file << "argin" << i+1; + + if((i+1 != args_in.size() || args_out.size() > 1)) + file << ", "; + } + + if(args_out.size() > 1) + for(unsigned int i = 0; i < args_out.size(); ++i) + { + file << "argout" << i+1; + + if(i+1 != args_out.size()) + file << ", "; + } + + file << ");" << endl; + + file << tab << tab << "DBus::ReturnMessage reply(call);" << endl; + + if(args_out.size() > 0) + { + file << tab << tab << "DBus::MessageIter wi = reply.w_iter();" << endl; + + for(unsigned int i = 0; i < args_out.size(); ++i) + { + file << tab << tab << "wi << argout" << i+1 << ";" << endl; + } + } + + file << tab << tab << "return reply;" << endl; + + file << tab << "}" << endl; + } + + file << "};" << endl + << endl; + + for(size_t i = 0; i < nspaces; ++i) + { + file << "} "; + } + file << endl; + } + + file << "#endif//" << cond_comp << endl; + + file.close(); +} + +int main( int argc, char** argv ) +{ + if(argc < 2) + { + usage(argv[0]); + } + + bool client_mode, adaptor_mode; + char *client, *adaptor; + + client_mode = false; + client = 0; + + adaptor_mode = false; + adaptor = 0; + + for(int a = 1; a < argc; ++a) + { + if(!strncmp(argv[a], "--client=", 9)) + { + client_mode = true; + client = argv[a] +9; + } + else + if(!strncmp(argv[a], "--adaptor=", 10)) + { + adaptor_mode = true; + adaptor = argv[a] +10; + } + } + + if(!client_mode && !adaptor_mode) usage(argv[0]); + + ifstream xmlfile(argv[1]); + + if(xmlfile.bad()) + { + cerr << "unable to open file " << argv[1] << endl; + return -1; + } + + Xml::Document doc; + + try + { + xmlfile >> doc; + //cout << doc.to_xml(); + } + catch(Xml::Error& e) + { + cerr << "error parsing " << argv[1] << ": " << e.what() << endl; + return -1; + } + + if(!doc.root) + { + cerr << "empty document" << endl; + return -1; + } + + if(client_mode) generate_client(doc, client); + if(adaptor_mode) generate_adaptor(doc, adaptor); + + return 0; +} |
