/* * This file is part of the Trinity Desktop Environment * * Original file taken from the OpenSUSE tdebase builds * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include // TODO includes, forwards /* FUNCTION RETURN_TYPE DELAYED_RETURN - use DCOP transaction in kded module, function will take some time to finish SKIP_QT - don't generate in qt file ONLY_QT - generate only in qt file ADD_APPINFO - generate wmclass arguments ARG TYPE ORIG_TYPE - for example when the function accepts TQWidget*, but WId is really used ORIG_CONVERSION IGNORE NEEDS_DEREF CONST_REF OUT_ARGUMENT CONVERSION BACK_CONVERSION - for out arguments CREATE - doesn't exist in TQt, create in qtkde using function PARENT - the argument is a parent window to be used for windows ENDARG ENDFUNCTION */ struct Arg { Arg() : ignore( false ), needs_deref( false ), const_ref( false ), out_argument( false ), parent( false ) {} TQString name; TQString type; TQString orig_type; TQString orig_conversion; bool ignore; bool needs_deref; bool const_ref; bool out_argument; TQString conversion; TQString back_conversion; TQString create; bool parent; }; struct Function { Function() : delayed_return( false ), skip_qt( false ), only_qt( false ), add_appinfo( false ) {} TQString name; TQString return_type; bool delayed_return; bool skip_qt; bool only_qt; bool add_appinfo; TQValueList< Arg > args; void stripNonOutArguments(); void stripCreatedArguments(); }; void Function::stripNonOutArguments() { TQValueList< Arg > new_args; for( TQValueList< Arg >::ConstIterator it = args.begin(); it != args.end(); ++it ) { const Arg& arg = (*it); if( arg.out_argument ) new_args.append( arg ); } args = new_args; } void Function::stripCreatedArguments() { TQValueList< Arg > new_args; for( TQValueList< Arg >::ConstIterator it = args.begin(); it != args.end(); ++it ) { const Arg& arg = (*it); if( arg.create.isEmpty()) new_args.append( arg ); } args = new_args; } TQValueList< Function > functions; TQFile* input_file = NULL; TQTextStream* input_stream = NULL; static TQString last_line; int last_lineno = 0; #define check( arg ) my_check( __FILE__, __LINE__, arg ) #define error() my_error( __FILE__, __LINE__ ) void my_error( const char* file, int line ) { fprintf( stderr, "Error: %s: %d\n", file, line ); fprintf( stderr, "Line %d: %s\n", last_lineno, last_line.utf8().data()); abort(); } void my_check( const char* file, int line, bool arg ) { if( !arg ) my_error( file, line ); } void openInputFile( const TQString& filename ) { check( input_file == NULL ); input_file = new TQFile( filename ); printf("[INFO] Reading bindings definitions from file %s\n\r", filename.ascii()); if( !input_file->open( IO_ReadOnly )) error(); input_stream = new TQTextStream( input_file ); last_lineno = 0; } TQString getInputLine() { while( !input_stream->atEnd()) { TQString line = input_stream->readLine().stripWhiteSpace(); ++last_lineno; last_line = line; if( line.isEmpty() || line[ 0 ] == '#' ) continue; return line; } return TQString(); } void closeInputFile() { delete input_stream; delete input_file; input_stream = NULL; input_file = NULL; } void parseArg( Function& function, const TQString& details ) { Arg arg; arg.name = details; TQString line = getInputLine(); while( !line.isNull() ) { if( line.startsWith( "ENDARG" )) { check( !arg.type.isEmpty()); function.args.append( arg ); return; } else if( line.startsWith( "TYPE" )) { check( arg.type.isEmpty()); arg.type = line.mid( strlen( "TYPE" )).stripWhiteSpace(); } else if( line.startsWith( "ORIG_TYPE" )) { check( arg.orig_type.isEmpty()); arg.orig_type = line.mid( strlen( "ORIG_TYPE" )).stripWhiteSpace(); } else if( line.startsWith( "ORIG_CONVERSION" )) { check( arg.orig_conversion.isEmpty()); arg.orig_conversion = line.mid( strlen( "ORIG_CONVERSION" )).stripWhiteSpace(); } else if( line.startsWith( "IGNORE" )) { check( !arg.out_argument ); arg.ignore = true; } else if( line.startsWith( "NEEDS_DEREF" )) { check( !arg.const_ref ); arg.needs_deref = true; } else if( line.startsWith( "CONST_REF" )) { check( !arg.needs_deref ); check( !arg.out_argument ); arg.const_ref = true; } else if( line.startsWith( "OUT_ARGUMENT" )) { check( !arg.ignore ); check( !arg.const_ref ); arg.out_argument = true; } else if( line.startsWith( "CONVERSION" )) { check( arg.conversion.isEmpty()); arg.conversion = line.mid( strlen( "CONVERSION" )).stripWhiteSpace(); } else if( line.startsWith( "BACK_CONVERSION" )) { check( arg.back_conversion.isEmpty()); arg.back_conversion = line.mid( strlen( "BACK_CONVERSION" )).stripWhiteSpace(); } else if( line.startsWith( "CREATE" )) { check( arg.create.isEmpty()); arg.create = line.mid( strlen( "CREATE" )).stripWhiteSpace(); } else if( line.startsWith( "PARENT" )) { arg.parent = true; } else error(); line = getInputLine(); } error(); } void parseFunction( const TQString& details ) { Function function; function.name = details; TQString line = getInputLine(); while( !line.isNull() ) { if( line.startsWith( "ENDFUNCTION" )) { if( function.add_appinfo ) { Arg arg; arg.name = "wmclass1"; arg.type = "TQCString"; arg.const_ref = true; arg.create = "tqAppName"; function.args.append( arg ); arg.name = "wmclass2"; arg.create = "tqAppClass"; function.args.append( arg ); } check( !function.return_type.isEmpty()); functions.append( function ); return; } else if( line.startsWith( "RETURN_TYPE" )) { check( function.return_type.isEmpty()); function.return_type = line.mid( strlen( "RETURN_TYPE" )).stripWhiteSpace(); } else if( line.startsWith( "DELAYED_RETURN" )) function.delayed_return = true; else if( line.startsWith( "SKIP_QT" )) function.skip_qt = true; else if( line.startsWith( "ONLY_QT" )) function.only_qt = true; else if( line.startsWith( "ADD_APPINFO" )) function.add_appinfo = true; else if( line.startsWith( "ARG" )) { parseArg( function, line.mid( strlen( "ARG" )).stripWhiteSpace()); } else error(); line = getInputLine(); } error(); } void parse(TQString filename) { openInputFile( filename ); TQString line = getInputLine(); while( !line.isNull() ) { if( line.startsWith( "FUNCTION" )) { parseFunction( line.mid( strlen( "FUNCTION" )).stripWhiteSpace()); } else error(); line = getInputLine(); } closeInputFile(); } TQString makeIndent( int indent ) { return indent > 0 ? TQString().fill( ' ', indent ) : ""; } void generateFunction( TQTextStream& stream, const Function& function, const TQString name, int indent, bool staticf, bool orig_type, bool ignore_deref, int ignore_level ) { TQString line; line += makeIndent( indent ); if( staticf ) line += "static "; line += function.return_type + " " + name + "("; bool need_comma = false; for( TQValueList< Arg >::ConstIterator it = function.args.begin(); it != function.args.end(); ++it ) { const Arg& arg = (*it); if( ignore_level >= 2 && arg.ignore ) continue; if( need_comma ) { line += ","; if( line.length() > 80 ) { stream << line << "\n"; line = makeIndent( indent + 4 ); } else line += " "; } else line += " "; need_comma = true; if( orig_type && !arg.orig_type.isEmpty()) line += arg.orig_type; else { if( arg.const_ref ) line += "const "; line += arg.type; if( !ignore_deref && arg.needs_deref ) line += "*"; if( arg.const_ref ) line += "&"; } if( ignore_level >= 1 && arg.ignore ) line += " /*" + arg.name + "*/"; else line += " " + arg.name; } line += " )"; stream << line; } void generateTQtH() { TQFile file( "qtkdeintegration_x11_p.h.gen" ); if( !file.open( IO_WriteOnly )) error(); TQTextStream stream( &file ); for( TQValueList< Function >::ConstIterator it = functions.begin(); it != functions.end(); ++it ) { Function f = *it; if( f.skip_qt ) continue; f.stripCreatedArguments(); generateFunction( stream, f, f.name, 8, true /*static*/, true /*orig type*/, false /*ignore deref*/, 0 /*ignore level*/ ); stream << ";\n"; } } void generateTQtCpp() { TQFile file( "qtkdeintegration_x11.cpp.gen" ); if( !file.open( IO_WriteOnly )) error(); TQTextStream stream( &file ); for( TQValueList< Function >::ConstIterator it = functions.begin(); it != functions.end(); ++it ) { Function f = *it; if( f.only_qt ) continue; f.stripCreatedArguments(); generateFunction( stream, f, "(*qtkde_" + f.name + ")", 0, true /*static*/, false /*orig type*/, false /*ignore deref*/, 0 /*ignore level*/ ); stream << ";\n"; } stream << "\n" "void TQKDEIntegration::initLibrary()\n" " {\n" " if( !inited )\n" " {\n" " enable = false;\n" " inited = true;\n" " TQString libpath = findLibrary();\n" " if( libpath.isEmpty())\n" " return;\n" " TQLibrary lib( libpath );\n" " if( !TQFile::exists( lib.library())) // avoid stupid TQt warning\n" " return;\n" " lib.setAutoUnload( false );\n"; for( TQValueList< Function >::ConstIterator it = functions.begin(); it != functions.end(); ++it ) { Function function = *it; if( function.only_qt ) continue; stream << makeIndent( 8 ) + "qtkde_" + function.name + " = (\n"; function.stripCreatedArguments(); generateFunction( stream, function, "(*)", 12, false /*static*/, false /*orig type*/, false /*ignore deref*/, 0 /*ignore level*/ ); stream << "\n" + makeIndent( 12 ) + ")\n"; stream << makeIndent( 12 ) + "lib.resolve(\"" + (*it).name + "\");\n"; stream << makeIndent( 8 ) + "if( qtkde_" + (*it).name + " == NULL )\n"; stream << makeIndent( 12 ) + "return;\n"; } stream << " enable = qtkde_initializeIntegration();\n" " }\n" " }\n" "\n"; for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { Function function = *it1; if( function.skip_qt || function.only_qt ) continue; function.stripCreatedArguments(); generateFunction( stream, function, "QKDEIntegration::" + function.name, 0, false /*static*/, true /*orig type*/, false /*ignore deref*/, 0 /*ignore level*/ ); stream << "\n"; stream << makeIndent( 4 ) + "{\n"; stream << makeIndent( 4 ) + "return qtkde_" + function.name + "(\n"; stream << makeIndent( 8 ); bool need_comma = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( need_comma ) stream << ", "; need_comma = true; if( !arg.orig_conversion.isEmpty()) { stream << arg.orig_conversion + "( " + arg.name + " )"; } else stream << arg.name; } stream << " );\n"; stream << makeIndent( 4 ) + "}\n"; } } void generateTQt() { generateTQtH(); generateTQtCpp(); } void generateTQtKde() { TQFile file( "tqtkde_functions.cpp" ); if( !file.open( IO_WriteOnly )) error(); TQTextStream stream( &file ); for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; Function stripped_function = function; stripped_function.stripCreatedArguments(); stream << "extern \"C\"\n"; generateFunction( stream, stripped_function, stripped_function.name, 0, false /*static*/, false /*orig type*/, false /*ignore deref*/, 1 /*ignore level*/ ); stream << "\n"; stream << " {\n" " if( qt_xdisplay() != NULL )\n" " XSync( qt_xdisplay(), False );\n"; TQString parent_arg; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; if( arg.parent ) { parent_arg = arg.name; break; } } if( !parent_arg.isEmpty()) { stream << " if( " << parent_arg << " == 0 )\n"; stream << " DCOPRef( \"kded\", \"MainApplication-Interface\" ).call( \"updateUserTimestamp\", qt_x_time );\n"; } stream << " TQByteArray data, replyData;\n" " TQCString replyType;\n"; if( !function.args.isEmpty()) { stream << " TQDataStream datastream( data, IO_WriteOnly );\n"; stream << " datastream"; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; stream << " << "; if( !(arg.conversion).isNull() ) stream << arg.conversion + "( "; if( !arg.create.isEmpty()) stream << arg.create + "()"; else { if( arg.needs_deref ) stream << "( " << arg.name << " != NULL ? *" << arg.name << " : " << arg.type << "())"; else stream << arg.name; } if( !(arg.conversion).isNull() ) stream << " )"; } stream << ";\n"; } stream << " if( !dcopClient()->call( \"kded\", \"kdeintegration\",\"" + function.name + "("; bool need_comma = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; if( need_comma ) stream << ","; need_comma = true; stream << arg.type; } stream << ")\", data, replyType, replyData, true ))\n"; stream << " {\n"; if( function.return_type != "void" ) { stream << " " + function.return_type << " ret;\n"; stream << " dcopTypeInit( ret ); // set to false/0/whatever\n"; stream << " return ret;\n"; } else stream << " return;\n"; stream << " }\n"; bool return_data = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); !return_data && it2 != function.args.end(); ++it2 ) { if( (*it2).out_argument ) return_data = true; } if( return_data || function.return_type != "void" ) stream << " TQDataStream replystream( replyData, IO_ReadOnly );\n"; if( function.return_type != "void" ) { stream << " " + function.return_type << " ret;\n"; stream << " replystream >> ret;\n"; } if( return_data ) { for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.out_argument && arg.needs_deref ) stream << " " << arg.type << " " << arg.name + "_dummy;\n"; } stream << " replystream"; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.out_argument ) { stream << " >> "; if( !(arg.back_conversion).isNull() ) stream << arg.name + "_dummy"; else { if( arg.needs_deref ) stream << "( " << arg.name << " != NULL ? *" << arg.name << " : " << arg.name << "_dummy )"; else stream << arg.name; } } } stream << ";\n"; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.out_argument && (!(arg.back_conversion).isNull()) ) stream << " if( " << arg.name << " != NULL )\n" << makeIndent( 8 ) << "*" << arg.name << " = " << arg.back_conversion << "( " << arg.name + "_dummy );\n"; } } if( function.return_type != "void" ) stream << " return ret;\n"; stream << " }\n"; stream << "\n"; } } void generateKdeDcop( TQTextStream& stream ) { stream << "bool Module::process(const TQCString &fun, const TQByteArray &data,\n" " TQCString &replyType, TQByteArray &replyData)\n" " {\n"; for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; stream << " if( fun == \"" + function.name + "("; bool need_comma = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; if( need_comma ) stream << ","; need_comma = true; stream << arg.type; } stream << ")\" )\n"; stream << " {\n"; if( function.delayed_return ) stream << " pre_" + function.name + "( data );\n"; else { stream << " pre_" + function.name + "( data, replyData );\n"; stream << " replyType = \"" << function.return_type << "\";\n"; } stream << " return true;\n"; stream << " }\n"; } stream << " return KDEDModule::process( fun, data, replyType, replyData );\n" " }\n" "\n"; stream << "QCStringList Module::functions()\n" " {\n" " QCStringList funcs = KDEDModule::functions();\n"; for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; stream << " funcs << \"" + function.name + "("; bool need_comma = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; if( need_comma ) stream << ","; need_comma = true; stream << arg.type; } stream << ")\";\n"; } stream << " return funcs;\n" " }\n" "\n" "QCStringList Module::interfaces()\n" " {\n" " QCStringList ifaces = KDEDModule::interfaces();\n" " ifaces << \"KDEIntegration\";\n" " return ifaces;\n" " }\n" "\n"; } void generateKdePreStub( TQTextStream& stream ) { for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; stream << "void Module::pre_" + function.name + "( const TQByteArray& " + ( function.args.isEmpty() ? "" : "data" ) + ( function.delayed_return ? "" : ", TQByteArray& replyData" ) + " )\n"; stream << " {\n"; if( function.delayed_return ) { stream << " JobData job;\n"; stream << " job.transaction = kapp->dcopClient()->beginTransaction();\n"; stream << " job.type = JobData::" + TQString( function.name[ 0 ].upper()) + function.name.mid( 1 ) + ";\n"; } for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; stream << " " + arg.type + " " + arg.name + ";\n"; } if( !function.args.isEmpty()) { stream << " TQDataStream datastream( data, IO_ReadOnly );\n"; stream << " datastream"; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; stream << " >> " + arg.name; } stream << ";\n"; } if( function.delayed_return ) stream << " void* handle = " + function.name + "( "; else stream << " post_" + function.name + "( " + function.name + "( "; bool need_comma = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.ignore ) continue; if( need_comma ) stream << ", "; need_comma = true; stream << arg.name; } if( function.delayed_return ) { stream << " );\n"; stream << " jobs[ handle ] = job;\n"; } else stream << " ), replyData );\n"; stream << " }\n"; stream << "\n"; } } void generateKdePostStub( TQTextStream& stream ) { for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; stream << "void Module::post_" + function.name + "( "; bool needs_comma = false; if( function.delayed_return ) { stream << "void* handle"; needs_comma = true; } if( function.return_type != "void" ) { if( needs_comma ) stream << ", "; needs_comma = true; stream << function.return_type + " ret"; } for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.out_argument ) { if( needs_comma ) stream << ", "; needs_comma = true; stream << arg.type + " " + arg.name; } } if( !function.delayed_return ) stream << ( needs_comma ? "," : "" ) << " TQByteArray& replyData"; stream << " )\n"; stream << " {\n"; if( function.delayed_return ) { stream << " assert( jobs.contains( handle ));\n"; stream << " JobData job = jobs[ handle ];\n"; stream << " jobs.remove( handle );\n"; stream << " TQByteArray replyData;\n"; stream << " TQCString replyType = \"qtkde\";\n"; } bool return_data = false; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); !return_data && it2 != function.args.end(); ++it2 ) { if( (*it2).out_argument ) return_data = true; } if( function.return_type != "void" || return_data ) stream << " TQDataStream replystream( replyData, IO_WriteOnly );\n"; if( function.return_type != "void" ) stream << " replystream << ret;\n"; if( return_data ) { stream << " replystream"; for( TQValueList< Arg >::ConstIterator it2 = function.args.begin(); it2 != function.args.end(); ++it2 ) { const Arg& arg = (*it2); if( arg.out_argument ) stream << " << " + arg.name; } stream << ";\n"; } if( function.delayed_return ) stream << " kapp->dcopClient()->endTransaction( job.transaction, replyType, replyData );\n"; stream << " }\n"; stream << "\n"; } } void generateKdeStubs( TQTextStream& stream ) { generateKdePreStub( stream ); generateKdePostStub( stream ); // TODO udelat i predbezne deklarace pro skutecne funkce? } void generateKdeCpp() { TQFile file( "module_functions.cpp" ); if( !file.open( IO_WriteOnly )) error(); TQTextStream stream( &file ); generateKdeDcop( stream ); generateKdeStubs( stream ); } void generateKdeH() { TQFile file( "module_functions.h" ); if( !file.open( IO_WriteOnly )) error(); TQTextStream stream( &file ); for( TQValueList< Function >::ConstIterator it1 = functions.begin(); it1 != functions.end(); ++it1 ) { const Function& function = *it1; if( function.only_qt ) continue; Function real_function = function; if( function.delayed_return ) real_function.return_type = "void*"; generateFunction( stream, real_function, real_function.name, 8, false /*static*/, false /*orig type*/, true /*ignore deref*/, 2 /*ignore level*/ ); stream << ";\n"; stream << makeIndent( 8 ) + "void pre_" + function.name + "( const TQByteArray& data" + ( function.delayed_return ? "" : ", TQByteArray& replyData" ) + " );\n"; Function post_function = function; post_function.stripNonOutArguments(); if( function.return_type != "void" ) { Arg return_arg; return_arg.name = "ret"; return_arg.type = function.return_type; post_function.args.prepend( return_arg ); } if( function.delayed_return ) { Arg handle_arg; handle_arg.name = "handle"; handle_arg.type = "void*"; post_function.args.prepend( handle_arg ); } else { Arg handle_arg; handle_arg.name = "replyData"; handle_arg.type = "TQByteArray&"; post_function.args.append( handle_arg ); } post_function.return_type = "void"; generateFunction( stream, post_function, "post_" + post_function.name, 8, false /*static*/, false /*orig type*/, true /*ignore deref*/, 2 /*ignore level*/ ); stream << ";\n"; } } void generateKde() { generateKdeCpp(); generateKdeH(); } void generate() { generateTQt(); generateTQtKde(); generateKde(); } int main (int argc, char *argv[]) { if (argc > 1) { parse(TQString(argv[1])); } else { parse(TQString("gen.txt")); } generate(); return 0; }