dcop Library API Documentation

skel.cpp

00001 /*****************************************************************
00002 Copyright (c) 1999 Torben Weis <weis@kde.org>
00003 Copyright (c) 2000 Matthias Ettrich <ettrich@kde.org>
00004 
00005 Permission is hereby granted, free of charge, to any person obtaining a copy
00006 of this software and associated documentation files (the "Software"), to deal
00007 in the Software without restriction, including without limitation the rights
00008 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00009 copies of the Software, and to permit persons to whom the Software is
00010 furnished to do so, subject to the following conditions:
00011 
00012 The above copyright notice and this permission notice shall be included in
00013 all copies or substantial portions of the Software.
00014 
00015 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00016 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00017 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00018 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00019 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00020 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00021 
00022 ******************************************************************/
00023 #include <qdom.h>
00024 #include <qfile.h>
00025 #include <qtextstream.h>
00026 #include <qstring.h>
00027 #include <qstringlist.h>
00028 
00029 #include <string.h>
00030 #include <stdlib.h>
00031 #include <stdio.h>
00032 #include <unistd.h>
00033 #include "main.h"
00034 
00035 static int const primes[] =
00036 {
00037     2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
00038     31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
00039     73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
00040     127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
00041     179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
00042     233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
00043     283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
00044     353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
00045     419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
00046     467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
00047     547, 557, 563, 569, 571, 577, 587, 593, 599, 601,0
00048 };
00049 
00050 
00051 struct Function
00052 {
00053     Function(){};
00054     Function( const QString& t, const QString& n, const QString&fn ) : type( t ), name( n ), fullName( fn ){}
00055     QString type;
00056     QString name;
00057     QString fullName;
00058 };
00059 
00060 
00064 void generateSkel( const QString& idl, const QString& filename, QDomElement de )
00065 {
00066     QFile skel( filename );
00067     if ( !skel.open( IO_WriteOnly ) )
00068     qFatal("Could not write to %s", filename.local8Bit().data() );
00069 
00070     QTextStream str( &skel );
00071 
00072     str << "/****************************************************************************" << endl;
00073     str << "**" << endl;
00074     str << "** DCOP Skeleton created by dcopidl2cpp from " << idl << endl;
00075     str << "**" << endl;
00076     str << "** WARNING! All changes made in this file will be lost!" << endl;
00077     str << "**" << endl;
00078     str << "*****************************************************************************/" << endl;
00079     str << endl;
00080 
00081     QDomElement e = de.firstChild().toElement();
00082     if ( e.tagName() == "SOURCE" ) {
00083     str << "#include \"" << e.firstChild().toText().data() << "\"" << endl << endl;
00084     }
00085 
00086     for( ; !e.isNull(); e = e.nextSibling().toElement() ) {
00087     if ( e.tagName() == "CLASS" ) {
00088         QDomElement n = e.firstChild().toElement();
00089         Q_ASSERT( n.tagName() == "NAME" );
00090         QString className = n.firstChild().toText().data();
00091         // find dcop parent ( rightmost super class )
00092         QString DCOPParent;
00093         QDomElement s = n.nextSibling().toElement();
00094         for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00095         if ( s.tagName() == "SUPER" )
00096             DCOPParent = s.firstChild().toText().data();
00097         }
00098     
00099         // get function table
00100         QValueList<Function> functions;
00101         s = n.nextSibling().toElement();
00102         for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00103         if ( s.tagName() == "FUNC" ) {
00104             QDomElement r = s.firstChild().toElement();
00105             Q_ASSERT( r.tagName() == "TYPE" );
00106             QString funcType = r.firstChild().toText().data();
00107             r = r.nextSibling().toElement();
00108             Q_ASSERT ( r.tagName() == "NAME" );
00109             QString funcName = r.firstChild().toText().data();
00110             QStringList argtypes;
00111             QStringList argnames;
00112             r = r.nextSibling().toElement();
00113             for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00114             Q_ASSERT( r.tagName() == "ARG" );
00115             QDomElement a = r.firstChild().toElement();
00116             Q_ASSERT( a.tagName() == "TYPE" );
00117             argtypes.append( a.firstChild().toText().data() );
00118             a = a.nextSibling().toElement();
00119             if ( !a.isNull() ) {
00120                 Q_ASSERT( a.tagName() == "NAME" );
00121                 argnames.append( a.firstChild().toText().data() );
00122             } else {
00123                 argnames.append( QString::null );
00124             }
00125             }
00126             funcName += '(';
00127             QString fullFuncName = funcName;
00128             bool first = TRUE;
00129             QStringList::Iterator ittype = argtypes.begin();
00130             QStringList::Iterator itname = argnames.begin();
00131             while ( ittype != argtypes.end() && itname != argnames.end() ) {
00132             if ( !first ) {
00133                 funcName += ',';
00134                 fullFuncName += ',';
00135             }
00136             first = FALSE;
00137             funcName += *ittype;
00138             fullFuncName += *ittype;
00139             if ( ! (*itname).isEmpty() ) {
00140                 fullFuncName += ' ';
00141                 fullFuncName += *itname;
00142             }
00143             ++ittype;
00144             ++itname;
00145             }
00146             funcName += ')';
00147             fullFuncName += ')';
00148             functions.append( Function( funcType, funcName, fullFuncName ) );
00149         }
00150         }
00151 
00152         // create static tables
00153     
00154         int fhash = functions.count() + 1;
00155         for ( int i = 0; primes[i]; i++ ) {
00156         if ( primes[i] >  static_cast<int>(functions.count()) ) {
00157             fhash = primes[i];
00158             break;
00159         }
00160         }
00161     
00162         str << "#include <kdatastream.h>" << endl;
00163 
00164         bool useHashing = functions.count() > 7;
00165         if ( useHashing ) {
00166         str << "#include <qasciidict.h>" << endl;
00167         }
00168 
00169             QString classNameFull = className; // class name with possible namespaces prepended
00170                                                // namespaces will be removed from className now
00171             int namespace_count = 0;
00172             QString namespace_tmp = className;
00173             str << endl;
00174             for(;;) {
00175                 int pos = namespace_tmp.find( "::" );
00176                 if( pos < 0 )
00177                     {
00178                     className = namespace_tmp;
00179                     break;
00180                     }
00181                 str << "namespace " << namespace_tmp.left( pos ) << " {" << endl;
00182                 ++namespace_count;
00183                 namespace_tmp = namespace_tmp.mid( pos + 2 );
00184             }
00185 
00186             str << endl;
00187 
00188         if ( useHashing ) {
00189         str << "static const int " << className << "_fhash = " << fhash << ";" << endl;
00190         }
00191         str << "static const char* const " << className << "_ftable[" << functions.count() + 1 << "][3] = {" << endl;
00192         for( QValueList<Function>::Iterator it = functions.begin(); it != functions.end(); ++it ){
00193         str << "    { \"" << (*it).type << "\", \"" << (*it).name << "\", \"" << (*it).fullName << "\" }," << endl;
00194         }
00195         str << "    { 0, 0, 0 }" << endl;
00196         str << "};" << endl;
00197     
00198         str << endl;
00199     
00200     
00201         // Write dispatcher
00202         str << "bool " << className;
00203         str << "::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)" << endl;
00204         str << "{" << endl;
00205         if ( useHashing ) {
00206         str << "    static QAsciiDict<int>* fdict = 0;" << endl;
00207     
00208         str << "    if ( !fdict ) {" << endl;
00209         str << "\tfdict = new QAsciiDict<int>( " << className << "_fhash, TRUE, FALSE );" << endl;
00210         str << "\tfor ( int i = 0; " << className << "_ftable[i][1]; i++ )" << endl;
00211         str << "\t    fdict->insert( " << className << "_ftable[i][1],  new int( i ) );" << endl;
00212         str << "    }" << endl;
00213     
00214         str << "    int* fp = fdict->find( fun );" << endl;
00215         str << "    switch ( fp?*fp:-1) {" << endl;
00216         }
00217         s = n.nextSibling().toElement();
00218         int fcount = 0; // counter of written functions
00219         bool firstFunc = TRUE;
00220         for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00221         if ( s.tagName() == "FUNC" ) {
00222             QDomElement r = s.firstChild().toElement();
00223             Q_ASSERT( r.tagName() == "TYPE" );
00224             QString funcType = r.firstChild().toText().data();
00225             if ( funcType == "ASYNC" )
00226             funcType = "void";
00227             r = r.nextSibling().toElement();
00228             Q_ASSERT ( r.tagName() == "NAME" );
00229             QString funcName = r.firstChild().toText().data();
00230             QStringList args;
00231             QStringList argtypes;
00232             r = r.nextSibling().toElement();
00233             for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00234             Q_ASSERT( r.tagName() == "ARG" );
00235             QDomElement a = r.firstChild().toElement();
00236             Q_ASSERT( a.tagName() == "TYPE" );
00237             argtypes.append( a.firstChild().toText().data() );
00238             args.append( QString("arg" ) + QString::number( args.count() ) );
00239             }
00240             QString plainFuncName = funcName;
00241             funcName += '(';
00242             bool first = TRUE;
00243             for( QStringList::Iterator argtypes_count = argtypes.begin(); argtypes_count != argtypes.end(); ++argtypes_count ){
00244             if ( !first )
00245                 funcName += ',';
00246             first = FALSE;
00247             funcName += *argtypes_count;
00248             }
00249             funcName += ')';
00250             
00251             if ( useHashing ) {
00252             str << "    case " << fcount << ": { // " << funcType << " " << funcName << endl;
00253             } else {
00254             if ( firstFunc )
00255                 str << "    if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
00256             else
00257                 str << " else if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
00258             firstFunc = FALSE;
00259             }
00260             if ( !args.isEmpty() ) {
00261             QStringList::Iterator ittypes = argtypes.begin();
00262             QStringList::Iterator args_count;
00263             for( args_count = args.begin(); args_count != args.end(); ++args_count ){
00264                 str << '\t'<< *ittypes << " " << *args_count << ";" <<  endl;
00265                 ++ittypes;
00266             }
00267             str << "\tQDataStream arg( data, IO_ReadOnly );" << endl;
00268             for( args_count = args.begin(); args_count != args.end(); ++args_count ){
00269                 str << "\targ >> " << *args_count << ";" << endl;
00270             }
00271             }
00272 
00273             str << "\treplyType = " << className << "_ftable[" << fcount++ << "][0]; " << endl;
00274             if ( funcType == "void" ) {
00275             str << '\t' << plainFuncName << '(';
00276             } else {
00277             str << "\tQDataStream _replyStream( replyData, IO_WriteOnly );"  << endl;
00278             str << "\t_replyStream << " << plainFuncName << '(';
00279             }
00280 
00281             first = TRUE;
00282             for ( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
00283             if ( !first )
00284                 str << ", ";
00285             first = FALSE;
00286             str << *args_count;
00287             }
00288             str << " );" << endl;
00289             if (useHashing ) {
00290             str << "    } break;" << endl;
00291             } else {
00292             str << "    }";
00293             }
00294         }
00295         }
00296 
00297             // only open an 'else' clause if there were one or more functions
00298         if ( fcount > 0 ) {
00299         if ( useHashing ) {
00300             str << "    default: " << endl;
00301         } else {
00302             str << " else {" << endl;
00303         }
00304         }
00305         
00306         // if no DCOP function was called, delegate the request to the parent
00307         if (!DCOPParent.isEmpty()) {
00308         str << "\treturn " << DCOPParent << "::process( fun, data, replyType, replyData );" << endl;
00309         } else {
00310         str << "\treturn FALSE;" << endl;
00311         }
00312 
00313             // only close the 'else' clause and add the default 'return TRUE'
00314             // (signifying a DCOP method was found and called) if there were
00315             // one or more functions.
00316         if ( fcount > 0 ) {
00317             str << "    }" << endl;
00318             str << "    return TRUE;" << endl;
00319         }
00320 
00321             // close the 'process' function
00322             str << "}" << endl << endl;
00323     
00324         str << "QCStringList " << className;
00325         str << "::interfaces()" << endl;
00326         str << "{" << endl;
00327         if (!DCOPParent.isEmpty()) {
00328         str << "    QCStringList ifaces = " << DCOPParent << "::interfaces();" << endl;
00329         } else {
00330         str << "    QCStringList ifaces;" << endl;
00331         }
00332         str << "    ifaces += \"" << classNameFull << "\";" << endl;
00333         str << "    return ifaces;" << endl;
00334         str << "}" << endl << endl;
00335         
00336         
00337         str << "QCStringList " << className;
00338         str << "::functions()" << endl;
00339         str << "{" << endl;
00340         if (!DCOPParent.isEmpty()) {
00341         str << "    QCStringList funcs = " << DCOPParent << "::functions();" << endl;
00342         } else {
00343         str << "    QCStringList funcs;" << endl;
00344         }
00345         str << "    for ( int i = 0; " << className << "_ftable[i][2]; i++ ) {" << endl;
00346         str << "\tQCString func = " << className << "_ftable[i][0];" << endl;
00347         str << "\tfunc += ' ';" << endl;
00348         str << "\tfunc += " << className << "_ftable[i][2];" << endl;
00349         str << "\tfuncs << func;" << endl;
00350         str << "    }" << endl;
00351         str << "    return funcs;" << endl;
00352         str << "}" << endl << endl;
00353         
00354         // Add signal stubs
00355 
00356         // Go over all children of the CLASS tag
00357         for(s = e.firstChild().toElement(); !s.isNull(); s = s.nextSibling().toElement() ) {
00358             if (s.tagName() == "SIGNAL") {
00359             QDomElement r = s.firstChild().toElement();
00360             Q_ASSERT( r.tagName() == "TYPE" );
00361             QString result = r.firstChild().toText().data();
00362             if ( r.hasAttribute( "qleft" ) )
00363             str << r.attribute("qleft") << " ";
00364             str << result;
00365             if ( r.hasAttribute( "qright" ) )
00366             str << r.attribute("qright") << " ";
00367             else
00368             str << " ";
00369 
00370             r = r.nextSibling().toElement();
00371             Q_ASSERT ( r.tagName() == "NAME" );
00372             QString funcName = r.firstChild().toText().data();
00373             str << className << "::" << funcName << "(";
00374 
00375             QStringList args;
00376             QStringList argtypes;
00377             bool first = TRUE;
00378             r = r.nextSibling().toElement();
00379             for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00380             if ( !first )
00381                 str << ", ";
00382             else
00383                 str << " ";
00384             first = FALSE;
00385             Q_ASSERT( r.tagName() == "ARG" );
00386             QDomElement a = r.firstChild().toElement();
00387             Q_ASSERT( a.tagName() == "TYPE" );
00388             if ( a.hasAttribute( "qleft" ) )
00389                 str << a.attribute("qleft") << " ";
00390             argtypes.append( a.firstChild().toText().data() );
00391             str << argtypes.last();
00392             if ( a.hasAttribute( "qright" ) )
00393                 str << a.attribute("qright") << " ";
00394             else
00395                 str << " ";
00396             args.append( QString("arg" ) + QString::number( args.count() ) ) ;
00397             str << args.last();
00398             }
00399             if ( !first )
00400             str << " ";
00401             str << ")";
00402 
00403             if ( s.hasAttribute("qual") )
00404             str << " " << s.attribute("qual");
00405             str << endl;
00406         
00407             str << "{" << endl ;
00408 
00409             funcName += "(";
00410             first = TRUE;
00411             for( QStringList::Iterator it = argtypes.begin(); it != argtypes.end(); ++it ){
00412             if ( !first )
00413                 funcName += ",";
00414             first = FALSE;
00415             funcName += *it;
00416             }
00417             funcName += ")";
00418         
00419             if ( result != "void" )
00420                        qFatal("Error in DCOP signal %s::%s: DCOP signals can not return values.", className.latin1(), funcName.latin1());
00421         
00422             str << "    QByteArray data;" << endl;
00423             if ( !args.isEmpty() ) {
00424                 str << "    QDataStream arg( data, IO_WriteOnly );" << endl;
00425             for( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
00426                 str << "    arg << " << *args_count << ";" << endl;
00427             }
00428             }
00429 
00430                     str << "    emitDCOPSignal( \"" << funcName << "\", data );" << endl;
00431 
00432             str << "}" << endl << endl;
00433             
00434             } // if SIGNAL tag
00435         } // for each class function 
00436 
00437             for(;
00438                  namespace_count > 0;
00439                  --namespace_count )
00440                 str << "} // namespace" << endl;
00441             str << endl;
00442 
00443     } // if CLASS tag
00444     } // for each CLASS-level tag
00445     
00446     skel.close();
00447 }
KDE Logo
This file is part of the documentation for kdelibs Version 3.1.0.
Documentation copyright © 1996-2002 the KDE developers.
Generated on Wed Oct 8 12:20:25 2003 by doxygen 1.2.18 written by Dimitri van Heesch, © 1997-2001