sbus_codegen revision b07852825eeb63a78e1b3863e42b3f328430da18
0N/A#!/usr/bin/env python
4597N/A
1008N/A#
1008N/A# Authors:
1008N/A# Stef Walter <stefw@redhat.com>
1008N/A#
2362N/A# Copyright (C) 2014 Red Hat
1008N/A#
2362N/A# This program is free software; you can redistribute it and/or modify
1008N/A# it under the terms of the GNU General Public License as published by
1008N/A# the Free Software Foundation; either version 3 of the License, or
1008N/A# (at your option) any later version.
1008N/A#
1008N/A# This program is distributed in the hope that it will be useful,
1008N/A# but WITHOUT ANY WARRANTY; without even the implied warranty of
1008N/A# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1008N/A# GNU General Public License for more details.
1008N/A#
1008N/A# You should have received a copy of the GNU General Public License
1008N/A# along with this program. If not, see <http://www.gnu.org/licenses/>.
2362N/A#
2362N/A
2362N/A#
1008N/A# Some parser code from GLib
1008N/A#
1008N/A# Copyright (C) 2008-2011 Red Hat, Inc.
1008N/A#
0N/A# This library is free software; you can redistribute it and/or
0N/A# modify it under the terms of the GNU Lesser General Public
1821N/A# License as published by the Free Software Foundation; either
1821N/A# version 2 of the License, or (at your option) any later version.
1821N/A#
1821N/A# This library is distributed in the hope that it will be useful,
1821N/A# but WITHOUT ANY WARRANTY; without even the implied warranty of
1821N/A# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1821N/A# Lesser General Public License for more details.
1821N/A#
1821N/A# You should have received a copy of the GNU Lesser General
1821N/A# Public License along with this library; if not, write to the
2391N/A# Free Software Foundation, Inc., 59 Temple Place, Suite 330,
1821N/A# Boston, MA 02111-1307, USA.
1821N/A#
2391N/A# Portions by: David Zeuthen <davidz@redhat.com>
1821N/A#
1821N/A
1821N/A#
2391N/A# DBus interfaces are defined here:
1821N/A#
1821N/A# http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
1821N/A#
1821N/A# The introspection data format has become the standard way to represent a
1821N/A# DBus interface. For many examples see /usr/share/dbus-1/interfaces/ on a
1821N/A# typical linux machine.
1821N/A#
1821N/A# A word about annotations. These are extra flags or values that can be
1821N/A# assigned to anything. So far, the codegen supports this annotation:
1821N/A#
1821N/A# org.freedesktop.DBus.GLib.CSymbol
1821N/A# - An annotation specified in the specification that tells us what C symbol
1008N/A# to generate for a given interface or method. By default the codegen will
1008N/A# build up a symbol name from the DBus name.
1821N/A#
1008N/Afrom __future__ import print_function
1008N/A
1008N/Aimport optparse
1008N/Aimport os
1008N/Aimport re
1821N/Aimport sys
1821N/Aimport xml.parsers.expat
1821N/A
1821N/Aif sys.version_info[0] > 2:
1821N/A import io as StringIO
1821N/Aelse:
1821N/A import StringIO
1821N/A
2228N/A# -----------------------------------------------------------------------------
2228N/A# Objects
2228N/A
2228N/Aclass DBusXmlException(Exception):
1821N/A line = 0
0N/A file = None
2402N/A
2402N/A # Lets us print problems like a compiler would
2402N/A def __str__(self):
2402N/A message = Exception.__str__(self)
2402N/A if self.file and self.line:
2402N/A return "%s:%d: %s" % (self.file, self.line, message)
2402N/A elif self.file:
2402N/A return "%s: %s" % (self.file, message)
2402N/A else:
2402N/A return message
2402N/A
2402N/Aclass Base(object):
2402N/A def __init__(self, name):
2402N/A if not name:
2402N/A raise DBusXmlException('No name on element')
2402N/A self.name = name
2402N/A self.annotations = { }
2402N/A def validate(self):
2402N/A pass
0N/A def c_name(self):
0N/A return self.annotations.get("org.freedesktop.DBus.GLib.CSymbol", self.name)
1008N/A
1821N/A# The basic types that we support marshalling right now. These
1821N/A# are the ones we can pass as basic arguments to libdbus directly.
1821N/A# If the dbus and sssd types are identical we pass things directly.
2228N/A# otherwise some copying is necessary.
2228N/ABASIC_TYPES = {
2228N/A 'y': ( "DBUS_TYPE_BYTE", "uint8_t", "uint8_t" ),
2228N/A 'b': ( "DBUS_TYPE_BOOLEAN", "dbus_bool_t", "bool" ),
2228N/A 'n': ( "DBUS_TYPE_INT16", "int16_t", "int16_t" ),
2228N/A 'q': ( "DBUS_TYPE_UINT16", "uint16_t", "uint16_t" ),
2228N/A 'i': ( "DBUS_TYPE_INT32", "int32_t", "int32_t" ),
2228N/A 'u': ( "DBUS_TYPE_UINT32", "uint32_t", "uint32_t" ),
2228N/A 'x': ( "DBUS_TYPE_INT64", "int64_t", "int64_t" ),
2228N/A 't': ( "DBUS_TYPE_UINT64", "uint64_t", "uint64_t" ),
2402N/A 'd': ( "DBUS_TYPE_DOUBLE", "double", "double" ),
2402N/A 's': ( "DBUS_TYPE_STRING", "const char *", "const char *" ),
2402N/A 'o': ( "DBUS_TYPE_OBJECT_PATH", "const char *", "const char *" ),
2402N/A}
2402N/A
2402N/Aclass Typed(Base):
2402N/A def __init__(self, name, type):
2402N/A Base.__init__(self, name)
2402N/A self.type = type
2402N/A self.is_basic = False
2402N/A self.is_array = False
2402N/A self.is_dictionary = False
2402N/A self.dbus_constant = None
2402N/A self.dbus_type = None
2402N/A self.sssd_type = None
2402N/A if type[0] == 'a':
2402N/A type = type[1:]
2402N/A self.is_array = True
2402N/A if "{" in type:
2402N/A self.is_dictionary = True
2402N/A if type in BASIC_TYPES:
1821N/A (self.dbus_constant, self.dbus_type, self.sssd_type) = BASIC_TYPES[type]
2228N/A # If types are not identical, we can't do array (yet)
2228N/A if self.is_array:
2228N/A self.is_basic = (self.dbus_type == self.sssd_type)
2228N/A else:
2228N/A self.is_basic = True
2228N/A
2228N/Aclass Arg(Typed):
2228N/A def __init__(self, method, name, type):
2228N/A Typed.__init__(self, name, type)
2228N/A self.method = method
2228N/A
1821N/Aclass Method(Base):
1821N/A def __init__(self, iface, name):
1821N/A Base.__init__(self, name)
2228N/A self.iface = iface
2228N/A self.in_args = []
2228N/A self.out_args = []
2228N/A def validate(self):
2228N/A if not self.only_basic_args() and not self.use_raw_handler():
1821N/A raise DBusXmlException("Method has complex arguments and requires " +
2228N/A "the 'org.freedesktop.sssd.RawHandler' annotation")
1821N/A def fq_c_name(self):
2228N/A return "%s_%s" % (self.iface.c_name(), self.c_name())
2228N/A def use_raw_handler(self):
1821N/A anno = 'org.freedesktop.sssd.RawHandler'
2228N/A return self.annotations.get(anno, self.iface.annotations.get(anno)) == 'true'
1821N/A def in_signature(self):
1821N/A return "".join([arg.type for arg in self.in_args])
1821N/A def only_basic_args(self):
1821N/A for arg in self.in_args + self.out_args:
1821N/A if not arg.is_basic:
1821N/A return False
1821N/A return True
1821N/A
1821N/Aclass Signal(Base):
1821N/A def __init__(self, iface, name):
2228N/A Base.__init__(self, name)
1821N/A self.iface = iface
1821N/A self.args = []
1821N/A def fq_c_name(self):
1821N/A return "%s_%s" % (self.iface.c_name(), self.c_name())
1821N/A
1821N/Aclass Property(Typed):
1821N/A def __init__(self, iface, name, type, access):
1821N/A Typed.__init__(self, name, type)
0N/A self.iface = iface
1821N/A self.readable = False
1008N/A self.writable = False
0N/A if access == 'readwrite':
0N/A self.readable = True
2228N/A self.writable = True
2228N/A elif access == 'read':
2228N/A self.readable = True
2228N/A elif access == 'write':
2228N/A self.writable = True
2228N/A else:
0N/A raise DBusXmlException('Invalid access type %s'%self.access)
1821N/A def fq_c_name(self):
0N/A return "%s_%s" % (self.iface.c_name(), self.c_name())
1008N/A def get_invoker_name(self):
1008N/A type = self.type
1008N/A type = type.replace("{", "DO")
1008N/A type = type.replace("}", "DE")
2228N/A return type
1008N/A def get_invoker_signature(self, name):
2228N/A sig = "void (*%s)(struct sbus_request *, void *data, " % (name)
2228N/A if self.is_dictionary:
0N/A sig += "hash_table_t **"
1008N/A elif self.is_array:
1008N/A sig += "%s**, int *" % (self.sssd_type)
1008N/A else:
2228N/A sig += "%s*" % (self.sssd_type)
2228N/A sig += ")"
2228N/A return sig
2228N/A
2228N/A
2228N/A def getter_name(self):
2228N/A return "get_%s" % self.c_name()
1008N/A def getter_invoker_name(self):
1008N/A return "sbus_invoke_get_%s" % self.get_invoker_name()
1008N/A def getter_signature(self):
1008N/A return self.get_invoker_signature(self.getter_name())
1008N/A
1008N/Aclass Interface(Base):
1821N/A def __init__(self, name):
1008N/A Base.__init__(self, name)
1008N/A self.methods = []
0N/A self.signals = []
0N/A self.properties = []
1008N/A def c_name(self):
1008N/A return self.annotations.get("org.freedesktop.DBus.GLib.CSymbol",
1008N/A self.name.replace(".", "_"))
1008N/A
1008N/A# -----------------------------------------------------------------------------
0N/A# Code Generation
1821N/A
1821N/Adef out(format, *args, **kwargs):
1821N/A str = format % args
1821N/A sys.stdout.write(str)
1821N/A # NOTE: Would like to use the following syntax for this function
1821N/A # but need to wait until python3 until it is supported:
1821N/A # def out(format, *args, new_line=True)
1821N/A if kwargs.pop("new_line", True):
1821N/A sys.stdout.write("\n")
1821N/A assert not kwargs, "unknown keyword argument(s): %s" % str(kwargs)
1821N/A
1821N/Adef method_arg_types(args, with_names=False):
1821N/A str = ""
1821N/A for arg in args:
1821N/A str += ", "
2402N/A str += arg.sssd_type
2402N/A if with_names:
2402N/A if str[-1] != '*':
2391N/A str += " "
2391N/A str += "arg_"
1008N/A str += arg.c_name()
1008N/A if arg.is_array:
1008N/A str += "[], int"
1008N/A if with_names:
1008N/A str += " len_"
0N/A str += arg.c_name()
1008N/A return str
1008N/A
2391N/Adef method_function_pointer(meth, name, with_names=False):
1008N/A if meth.use_raw_handler():
3866N/A return "sbus_msg_handler_fn " + name
1008N/A else:
1821N/A return "int (*%s)(struct sbus_request *%s, void *%s%s)" % \
1821N/A (name, with_names and "req" or "",
1821N/A with_names and "data" or "",
1821N/A method_arg_types(meth.in_args, with_names))
1821N/A
1821N/Adef property_handlers(prop):
1947N/A return prop.getter_signature()
1947N/A
1947N/Adef forward_method_invoker(signature, args):
1947N/A out("")
1947N/A out("/* invokes a handler with a '%s' DBus signature */", signature)
1947N/A out("static int invoke_%s_method(struct sbus_request *dbus_req, void *function_ptr);", signature)
1947N/A
1947N/Adef source_method_invoker(signature, args):
1947N/A out("")
2017N/A out("/* invokes a handler with a '%s' DBus signature */", signature)
1947N/A out("static int invoke_%s_method(struct sbus_request *dbus_req, void *function_ptr)", signature)
1821N/A out("{")
1821N/A for i in range(0, len(args)):
1947N/A arg = args[i]
1821N/A if arg.is_array:
1947N/A out(" %s *arg_%d;", arg.dbus_type, i)
1947N/A out(" int len_%d;", i)
1821N/A else:
2017N/A out(" %s arg_%d;", arg.dbus_type, i)
1821N/A out(" int (*handler)(struct sbus_request *, void *%s) = function_ptr;", method_arg_types(args))
1821N/A out("")
1821N/A out(" if (!sbus_request_parse_or_finish(dbus_req,")
1821N/A for i in range(0, len(args)):
1821N/A arg = args[i]
1821N/A if arg.is_array:
1821N/A out(" DBUS_TYPE_ARRAY, %s, &arg_%d, &len_%d,",
1821N/A arg.dbus_constant, i, i)
1947N/A else:
1821N/A out(" %s, &arg_%d,", arg.dbus_constant, i)
1821N/A out(" DBUS_TYPE_INVALID)) {")
1821N/A out(" return EOK; /* request handled */")
1947N/A out(" }")
1947N/A out("")
1947N/A
1821N/A out(" return (handler)(dbus_req, dbus_req->intf->handler_data", new_line=False)
1821N/A for i in range(0, len(args)):
1821N/A arg = args[i]
1821N/A out(",\n arg_%d", i, new_line=False)
1821N/A if arg.is_array:
2500N/A out(",\n len_%d", i, new_line=False)
1821N/A out(");")
1821N/A out("}")
1821N/A
1821N/Adef source_prop_types(prop, type_prefix=False):
3866N/A prefix = "%s_" % prop.type if type_prefix else ""
3866N/A if prop.is_array:
3866N/A out(" %s *%sprop_val;", prop.sssd_type, prefix)
2203N/A out(" int %sprop_len;", prefix)
1947N/A out(" %s *%sout_val;", prop.dbus_type, prefix)
1821N/A else:
1008N/A out(" %s %sprop_val;", prop.sssd_type, prefix)
1008N/A out(" %s %sout_val;", prop.dbus_type, prefix)
0N/A
1008N/Adef source_prop_handler(prop, type_prefix=False):
1008N/A prefix = "%s_" % prop.type if type_prefix else ""
1008N/A out(" %s", prop.getter_signature("%shandler" % prefix), new_line=False)
0N/A out(";")
1008N/A
1008N/Adef forward_method_invokers(ifaces):
1008N/A invokers = { }
2500N/A for iface in ifaces:
0N/A for meth in iface.methods:
0N/A if meth.use_raw_handler() or not meth.in_args:
0N/A continue
1008N/A signature = meth.in_signature()
1008N/A if signature in invokers:
1008N/A continue
1008N/A forward_method_invoker(signature, meth.in_args)
1008N/A invokers[signature] = meth
1008N/A return invokers
1008N/A
1008N/Adef source_method_invokers(invokers):
1934N/A for (signature, meth) in invokers.items():
1934N/A source_method_invoker(signature, meth.in_args)
1934N/A
1934N/Adef source_finisher(meth):
1934N/A out("")
1008N/A out("int %s_finish(struct sbus_request *req%s)",
1008N/A meth.fq_c_name(), method_arg_types(meth.out_args, with_names=True))
1008N/A out("{")
1008N/A
1821N/A for arg in meth.out_args:
1821N/A if arg.dbus_type != arg.sssd_type:
1821N/A out(" %s cast_%s = arg_%s;", arg.dbus_type, arg.c_name(), arg.c_name())
1821N/A
1821N/A out(" return sbus_request_return_and_finish(req,")
1821N/A for arg in meth.out_args:
1821N/A out(" ", new_line=False)
1821N/A if arg.is_array:
1821N/A out("DBUS_TYPE_ARRAY, %s, &arg_%s, len_%s,",
2020N/A arg.dbus_constant, arg.c_name(), arg.c_name())
2020N/A elif arg.dbus_type != arg.sssd_type:
1821N/A out("%s, &cast_%s,", arg.dbus_constant, arg.c_name())
1821N/A else:
1821N/A out("%s, &arg_%s,", arg.dbus_constant, arg.c_name())
1821N/A out(" DBUS_TYPE_INVALID);")
1821N/A out("}")
1821N/A
1821N/Adef header_reply(meth):
1934N/A for arg in meth.out_args:
1821N/A if arg.is_array:
1821N/A out(" %s *%s", arg.dbus_type, arg.c_name())
1821N/A out(" int %s__len", arg.c_name())
1821N/A else:
3866N/A out(" %s %s;", arg.dbus_type, arg.c_name())
1821N/A types = [arg.sssd_type for arg in meth.in_args]
1821N/A
3866N/Adef source_args(parent, args, suffix):
1821N/A out("")
1934N/A out("/* arguments for %s.%s */", parent.iface.name, parent.name)
2500N/A out("const struct sbus_arg_meta %s%s[] = {", parent.fq_c_name(), suffix)
2228N/A for arg in args:
1934N/A out(" { \"%s\", \"%s\" },", arg.name, arg.type)
1934N/A out(" { NULL, }")
2228N/A out("};")
1934N/A
1934N/Adef source_methods(iface, methods):
1821N/A for meth in methods:
1821N/A if meth.in_args:
3866N/A source_args(meth, meth.in_args, "__in")
1821N/A if meth.out_args:
1821N/A source_args(meth, meth.out_args, "__out")
1821N/A
1821N/A if not meth.use_raw_handler():
1821N/A source_finisher(meth)
1008N/A
1008N/A out("")
1934N/A out("/* methods for %s */", iface.name)
1934N/A out("const struct sbus_method_meta %s__methods[] = {", iface.c_name())
1934N/A for meth in methods:
1934N/A out(" {")
1821N/A out(" \"%s\", /* name */", meth.name)
1821N/A if meth.in_args:
3740N/A out(" %s__in,", meth.fq_c_name())
3866N/A else:
1821N/A out(" NULL, /* no in_args */")
1821N/A if meth.out_args:
3740N/A out(" %s__out,", meth.fq_c_name())
3866N/A else:
1821N/A out(" NULL, /* no out_args */")
1821N/A out(" offsetof(struct %s, %s),", iface.c_name(), meth.c_name())
2017N/A if meth.use_raw_handler() or not meth.in_args:
1821N/A out(" NULL, /* no invoker */")
2017N/A else:
1821N/A out(" invoke_%s_method,", meth.in_signature())
1821N/A out(" },")
1821N/A out(" { NULL, }")
1821N/A out("};")
1821N/A
1821N/Adef source_signals(iface, signals):
1821N/A for sig in iface.signals:
1821N/A if sig.args:
1821N/A source_args(sig, sig.args, "__args")
1821N/A
3740N/A out("")
1821N/A out("/* signals for %s */", iface.name)
1821N/A out("const struct sbus_signal_meta %s__signals[] = {", iface.c_name())
1821N/A for sig in signals:
1821N/A out(" {")
3740N/A out(" \"%s\", /* name */", sig.name)
3740N/A if sig.args:
1821N/A out(" %s__args", sig.fq_c_name())
3740N/A else:
1821N/A out(" NULL, /* no args */")
1821N/A out(" },")
1821N/A out(" { NULL, }")
1821N/A out("};")
1821N/A
3740N/Adef source_properties(iface, properties):
3740N/A out("")
3740N/A out("/* property info for %s */", iface.name)
1821N/A
2017N/A out("const struct sbus_property_meta %s__properties[] = {", iface.c_name())
2017N/A for prop in properties:
2017N/A out(" {")
1821N/A out(" \"%s\", /* name */", prop.name)
3740N/A out(" \"%s\", /* type */", prop.type)
1821N/A if prop.readable and prop.writable:
1821N/A out(" SBUS_PROPERTY_READABLE | SBUS_PROPERTY_WRITABLE,")
2017N/A elif prop.readable:
1934N/A out(" SBUS_PROPERTY_READABLE,")
1934N/A elif prop.writable:
1934N/A out(" SBUS_PROPERTY_WRITABLE,")
1821N/A else:
1821N/A assert False, "should not be reached"
3740N/A if prop.readable:
1821N/A out(" offsetof(struct %s, %s),", iface.c_name(), prop.getter_name())
1821N/A out(" %s,", prop.getter_invoker_name())
1821N/A else:
1821N/A out(" 0, /* not readable */")
3740N/A out(" NULL, /* no invoker */")
1821N/A out(" 0, /* not writable */")
1821N/A out(" NULL, /* no invoker */")
1821N/A out(" },")
1821N/A out(" { NULL, }")
1821N/A out("};")
3740N/A
1821N/Adef header_interface(iface):
1821N/A out("")
1821N/A out("/* interface info for %s */", iface.name)
1821N/A out("extern const struct sbus_interface_meta %s_meta;", iface.c_name())
1821N/A
3740N/Adef source_interface(iface):
1821N/A out("")
1821N/A out("/* interface info for %s */", iface.name)
2017N/A out("const struct sbus_interface_meta %s_meta = {", iface.c_name())
1934N/A out(" \"%s\", /* name */", iface.name)
1934N/A if iface.methods:
1934N/A out(" %s__methods,", iface.c_name())
1821N/A else:
1821N/A out(" NULL, /* no methods */")
3740N/A if iface.signals:
1821N/A out(" %s__signals,", iface.c_name())
1821N/A else:
1821N/A out(" NULL, /* no signals */")
1821N/A if iface.properties:
3740N/A out(" %s__properties,", iface.c_name())
3740N/A else:
1821N/A out(" NULL, /* no properties */")
3740N/A out(" sbus_invoke_get_all, /* GetAll invoker */")
1821N/A out("};")
1821N/A
1821N/Adef generate_source(ifaces, filename, include_header=None):
1821N/A basename = os.path.basename(filename)
3740N/A
1821N/A out("/* The following definitions are auto-generated from %s */", basename)
1821N/A out("")
1821N/A
1821N/A out("#include <stddef.h>")
3740N/A out("")
1821N/A out("#include \"dbus/dbus-protocol.h\"")
1821N/A out("#include \"util/util_errors.h\"")
2546N/A out("#include \"sbus/sssd_dbus.h\"")
1821N/A out("#include \"sbus/sssd_dbus_meta.h\"")
3740N/A out("#include \"sbus/sssd_dbus_invokers.h\"")
3887N/A if include_header:
2402N/A out("#include \"%s\"", os.path.basename(include_header))
2546N/A
2017N/A meth_invokers = forward_method_invokers(ifaces)
2546N/A
1821N/A for iface in ifaces:
4499N/A
2546N/A # The methods
1821N/A if iface.methods:
2017N/A source_methods(iface, iface.methods)
1934N/A
1934N/A # The signals array
1934N/A if iface.signals:
4499N/A source_signals(iface, iface.signals)
4499N/A
4499N/A # The properties array
4499N/A if iface.properties:
1821N/A source_properties(iface, iface.properties)
1821N/A
1821N/A # The sbus_interface structure
3740N/A source_interface(iface)
1821N/A
1821N/A source_method_invokers(meth_invokers)
1821N/A
1821N/Adef header_finisher(iface, meth):
3740N/A if meth.use_raw_handler():
1821N/A return
1821N/A out("")
1821N/A out("/* finish function for %s */", meth.name)
1821N/A out("int %s_finish(struct sbus_request *req%s);",
1821N/A meth.fq_c_name(), method_arg_types(meth.out_args, with_names=True))
3740N/A
1821N/Adef header_vtable(iface, methods):
2017N/A out("")
2017N/A out("/* vtable for %s */", iface.name)
2017N/A out("struct %s {", iface.c_name())
1821N/A out(" struct sbus_vtable vtable; /* derive from sbus_vtable */")
3740N/A
4597N/A # All methods
4597N/A for meth in iface.methods:
2402N/A out(" %s;", method_function_pointer(meth, meth.c_name(), with_names=True))
1821N/A for prop in iface.properties:
1821N/A out(" %s;", property_handlers(prop))
2017N/A
1934N/A out("};")
1934N/A
1934N/Adef header_constants(iface):
1821N/A out("")
1821N/A out("/* constants for %s */", iface.name)
1821N/A out("#define %s \"%s\"", iface.c_name().upper(), iface.name)
3740N/A for meth in iface.methods:
1821N/A out("#define %s \"%s\"", meth.fq_c_name().upper(), meth.name)
1821N/A for sig in iface.signals:
1821N/A out("#define %s \"%s\"", sig.fq_c_name().upper(), sig.name)
1821N/A for prop in iface.properties:
3740N/A out("#define %s \"%s\"", prop.fq_c_name().upper(), prop.name)
1821N/A
1821N/Adef generate_header(ifaces, filename):
2017N/A basename = os.path.basename(filename)
1821N/A guard = "__%s__" % re.sub(r'([^_A-Z0-9])', "_", basename.upper())
3740N/A
1940N/A out("/* The following declarations are auto-generated from %s */", basename)
2017N/A out("")
2017N/A out("#ifndef %s", guard)
2017N/A out("#define %s", guard)
1821N/A out("")
3740N/A out("#include \"sbus/sssd_dbus.h\"")
3740N/A out("#include \"sbus/sssd_dbus_meta.h\"")
3740N/A
2402N/A out("")
2500N/A out("/* ------------------------------------------------------------------------")
1821N/A out(" * DBus Constants")
2017N/A out(" *")
1934N/A out(" * Various constants of interface and method names mostly for use by clients")
1934N/A out(" */")
1934N/A
1821N/A for iface in ifaces:
1821N/A header_constants(iface)
3740N/A
1821N/A out("")
1821N/A out("/* ------------------------------------------------------------------------")
1821N/A out(" * DBus handlers")
1821N/A out(" *")
1821N/A out(" * These structures are filled in by implementors of the different")
2017N/A out(" * dbus interfaces to handle method calls.")
2017N/A out(" *")
2017N/A out(" * Handler functions of type sbus_msg_handler_fn accept raw messages,")
1821N/A out(" * other handlers are typed appropriately. If a handler that is")
1821N/A out(" * set to NULL is invoked it will result in a")
1821N/A out(" * org.freedesktop.DBus.Error.NotSupported error for the caller.")
1821N/A out(" *")
1821N/A out(" * Handlers have a matching xxx_finish() function (unless the method has")
1821N/A out(" * accepts raw messages). These finish functions the")
1821N/A out(" * sbus_request_return_and_finish() with the appropriate arguments to")
1008N/A out(" * construct a valid reply. Once a finish function has been called, the")
1008N/A out(" * @dbus_req it was called with is freed and no longer valid.")
1821N/A out(" */")
1821N/A
1821N/A for iface in ifaces:
1821N/A if iface.methods or iface.properties:
2020N/A header_vtable(iface, iface.methods)
2020N/A for meth in iface.methods:
2020N/A header_finisher(iface, meth)
1821N/A
1821N/A out("")
1821N/A out("/* ------------------------------------------------------------------------")
1821N/A out(" * DBus Interface Metadata")
1821N/A out(" *")
2020N/A out(" * These structure definitions are filled in with the information about")
2020N/A out(" * the interfaces, methods, properties and so on.")
2017N/A out(" *")
2020N/A out(" * The actual definitions are found in the accompanying C file next")
2020N/A out(" * to this header.")
1821N/A out(" */")
2020N/A
2020N/A for iface in ifaces:
1008N/A header_interface(iface)
1821N/A
1821N/A out("")
1821N/A out("#endif /* %s */", guard)
1821N/A
1821N/A# -----------------------------------------------------------------------------
1821N/A# XML Interface Parsing
1821N/A
1821N/ASTATE_TOP = 'top'
1821N/ASTATE_NODE = 'node'
1821N/ASTATE_INTERFACE = 'interface'
1821N/ASTATE_METHOD = 'method'
1821N/ASTATE_SIGNAL = 'signal'
1821N/ASTATE_PROPERTY = 'property'
1821N/ASTATE_ARG = 'arg'
1821N/ASTATE_ANNOTATION = 'annotation'
1821N/ASTATE_IGNORED = 'ignored'
1821N/A
1821N/Adef expect_attr(attrs, name):
1821N/A if name not in attrs:
1821N/A raise DBusXmlException("Missing attribute '%s'" % name)
1947N/A if attrs[name] == "":
1008N/A raise DBusXmlException("Empty attribute '%s'" % name)
2402N/A return attrs[name]
2402N/A
2402N/Aclass DBusXMLParser(object):
2402N/A def __init__(self, filename):
2402N/A parser = xml.parsers.expat.ParserCreate()
2402N/A parser.CommentHandler = self.handle_comment
2402N/A parser.CharacterDataHandler = self.handle_char_data
2402N/A parser.StartElementHandler = self.handle_start_element
2402N/A parser.EndElementHandler = self.handle_end_element
2402N/A
2402N/A self.parsed_interfaces = []
2402N/A self.cur_object = None
2402N/A
2402N/A self.state = STATE_TOP
2402N/A self.state_stack = []
2402N/A self.cur_object = None
2402N/A self.cur_object_stack = []
2402N/A self.arg_count = 0
2402N/A
2402N/A try:
1008N/A with open(filename, "rb") as f:
1008N/A parser.ParseFile(f)
1008N/A except DBusXmlException as ex:
1008N/A ex.line = parser.CurrentLineNumber
1008N/A ex.file = filename
1008N/A raise
1008N/A except xml.parsers.expat.ExpatError as ex:
1008N/A exc = DBusXmlException(str(ex))
1008N/A exc.line = ex.lineno
1008N/A exc.file = filename
1008N/A raise exc
1008N/A
1008N/A def handle_comment(self, data):
1008N/A pass
1008N/A
1008N/A def handle_char_data(self, data):
1008N/A pass
1008N/A
1008N/A def handle_start_element(self, name, attrs):
1008N/A old_state = self.state
1008N/A old_cur_object = self.cur_object
1008N/A if self.state == STATE_IGNORED:
1008N/A self.state = STATE_IGNORED
1008N/A elif self.cur_object and name == STATE_ANNOTATION:
1008N/A val = attrs.get('value', '')
1008N/A self.cur_object.annotations[expect_attr(attrs, 'name')] = val
1008N/A self.state = STATE_IGNORED
1008N/A elif self.state == STATE_TOP:
1008N/A if name == STATE_NODE:
3887N/A self.state = STATE_NODE
1254N/A else:
1254N/A self.state = STATE_IGNORED
2402N/A elif self.state == STATE_NODE:
1254N/A if name == STATE_INTERFACE:
1254N/A self.state = STATE_INTERFACE
1254N/A iface = Interface(expect_attr(attrs, 'name'))
1254N/A self.cur_object = iface
1254N/A self.parsed_interfaces.append(iface)
1254N/A else:
1254N/A self.state = STATE_IGNORED
1254N/A
1254N/A elif self.state == STATE_INTERFACE:
1254N/A if name == STATE_METHOD:
1254N/A self.state = STATE_METHOD
1254N/A method = Method(self.cur_object, expect_attr(attrs, 'name'))
1254N/A self.cur_object.methods.append(method)
1254N/A self.cur_object = method
1254N/A self.arg_count = 0
1008N/A elif name == STATE_SIGNAL:
1008N/A self.state = STATE_SIGNAL
1008N/A signal = Signal(self.cur_object, expect_attr(attrs, 'name'))
3866N/A self.cur_object.signals.append(signal)
1008N/A self.cur_object = signal
1008N/A self.arg_count = 0
1008N/A elif name == STATE_PROPERTY:
1008N/A self.state = STATE_PROPERTY
1008N/A prop = Property(self.cur_object,
1008N/A expect_attr(attrs, 'name'),
1008N/A expect_attr(attrs, 'type'),
1008N/A expect_attr(attrs, 'access'))
1008N/A self.cur_object.properties.append(prop)
1008N/A self.cur_object = prop
1008N/A else:
3866N/A self.state = STATE_IGNORED
1008N/A
1008N/A elif self.state == STATE_METHOD:
1008N/A if name == STATE_ARG:
1008N/A self.state = STATE_ARG
1008N/A arg = Arg(self.cur_object,
1008N/A expect_attr(attrs, 'name'),
1008N/A expect_attr(attrs, 'type'))
1008N/A direction = attrs.get('direction', 'in')
1008N/A if direction == 'in':
1008N/A self.cur_object.in_args.append(arg)
1008N/A elif direction == 'out':
1008N/A self.cur_object.out_args.append(arg)
1008N/A else:
1008N/A raise DBusXmlException('Invalid direction "%s"' % direction)
1008N/A self.cur_object = arg
1008N/A else:
1008N/A self.state = STATE_IGNORED
1008N/A
1008N/A elif self.state == STATE_SIGNAL:
1008N/A if name == STATE_ARG:
1008N/A self.state = STATE_ARG
1008N/A arg = Arg(self.cur_object,
1008N/A expect_attr(attrs, 'name'),
1008N/A expect_attr(attrs, 'type'))
1008N/A self.cur_object.args.append(arg)
1008N/A self.cur_object = arg
1008N/A else:
1008N/A self.state = STATE_IGNORED
1008N/A
1008N/A elif self.state == STATE_PROPERTY:
1008N/A self.state = STATE_IGNORED
1008N/A
1008N/A elif self.state == STATE_ARG:
1008N/A self.state = STATE_IGNORED
1008N/A
1008N/A else:
1008N/A assert False, 'Unhandled state "%s" while entering element with name "%s"' % (self.state, name)
1008N/A
1008N/A self.state_stack.append(old_state)
1008N/A self.cur_object_stack.append(old_cur_object)
1008N/A
1008N/A def handle_end_element(self, name):
1008N/A if self.cur_object:
1008N/A self.cur_object.validate()
1008N/A self.state = self.state_stack.pop()
1008N/A self.cur_object = self.cur_object_stack.pop()
1008N/A
1008N/Adef parse_options():
1008N/A parser = optparse.OptionParser("usage: %prog [options] introspect.xml ...")
1008N/A parser.set_description("sbus_codegen generates sbus interface structures \
1008N/A from standard XML Introspect data.")
0N/A parser.add_option("--mode",
3866N/A dest="mode", default="header",
3866N/A help="'header' or 'source' (default: header)",
1008N/A metavar="MODE")
1008N/A parser.add_option("--output",
3866N/A dest="output", default=None,
1008N/A help="Set output file name (default: stdout)",
3866N/A metavar="FILE")
1008N/A parser.add_option("--include",
1008N/A dest="include", default=None,
1008N/A help="name of a header to #include",
3866N/A metavar="HEADER")
1008N/A (options, args) = parser.parse_args()
3866N/A
1008N/A if not args:
1008N/A print("sbus_codegen: no input file specified", file=sys.stderr)
1008N/A sys.exit(2)
3866N/A
1008N/A if options.mode not in ["header", "source"]:
3866N/A print("sbus_codegen: specify --mode=header or --mode=source", file=sys.stderr)
3866N/A
3866N/A return options, args
3866N/A
3866N/Adef main():
3866N/A options, args = parse_options()
3866N/A
3866N/A if options.output:
3866N/A sys.stdout = buf = StringIO.StringIO()
3866N/A
3866N/A for filename in args:
3866N/A parser = DBusXMLParser(filename)
3866N/A
3866N/A if options.mode == "header":
3866N/A generate_header(parser.parsed_interfaces, filename)
3866N/A elif options.mode == "source":
3866N/A generate_source(parser.parsed_interfaces, filename, options.include)
1008N/A else:
1008N/A assert False, "should not be reached"
3866N/A
3866N/A # Write output at end to be nice to 'make'
3866N/A if options.output:
3866N/A output = open(options.output, "w")
3866N/A output.write(buf.getvalue())
3866N/A output.close()
3866N/A
3866N/Aif __name__ == "__main__":
3866N/A try:
3866N/A main()
3866N/A except DBusXmlException as ex:
3866N/A print(str(ex), file=sys.stderr)
3866N/A sys.exit(1)
3866N/A