Mercurial > projects > dbus-d
diff dbus-d/dsrc/org/freedesktop/dbus/tool/CreateInterface.d @ 0:a5576806d36d
recreate repository without any libs for lightweight repository
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 20 Oct 2007 18:07:18 +0200 |
parents | |
children | 427c0332a111 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbus-d/dsrc/org/freedesktop/dbus/tool/CreateInterface.d Sat Oct 20 18:07:18 2007 +0200 @@ -0,0 +1,1006 @@ +/* + * Copyright (C) 2007 Frank Benoit + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +module org.freedesktop.dbus.tool.CreateInterface; + +import tango.io.Stdout; +import tango.io.Print; +import tango.text.convert.Integer : toUtf8; +import tango.text.Util : layout, split, join, replace; +import tango.net.Uri; // make dsss and linker happy :( +import tango.core.Exception : TracedException; + +import org.freedesktop.dbus.tool.XmlSupport; + +class TerminateException : TracedException { + int code; + this( int code ){ + super( null ); + this.code = code; + } +} +const char[] ID_NODE = "node"; +const char[] ID_INTF = "interface"; +const char[] ID_METH = "method"; +const char[] ID_SIGN = "signal"; +const char[] ID_PROP = "property"; +const char[] ID_ANNO = "annotation"; +const char[] ID_ARGU = "arg"; +const char[] ID_DIRECTION = "direction"; +const char[] ID_DIRECTION_IN = "in"; +const char[] ID_DIRECTION_OUT = "out"; +const char[] ID_TYPE = "type"; +const char[] ANNO_RETURNS = "org.dsource.tiolink.Returns"; +IntfTree intfTree; + +//----------------------------------------- + +private void createStdInterfaces() { + DefInterface intf; + DefMethod meth; + DefArgument argu; + + intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Peer" )); + { + intf.addMethod( meth = new DefMethod( "Ping" )); + meth.complete(); + + intf.addMethod( meth = new DefMethod( "GetMachineId" )); + meth.addArgument( argu = new DefArgument( "machine_uuid", "s", DefArgument.EDir.DIR_OUT)); + meth.addAnnotation( ANNO_RETURNS, "machine_uuid" ); + meth.complete(); + } + + intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Introspectable" )); + { + intf.addMethod( meth = new DefMethod( "Introspect" )); + meth.addArgument( argu = new DefArgument( "xml_data", "s", DefArgument.EDir.DIR_OUT)); + meth.addAnnotation( ANNO_RETURNS, "xml_data" ); + meth.complete(); + } + + intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Properties" )); + { + intf.addMethod( meth = new DefMethod( "Get" )); + meth.addArgument( argu = new DefArgument( "intf_name", "s", DefArgument.EDir.DIR_IN )); + meth.addArgument( argu = new DefArgument( "prop_name", "s", DefArgument.EDir.DIR_IN )); + meth.addArgument( argu = new DefArgument( "prop" , "v", DefArgument.EDir.DIR_OUT)); + meth.addAnnotation( ANNO_RETURNS, "prop" ); + meth.complete(); + + intf.addMethod( meth = new DefMethod( "Set" )); + meth.addArgument( argu = new DefArgument( "intf_name", "s", DefArgument.EDir.DIR_IN )); + meth.addArgument( argu = new DefArgument( "prop_name", "s", DefArgument.EDir.DIR_IN )); + meth.addArgument( argu = new DefArgument( "prop" , "v", DefArgument.EDir.DIR_IN )); + meth.complete(); + + intf.addMethod( meth = new DefMethod( "GetAll" )); + meth.addArgument( argu = new DefArgument( "intf_name", "s" , DefArgument.EDir.DIR_IN )); + meth.addArgument( argu = new DefArgument( "allprops" , "a{sv}", DefArgument.EDir.DIR_OUT)); + meth.addAnnotation( ANNO_RETURNS, "allprops" ); + meth.complete(); + } +} + + +alias char[] DBusObjPath; +alias void function() DBusHandler; + +struct DBusVariant{ + byte type; + union{ + byte v_byte; + bool v_bool; + } +} + + + +class IntfTree{ + class Node{ + char[] mName; + DefInterface mValue; + Node[] mChilds; + } + + Node mRoot; + char[][] allInterfaces; + + public this(){ + mRoot = new Node(); + } + + public void add( DefInterface intf ){ + allInterfaces ~= intf.mName; + char[][] parts = split( intf.mName, "." ); + + Node findNode( char[][] names ){ + if( names.length == 0 ){ + return mRoot; + } + Node par = findNode( names[ 0 .. $-1 ] ); + foreach( child; par.mChilds ){ + if( child.mName == names[ $-1 ] ){ + return child; + } + } + auto child = new Node; + child.mName = names[ $-1 ].dup; + par.mChilds ~= child; + return child; + } + + Node node = findNode( parts ); + node.mValue = intf; + } + + public DefInterface getInterface( char[] intfName ){ + char[][] parts = split( intfName, "." ); + + Node findNode( char[][] names ){ + if( names.length == 0 ){ + return mRoot; + } + Node par = findNode( names[ 0 .. $-1 ] ); + foreach( child; par.mChilds ){ + if( child.mName == names[ $-1 ] ){ + return child; + } + } + return null; + } + Node node = findNode( parts ); + if( node is null ){ + return null; + } + return node.mValue; + } + + public char[][] getChildNames( char[] parentName ){ + char[][] parts = split( parentName, "." ); + + Node findNode( char[][] names ){ + if( names.length == 0 ){ + return mRoot; + } + Node par = findNode( names[ 0 .. $-1 ] ); + foreach( child; par.mChilds ){ + if( child.mName == names[ $-1 ] ){ + return child; + } + } + return null; + } + Node node = findNode( parts ); + if( node is null ){ + return null; + } + char[][] res; + foreach( idx, child; node.mChilds ){ + char[] txt; + if( parentName.length > 0 ){ + res ~= parentName ~ '.' ~ child.mName; + } + else{ + res ~= child.mName; + } + } + return res; + } +} + +class DefInterface{ + char[] mName; + + DefMethod[] mMethods; + DefSignal[] mSignals; + DefProperty[] mProperties; + char[][ char[] ] mAnnotations; + + public this( char[] aName ){ + mName = aName.dup; + } + + public void addMethod( DefMethod meth ){ + mMethods ~= meth; + } + + public void addSignal( DefSignal sign ){ + mSignals ~= sign; + } + + public void addProperty( DefProperty prop ){ + mProperties ~= prop; + } + + public void addAnnotation( char[] name, char[] value ){ + mAnnotations[ name.dup ] = value.dup; + } +} + +class DefSignal : ArgumentContainer { + + char[] mName; + DefArgument[] mArguments; + char[][ char[] ] mAnnotations; + public this( char[] aName ){ + mName = aName.dup; + } + + public void addArgument( DefArgument aArg ){ + mArguments ~= aArg; + } + public void addAnnotation( char[] name, char[] value ){ + mAnnotations[ name.dup ] = value.dup; + } +} + +class DefProperty { + + char[] mName; + public this( char[] aName ){ + mName = aName.dup; + } + +} + +class DefMethod : ArgumentContainer { + char[] mName; + DefArgument[] mArguments; + char[][ char[] ] mAnnotations; + + DefArgument mDRetArgument; + DefArgument[] mDArguments; + + public this( char[] aName ){ + mName = aName.dup; + } + public void addArgument( DefArgument aArg ){ + mArguments ~= aArg; + } + public void addAnnotation( char[] name, char[] value ){ + mAnnotations[ name.dup ] = value.dup; + } + + public void complete(){ + char[]* retArgName = ANNO_RETURNS in mAnnotations; + if( retArgName !is null ){ + int idx = 0; + bool found = false; + foreach( arg; mArguments ){ + if( *retArgName == arg.mName && arg.mDirection == DefArgument.EDir.DIR_OUT ){ + if( found ){ + error( "there are two or more out arguements in the same method" ); + } + found = true; + mDRetArgument = arg; + } + else{ + mDArguments ~= arg; + } + } + } + else{ + mDRetArgument = null; + mDArguments = mArguments; + } + } + + +} + +interface ArgumentContainer{ + public void addArgument( DefArgument aPar ); +} + +class DefArgument{ + + enum EDir{ + DIR_IN, DIR_OUT + } + + EDir mDirection; + char[] mName; + char[] mType; + + public this( char[] aName, char[] aType, EDir aDir ){ + mName = aName.dup; + mType = aType.dup; + mDirection = aDir; + } + + char[] toDType(){ + char[] rem; + char[] res = signatureToDType( mType, rem ); + if( rem.length > 0 ){ + error( "not a complete type %0 %1", mType, rem ); + } + return res; + } + + private char[] signatureToDType( char[] sigText, out char[] remainingSigText ){ + + remainingSigText = null; + if( sigText.length == 0 ){ + return null; + } + + remainingSigText = sigText[ 1.. $ ]; + + switch( sigText[0] ){ + case 'y': return "byte"; + case 'b': return "bool"; + case 'n': return "short"; + case 'q': return "ushort"; + case 'i': return "int"; + case 'u': return "uint"; + case 'x': return "long"; + case 't': return "ulong"; + case 'd': return "double"; + case 's': return "char[]"; + case 'o': return "DBusObject"; + case 'g': return "DBusSignature"; + case 'v': return "DBusVariant"; + default: + break; + } + if( sigText[0] == 'a' ){ + if( sigText.length > 1 && sigText[ 1 ] == '{' ){ + char[] rem; + char[] tkey = signatureToDType( sigText[2..$], rem ); + char[] rem2; + char[] tval = signatureToDType( rem, rem2 ); + char[] res = tval ~ "[ "~ tkey ~" ]"; + if( rem2.length == 0 || rem2[0] != '}' ){ + error( "no valid closing bracket for dict Entry" ); + } + remainingSigText = rem2[ 1 .. $ ]; + return res; + } + else{ + return signatureToDType( sigText[1..$], remainingSigText ) ~ "[]"; + } + } + else if( sigText[0] == '(' ){ + char[][] flds; + char[] rem = sigText[ 1 .. $ ]; + do{ + char[] rem2; + flds ~= signatureToDType( rem, rem2 ); + rem = rem2; + } + while( rem.length > 0 && rem[ 0 ] != ')' ); + remainingSigText = ( rem.length > 0 ) ? rem[ 1 .. $ ] : null; + return "Struct!( " ~ join( flds, ", " ) ~ " )"; + } + error( "unknown type "~sigText ); + assert(false); + } + + +} + + + + + +// array Attt_ AttAtt_i_ alles bis zum abschließenden _ +// map Mtt zwei typen nach M + +// BYTE 121 (ASCII 'y') 8-bit unsigned integer +// BOOLEAN 98 (ASCII 'b') Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid. +// INT16 110 (ASCII 'n') 16-bit signed integer +// UINT16 113 (ASCII 'q') 16-bit unsigned integer +// INT32 105 (ASCII 'i') 32-bit signed integer +// UINT32 117 (ASCII 'u') 32-bit unsigned integer +// INT64 120 (ASCII 'x') 64-bit signed integer +// UINT64 116 (ASCII 't') 64-bit unsigned integer +// DOUBLE 100 (ASCII 'd') IEEE 754 double +// STRING 115 (ASCII 's') UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes. +// OBJECT_PATH 111 (ASCII 'o') Name of an object instance +// SIGNATURE 103 (ASCII 'g') A type signature +// ARRAY 97 (ASCII 'a') Array +// STRUCT 114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')') Struct +// VARIANT 118 (ASCII 'v') Variant type (the type of the value is part of the value itself) +// DICT_ENTRY 101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') Entry in a dict or map (array of key-value pairs) +// + + +void parseNode( Element el ){ + + el.checkAllowedChilds( ID_INTF, ID_NODE ); + + foreach( intf; el.getChilds( ID_INTF )){ + auto defIntf = parseInterface( intf ); + intfTree.add( defIntf ); + } + foreach( node; el.getChilds( ID_NODE )){ + parseNode( node ); + } +} + +void unknownElement( char[][] msg ... ){ + char[200] buf; + Stderr( layout( buf, msg ) ).newline; +} + +DefInterface parseInterface( Element intf ){ + + char[] elname = intf.getAttribute( "name" ); + auto defIntf = new DefInterface( elname ); + + foreach( child; intf.getChilds() ){ + switch( child.getName() ){ + case ID_METH: + defIntf.addMethod( parseMethod( child )); + break; + case ID_SIGN: + defIntf.addSignal( parseSignal( child )); + break; + case ID_PROP: + defIntf.addProperty( parseProperty( child )); + break; + case ID_ANNO: + char[] name = child.getAttribute( "name" ); + char[] value = child.getAttribute( "value" ); + defIntf.addAnnotation( name, value ); + break; + default: + unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() ); + break; + } + } + return defIntf; +} + +DefMethod parseMethod( Element meth ){ + + char[] methName = meth.getAttribute( "name" ); + auto defMeth = new DefMethod( methName ); + + foreach( child; meth.getChilds() ){ + switch( child.getName() ){ + case ID_ARGU: + defMeth.addArgument( parseArgument( child, true )); + break; + case ID_ANNO: + char[] name = child.getAttribute( "name" ); + char[] value = child.getAttribute( "value" ); + defMeth.addAnnotation( name, value ); + break; + default: + unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() ); + break; + } + } + defMeth.complete(); + return defMeth; +} + +DefSignal parseSignal( Element sign ){ + char[] name = sign.getAttribute( "name" ); + auto defSign = new DefSignal( name ); + foreach( child; sign.getChilds() ){ + switch( child.getName() ){ + case ID_ARGU: + defSign.addArgument( parseArgument( child, false )); + break; + case ID_ANNO: + char[] annoName = child.getAttribute( "name" ); + char[] annoValue = child.getAttribute( "value" ); + defSign.addAnnotation( annoName, annoValue ); + break; + default: + unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() ); + break; + } + } + return defSign; +} +DefProperty parseProperty( Element prop ){ + char[] name = prop.getAttribute( "name" ); + auto res = new DefProperty( name ); + return res; +} + + +DefArgument parseArgument( Element arg, bool dirDefIn ){ + char[] name = arg.getAttribute( "name" ); + DefArgument.EDir dir = dirDefIn ? DefArgument.EDir.DIR_IN : DefArgument.EDir.DIR_OUT; + if( arg.hasAttribute( ID_DIRECTION )){ + char[] dirtxt = arg.getAttribute( ID_DIRECTION ); + switch( dirtxt ){ + case ID_DIRECTION_OUT: + dir = DefArgument.EDir.DIR_OUT; + break; + case ID_DIRECTION_IN: + dir = DefArgument.EDir.DIR_IN; + break; + default: + unknownElement( "Warning: direction attribute has unknown value %0", dirtxt ); + break; + } + } + char[] typetxt = arg.getAttribute( ID_TYPE ); + auto res = new DefArgument( name, typetxt, dir ); + return res; +} + +char[] getIndent( int indent ){ + static char[] spaces = " "; + int count = indent*4; + assert( count >= 0 ); + assert( count < spaces.length ); + return spaces[0..count]; +} + +//char[][ char[] ] introspection = [ `sdklf`:`ldkfj`]; + +void writeIntrospectionData( Print!(char) p ){ + char[200] buf; + char[] getArgIntrospectionData( DefArgument arg ){ + char[] res = ` <arg `; + res ~= layout( buf, ` name=\"%0\"`, arg.mName ).dup; + res ~= layout( buf, ` type=\"%0\"`, arg.mType ).dup; + res ~= layout( buf, ` direction=\"%0\"`, arg.mDirection == DefArgument.EDir.DIR_IN ? ID_DIRECTION_IN : ID_DIRECTION_OUT ).dup; + res ~= ` />\\n`; + return res; + } + char[] getAnnotationIntrospectionData( char[] name, char[] value, int indent ){ + return layout( buf, `%2<annotation name=\"%0\" value=\"%1\" />\\n`, name, value, getIndent( indent ) ).dup; + } + char[][] getMethodIntrospectionData( DefMethod meth ){ + char[][] res; + res ~= layout( buf, ` <method name=\"%0\">\\n`, meth.mName ).dup; + foreach( key, value ; meth.mAnnotations ){ + res ~= getAnnotationIntrospectionData( key, value, 2 ); + } + foreach( argu ; meth.mArguments ){ + res ~= getArgIntrospectionData( argu ); + } + res ~= ` </method>\\n`.dup; + return res; + } + char[][] getIntrospectionData( DefInterface intf ){ + char[][] res; + res ~= layout( buf, `<interface name=\"%0\">\\n`, intf.mName ).dup; + foreach( meth; intf.mMethods ){ + res ~= getMethodIntrospectionData( meth ); + } + res ~= `</interface>\\n`.dup; + return res; + } + p.formatln( "private void init_introspectionData(){{" ); + foreach( intfIdx, intf; intfTree.allInterfaces ){ + p.formatln( " registerIntrospectionData(" ); + p.formatln( " DBusInterface.{}.classinfo,", intf ); + char[][] data = getIntrospectionData( intfTree.getInterface( intf ) ); + foreach( idx, line; data ){ + if( idx < data.length-1 ){ + p.formatln( " \"{}\"", line ); + } + else{ + p.formatln( " \"{}\");", line, (intfIdx<intfTree.allInterfaces.length-1)?",":"" ); + } + } + } + p.formatln( "}" ); +} + +void error( char[][] msg... ){ + char[200] buf; + throw new TracedException( layout( buf, msg )); +} + +void writeInterfaceMethod( Print!(char) p, DefMethod meth, int indent ){ + DefArgument retArg = meth.mDRetArgument; + DefArgument[] args = meth.mDArguments; + char[] retType = ( retArg is null ) ? "void" : retArg.toDType(); + char[] argList; + foreach( idx, arg; args ){ + if( idx > 0 ){ + argList ~= ","; + } + argList ~= " "; + argList ~= (arg.mDirection == DefArgument.EDir.DIR_OUT) ? "out" : "in"; + argList ~= " "; + argList ~= arg.toDType(); + argList ~= " "; + argList ~= ( arg.mName.length == 0 ) ? "arg_" ~ toUtf8(idx) : arg.mName; + } + if( argList.length > 0 ){ + argList ~= " "; + } + p.formatln( "{}public {} {}({});", getIndent(indent), retType, meth.mName, argList ); +} + +void writeInterfaceSignal( Print!(char) p, DefSignal sign, int indent ){ + char[] argList; + foreach( idx, arg; sign.mArguments ){ + if( idx > 0 ){ + argList ~= ","; + } + argList ~= " "; + argList ~= arg.toDType(); + } + if( argList.length > 0 ){ + argList ~= " "; + } + p.formatln( "{}public tango.core.Signal.Signal!({})* {}();", getIndent(indent), argList, sign.mName ); +} + +void writeInterface( Print!(char) p, char[] name, int indent ){ + p.formatln( "{}// {}", getIndent(indent), name ); + char[] nodeName = split( name, "." )[ $-1 ]; + p.formatln( "{}public interface {} {{", getIndent(indent), nodeName ); + DefInterface intf = intfTree.getInterface( name ); + if( intf !is null ){ + foreach( meth; intf.mMethods ){ + writeInterfaceMethod( p, meth, indent+1 ); + } + foreach( sign; intf.mSignals ){ + writeInterfaceSignal( p, sign, indent+1 ); + } + } + foreach( child; intfTree.getChildNames( name ) ){ + writeInterface( p, child, indent +1 ); + } + p.formatln( "{}}", getIndent(indent) ); +} + +void writeHeader( Print!(char) p, char[] modName ){ + static char[] HEADER = + "/**\n" + " * Generated with TioLink\n" + " * TioLink was written by Frank Benoit <benoit@tionex.de>\n" + " * http://www.dsource.org/projects/tiolink\n" + " *\n" + " * File type: D programming language source code\n" + " */\n"; + p(HEADER); + p.formatln( "module {};", modName ); + p.newline; + p.formatln( "public import org.freedesktop.dbus.Struct;" ); + p.formatln( "public import org.freedesktop.dbus.Variant;" ); + p.newline; + p.formatln( "import tango.core.Signal;" ); + p.formatln( "import org.freedesktop.dbus.DBus;" ); + p.formatln( "import org.freedesktop.dbus.c.Connection : DBusConnection;" ); + p.formatln( "import org.freedesktop.dbus.c.Message : DBusMessage;" ); + p.formatln( "import org.freedesktop.dbus.c.Shared : DBusHandlerResult;" ); + p.newline; + p.newline; +} + +void writeInterfaces( Print!(char) p ){ + + p.formatln( "// DBus interfaces" ); + p.formatln( "public interface DBusInterface {{" ); + foreach( child; intfTree.getChildNames( "" ) ){ + writeInterface( p, child, 1 ); + } + p.formatln( "}" ); + p.newline; + p.newline; + +} + +void writePeerMethod( Print!(char) p, DefMethod mth, int indent ){ + DefArgument retArg = mth.mDRetArgument; + DefArgument[] args = mth.mDArguments; + char[] retType = ( retArg is null ) ? "void" : retArg.toDType(); + char[] argList; + foreach( idx, arg; args ){ + if( idx > 0 ){ + argList ~= ","; + } + argList ~= " "; + argList ~= (arg.mDirection == DefArgument.EDir.DIR_OUT) ? "out" : "in"; + argList ~= " "; + argList ~= arg.toDType(); + argList ~= " "; + argList ~= ( arg.mName.length == 0 ) ? "arg_" ~ toUtf8(idx) : arg.mName; + } + if( argList.length > 0 ){ + argList ~= " "; + } + p.formatln( "{}public {} {}({}){{", getIndent(indent), retType, mth.mName, argList ); + p.formatln( "{}}", getIndent(indent) ); +} + +void writePeerSignal( Print!(char) p, DefSignal sig, int indent ){ +} + +void writePeerImpl( Print!(char) p, char[] name, int indent ){ + p.formatln( "{}// {}", getIndent(indent), name ); + char[] nodeName = split( name, "." )[ $-1 ]; + p.formatln( "{}public class {} : DBusPeerObject, DBusInterface.{} {{", getIndent(indent), nodeName, name ); + DefInterface intf = intfTree.getInterface( name ); + if( intf !is null ){ + foreach( meth; intf.mMethods ){ + writePeerMethod( p, meth, indent+1 ); + } + foreach( sign; intf.mSignals ){ + writePeerSignal( p, sign, indent+1 ); + } + } + foreach( child; intfTree.getChildNames( name ) ){ + writePeerImpl( p, child, indent +1 ); + } + p.formatln( "{}}", getIndent(indent) ); +} +void writePeerImpls( Print!(char) p ){ + + p.formatln( "// Peer implementations" ); + p.formatln( "public interface DBusPeers {{" ); + foreach( child; intfTree.getChildNames( "" ) ){ + writePeerImpl( p, child, 1 ); + } + p.formatln( "}" ); + p.newline; + p.newline; + +} + +void writeDBusObject( Print!(char) p ){ + p.formatln( "// DBusObject" ); + p.formatln( "public class DBusObject : DBusObjectImpl, DBusInterface.org.freedesktop.DBus.Introspectable {{" ); + p.formatln( " this(){{" ); + p.formatln( " super();" ); + p.formatln( " }" ); + p.formatln( " public char[] Introspect(){{" ); + p.formatln( " return super.Introspect();" ); + p.formatln( " }" ); + p.formatln( "}" ); + p.newline; + p.newline; +} +void writeDBusPeerObject( Print!(char) p ){ + p.formatln( "// DBusPeerObject" ); + p.formatln( "public class DBusPeerObject {{" ); + p.formatln( "}" ); + p.newline; + p.newline; +} +class TextList { + + private char[] separator; + private char[] sb; + private char[] prefix; + private char[] postfix; + private bool completed = false; + + public this( char[] separator ){ + this.separator = separator; + this.prefix = ""; + this.postfix = ""; + } + public this( char[] prefix, char[] separator, char[] postfix ){ + this.prefix = prefix; + this.separator = separator; + this.postfix = postfix; + } + + public static TextList createParameterList(){ + return new TextList( " ", ", ", " " ); + } + + public void add( char[] value ){ + if( sb.length == 0 ){ + sb ~= prefix; + } + else{ + sb ~= separator; + } + sb ~= value; + } + public char[] toUtf8(){ + if( !completed ){ + if( sb.length > 0 ){ + sb ~= postfix; + } + completed = true; + } + return sb; + } +} + +void writeHandlerInterfaceMethod( Print!(char) p, DefMethod mth ){ + char[] sig = mth.mName ~ "|"; + foreach( arg; mth.mArguments ){ + if( arg.mDirection == DefArgument.EDir.DIR_IN ){ + sig ~= arg.mType; + } + } + + DefArgument retArg = mth.mDRetArgument; + DefArgument[] args = mth.mDArguments; + + p.formatln(" case \"{}\":", sig ); + p.formatln(" {{" ); + TextList callParams = TextList.createParameterList(); + TextList callTypes = TextList.createParameterList(); + TextList callInTypes = TextList.createParameterList(); + TextList callOutTypes = TextList.createParameterList(); + int idxi, idxo; + char[] retAssign = ""; + char[] retVar = ""; + bool hasOutputs = false; + bool hasInputs = false; + foreach( idx, arg; mth.mArguments ){ + callTypes.add( arg.toDType()); + if( arg.mDirection == DefArgument.EDir.DIR_IN ){ + hasInputs = true; + callInTypes.add( arg.toDType()); + callParams.add( "pi.t["~toUtf8(idxi)~"]" ); + idxi++; + } + else{ + hasOutputs = true; + callOutTypes.add( arg.toDType()); + + char[] outArg = "po.t["~toUtf8(idxo)~"]"; + idxo++; + if( arg is mth.mDRetArgument ){ + retVar = outArg; + retAssign = retVar~" = "; + } + else{ + callParams.add( outArg ); + } + } + } + if( hasInputs ){ + p.formatln(" Struct!({0}) pi = getCallValues!({0})( message );", callInTypes.toUtf8() ); + } + if( hasOutputs ){ + p.formatln(" Struct!({0}) po;" , callOutTypes.toUtf8() ); + } + p.formatln(" {}o.{}({});", retAssign, mth.mName, callParams.toUtf8() ); + if( hasOutputs ){ + p.formatln(" sendReplyData!({})( conn, message, po );", callOutTypes.toUtf8() ); + } + else{ + p.formatln(" sendReply( conn, message );" ); + } + p.formatln(" }" ); + p.formatln(" break;" ); + + +} +void writeHandlerInterfaceSignal( Print!(char) p, DefSignal sig ){ + char[] signature = sig.mName ~ ">"; + foreach( arg; sig.mArguments ){ + signature ~= arg.mType; + } + + DefArgument[] args = sig.mArguments; + + p.formatln(" case \"{}\":", signature ); + p.formatln(" {{" ); + TextList callParams = TextList.createParameterList(); + TextList callInTypes = TextList.createParameterList(); + int idxi; + char[] retAssign = ""; + char[] retVar = ""; + bool hasInputs = false; + foreach( idx, arg; sig.mArguments ){ + hasInputs = true; + callInTypes.add( arg.toDType()); + callParams.add( "pi.t["~toUtf8(idxi)~"]" ); + idxi++; + } + if( hasInputs ){ + p.formatln(" Struct!({0}) pi = getCallValues!({0})( message );", callInTypes.toUtf8() ); + } + p.formatln(" o.{}().opCall({});", sig.mName, callParams.toUtf8() ); + p.formatln(" }" ); + p.formatln(" break;" ); + + +} +void writeHandlerInterface( Print!(char) p, DefInterface intf ){ + p.formatln("private DBusHandlerResult intfHandler__{}( " + "DBusConnection* conn, DBusMessage* message, void* user_data ){{", + replace( intf.mName.dup, '.', '_') ); + p.formatln(" DBusInterface.{} o = cast(DBusInterface.{0})cast(Object)user_data;", intf.mName ); + p.formatln(" if( o is null || !checkIntf( \"{}\", message) )", intf.mName ); + p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;" ); + p.formatln(""); + p.formatln(" try{{"); + p.formatln(" char[METHOD_SIG_MAXLENGTH] buf;"); + p.formatln(" switch( methodSignature( message, buf ) ){{"); + foreach( DefMethod mth ; intf.mMethods ){ + writeHandlerInterfaceMethod( p, mth ); + } + foreach( DefSignal sig ; intf.mSignals ){ + writeHandlerInterfaceSignal( p, sig ); + } + p.formatln(" default:" ); + p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;"); + p.formatln(" }"); + p.formatln(" }"); + p.formatln(" catch( Exception e ){{"); + p.formatln(" sendException( conn, message, e );" ); + p.formatln(" }"); + p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;"); + p.formatln("}"); + p.newline; +} +void writeHandlers( Print!(char) p ){ + + + foreach( intfIdx, intf; intfTree.allInterfaces ){ + writeHandlerInterface( p, intfTree.getInterface( intf )); + } + + p.formatln( "private void init_handlers(){{" ); + foreach( intfIdx, intf; intfTree.allInterfaces ){ + p.formatln( " registerHandler(" ); + p.formatln( " DBusInterface.{}.classinfo,", intf ); + p.formatln( " & intfHandler__{} );", replace( intf.dup, '.', '_' )); + } + p.formatln( "}" ); + p.newline; + +} +void writeStaticInit( Print!(char) p ){ + p.formatln( "static this(){{" ); + p.formatln( " init_introspectionData();" ); + p.formatln( " init_handlers();" ); + p.formatln( "}" ); + p.newline; +} + +int main(char[][] args) { + try{ + if( args.length != 3 ){ + printSyntax(); + throw new TerminateException(1); + } + char[] introxml = args[1]; + char[] modname = args[2]; + intfTree = new IntfTree(); + auto root = parse( introxml ); + createStdInterfaces(); + parseNode( root ); + Print!(char) output = Stdout; + writeHeader( output, modname ); + writeInterfaces( output ); + //writePeerImpls( output ); + writeDBusObject( output ); + //writeDBusPeerObject( output ); + writeIntrospectionData( output ); + writeHandlers( output ); + writeStaticInit( output ); + } + catch( TerminateException e ){ + return e.code; + } + return(0); +} + + +void printSyntax() { + Stdout.formatln("dbus-createinterface <introspectionsdata.xml> <modulename>"); +} + + +