summaryrefslogtreecommitdiffstats
path: root/dcop/dcopidl2cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dcop/dcopidl2cpp')
-rw-r--r--dcop/dcopidl2cpp/Makefile.am20
-rw-r--r--dcop/dcopidl2cpp/dcopidl_test.h109
-rw-r--r--dcop/dcopidl2cpp/main.cpp128
-rw-r--r--dcop/dcopidl2cpp/main.h40
-rw-r--r--dcop/dcopidl2cpp/skel.cpp445
-rw-r--r--dcop/dcopidl2cpp/stub.cpp216
-rw-r--r--dcop/dcopidl2cpp/stubimpl.cpp277
-rw-r--r--dcop/dcopidl2cpp/type.h22
8 files changed, 1257 insertions, 0 deletions
diff --git a/dcop/dcopidl2cpp/Makefile.am b/dcop/dcopidl2cpp/Makefile.am
new file mode 100644
index 000000000..9b9a6b599
--- /dev/null
+++ b/dcop/dcopidl2cpp/Makefile.am
@@ -0,0 +1,20 @@
+
+INCLUDES = $(all_includes)
+AM_LDFLAGS = $(all_libraries)
+
+####### Files
+
+bin_PROGRAMS = dcopidl2cpp
+
+dcopidl2cpp_SOURCES = main.cpp skel.cpp stub.cpp stubimpl.cpp
+noinst_HEADERS = main.h
+
+dcopidl2cpp_LDADD = $(LIB_QT)
+dcopidl2cpp_LDFLAGS = $(KDE_RPATH) $(AM_LDFLAGS)
+
+dcopidl_output.kidl: ../dcopidl/dcopidl $(srcdir)/dcopidl_test.h
+ ../dcopidl/dcopidl $(srcdir)/dcopidl_test.h > dcopidl_output.kidl
+
+check-local: dcopidl_output.kidl
+ ./dcopidl2cpp dcopidl_output.kidl
+ $(MD5SUM) dcopidl_output_*
diff --git a/dcop/dcopidl2cpp/dcopidl_test.h b/dcop/dcopidl2cpp/dcopidl_test.h
new file mode 100644
index 000000000..a6c625abe
--- /dev/null
+++ b/dcop/dcopidl2cpp/dcopidl_test.h
@@ -0,0 +1,109 @@
+#include <klistview.h>
+#include "main.h"
+
+#ifndef TEST_H
+#define TEST_H
+
+// still todo:
+// stub:
+// - includes to super relationship, a bit much to test, needs multiple files?
+
+class KDEUI_EXPORT DefaultTest : public QObject, virtual public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ DefaultTest();
+ void nonDcopFunction( QString filename, QString url, QString text, QString address, QString icon );
+k_dcop:
+ void noArgsTest();
+ void argsTest( QString filename, QString url );
+ void unNamedArgsTest( QString, QString );
+
+ void constTest( QString, QString ) const;
+ QStringList writeTypeTest( const QString &, QPtrList<int> );
+
+ void voidReturnType( QString filename, QString url, QString text, QString address, QString icon );
+ QString nonVoidReturnType( QString filename, QString text, QString address );
+ int intReturnType( QString filename, QString text, QString address );
+ bool boolReturnType( QString filename, QString text, QString address );
+
+ ASYNC asyncTest( QString filename, QString text, QString address );
+};
+
+namespace TestNamespace {
+ class NamespaceTest
+ {
+ K_DCOP
+ public:
+ NamespaceTest();
+ k_dcop:
+ void function1( QString filename, QString url, QString text, QString address, QString icon );
+ };
+}
+
+class NoSuper
+{
+ K_DCOP
+public:
+ NoSuper();
+k_dcop:
+ void function1( QString filename, QString url, QString text, QString address, QString icon );
+};
+
+class NonDCOPObject : public MyDCOPObjectBase
+{
+ K_DCOP
+public:
+ NonDCOPObject();
+k_dcop:
+ void function1( QString filename, QString url, QString text, QString address, QString icon );
+};
+
+class NoFunctions : public DCOPObject
+{
+ K_DCOP
+public:
+ NonDCOPObject();
+ void nonDcopFunction( QString filename, QString url, QString text, QString address, QString icon );
+};
+
+class NonHashingTest : public QObject, virtual public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ NonHashingTest();
+k_dcop:
+ void function1( QString );
+};
+
+class HashingTest : public QObject, virtual public DCOPObject
+{
+ Q_OBJECT
+ K_DCOP
+public:
+ HashingTest();
+k_dcop:
+ void function1( QString );
+ void function2( QString, QString );
+ void function3( QString, QString, QString );
+ void function4( QString, QString, QString, QString );
+ void function5( QString, QString, QString, QString, QString );
+ void function6( QString, QString, QString, QString, QString, QString );
+ void function7( QString, QString, QString, QString, QString, QString, QString );
+ void function8( QString, QString, QString, QString, QString, QString, QString, QString );
+};
+
+class SignalTest : virtual public DCOPObject
+{
+ K_DCOP
+public:
+ SignalTest(QCString objId = "KBookmarkNotifier") : DCOPObject(objId) {}
+k_dcop_signals:
+ void signal1( QString filename, QString url, QString text, QString address, QString icon );
+ void signal2( QString filename, QString text, QString address );
+ void signal3( QString filename, QString url );
+};
+
+#endif // end
diff --git a/dcop/dcopidl2cpp/main.cpp b/dcop/dcopidl2cpp/main.cpp
new file mode 100644
index 000000000..32d128c30
--- /dev/null
+++ b/dcop/dcopidl2cpp/main.cpp
@@ -0,0 +1,128 @@
+/*****************************************************************
+Copyright (c) 1999 Torben Weis <weis@kde.org>
+Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstring.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "main.h"
+
+
+
+void usage()
+{
+ fprintf( stderr, "Usage: dcopidl2cpp [ --no-skel | --no-stub ] [--c++-suffix <suffix>] file\n" );
+}
+
+int main( int argc, char** argv )
+{
+
+ if ( *qVersion() == '1' ) {
+ fprintf( stderr, "dcopidl2cpp appears to be linked to Qt 1 instead of Qt >= 2 ! Aborting.\n" );
+ exit(1);
+ }
+ if ( argc < 2 ) {
+ usage();
+ return 1;
+ }
+ int argpos = 1;
+ bool generate_skel = true;
+ bool generate_stub = true;
+
+ QString suffix = "cpp";
+
+ while (argc > 2) {
+
+ if ( strcmp( argv[argpos], "--no-skel" ) == 0 )
+ {
+ generate_skel = false;
+ for (int i = argpos; i < argc - 1; i++) argv[i] = argv[i+1];
+ argc--;
+ }
+ else if ( strcmp( argv[argpos], "--no-stub" ) == 0 )
+ {
+ generate_stub = false;
+ for (int i = argpos; i < argc - 1; i++) argv[i] = argv[i+1];
+ argc--;
+ }
+ else if ( strcmp( argv[argpos], "--no-signals" ) == 0 )
+ {
+ // Obsolete: Signal stubs are now always generated.
+ // Leave this command line argument intact, so old Makefiles won't break.
+ for (int i = argpos; i < argc - 1; i++) argv[i] = argv[i+1];
+ argc--;
+ }
+ else if ( strcmp( argv[argpos], "--c++-suffix" ) == 0)
+ {
+ if (argc - 1 < argpos) {
+ usage();
+ exit(1);
+ }
+ suffix = argv[argpos+1];
+ for (int i = argpos; i < argc - 2; i++) argv[i] = argv[i+2];
+ argc -= 2;
+ } else {
+ usage();
+ exit(1);
+ }
+ }
+
+ QFile in( QFile::decodeName(argv[argpos]) );
+ if ( !in.open( IO_ReadOnly ) )
+ qFatal("Could not read %s", argv[argpos] );
+
+ QDomDocument doc;
+ doc.setContent( &in );
+
+ QDomElement de = doc.documentElement();
+ Q_ASSERT( de.tagName() == "DCOP-IDL" );
+
+ QString base( argv[argpos] );
+ QString idl = base;
+
+ int pos = base.findRev( '.' );
+ if ( pos != -1 )
+ base = base.left( pos );
+
+ pos = idl.findRev('/');
+ if ( pos != -1 )
+ idl = idl.mid( pos+1 );
+
+ if ( generate_skel )
+ generateSkel( idl, base + "_skel." + suffix, de );
+
+ if ( generate_stub ) {
+ QString header = base;
+ generateStub( idl, header + "_stub.h", de );
+ pos = header.findRev('/');
+ if ( pos != -1 )
+ header = header.mid( pos+1 );
+ generateStubImpl( idl, header + "_stub.h", base+".h", base + "_stub." + suffix, de);
+ }
+
+ return 0;
+}
diff --git a/dcop/dcopidl2cpp/main.h b/dcop/dcopidl2cpp/main.h
new file mode 100644
index 000000000..a0ecdb250
--- /dev/null
+++ b/dcop/dcopidl2cpp/main.h
@@ -0,0 +1,40 @@
+/*****************************************************************
+Copyright (c) 1999 Torben Weis <weis@kde.org>
+Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+#include <qdom.h>
+#include <qstring.h>
+
+/**
+ * Writes the skeleton
+ */
+void generateSkel( const QString& idl, const QString& filename, QDomElement de );
+
+/**
+ * Writes the stubs header
+ */
+void generateStub( const QString& idl, const QString& filename, QDomElement de);
+
+/**
+ * Writes the stub implementation
+ */
+void generateStubImpl( const QString& idl, const QString& header, const QString& headerBase, const QString& filename, QDomElement de);
+
diff --git a/dcop/dcopidl2cpp/skel.cpp b/dcop/dcopidl2cpp/skel.cpp
new file mode 100644
index 000000000..fe79aec92
--- /dev/null
+++ b/dcop/dcopidl2cpp/skel.cpp
@@ -0,0 +1,445 @@
+/*****************************************************************
+Copyright (c) 1999 Torben Weis <weis@kde.org>
+Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "main.h"
+#include "type.h"
+
+static int const primes[] =
+{
+ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
+ 31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
+ 73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
+ 127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
+ 179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
+ 233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
+ 283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
+ 353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
+ 419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
+ 467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
+ 547, 557, 563, 569, 571, 577, 587, 593, 599, 601,0
+};
+
+
+struct Function
+{
+ Function(){}
+ Function( const QString& t, const QString& n, const QString&fn, bool h )
+ : type( t ), name( n ), fullName( fn ), hidden( h ) {}
+ QString type;
+ QString name;
+ QString fullName;
+ bool hidden;
+};
+
+
+/*
+ * Writes the skeleton
+ */
+void generateSkel( const QString& idl, const QString& filename, QDomElement de )
+{
+ QFile skel( filename );
+ if ( !skel.open( IO_WriteOnly ) )
+ qFatal("Could not write to %s", filename.local8Bit().data() );
+
+ QTextStream str( &skel );
+
+ str << "/****************************************************************************" << endl;
+ str << "**" << endl;
+ str << "** DCOP Skeleton generated by dcopidl2cpp from " << idl << endl;
+ str << "**" << endl;
+ str << "** WARNING! All changes made in this file will be lost!" << endl;
+ str << "**" << endl;
+ str << "*****************************************************************************/" << endl;
+ str << endl;
+
+ QDomElement e = de.firstChild().toElement();
+ if ( e.tagName() == "SOURCE" ) {
+ str << "#include \"" << e.firstChild().toText().data() << "\"" << endl << endl;
+ }
+
+ for( ; !e.isNull(); e = e.nextSibling().toElement() ) {
+ if ( e.tagName() != "CLASS" )
+ continue;
+ QDomElement n = e.firstChild().toElement();
+ Q_ASSERT( n.tagName() == "NAME" );
+ QString className = n.firstChild().toText().data();
+ // find dcop parent ( rightmost super class )
+ QString DCOPParent;
+ QDomElement s = n.nextSibling().toElement();
+ for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
+ if ( s.tagName() == "SUPER" )
+ DCOPParent = s.firstChild().toText().data();
+ }
+
+ // get function table
+ QValueList<Function> functions;
+ s = n.nextSibling().toElement();
+ for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
+ if ( s.tagName() != "FUNC" )
+ continue;
+ QDomElement r = s.firstChild().toElement();
+ Q_ASSERT( r.tagName() == "TYPE" );
+ QString funcType = r.firstChild().toText().data();
+ r = r.nextSibling().toElement();
+ Q_ASSERT ( r.tagName() == "NAME" );
+ QString funcName = r.firstChild().toText().data();
+ QStringList argtypes;
+ QStringList argnames;
+ r = r.nextSibling().toElement();
+ for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
+ Q_ASSERT( r.tagName() == "ARG" );
+ QDomElement a = r.firstChild().toElement();
+ Q_ASSERT( a.tagName() == "TYPE" );
+ argtypes.append( a.firstChild().toText().data() );
+ a = a.nextSibling().toElement();
+ if ( !a.isNull() ) {
+ Q_ASSERT( a.tagName() == "NAME" );
+ argnames.append( a.firstChild().toText().data() );
+ } else {
+ argnames.append( QString::null );
+ }
+ }
+ funcName += '(';
+ QString fullFuncName = funcName;
+ bool first = true;
+ QStringList::Iterator ittype = argtypes.begin();
+ QStringList::Iterator itname = argnames.begin();
+ while ( ittype != argtypes.end() && itname != argnames.end() ) {
+ if ( !first ) {
+ funcName += ',';
+ fullFuncName += ',';
+ }
+ first = false;
+ funcName += *ittype;
+ fullFuncName += *ittype;
+ if ( ! (*itname).isEmpty() ) {
+ fullFuncName += ' ';
+ fullFuncName += *itname;
+ }
+ ++ittype;
+ ++itname;
+ }
+ funcName += ')';
+ fullFuncName += ')';
+ bool hidden = (s.attribute("hidden") == "yes");
+ functions.append( Function( funcType, funcName, fullFuncName, hidden ) );
+ }
+
+ // create static tables
+
+ int fhash = functions.count() + 1;
+ for ( int i = 0; primes[i]; i++ ) {
+ if ( primes[i] > static_cast<int>(functions.count()) ) {
+ fhash = primes[i];
+ break;
+ }
+ }
+
+ str << "#include <kdatastream.h>" << endl;
+
+ bool useHashing = functions.count() > 7;
+ if ( useHashing ) {
+ str << "#include <qasciidict.h>" << endl;
+ }
+
+ QString classNameFull = className; // class name with possible namespaces prepended
+ // namespaces will be removed from className now
+ int namespace_count = 0;
+ QString namespace_tmp = className;
+ str << endl;
+ for(;;) {
+ int pos = namespace_tmp.find( "::" );
+ if( pos < 0 ) {
+ className = namespace_tmp;
+ break;
+ }
+ str << "namespace " << namespace_tmp.left( pos ) << " {" << endl;
+ ++namespace_count;
+ namespace_tmp = namespace_tmp.mid( pos + 2 );
+ }
+
+ str << endl;
+
+ if ( useHashing ) {
+ str << "static const int " << className << "_fhash = " << fhash << ";" << endl;
+ }
+ str << "static const char* const " << className << "_ftable[" << functions.count() + 1 << "][3] = {" << endl;
+ for( QValueList<Function>::Iterator it = functions.begin(); it != functions.end(); ++it ){
+ str << " { \"" << (*it).type << "\", \"" << (*it).name << "\", \"" << (*it).fullName << "\" }," << endl;
+ }
+ str << " { 0, 0, 0 }" << endl;
+ str << "};" << endl;
+
+ if (functions.count() > 0) {
+ str << "static const int " << className << "_ftable_hiddens[" << functions.count() << "] = {" << endl;
+ for( QValueList<Function>::Iterator it = functions.begin(); it != functions.end(); ++it ){
+ str << " " << !!(*it).hidden << "," << endl;
+ }
+ str << "};" << endl;
+ }
+
+ str << endl;
+
+
+ // Write dispatcher
+ str << "bool " << className;
+ str << "::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)" << endl;
+ str << "{" << endl;
+ if ( useHashing ) {
+ str << " static QAsciiDict<int>* fdict = 0;" << endl;
+
+ str << " if ( !fdict ) {" << endl;
+ str << "\tfdict = new QAsciiDict<int>( " << className << "_fhash, true, false );" << endl;
+ str << "\tfor ( int i = 0; " << className << "_ftable[i][1]; i++ )" << endl;
+ str << "\t fdict->insert( " << className << "_ftable[i][1], new int( i ) );" << endl;
+ str << " }" << endl;
+
+ str << " int* fp = fdict->find( fun );" << endl;
+ str << " switch ( fp?*fp:-1) {" << endl;
+ }
+ s = n.nextSibling().toElement();
+ int fcount = 0; // counter of written functions
+ bool firstFunc = true;
+ for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
+ if ( s.tagName() != "FUNC" )
+ continue;
+ QDomElement r = s.firstChild().toElement();
+ Q_ASSERT( r.tagName() == "TYPE" );
+ QString funcType = r.firstChild().toText().data();
+ if ( funcType == "ASYNC" )
+ funcType = "void";
+ r = r.nextSibling().toElement();
+ Q_ASSERT ( r.tagName() == "NAME" );
+ QString funcName = r.firstChild().toText().data();
+ QStringList args;
+ QStringList argtypes;
+ r = r.nextSibling().toElement();
+ for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
+ Q_ASSERT( r.tagName() == "ARG" );
+ QDomElement a = r.firstChild().toElement();
+ Q_ASSERT( a.tagName() == "TYPE" );
+ argtypes.append( a.firstChild().toText().data() );
+ args.append( QString("arg" ) + QString::number( args.count() ) );
+ }
+ QString plainFuncName = funcName;
+ funcName += '(';
+ bool first = true;
+ for( QStringList::Iterator argtypes_count = argtypes.begin(); argtypes_count != argtypes.end(); ++argtypes_count ){
+ if ( !first )
+ funcName += ',';
+ first = false;
+ funcName += *argtypes_count;
+ }
+ funcName += ')';
+
+ if ( useHashing ) {
+ str << " case " << fcount << ": { // " << funcType << " " << funcName << endl;
+ } else {
+ if ( firstFunc )
+ str << " if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
+ else
+ str << " else if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
+ firstFunc = false;
+ }
+ if ( !args.isEmpty() ) {
+ QStringList::Iterator ittypes = argtypes.begin();
+ QStringList::Iterator args_count;
+ for( args_count = args.begin(); args_count != args.end(); ++args_count ){
+ str << '\t'<< *ittypes << " " << *args_count << ";" << endl;
+ ++ittypes;
+ }
+ str << "\tQDataStream arg( data, IO_ReadOnly );" << endl;
+ for( args_count = args.begin(); args_count != args.end(); ++args_count ){
+ str << "\tif (arg.atEnd()) return false;" << endl; // Basic error checking
+ str << "\targ >> " << *args_count << ";" << endl;
+ }
+ }
+
+ str << "\treplyType = " << className << "_ftable[" << fcount++ << "][0]; " << endl;
+ if ( funcType == "void" ) {
+ str << '\t' << plainFuncName << '(';
+ } else {
+ str << "\tQDataStream _replyStream( replyData, IO_WriteOnly );" << endl;
+ str << "\t_replyStream << " << plainFuncName << '(';
+ }
+
+ first = true;
+ for ( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
+ if ( !first )
+ str << ", ";
+ first = false;
+ str << *args_count;
+ }
+ str << " );" << endl;
+ if (useHashing ) {
+ str << " } break;" << endl;
+ } else {
+ str << " }";
+ }
+ }
+
+ // only open an 'else' clause if there were one or more functions
+ if ( fcount > 0 ) {
+ if ( useHashing ) {
+ str << " default: " << endl;
+ } else {
+ str << " else {" << endl;
+ }
+ }
+
+ // if no DCOP function was called, delegate the request to the parent
+ if (!DCOPParent.isEmpty()) {
+ str << "\treturn " << DCOPParent << "::process( fun, data, replyType, replyData );" << endl;
+ } else {
+ str << "\treturn false;" << endl;
+ }
+
+ // only close the 'else' clause and add the default 'return true'
+ // (signifying a DCOP method was found and called) if there were
+ // one or more functions.
+ if ( fcount > 0 ) {
+ str << " }" << endl;
+ str << " return true;" << endl;
+ }
+
+ // close the 'process' function
+ str << "}" << endl << endl;
+
+ str << "QCStringList " << className;
+ str << "::interfaces()" << endl;
+ str << "{" << endl;
+ if (!DCOPParent.isEmpty()) {
+ str << " QCStringList ifaces = " << DCOPParent << "::interfaces();" << endl;
+ } else {
+ str << " QCStringList ifaces;" << endl;
+ }
+ str << " ifaces += \"" << classNameFull << "\";" << endl;
+ str << " return ifaces;" << endl;
+ str << "}" << endl << endl;
+
+
+ str << "QCStringList " << className;
+ str << "::functions()" << endl;
+ str << "{" << endl;
+ if (!DCOPParent.isEmpty()) {
+ str << " QCStringList funcs = " << DCOPParent << "::functions();" << endl;
+ } else {
+ str << " QCStringList funcs;" << endl;
+ }
+ str << " for ( int i = 0; " << className << "_ftable[i][2]; i++ ) {" << endl;
+ if (functions.count() > 0) {
+ str << "\tif (" << className << "_ftable_hiddens[i])" << endl;
+ str << "\t continue;" << endl;
+ }
+ str << "\tQCString func = " << className << "_ftable[i][0];" << endl;
+ str << "\tfunc += ' ';" << endl;
+ str << "\tfunc += " << className << "_ftable[i][2];" << endl;
+ str << "\tfuncs << func;" << endl;
+ str << " }" << endl;
+ str << " return funcs;" << endl;
+ str << "}" << endl << endl;
+
+ // Add signal stubs
+ for(s = e.firstChild().toElement(); !s.isNull(); s = s.nextSibling().toElement() ) {
+ if (s.tagName() != "SIGNAL")
+ continue;
+ QDomElement r = s.firstChild().toElement();
+ QString result = writeType( str, r );
+
+ r = r.nextSibling().toElement();
+ Q_ASSERT ( r.tagName() == "NAME" );
+ QString funcName = r.firstChild().toText().data();
+ str << className << "::" << funcName << "(";
+
+ QStringList args;
+ QStringList argtypes;
+ bool first = true;
+ r = r.nextSibling().toElement();
+ for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
+ if ( !first )
+ str << ", ";
+ else
+ str << " ";
+ first = false;
+ Q_ASSERT( r.tagName() == "ARG" );
+ QDomElement a = r.firstChild().toElement();
+ QString type = writeType( str, a );
+ argtypes.append( type );
+ args.append( QString("arg" ) + QString::number( args.count() ) ) ;
+ str << args.last();
+ }
+ if ( !first )
+ str << " ";
+ str << ")";
+
+ if ( s.hasAttribute("qual") )
+ str << " " << s.attribute("qual");
+ str << endl;
+
+ str << "{" << endl ;
+
+ funcName += "(";
+ first = true;
+ for( QStringList::Iterator it = argtypes.begin(); it != argtypes.end(); ++it ){
+ if ( !first )
+ funcName += ",";
+ first = false;
+ funcName += *it;
+ }
+ funcName += ")";
+
+ if ( result != "void" )
+ qFatal("Error in DCOP signal %s::%s: DCOP signals can not return values.", className.latin1(), funcName.latin1());
+
+ str << " QByteArray data;" << endl;
+ if ( !args.isEmpty() ) {
+ str << " QDataStream arg( data, IO_WriteOnly );" << endl;
+ for( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
+ str << " arg << " << *args_count << ";" << endl;
+ }
+ }
+
+ str << " emitDCOPSignal( \"" << funcName << "\", data );" << endl;
+
+ str << "}" << endl << endl;
+
+ }
+
+ for(; namespace_count > 0; --namespace_count )
+ str << "} // namespace" << endl;
+ str << endl;
+ }
+
+ skel.close();
+}
+
+// :set expandtab!<RETURN>:set ts=8<RETURN>:set sts=4<RETURN>:set sw=4<RETURN>
diff --git a/dcop/dcopidl2cpp/stub.cpp b/dcop/dcopidl2cpp/stub.cpp
new file mode 100644
index 000000000..4060ae88f
--- /dev/null
+++ b/dcop/dcopidl2cpp/stub.cpp
@@ -0,0 +1,216 @@
+/*****************************************************************
+Copyright (c) 1999 Torben Weis <weis@kde.org>
+Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "main.h"
+#include "type.h"
+
+/*
+ * Writes the stubs header
+ */
+void generateStub( const QString& idl, const QString& filename, QDomElement de)
+{
+ QFile stub( filename );
+ if ( !stub.open( IO_WriteOnly ) )
+ qFatal("Could not write to %s", filename.local8Bit().data() );
+
+ QTextStream str( &stub );
+
+ str << "/****************************************************************************" << endl;
+ str << "**" << endl;
+ str << "** DCOP Stub Definition created by dcopidl2cpp from " << idl << endl;
+ str << "**" << endl;
+ str << "** WARNING! All changes made in this file will be lost!" << endl;
+ str << "**" << endl;
+ str << "*****************************************************************************/" << endl;
+ str << endl;
+
+ QString ifdefstring = idl.upper();
+ int pos = idl.findRev( '.' );
+ if ( pos != -1 )
+ ifdefstring = ifdefstring.left( pos );
+
+ QString ifdefsuffix = "_STUB__";
+ str << "#ifndef __" << ifdefstring << ifdefsuffix << endl;
+ str << "#define __" << ifdefstring << ifdefsuffix << endl << endl;
+
+ str << "#include <dcopstub.h>" << endl;
+
+ QStringList includeslist, all_includes;
+ QDomElement e = de.firstChild().toElement();
+ for( ; !e.isNull(); e = e.nextSibling().toElement() ) {
+ if ( e.tagName() == "INCLUDE" ) {
+ // dcopidl lists the includes in reversed order because of the used yacc/bison gramatic
+ // so let's reverse it back, as the order may be important
+ includeslist.prepend( e.firstChild().toText().data());
+ continue;
+ }
+ if( !includeslist.empty()) {
+ for( QStringList::ConstIterator it = includeslist.begin();
+ it != includeslist.end();
+ ++it ) {
+ str << "#include <" << ( *it ) << ">" << endl;
+ all_includes.append( *it );
+ }
+ includeslist.clear();
+ }
+ if ( e.tagName() != "CLASS" )
+ continue;
+
+ str << endl;
+
+ QDomElement n = e.firstChild().toElement();
+ Q_ASSERT( n.tagName() == "NAME" );
+ QString className = n.firstChild().toText().data() + ( "_stub" );
+
+ //add link scope, if available
+ n = n.nextSibling().toElement();
+ QString linkScope;
+ if (n.tagName()=="LINK_SCOPE") {
+ linkScope = n.firstChild().toText().data() + " ";
+ n = n.nextSibling().toElement();
+ }
+
+ // find dcop parent ( rightmost super class )
+ QString DCOPParent;
+ for( ; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if ( n.tagName() == "SUPER" )
+ DCOPParent = n.firstChild().toText().data();
+ }
+
+ if( DCOPParent != "DCOPObject" ) { // we need to include the .h file for the base stub
+ if( all_includes.contains( DCOPParent + ".h" ))
+ str << "#include <" << DCOPParent << "_stub.h>" << endl;
+ else if( all_includes.contains( DCOPParent.lower() + ".h" ))
+ str << "#include <" << DCOPParent.lower() << "_stub.h>" << endl;
+ else {// damn ... let's assume it's the last include
+ QString stub_h = all_includes.last();
+ unsigned int pos = stub_h.find( ".h" );
+ if( pos > 0 ) {
+ stub_h = stub_h.remove( pos, 100000 );
+ str << "#include <" << stub_h << "_stub.h>" << endl;
+ }
+ else
+ str << "#include <" << stub_h << ">" << endl;
+ }
+ }
+
+ QString classNameFull = className; // class name with possible namespaces prepended
+ // namespaces will be removed from className now
+ int namespace_count = 0;
+ QString namespace_tmp = className;
+ for(;;) {
+ int pos = namespace_tmp.find( "::" );
+ if( pos < 0 ) {
+ className = namespace_tmp;
+ break;
+ }
+ str << "namespace " << namespace_tmp.left( pos ) << " {" << endl;
+ ++namespace_count;
+ namespace_tmp = namespace_tmp.mid( pos + 2 );
+ }
+
+ str << endl;
+
+ // Stub class definition
+ str << "class " << linkScope << className;
+
+ // Parent : inherited interface stub or dcopstub
+ if ( !DCOPParent.isEmpty() && DCOPParent != "DCOPObject" ) {
+ str << " : ";
+ str << "virtual public " << DCOPParent << "_stub";
+ } else {
+ str << " : virtual public DCOPStub";
+ }
+
+ str << endl;
+ str << "{" << endl;
+ str << "public:" << endl;
+
+ // Constructors
+ str << " " << className << "( const QCString& app, const QCString& id );" << endl;
+ str << " " << className << "( DCOPClient* client, const QCString& app, const QCString& id );" << endl;
+ str << " explicit " << className << "( const DCOPRef& ref );" << endl;
+
+ n = e.firstChild().toElement();
+ for( ; !n.isNull(); n = n.nextSibling().toElement() ) {
+ if (n.tagName() != "FUNC")
+ continue;
+ QDomElement r = n.firstChild().toElement();
+ str << " virtual "; // KDE4 - I really don't think these need to be virtual
+ writeType( str, r );
+
+ r = r.nextSibling().toElement();
+ Q_ASSERT ( r.tagName() == "NAME" );
+ str << r.firstChild().toText().data() << "(";
+
+ bool first = true;
+ r = r.nextSibling().toElement();
+ for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
+ if ( !first )
+ str << ", ";
+ else
+ str << " ";
+ first = false;
+ Q_ASSERT( r.tagName() == "ARG" );
+ QDomElement a = r.firstChild().toElement();
+ writeType( str, a );
+ a = a.nextSibling().toElement();
+ if ( a.tagName() == "NAME" )
+ str << a.firstChild().toText().data();
+ }
+ if ( !first )
+ str << " ";
+ str << ")";
+
+ //const methods stubs can't compile, they need to call setStatus().
+ //if ( n.hasAttribute("qual") )
+ // str << " " << n.attribute("qual");
+ str << ";" << endl;
+ }
+
+ // needed for inherited stubs
+ str << "protected:" << endl;
+ str << " " << className << "() : DCOPStub( never_use ) {}" << endl;
+
+ str << "};" << endl;
+ str << endl;
+
+ for(; namespace_count > 0; --namespace_count )
+ str << "} // namespace" << endl;
+ str << endl;
+ }
+
+ str << "#endif" << endl;
+ stub.close();
+}
+
+// :set expandtab!<RETURN>:set ts=8<RETURN>:set sts=4<RETURN>:set sw=4<RETURN>
diff --git a/dcop/dcopidl2cpp/stubimpl.cpp b/dcop/dcopidl2cpp/stubimpl.cpp
new file mode 100644
index 000000000..22c11527b
--- /dev/null
+++ b/dcop/dcopidl2cpp/stubimpl.cpp
@@ -0,0 +1,277 @@
+/*****************************************************************
+Copyright (c) 1999 Torben Weis <weis@kde.org>
+Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+#include <qdom.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qstring.h>
+#include <qstringlist.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "main.h"
+#include "type.h"
+
+static bool isIntType( const QString& t )
+{
+ return ((t == "int")
+ || (t == "signed int")
+ || (t == "unsigned int")
+ || (t == "uint")
+ || (t == "unsigned")
+ || (t == "signed short int")
+ || (t == "signed short")
+ || (t == "short int")
+ || (t == "short")
+ || (t == "unsigned short int")
+ || (t == "unsigned short")
+ || (t == "ushort")
+ || (t == "long int")
+ || (t == "signed long int")
+ || (t == "long")
+ || (t == "signed long")
+ || (t == "unsigned long int")
+ || (t == "unsigned long")
+ || (t == "ulong")
+ || (t == "char")
+ || (t == "signed char")
+ || (t == "unsigned char"));
+}
+
+/*
+ * Writes the stub implementation
+ */
+void generateStubImpl( const QString& idl, const QString& header, const QString& /*headerBase*/, const QString& filename, QDomElement de )
+{
+ QFile impl( filename );
+ if ( !impl.open( IO_WriteOnly ) )
+ qFatal("Could not write to %s", filename.latin1() );
+
+ QTextStream str( &impl );
+
+ str << "/****************************************************************************" << endl;
+ str << "**" << endl;
+ str << "** DCOP Stub Implementation created by dcopidl2cpp from " << idl << endl;
+ str << "**" << endl;
+ str << "** WARNING! All changes made in this file will be lost!" << endl;
+ str << "**" << endl;
+ str << "*****************************************************************************/" << endl;
+ str << endl;
+
+ str << "#include \"" << header << "\"" << endl;
+ str << "#include <dcopclient.h>" << endl << endl;
+ str << "#include <kdatastream.h>" << endl;
+
+ QDomElement e = de.firstChild().toElement();
+ for( ; !e.isNull(); e = e.nextSibling().toElement() ) {
+ if ( e.tagName() != "CLASS" )
+ continue;
+ QDomElement n = e.firstChild().toElement();
+ Q_ASSERT( n.tagName() == "NAME" );
+ QString classNameBase = n.firstChild().toText().data();
+ QString className_stub = classNameBase + "_stub";
+
+ QString classNameFull = className_stub; // class name with possible namespaces prepended
+ // namespaces will be removed from className now
+ int namespace_count = 0;
+ QString namespace_tmp = className_stub;
+ str << endl;
+ for(;;) {
+ int pos = namespace_tmp.find( "::" );
+ if( pos < 0 ) {
+ className_stub = namespace_tmp;
+ break;
+ }
+ str << "namespace " << namespace_tmp.left( pos ) << " {" << endl;
+ ++namespace_count;
+ namespace_tmp = namespace_tmp.mid( pos + 2 );
+ }
+
+ str << endl;
+
+ // Write constructors
+ str << className_stub << "::" << className_stub << "( const QCString& app, const QCString& obj )" << endl;
+ str << " : ";
+
+ // Always explicitly call DCOPStub constructor, because it's virtual base class.
+ // Calling other ones doesn't matter, as they don't do anything important.
+ str << "DCOPStub( app, obj )" << endl;
+
+ str << "{" << endl;
+ str << "}" << endl << endl;
+
+ str << className_stub << "::" << className_stub << "( DCOPClient* client, const QCString& app, const QCString& obj )" << endl;
+ str << " : ";
+
+ str << "DCOPStub( client, app, obj )" << endl;
+
+ str << "{" << endl;
+ str << "}" << endl << endl;
+
+ str << className_stub << "::" << className_stub << "( const DCOPRef& ref )" << endl;
+ str << " : ";
+
+ str << "DCOPStub( ref )" << endl;
+
+ str << "{" << endl;
+ str << "}" << endl << endl;
+
+ // Write marshalling code
+ QDomElement s = e.firstChild().toElement();
+ for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
+ if (s.tagName() != "FUNC")
+ continue;
+ QDomElement r = s.firstChild().toElement();
+ Q_ASSERT( r.tagName() == "TYPE" );
+ QString result = r.firstChild().toText().data();
+ bool async = result == "ASYNC";
+ if ( async) {
+ result = "void";
+ str << result << " ";
+ } else
+ result = writeType( str, r );
+
+ r = r.nextSibling().toElement();
+ Q_ASSERT ( r.tagName() == "NAME" );
+ QString funcName = r.firstChild().toText().data();
+ str << className_stub << "::" << funcName << "(";
+
+ QStringList args;
+ QStringList argtypes;
+ bool first = true;
+ r = r.nextSibling().toElement();
+ for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
+ if ( !first )
+ str << ", ";
+ else
+ str << " ";
+ first = false;
+ Q_ASSERT( r.tagName() == "ARG" );
+ QDomElement a = r.firstChild().toElement();
+ QString type = writeType( str, a );
+ argtypes.append( type );
+ args.append( QString("arg" ) + QString::number( args.count() ) ) ;
+ str << args.last();
+ }
+ if ( !first )
+ str << " ";
+ str << ")";
+
+ //const methods in a stub can't compile, they need to call setStatus()
+ //if ( s.hasAttribute("qual") )
+ // str << " " << s.attribute("qual");
+ str << endl;
+
+ str << "{" << endl ;
+
+
+ funcName += "(";
+ first = true;
+ for( QStringList::Iterator it = argtypes.begin(); it != argtypes.end(); ++it ){
+ if ( !first )
+ funcName += ",";
+ first = false;
+ funcName += *it;
+ }
+ funcName += ")";
+
+ if ( async ) {
+
+ str << " if ( !dcopClient() ) {"<< endl;
+ str << "\tsetStatus( CallFailed );" << endl;
+ str << "\treturn;" << endl;
+ str << " }" << endl;
+
+ str << " QByteArray data;" << endl;
+ if ( !args.isEmpty() ) {
+ str << " QDataStream arg( data, IO_WriteOnly );" << endl;
+ for( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
+ str << " arg << " << *args_count << ";" << endl;
+ }
+ }
+
+ str << " dcopClient()->send( app(), obj(), \"" << funcName << "\", data );" << endl;
+ str << " setStatus( CallSucceeded );" << endl;
+
+ } else {
+
+ if ( result != "void" ) {
+ str << " " << result << " result";
+ if (isIntType( result ))
+ str << " = 0";
+ else if (result == "float" || result == "double")
+ str << " = 0.0";
+ else if ( result == "bool" )
+ str << " = false";
+
+ str << ";" << endl;
+ }
+
+ str << " if ( !dcopClient() ) {"<< endl;
+ str << "\tsetStatus( CallFailed );" << endl;
+ if ( result != "void" )
+ str << "\treturn result;" << endl;
+ else
+ str << "\treturn;" << endl;
+ str << " }" << endl;
+
+ str << " QByteArray data, replyData;" << endl;
+ str << " QCString replyType;" << endl;
+
+ if ( !args.isEmpty() ) {
+ str << " QDataStream arg( data, IO_WriteOnly );" << endl;
+ for( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
+ str << " arg << " << *args_count << ";" << endl;
+ }
+ }
+ str << " if ( dcopClient()->call( app(), obj(), \"" << funcName << "\",";
+ str << " data, replyType, replyData ) ) {" << endl;
+ if ( result != "void" ) {
+ str << "\tif ( replyType == \"" << result << "\" ) {" << endl;
+ str << "\t QDataStream _reply_stream( replyData, IO_ReadOnly );" << endl;
+ str << "\t _reply_stream >> result;" << endl;
+ str << "\t setStatus( CallSucceeded );" << endl;
+ str << "\t} else {" << endl;
+ str << "\t callFailed();" << endl;
+ str << "\t}" << endl;
+ } else {
+ str << "\tsetStatus( CallSucceeded );" << endl;
+ }
+ str << " } else { " << endl;
+ str << "\tcallFailed();" << endl;
+ str << " }" << endl;
+ if ( result != "void" )
+ str << " return result;" << endl;
+ }
+ str << "}" << endl << endl;
+ }
+
+ for(; namespace_count > 0; --namespace_count )
+ str << "} // namespace" << endl;
+ str << endl;
+ }
+ impl.close();
+}
+
+// :set expandtab!<RETURN>:set ts=8<RETURN>:set sts=4<RETURN>:set sw=4<RETURN>
diff --git a/dcop/dcopidl2cpp/type.h b/dcop/dcopidl2cpp/type.h
new file mode 100644
index 000000000..baaacacfb
--- /dev/null
+++ b/dcop/dcopidl2cpp/type.h
@@ -0,0 +1,22 @@
+#ifndef TYPE_H
+#define TYPE_H
+
+#include <qtextstream.h>
+#include <qdom.h>
+
+static QString writeType( QTextStream& str, const QDomElement& r )
+{
+ Q_ASSERT( r.tagName() == "TYPE" );
+ if ( r.hasAttribute( "qleft" ) )
+ str << r.attribute("qleft") << " ";
+ QString t = r.firstChild().toText().data();
+ t = t.replace( ">>", "> >" );
+ str << t;
+ if ( r.hasAttribute( "qright" ) )
+ str << r.attribute("qright") << " ";
+ else
+ str << " ";
+ return t;
+}
+
+#endif