00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
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 
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     
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     
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     
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; 
00175                        
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     
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; 
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     
00310     if ( fcount > 0 ) {
00311         if ( useHashing ) {
00312         str << "    default: " << endl;
00313         } else {
00314         str << " else {" << endl;
00315         }
00316     }
00317     
00318     
00319     if (!DCOPParent.isEmpty()) {
00320         str << "\treturn " << DCOPParent << "::process( fun, data, replyType, replyData );" << endl;
00321     } else {
00322         str << "\treturn false;" << endl;
00323     }
00324 
00325     
00326     
00327     
00328     if ( fcount > 0 ) {
00329         str << "    }" << endl;
00330         str << "    return true;" << endl;
00331     }
00332 
00333     
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     
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