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 #include "type.h"
00035 
00036 static int const primes[] =
00037 {
00038     2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
00039     31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
00040     73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
00041     127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
00042     179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
00043     233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
00044     283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
00045     353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
00046     419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
00047     467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
00048     547, 557, 563, 569, 571, 577, 587, 593, 599, 601,0
00049 };
00050 
00051 
00052 struct Function
00053 {
00054     Function(){};
00055     Function( const QString& t, const QString& n, const QString&fn, bool h ) 
00056     : type( t ), name( n ), fullName( fn ), hidden( h ) {}
00057     QString type;
00058     QString name;
00059     QString fullName;
00060     bool hidden;
00061 };
00062 
00063 
00064 /*
00065  * Writes the skeleton
00066  */
00067 void generateSkel( const QString& idl, const QString& filename, QDomElement de )
00068 {
00069     QFile skel( filename );
00070     if ( !skel.open( IO_WriteOnly ) )
00071     qFatal("Could not write to %s", filename.local8Bit().data() );
00072 
00073     QTextStream str( &skel );
00074 
00075     str << "/****************************************************************************" << endl;
00076     str << "**" << endl;
00077     str << "** DCOP Skeleton created by dcopidl2cpp from " << idl << endl;
00078     str << "**" << endl;
00079     str << "** WARNING! All changes made in this file will be lost!" << endl;
00080     str << "**" << endl;
00081     str << "*****************************************************************************/" << endl;
00082     str << endl;
00083 
00084     QDomElement e = de.firstChild().toElement();
00085     if ( e.tagName() == "SOURCE" ) {
00086     str << "#include \"" << e.firstChild().toText().data() << "\"" << endl << endl;
00087     }
00088 
00089     for( ; !e.isNull(); e = e.nextSibling().toElement() ) {
00090     if ( e.tagName() != "CLASS" )
00091         continue;
00092     QDomElement n = e.firstChild().toElement();
00093     Q_ASSERT( n.tagName() == "NAME" );
00094     QString className = n.firstChild().toText().data();
00095     // find dcop parent ( rightmost super class )
00096     QString DCOPParent;
00097     QDomElement s = n.nextSibling().toElement();
00098     for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00099         if ( s.tagName() == "SUPER" )
00100         DCOPParent = s.firstChild().toText().data();
00101     }
00102     
00103     // get function table
00104     QValueList<Function> functions;
00105     s = n.nextSibling().toElement();
00106     for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00107         if ( s.tagName() != "FUNC" )
00108         continue;
00109         QDomElement r = s.firstChild().toElement();
00110         Q_ASSERT( r.tagName() == "TYPE" );
00111         QString funcType = r.firstChild().toText().data();
00112         r = r.nextSibling().toElement();
00113         Q_ASSERT ( r.tagName() == "NAME" );
00114         QString funcName = r.firstChild().toText().data();
00115         QStringList argtypes;
00116         QStringList argnames;
00117         r = r.nextSibling().toElement();
00118         for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00119         Q_ASSERT( r.tagName() == "ARG" );
00120         QDomElement a = r.firstChild().toElement();
00121         Q_ASSERT( a.tagName() == "TYPE" );
00122         argtypes.append( a.firstChild().toText().data() );
00123         a = a.nextSibling().toElement();
00124         if ( !a.isNull() ) {
00125             Q_ASSERT( a.tagName() == "NAME" );
00126             argnames.append( a.firstChild().toText().data() );
00127         } else {
00128             argnames.append( QString::null );
00129         }
00130         }
00131         funcName += '(';
00132         QString fullFuncName = funcName;
00133         bool first = true;
00134         QStringList::Iterator ittype = argtypes.begin();
00135         QStringList::Iterator itname = argnames.begin();
00136         while ( ittype != argtypes.end() && itname != argnames.end() ) {
00137         if ( !first ) {
00138             funcName += ',';
00139             fullFuncName += ',';
00140         }
00141         first = false;
00142         funcName += *ittype;
00143         fullFuncName += *ittype;
00144         if ( ! (*itname).isEmpty() ) {
00145             fullFuncName += ' ';
00146             fullFuncName += *itname;
00147         }
00148         ++ittype;
00149         ++itname;
00150         }
00151         funcName += ')';
00152         fullFuncName += ')';
00153         bool hidden = (s.attribute("hidden") == "yes");
00154         functions.append( Function( funcType, funcName, fullFuncName, hidden ) );
00155     }
00156 
00157     // create static tables
00158     
00159     int fhash = functions.count() + 1;
00160     for ( int i = 0; primes[i]; i++ ) {
00161         if ( primes[i] >  static_cast<int>(functions.count()) ) {
00162         fhash = primes[i];
00163         break;
00164         }
00165     }
00166     
00167     str << "#include <kdatastream.h>" << endl;
00168 
00169     bool useHashing = functions.count() > 7;
00170     if ( useHashing ) {
00171         str << "#include <qasciidict.h>" << endl;
00172     }
00173 
00174     QString classNameFull = className; // class name with possible namespaces prepended
00175                        // namespaces will be removed from className now
00176     int namespace_count = 0;
00177     QString namespace_tmp = className;
00178     str << endl;
00179     for(;;) {
00180         int pos = namespace_tmp.find( "::" );
00181         if( pos < 0 ) {
00182         className = namespace_tmp;
00183         break;
00184         }
00185         str << "namespace " << namespace_tmp.left( pos ) << " {" << endl;
00186         ++namespace_count;
00187         namespace_tmp = namespace_tmp.mid( pos + 2 );
00188     }
00189 
00190     str << endl;
00191 
00192     if ( useHashing ) {
00193         str << "static const int " << className << "_fhash = " << fhash << ";" << endl;
00194     }
00195     str << "static const char* const " << className << "_ftable[" << functions.count() + 1 << "][3] = {" << endl;
00196     for( QValueList<Function>::Iterator it = functions.begin(); it != functions.end(); ++it ){
00197         str << "    { \"" << (*it).type << "\", \"" << (*it).name << "\", \"" << (*it).fullName << "\" }," << endl;
00198     }
00199     str << "    { 0, 0, 0 }" << endl;
00200     str << "};" << endl;
00201 
00202     if (functions.count() > 0) {
00203         str << "static const int " << className << "_ftable_hiddens[" << functions.count() << "] = {" << endl;
00204         for( QValueList<Function>::Iterator it = functions.begin(); it != functions.end(); ++it ){
00205         str << "    " << !!(*it).hidden << "," << endl;
00206         }
00207         str << "};" << endl;
00208     }
00209     
00210     str << endl;
00211     
00212     
00213     // Write dispatcher
00214     str << "bool " << className;
00215     str << "::process(const QCString &fun, const QByteArray &data, QCString& replyType, QByteArray &replyData)" << endl;
00216     str << "{" << endl;
00217     if ( useHashing ) {
00218         str << "    static QAsciiDict<int>* fdict = 0;" << endl;
00219     
00220         str << "    if ( !fdict ) {" << endl;
00221         str << "\tfdict = new QAsciiDict<int>( " << className << "_fhash, true, false );" << endl;
00222         str << "\tfor ( int i = 0; " << className << "_ftable[i][1]; i++ )" << endl;
00223         str << "\t    fdict->insert( " << className << "_ftable[i][1],  new int( i ) );" << endl;
00224         str << "    }" << endl;
00225     
00226         str << "    int* fp = fdict->find( fun );" << endl;
00227         str << "    switch ( fp?*fp:-1) {" << endl;
00228     }
00229     s = n.nextSibling().toElement();
00230     int fcount = 0; // counter of written functions
00231     bool firstFunc = true;
00232     for( ; !s.isNull(); s = s.nextSibling().toElement() ) {
00233         if ( s.tagName() != "FUNC" )
00234         continue;
00235         QDomElement r = s.firstChild().toElement();
00236         Q_ASSERT( r.tagName() == "TYPE" );
00237         QString funcType = r.firstChild().toText().data();
00238         if ( funcType == "ASYNC" )
00239         funcType = "void";
00240         r = r.nextSibling().toElement();
00241         Q_ASSERT ( r.tagName() == "NAME" );
00242         QString funcName = r.firstChild().toText().data();
00243         QStringList args;
00244         QStringList argtypes;
00245         r = r.nextSibling().toElement();
00246         for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00247         Q_ASSERT( r.tagName() == "ARG" );
00248         QDomElement a = r.firstChild().toElement();
00249         Q_ASSERT( a.tagName() == "TYPE" );
00250         argtypes.append( a.firstChild().toText().data() );
00251         args.append( QString("arg" ) + QString::number( args.count() ) );
00252         }
00253         QString plainFuncName = funcName;
00254         funcName += '(';
00255         bool first = true;
00256         for( QStringList::Iterator argtypes_count = argtypes.begin(); argtypes_count != argtypes.end(); ++argtypes_count ){
00257         if ( !first )
00258             funcName += ',';
00259         first = false;
00260         funcName += *argtypes_count;
00261         }
00262         funcName += ')';
00263         
00264         if ( useHashing ) {
00265         str << "    case " << fcount << ": { // " << funcType << " " << funcName << endl;
00266         } else {
00267         if ( firstFunc )
00268             str << "    if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
00269         else
00270             str << " else if ( fun == " << className << "_ftable[" << fcount << "][1] ) { // " << funcType << " " << funcName << endl;
00271         firstFunc = false;
00272         }
00273         if ( !args.isEmpty() ) {
00274         QStringList::Iterator ittypes = argtypes.begin();
00275         QStringList::Iterator args_count;
00276         for( args_count = args.begin(); args_count != args.end(); ++args_count ){
00277             str << '\t'<< *ittypes << " " << *args_count << ";" <<  endl;
00278             ++ittypes;
00279         }
00280         str << "\tQDataStream arg( data, IO_ReadOnly );" << endl;
00281         for( args_count = args.begin(); args_count != args.end(); ++args_count ){
00282             str << "\targ >> " << *args_count << ";" << endl;
00283         }
00284         }
00285 
00286         str << "\treplyType = " << className << "_ftable[" << fcount++ << "][0]; " << endl;
00287         if ( funcType == "void" ) {
00288         str << '\t' << plainFuncName << '(';
00289         } else {
00290         str << "\tQDataStream _replyStream( replyData, IO_WriteOnly );"  << endl;
00291         str << "\t_replyStream << " << plainFuncName << '(';
00292         }
00293 
00294         first = true;
00295         for ( QStringList::Iterator args_count = args.begin(); args_count != args.end(); ++args_count ){
00296         if ( !first )
00297             str << ", ";
00298         first = false;
00299         str << *args_count;
00300         }
00301         str << " );" << endl;
00302         if (useHashing ) {
00303         str << "    } break;" << endl;
00304         } else {
00305         str << "    }";
00306         }
00307     }
00308 
00309     // only open an 'else' clause if there were one or more functions
00310     if ( fcount > 0 ) {
00311         if ( useHashing ) {
00312         str << "    default: " << endl;
00313         } else {
00314         str << " else {" << endl;
00315         }
00316     }
00317     
00318     // if no DCOP function was called, delegate the request to the parent
00319     if (!DCOPParent.isEmpty()) {
00320         str << "\treturn " << DCOPParent << "::process( fun, data, replyType, replyData );" << endl;
00321     } else {
00322         str << "\treturn false;" << endl;
00323     }
00324 
00325     // only close the 'else' clause and add the default 'return true'
00326     // (signifying a DCOP method was found and called) if there were
00327     // one or more functions.
00328     if ( fcount > 0 ) {
00329         str << "    }" << endl;
00330         str << "    return true;" << endl;
00331     }
00332 
00333     // close the 'process' function
00334     str << "}" << endl << endl;
00335     
00336     str << "QCStringList " << className;
00337     str << "::interfaces()" << endl;
00338     str << "{" << endl;
00339     if (!DCOPParent.isEmpty()) {
00340         str << "    QCStringList ifaces = " << DCOPParent << "::interfaces();" << endl;
00341     } else {
00342         str << "    QCStringList ifaces;" << endl;
00343     }
00344     str << "    ifaces += \"" << classNameFull << "\";" << endl;
00345     str << "    return ifaces;" << endl;
00346     str << "}" << endl << endl;
00347     
00348     
00349     str << "QCStringList " << className;
00350     str << "::functions()" << endl;
00351     str << "{" << endl;
00352     if (!DCOPParent.isEmpty()) {
00353         str << "    QCStringList funcs = " << DCOPParent << "::functions();" << endl;
00354     } else {
00355         str << "    QCStringList funcs;" << endl;
00356     }
00357     str << "    for ( int i = 0; " << className << "_ftable[i][2]; i++ ) {" << endl;
00358         if (functions.count() > 0) {
00359         str << "\tif (" << className << "_ftable_hiddens[i])" << endl;
00360         str << "\t    continue;" << endl;
00361         }
00362     str << "\tQCString func = " << className << "_ftable[i][0];" << endl;
00363     str << "\tfunc += ' ';" << endl;
00364     str << "\tfunc += " << className << "_ftable[i][2];" << endl;
00365     str << "\tfuncs << func;" << endl;
00366     str << "    }" << endl;
00367     str << "    return funcs;" << endl;
00368     str << "}" << endl << endl;
00369     
00370     // Add signal stubs
00371     for(s = e.firstChild().toElement(); !s.isNull(); s = s.nextSibling().toElement() ) {
00372         if (s.tagName() != "SIGNAL")
00373         continue;
00374         QDomElement r = s.firstChild().toElement();
00375         QString result = writeType( str, r );
00376 
00377         r = r.nextSibling().toElement();
00378         Q_ASSERT ( r.tagName() == "NAME" );
00379         QString funcName = r.firstChild().toText().data();
00380         str << className << "::" << funcName << "(";
00381 
00382         QStringList args;
00383         QStringList argtypes;
00384         bool first = true;
00385         r = r.nextSibling().toElement();
00386         for( ; !r.isNull(); r = r.nextSibling().toElement() ) {
00387         if ( !first )
00388             str << ", ";
00389         else
00390             str << " ";
00391         first = false;
00392         Q_ASSERT( r.tagName() == "ARG" );
00393         QDomElement a = r.firstChild().toElement();
00394         QString type = writeType( str, a );
00395         argtypes.append( type );
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     }
00435 
00436     for(; namespace_count > 0; --namespace_count )
00437         str << "} // namespace" << endl;
00438     str << endl;
00439     }
00440     
00441     skel.close();
00442 }
00443 
00444 // :set expandtab!<RETURN>:set ts=8<RETURN>:set sts=4<RETURN>:set sw=4<RETURN>
KDE Logo
This file is part of the documentation for dcop Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Wed Aug 4 05:22:38 2004 by doxygen 1.3.4 written by Dimitri van Heesch, © 1997-2003