comparison 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
comparison
equal deleted inserted replaced
-1:000000000000 0:a5576806d36d
1 /*
2 * Copyright (C) 2007 Frank Benoit
3 *
4 * Licensed under the Academic Free License version 2.1
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21 module org.freedesktop.dbus.tool.CreateInterface;
22
23 import tango.io.Stdout;
24 import tango.io.Print;
25 import tango.text.convert.Integer : toUtf8;
26 import tango.text.Util : layout, split, join, replace;
27 import tango.net.Uri; // make dsss and linker happy :(
28 import tango.core.Exception : TracedException;
29
30 import org.freedesktop.dbus.tool.XmlSupport;
31
32 class TerminateException : TracedException {
33 int code;
34 this( int code ){
35 super( null );
36 this.code = code;
37 }
38 }
39 const char[] ID_NODE = "node";
40 const char[] ID_INTF = "interface";
41 const char[] ID_METH = "method";
42 const char[] ID_SIGN = "signal";
43 const char[] ID_PROP = "property";
44 const char[] ID_ANNO = "annotation";
45 const char[] ID_ARGU = "arg";
46 const char[] ID_DIRECTION = "direction";
47 const char[] ID_DIRECTION_IN = "in";
48 const char[] ID_DIRECTION_OUT = "out";
49 const char[] ID_TYPE = "type";
50 const char[] ANNO_RETURNS = "org.dsource.tiolink.Returns";
51 IntfTree intfTree;
52
53 //-----------------------------------------
54
55 private void createStdInterfaces() {
56 DefInterface intf;
57 DefMethod meth;
58 DefArgument argu;
59
60 intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Peer" ));
61 {
62 intf.addMethod( meth = new DefMethod( "Ping" ));
63 meth.complete();
64
65 intf.addMethod( meth = new DefMethod( "GetMachineId" ));
66 meth.addArgument( argu = new DefArgument( "machine_uuid", "s", DefArgument.EDir.DIR_OUT));
67 meth.addAnnotation( ANNO_RETURNS, "machine_uuid" );
68 meth.complete();
69 }
70
71 intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Introspectable" ));
72 {
73 intf.addMethod( meth = new DefMethod( "Introspect" ));
74 meth.addArgument( argu = new DefArgument( "xml_data", "s", DefArgument.EDir.DIR_OUT));
75 meth.addAnnotation( ANNO_RETURNS, "xml_data" );
76 meth.complete();
77 }
78
79 intfTree.add( intf = new DefInterface( "org.freedesktop.DBus.Properties" ));
80 {
81 intf.addMethod( meth = new DefMethod( "Get" ));
82 meth.addArgument( argu = new DefArgument( "intf_name", "s", DefArgument.EDir.DIR_IN ));
83 meth.addArgument( argu = new DefArgument( "prop_name", "s", DefArgument.EDir.DIR_IN ));
84 meth.addArgument( argu = new DefArgument( "prop" , "v", DefArgument.EDir.DIR_OUT));
85 meth.addAnnotation( ANNO_RETURNS, "prop" );
86 meth.complete();
87
88 intf.addMethod( meth = new DefMethod( "Set" ));
89 meth.addArgument( argu = new DefArgument( "intf_name", "s", DefArgument.EDir.DIR_IN ));
90 meth.addArgument( argu = new DefArgument( "prop_name", "s", DefArgument.EDir.DIR_IN ));
91 meth.addArgument( argu = new DefArgument( "prop" , "v", DefArgument.EDir.DIR_IN ));
92 meth.complete();
93
94 intf.addMethod( meth = new DefMethod( "GetAll" ));
95 meth.addArgument( argu = new DefArgument( "intf_name", "s" , DefArgument.EDir.DIR_IN ));
96 meth.addArgument( argu = new DefArgument( "allprops" , "a{sv}", DefArgument.EDir.DIR_OUT));
97 meth.addAnnotation( ANNO_RETURNS, "allprops" );
98 meth.complete();
99 }
100 }
101
102
103 alias char[] DBusObjPath;
104 alias void function() DBusHandler;
105
106 struct DBusVariant{
107 byte type;
108 union{
109 byte v_byte;
110 bool v_bool;
111 }
112 }
113
114
115
116 class IntfTree{
117 class Node{
118 char[] mName;
119 DefInterface mValue;
120 Node[] mChilds;
121 }
122
123 Node mRoot;
124 char[][] allInterfaces;
125
126 public this(){
127 mRoot = new Node();
128 }
129
130 public void add( DefInterface intf ){
131 allInterfaces ~= intf.mName;
132 char[][] parts = split( intf.mName, "." );
133
134 Node findNode( char[][] names ){
135 if( names.length == 0 ){
136 return mRoot;
137 }
138 Node par = findNode( names[ 0 .. $-1 ] );
139 foreach( child; par.mChilds ){
140 if( child.mName == names[ $-1 ] ){
141 return child;
142 }
143 }
144 auto child = new Node;
145 child.mName = names[ $-1 ].dup;
146 par.mChilds ~= child;
147 return child;
148 }
149
150 Node node = findNode( parts );
151 node.mValue = intf;
152 }
153
154 public DefInterface getInterface( char[] intfName ){
155 char[][] parts = split( intfName, "." );
156
157 Node findNode( char[][] names ){
158 if( names.length == 0 ){
159 return mRoot;
160 }
161 Node par = findNode( names[ 0 .. $-1 ] );
162 foreach( child; par.mChilds ){
163 if( child.mName == names[ $-1 ] ){
164 return child;
165 }
166 }
167 return null;
168 }
169 Node node = findNode( parts );
170 if( node is null ){
171 return null;
172 }
173 return node.mValue;
174 }
175
176 public char[][] getChildNames( char[] parentName ){
177 char[][] parts = split( parentName, "." );
178
179 Node findNode( char[][] names ){
180 if( names.length == 0 ){
181 return mRoot;
182 }
183 Node par = findNode( names[ 0 .. $-1 ] );
184 foreach( child; par.mChilds ){
185 if( child.mName == names[ $-1 ] ){
186 return child;
187 }
188 }
189 return null;
190 }
191 Node node = findNode( parts );
192 if( node is null ){
193 return null;
194 }
195 char[][] res;
196 foreach( idx, child; node.mChilds ){
197 char[] txt;
198 if( parentName.length > 0 ){
199 res ~= parentName ~ '.' ~ child.mName;
200 }
201 else{
202 res ~= child.mName;
203 }
204 }
205 return res;
206 }
207 }
208
209 class DefInterface{
210 char[] mName;
211
212 DefMethod[] mMethods;
213 DefSignal[] mSignals;
214 DefProperty[] mProperties;
215 char[][ char[] ] mAnnotations;
216
217 public this( char[] aName ){
218 mName = aName.dup;
219 }
220
221 public void addMethod( DefMethod meth ){
222 mMethods ~= meth;
223 }
224
225 public void addSignal( DefSignal sign ){
226 mSignals ~= sign;
227 }
228
229 public void addProperty( DefProperty prop ){
230 mProperties ~= prop;
231 }
232
233 public void addAnnotation( char[] name, char[] value ){
234 mAnnotations[ name.dup ] = value.dup;
235 }
236 }
237
238 class DefSignal : ArgumentContainer {
239
240 char[] mName;
241 DefArgument[] mArguments;
242 char[][ char[] ] mAnnotations;
243 public this( char[] aName ){
244 mName = aName.dup;
245 }
246
247 public void addArgument( DefArgument aArg ){
248 mArguments ~= aArg;
249 }
250 public void addAnnotation( char[] name, char[] value ){
251 mAnnotations[ name.dup ] = value.dup;
252 }
253 }
254
255 class DefProperty {
256
257 char[] mName;
258 public this( char[] aName ){
259 mName = aName.dup;
260 }
261
262 }
263
264 class DefMethod : ArgumentContainer {
265 char[] mName;
266 DefArgument[] mArguments;
267 char[][ char[] ] mAnnotations;
268
269 DefArgument mDRetArgument;
270 DefArgument[] mDArguments;
271
272 public this( char[] aName ){
273 mName = aName.dup;
274 }
275 public void addArgument( DefArgument aArg ){
276 mArguments ~= aArg;
277 }
278 public void addAnnotation( char[] name, char[] value ){
279 mAnnotations[ name.dup ] = value.dup;
280 }
281
282 public void complete(){
283 char[]* retArgName = ANNO_RETURNS in mAnnotations;
284 if( retArgName !is null ){
285 int idx = 0;
286 bool found = false;
287 foreach( arg; mArguments ){
288 if( *retArgName == arg.mName && arg.mDirection == DefArgument.EDir.DIR_OUT ){
289 if( found ){
290 error( "there are two or more out arguements in the same method" );
291 }
292 found = true;
293 mDRetArgument = arg;
294 }
295 else{
296 mDArguments ~= arg;
297 }
298 }
299 }
300 else{
301 mDRetArgument = null;
302 mDArguments = mArguments;
303 }
304 }
305
306
307 }
308
309 interface ArgumentContainer{
310 public void addArgument( DefArgument aPar );
311 }
312
313 class DefArgument{
314
315 enum EDir{
316 DIR_IN, DIR_OUT
317 }
318
319 EDir mDirection;
320 char[] mName;
321 char[] mType;
322
323 public this( char[] aName, char[] aType, EDir aDir ){
324 mName = aName.dup;
325 mType = aType.dup;
326 mDirection = aDir;
327 }
328
329 char[] toDType(){
330 char[] rem;
331 char[] res = signatureToDType( mType, rem );
332 if( rem.length > 0 ){
333 error( "not a complete type %0 %1", mType, rem );
334 }
335 return res;
336 }
337
338 private char[] signatureToDType( char[] sigText, out char[] remainingSigText ){
339
340 remainingSigText = null;
341 if( sigText.length == 0 ){
342 return null;
343 }
344
345 remainingSigText = sigText[ 1.. $ ];
346
347 switch( sigText[0] ){
348 case 'y': return "byte";
349 case 'b': return "bool";
350 case 'n': return "short";
351 case 'q': return "ushort";
352 case 'i': return "int";
353 case 'u': return "uint";
354 case 'x': return "long";
355 case 't': return "ulong";
356 case 'd': return "double";
357 case 's': return "char[]";
358 case 'o': return "DBusObject";
359 case 'g': return "DBusSignature";
360 case 'v': return "DBusVariant";
361 default:
362 break;
363 }
364 if( sigText[0] == 'a' ){
365 if( sigText.length > 1 && sigText[ 1 ] == '{' ){
366 char[] rem;
367 char[] tkey = signatureToDType( sigText[2..$], rem );
368 char[] rem2;
369 char[] tval = signatureToDType( rem, rem2 );
370 char[] res = tval ~ "[ "~ tkey ~" ]";
371 if( rem2.length == 0 || rem2[0] != '}' ){
372 error( "no valid closing bracket for dict Entry" );
373 }
374 remainingSigText = rem2[ 1 .. $ ];
375 return res;
376 }
377 else{
378 return signatureToDType( sigText[1..$], remainingSigText ) ~ "[]";
379 }
380 }
381 else if( sigText[0] == '(' ){
382 char[][] flds;
383 char[] rem = sigText[ 1 .. $ ];
384 do{
385 char[] rem2;
386 flds ~= signatureToDType( rem, rem2 );
387 rem = rem2;
388 }
389 while( rem.length > 0 && rem[ 0 ] != ')' );
390 remainingSigText = ( rem.length > 0 ) ? rem[ 1 .. $ ] : null;
391 return "Struct!( " ~ join( flds, ", " ) ~ " )";
392 }
393 error( "unknown type "~sigText );
394 assert(false);
395 }
396
397
398 }
399
400
401
402
403
404 // array Attt_ AttAtt_i_ alles bis zum abschließenden _
405 // map Mtt zwei typen nach M
406
407 // BYTE 121 (ASCII 'y') 8-bit unsigned integer
408 // BOOLEAN 98 (ASCII 'b') Boolean value, 0 is FALSE and 1 is TRUE. Everything else is invalid.
409 // INT16 110 (ASCII 'n') 16-bit signed integer
410 // UINT16 113 (ASCII 'q') 16-bit unsigned integer
411 // INT32 105 (ASCII 'i') 32-bit signed integer
412 // UINT32 117 (ASCII 'u') 32-bit unsigned integer
413 // INT64 120 (ASCII 'x') 64-bit signed integer
414 // UINT64 116 (ASCII 't') 64-bit unsigned integer
415 // DOUBLE 100 (ASCII 'd') IEEE 754 double
416 // STRING 115 (ASCII 's') UTF-8 string (must be valid UTF-8). Must be nul terminated and contain no other nul bytes.
417 // OBJECT_PATH 111 (ASCII 'o') Name of an object instance
418 // SIGNATURE 103 (ASCII 'g') A type signature
419 // ARRAY 97 (ASCII 'a') Array
420 // STRUCT 114 (ASCII 'r'), 40 (ASCII '('), 41 (ASCII ')') Struct
421 // VARIANT 118 (ASCII 'v') Variant type (the type of the value is part of the value itself)
422 // DICT_ENTRY 101 (ASCII 'e'), 123 (ASCII '{'), 125 (ASCII '}') Entry in a dict or map (array of key-value pairs)
423 //
424
425
426 void parseNode( Element el ){
427
428 el.checkAllowedChilds( ID_INTF, ID_NODE );
429
430 foreach( intf; el.getChilds( ID_INTF )){
431 auto defIntf = parseInterface( intf );
432 intfTree.add( defIntf );
433 }
434 foreach( node; el.getChilds( ID_NODE )){
435 parseNode( node );
436 }
437 }
438
439 void unknownElement( char[][] msg ... ){
440 char[200] buf;
441 Stderr( layout( buf, msg ) ).newline;
442 }
443
444 DefInterface parseInterface( Element intf ){
445
446 char[] elname = intf.getAttribute( "name" );
447 auto defIntf = new DefInterface( elname );
448
449 foreach( child; intf.getChilds() ){
450 switch( child.getName() ){
451 case ID_METH:
452 defIntf.addMethod( parseMethod( child ));
453 break;
454 case ID_SIGN:
455 defIntf.addSignal( parseSignal( child ));
456 break;
457 case ID_PROP:
458 defIntf.addProperty( parseProperty( child ));
459 break;
460 case ID_ANNO:
461 char[] name = child.getAttribute( "name" );
462 char[] value = child.getAttribute( "value" );
463 defIntf.addAnnotation( name, value );
464 break;
465 default:
466 unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() );
467 break;
468 }
469 }
470 return defIntf;
471 }
472
473 DefMethod parseMethod( Element meth ){
474
475 char[] methName = meth.getAttribute( "name" );
476 auto defMeth = new DefMethod( methName );
477
478 foreach( child; meth.getChilds() ){
479 switch( child.getName() ){
480 case ID_ARGU:
481 defMeth.addArgument( parseArgument( child, true ));
482 break;
483 case ID_ANNO:
484 char[] name = child.getAttribute( "name" );
485 char[] value = child.getAttribute( "value" );
486 defMeth.addAnnotation( name, value );
487 break;
488 default:
489 unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() );
490 break;
491 }
492 }
493 defMeth.complete();
494 return defMeth;
495 }
496
497 DefSignal parseSignal( Element sign ){
498 char[] name = sign.getAttribute( "name" );
499 auto defSign = new DefSignal( name );
500 foreach( child; sign.getChilds() ){
501 switch( child.getName() ){
502 case ID_ARGU:
503 defSign.addArgument( parseArgument( child, false ));
504 break;
505 case ID_ANNO:
506 char[] annoName = child.getAttribute( "name" );
507 char[] annoValue = child.getAttribute( "value" );
508 defSign.addAnnotation( annoName, annoValue );
509 break;
510 default:
511 unknownElement( "Warning: found unknown nodetype %0 in interface", child.getName() );
512 break;
513 }
514 }
515 return defSign;
516 }
517 DefProperty parseProperty( Element prop ){
518 char[] name = prop.getAttribute( "name" );
519 auto res = new DefProperty( name );
520 return res;
521 }
522
523
524 DefArgument parseArgument( Element arg, bool dirDefIn ){
525 char[] name = arg.getAttribute( "name" );
526 DefArgument.EDir dir = dirDefIn ? DefArgument.EDir.DIR_IN : DefArgument.EDir.DIR_OUT;
527 if( arg.hasAttribute( ID_DIRECTION )){
528 char[] dirtxt = arg.getAttribute( ID_DIRECTION );
529 switch( dirtxt ){
530 case ID_DIRECTION_OUT:
531 dir = DefArgument.EDir.DIR_OUT;
532 break;
533 case ID_DIRECTION_IN:
534 dir = DefArgument.EDir.DIR_IN;
535 break;
536 default:
537 unknownElement( "Warning: direction attribute has unknown value %0", dirtxt );
538 break;
539 }
540 }
541 char[] typetxt = arg.getAttribute( ID_TYPE );
542 auto res = new DefArgument( name, typetxt, dir );
543 return res;
544 }
545
546 char[] getIndent( int indent ){
547 static char[] spaces = " ";
548 int count = indent*4;
549 assert( count >= 0 );
550 assert( count < spaces.length );
551 return spaces[0..count];
552 }
553
554 //char[][ char[] ] introspection = [ `sdklf`:`ldkfj`];
555
556 void writeIntrospectionData( Print!(char) p ){
557 char[200] buf;
558 char[] getArgIntrospectionData( DefArgument arg ){
559 char[] res = ` <arg `;
560 res ~= layout( buf, ` name=\"%0\"`, arg.mName ).dup;
561 res ~= layout( buf, ` type=\"%0\"`, arg.mType ).dup;
562 res ~= layout( buf, ` direction=\"%0\"`, arg.mDirection == DefArgument.EDir.DIR_IN ? ID_DIRECTION_IN : ID_DIRECTION_OUT ).dup;
563 res ~= ` />\\n`;
564 return res;
565 }
566 char[] getAnnotationIntrospectionData( char[] name, char[] value, int indent ){
567 return layout( buf, `%2<annotation name=\"%0\" value=\"%1\" />\\n`, name, value, getIndent( indent ) ).dup;
568 }
569 char[][] getMethodIntrospectionData( DefMethod meth ){
570 char[][] res;
571 res ~= layout( buf, ` <method name=\"%0\">\\n`, meth.mName ).dup;
572 foreach( key, value ; meth.mAnnotations ){
573 res ~= getAnnotationIntrospectionData( key, value, 2 );
574 }
575 foreach( argu ; meth.mArguments ){
576 res ~= getArgIntrospectionData( argu );
577 }
578 res ~= ` </method>\\n`.dup;
579 return res;
580 }
581 char[][] getIntrospectionData( DefInterface intf ){
582 char[][] res;
583 res ~= layout( buf, `<interface name=\"%0\">\\n`, intf.mName ).dup;
584 foreach( meth; intf.mMethods ){
585 res ~= getMethodIntrospectionData( meth );
586 }
587 res ~= `</interface>\\n`.dup;
588 return res;
589 }
590 p.formatln( "private void init_introspectionData(){{" );
591 foreach( intfIdx, intf; intfTree.allInterfaces ){
592 p.formatln( " registerIntrospectionData(" );
593 p.formatln( " DBusInterface.{}.classinfo,", intf );
594 char[][] data = getIntrospectionData( intfTree.getInterface( intf ) );
595 foreach( idx, line; data ){
596 if( idx < data.length-1 ){
597 p.formatln( " \"{}\"", line );
598 }
599 else{
600 p.formatln( " \"{}\");", line, (intfIdx<intfTree.allInterfaces.length-1)?",":"" );
601 }
602 }
603 }
604 p.formatln( "}" );
605 }
606
607 void error( char[][] msg... ){
608 char[200] buf;
609 throw new TracedException( layout( buf, msg ));
610 }
611
612 void writeInterfaceMethod( Print!(char) p, DefMethod meth, int indent ){
613 DefArgument retArg = meth.mDRetArgument;
614 DefArgument[] args = meth.mDArguments;
615 char[] retType = ( retArg is null ) ? "void" : retArg.toDType();
616 char[] argList;
617 foreach( idx, arg; args ){
618 if( idx > 0 ){
619 argList ~= ",";
620 }
621 argList ~= " ";
622 argList ~= (arg.mDirection == DefArgument.EDir.DIR_OUT) ? "out" : "in";
623 argList ~= " ";
624 argList ~= arg.toDType();
625 argList ~= " ";
626 argList ~= ( arg.mName.length == 0 ) ? "arg_" ~ toUtf8(idx) : arg.mName;
627 }
628 if( argList.length > 0 ){
629 argList ~= " ";
630 }
631 p.formatln( "{}public {} {}({});", getIndent(indent), retType, meth.mName, argList );
632 }
633
634 void writeInterfaceSignal( Print!(char) p, DefSignal sign, int indent ){
635 char[] argList;
636 foreach( idx, arg; sign.mArguments ){
637 if( idx > 0 ){
638 argList ~= ",";
639 }
640 argList ~= " ";
641 argList ~= arg.toDType();
642 }
643 if( argList.length > 0 ){
644 argList ~= " ";
645 }
646 p.formatln( "{}public tango.core.Signal.Signal!({})* {}();", getIndent(indent), argList, sign.mName );
647 }
648
649 void writeInterface( Print!(char) p, char[] name, int indent ){
650 p.formatln( "{}// {}", getIndent(indent), name );
651 char[] nodeName = split( name, "." )[ $-1 ];
652 p.formatln( "{}public interface {} {{", getIndent(indent), nodeName );
653 DefInterface intf = intfTree.getInterface( name );
654 if( intf !is null ){
655 foreach( meth; intf.mMethods ){
656 writeInterfaceMethod( p, meth, indent+1 );
657 }
658 foreach( sign; intf.mSignals ){
659 writeInterfaceSignal( p, sign, indent+1 );
660 }
661 }
662 foreach( child; intfTree.getChildNames( name ) ){
663 writeInterface( p, child, indent +1 );
664 }
665 p.formatln( "{}}", getIndent(indent) );
666 }
667
668 void writeHeader( Print!(char) p, char[] modName ){
669 static char[] HEADER =
670 "/**\n"
671 " * Generated with TioLink\n"
672 " * TioLink was written by Frank Benoit <benoit@tionex.de>\n"
673 " * http://www.dsource.org/projects/tiolink\n"
674 " *\n"
675 " * File type: D programming language source code\n"
676 " */\n";
677 p(HEADER);
678 p.formatln( "module {};", modName );
679 p.newline;
680 p.formatln( "public import org.freedesktop.dbus.Struct;" );
681 p.formatln( "public import org.freedesktop.dbus.Variant;" );
682 p.newline;
683 p.formatln( "import tango.core.Signal;" );
684 p.formatln( "import org.freedesktop.dbus.DBus;" );
685 p.formatln( "import org.freedesktop.dbus.c.Connection : DBusConnection;" );
686 p.formatln( "import org.freedesktop.dbus.c.Message : DBusMessage;" );
687 p.formatln( "import org.freedesktop.dbus.c.Shared : DBusHandlerResult;" );
688 p.newline;
689 p.newline;
690 }
691
692 void writeInterfaces( Print!(char) p ){
693
694 p.formatln( "// DBus interfaces" );
695 p.formatln( "public interface DBusInterface {{" );
696 foreach( child; intfTree.getChildNames( "" ) ){
697 writeInterface( p, child, 1 );
698 }
699 p.formatln( "}" );
700 p.newline;
701 p.newline;
702
703 }
704
705 void writePeerMethod( Print!(char) p, DefMethod mth, int indent ){
706 DefArgument retArg = mth.mDRetArgument;
707 DefArgument[] args = mth.mDArguments;
708 char[] retType = ( retArg is null ) ? "void" : retArg.toDType();
709 char[] argList;
710 foreach( idx, arg; args ){
711 if( idx > 0 ){
712 argList ~= ",";
713 }
714 argList ~= " ";
715 argList ~= (arg.mDirection == DefArgument.EDir.DIR_OUT) ? "out" : "in";
716 argList ~= " ";
717 argList ~= arg.toDType();
718 argList ~= " ";
719 argList ~= ( arg.mName.length == 0 ) ? "arg_" ~ toUtf8(idx) : arg.mName;
720 }
721 if( argList.length > 0 ){
722 argList ~= " ";
723 }
724 p.formatln( "{}public {} {}({}){{", getIndent(indent), retType, mth.mName, argList );
725 p.formatln( "{}}", getIndent(indent) );
726 }
727
728 void writePeerSignal( Print!(char) p, DefSignal sig, int indent ){
729 }
730
731 void writePeerImpl( Print!(char) p, char[] name, int indent ){
732 p.formatln( "{}// {}", getIndent(indent), name );
733 char[] nodeName = split( name, "." )[ $-1 ];
734 p.formatln( "{}public class {} : DBusPeerObject, DBusInterface.{} {{", getIndent(indent), nodeName, name );
735 DefInterface intf = intfTree.getInterface( name );
736 if( intf !is null ){
737 foreach( meth; intf.mMethods ){
738 writePeerMethod( p, meth, indent+1 );
739 }
740 foreach( sign; intf.mSignals ){
741 writePeerSignal( p, sign, indent+1 );
742 }
743 }
744 foreach( child; intfTree.getChildNames( name ) ){
745 writePeerImpl( p, child, indent +1 );
746 }
747 p.formatln( "{}}", getIndent(indent) );
748 }
749 void writePeerImpls( Print!(char) p ){
750
751 p.formatln( "// Peer implementations" );
752 p.formatln( "public interface DBusPeers {{" );
753 foreach( child; intfTree.getChildNames( "" ) ){
754 writePeerImpl( p, child, 1 );
755 }
756 p.formatln( "}" );
757 p.newline;
758 p.newline;
759
760 }
761
762 void writeDBusObject( Print!(char) p ){
763 p.formatln( "// DBusObject" );
764 p.formatln( "public class DBusObject : DBusObjectImpl, DBusInterface.org.freedesktop.DBus.Introspectable {{" );
765 p.formatln( " this(){{" );
766 p.formatln( " super();" );
767 p.formatln( " }" );
768 p.formatln( " public char[] Introspect(){{" );
769 p.formatln( " return super.Introspect();" );
770 p.formatln( " }" );
771 p.formatln( "}" );
772 p.newline;
773 p.newline;
774 }
775 void writeDBusPeerObject( Print!(char) p ){
776 p.formatln( "// DBusPeerObject" );
777 p.formatln( "public class DBusPeerObject {{" );
778 p.formatln( "}" );
779 p.newline;
780 p.newline;
781 }
782 class TextList {
783
784 private char[] separator;
785 private char[] sb;
786 private char[] prefix;
787 private char[] postfix;
788 private bool completed = false;
789
790 public this( char[] separator ){
791 this.separator = separator;
792 this.prefix = "";
793 this.postfix = "";
794 }
795 public this( char[] prefix, char[] separator, char[] postfix ){
796 this.prefix = prefix;
797 this.separator = separator;
798 this.postfix = postfix;
799 }
800
801 public static TextList createParameterList(){
802 return new TextList( " ", ", ", " " );
803 }
804
805 public void add( char[] value ){
806 if( sb.length == 0 ){
807 sb ~= prefix;
808 }
809 else{
810 sb ~= separator;
811 }
812 sb ~= value;
813 }
814 public char[] toUtf8(){
815 if( !completed ){
816 if( sb.length > 0 ){
817 sb ~= postfix;
818 }
819 completed = true;
820 }
821 return sb;
822 }
823 }
824
825 void writeHandlerInterfaceMethod( Print!(char) p, DefMethod mth ){
826 char[] sig = mth.mName ~ "|";
827 foreach( arg; mth.mArguments ){
828 if( arg.mDirection == DefArgument.EDir.DIR_IN ){
829 sig ~= arg.mType;
830 }
831 }
832
833 DefArgument retArg = mth.mDRetArgument;
834 DefArgument[] args = mth.mDArguments;
835
836 p.formatln(" case \"{}\":", sig );
837 p.formatln(" {{" );
838 TextList callParams = TextList.createParameterList();
839 TextList callTypes = TextList.createParameterList();
840 TextList callInTypes = TextList.createParameterList();
841 TextList callOutTypes = TextList.createParameterList();
842 int idxi, idxo;
843 char[] retAssign = "";
844 char[] retVar = "";
845 bool hasOutputs = false;
846 bool hasInputs = false;
847 foreach( idx, arg; mth.mArguments ){
848 callTypes.add( arg.toDType());
849 if( arg.mDirection == DefArgument.EDir.DIR_IN ){
850 hasInputs = true;
851 callInTypes.add( arg.toDType());
852 callParams.add( "pi.t["~toUtf8(idxi)~"]" );
853 idxi++;
854 }
855 else{
856 hasOutputs = true;
857 callOutTypes.add( arg.toDType());
858
859 char[] outArg = "po.t["~toUtf8(idxo)~"]";
860 idxo++;
861 if( arg is mth.mDRetArgument ){
862 retVar = outArg;
863 retAssign = retVar~" = ";
864 }
865 else{
866 callParams.add( outArg );
867 }
868 }
869 }
870 if( hasInputs ){
871 p.formatln(" Struct!({0}) pi = getCallValues!({0})( message );", callInTypes.toUtf8() );
872 }
873 if( hasOutputs ){
874 p.formatln(" Struct!({0}) po;" , callOutTypes.toUtf8() );
875 }
876 p.formatln(" {}o.{}({});", retAssign, mth.mName, callParams.toUtf8() );
877 if( hasOutputs ){
878 p.formatln(" sendReplyData!({})( conn, message, po );", callOutTypes.toUtf8() );
879 }
880 else{
881 p.formatln(" sendReply( conn, message );" );
882 }
883 p.formatln(" }" );
884 p.formatln(" break;" );
885
886
887 }
888 void writeHandlerInterfaceSignal( Print!(char) p, DefSignal sig ){
889 char[] signature = sig.mName ~ ">";
890 foreach( arg; sig.mArguments ){
891 signature ~= arg.mType;
892 }
893
894 DefArgument[] args = sig.mArguments;
895
896 p.formatln(" case \"{}\":", signature );
897 p.formatln(" {{" );
898 TextList callParams = TextList.createParameterList();
899 TextList callInTypes = TextList.createParameterList();
900 int idxi;
901 char[] retAssign = "";
902 char[] retVar = "";
903 bool hasInputs = false;
904 foreach( idx, arg; sig.mArguments ){
905 hasInputs = true;
906 callInTypes.add( arg.toDType());
907 callParams.add( "pi.t["~toUtf8(idxi)~"]" );
908 idxi++;
909 }
910 if( hasInputs ){
911 p.formatln(" Struct!({0}) pi = getCallValues!({0})( message );", callInTypes.toUtf8() );
912 }
913 p.formatln(" o.{}().opCall({});", sig.mName, callParams.toUtf8() );
914 p.formatln(" }" );
915 p.formatln(" break;" );
916
917
918 }
919 void writeHandlerInterface( Print!(char) p, DefInterface intf ){
920 p.formatln("private DBusHandlerResult intfHandler__{}( "
921 "DBusConnection* conn, DBusMessage* message, void* user_data ){{",
922 replace( intf.mName.dup, '.', '_') );
923 p.formatln(" DBusInterface.{} o = cast(DBusInterface.{0})cast(Object)user_data;", intf.mName );
924 p.formatln(" if( o is null || !checkIntf( \"{}\", message) )", intf.mName );
925 p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;" );
926 p.formatln("");
927 p.formatln(" try{{");
928 p.formatln(" char[METHOD_SIG_MAXLENGTH] buf;");
929 p.formatln(" switch( methodSignature( message, buf ) ){{");
930 foreach( DefMethod mth ; intf.mMethods ){
931 writeHandlerInterfaceMethod( p, mth );
932 }
933 foreach( DefSignal sig ; intf.mSignals ){
934 writeHandlerInterfaceSignal( p, sig );
935 }
936 p.formatln(" default:" );
937 p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_NOT_YET_HANDLED;");
938 p.formatln(" }");
939 p.formatln(" }");
940 p.formatln(" catch( Exception e ){{");
941 p.formatln(" sendException( conn, message, e );" );
942 p.formatln(" }");
943 p.formatln(" return DBusHandlerResult.DBUS_HANDLER_RESULT_HANDLED;");
944 p.formatln("}");
945 p.newline;
946 }
947 void writeHandlers( Print!(char) p ){
948
949
950 foreach( intfIdx, intf; intfTree.allInterfaces ){
951 writeHandlerInterface( p, intfTree.getInterface( intf ));
952 }
953
954 p.formatln( "private void init_handlers(){{" );
955 foreach( intfIdx, intf; intfTree.allInterfaces ){
956 p.formatln( " registerHandler(" );
957 p.formatln( " DBusInterface.{}.classinfo,", intf );
958 p.formatln( " & intfHandler__{} );", replace( intf.dup, '.', '_' ));
959 }
960 p.formatln( "}" );
961 p.newline;
962
963 }
964 void writeStaticInit( Print!(char) p ){
965 p.formatln( "static this(){{" );
966 p.formatln( " init_introspectionData();" );
967 p.formatln( " init_handlers();" );
968 p.formatln( "}" );
969 p.newline;
970 }
971
972 int main(char[][] args) {
973 try{
974 if( args.length != 3 ){
975 printSyntax();
976 throw new TerminateException(1);
977 }
978 char[] introxml = args[1];
979 char[] modname = args[2];
980 intfTree = new IntfTree();
981 auto root = parse( introxml );
982 createStdInterfaces();
983 parseNode( root );
984 Print!(char) output = Stdout;
985 writeHeader( output, modname );
986 writeInterfaces( output );
987 //writePeerImpls( output );
988 writeDBusObject( output );
989 //writeDBusPeerObject( output );
990 writeIntrospectionData( output );
991 writeHandlers( output );
992 writeStaticInit( output );
993 }
994 catch( TerminateException e ){
995 return e.code;
996 }
997 return(0);
998 }
999
1000
1001 void printSyntax() {
1002 Stdout.formatln("dbus-createinterface <introspectionsdata.xml> <modulename>");
1003 }
1004
1005
1006