Mercurial > projects > dbus-d
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 |