summaryrefslogtreecommitdiffstats
path: root/kode/kodemain.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kode/kodemain.cpp')
-rw-r--r--kode/kodemain.cpp633
1 files changed, 633 insertions, 0 deletions
diff --git a/kode/kodemain.cpp b/kode/kodemain.cpp
new file mode 100644
index 000000000..a567f20a0
--- /dev/null
+++ b/kode/kodemain.cpp
@@ -0,0 +1,633 @@
+/*
+ This file is part of kdepim.
+
+ Copyright (c) 2004 Cornelius Schumacher <schumacher@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Library General Public
+ License as published by the Free Software Foundation; either
+ version 2 of the License, or (at your option) any later version.
+
+ This library 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
+ Library General Public License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to
+ the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA.
+*/
+
+#include "code.h"
+#include "printer.h"
+#include "license.h"
+#include "automakefile.h"
+
+#include <kabc/stdaddressbook.h>
+
+#include <kaboutdata.h>
+#include <kapplication.h>
+#include <kcmdlineargs.h>
+#include <kconfig.h>
+#include <kdebug.h>
+#include <kglobal.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ksimpleconfig.h>
+#include <ksavefile.h>
+#include <kprocess.h>
+
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qfileinfo.h>
+#include <qregexp.h>
+
+#include <iostream>
+
+static const KCmdLineOptions options[] =
+{
+ { "c", 0, 0 },
+ { "create-class", I18N_NOOP("Create class"), 0 },
+ { "d", 0, 0 },
+ { "create-dialog", I18N_NOOP("Create dialog"), 0 },
+ { "create-kioslave", I18N_NOOP("Create kioslave"), 0 },
+ { "create-main", I18N_NOOP("Create main function template"), 0 },
+ { "y", 0, 0 },
+ { "codify", I18N_NOOP("Create generator code for given source"), 0 },
+ { "add-property", I18N_NOOP("Add property to class"), 0 },
+ { "inplace", I18N_NOOP("Change file in place"), 0 },
+ { "author-email <name>", I18N_NOOP("Add author with given email address"), 0 },
+ { "project <name>", I18N_NOOP("Name of project"), 0 },
+ { "gpl", I18N_NOOP("Use GPL as license"), 0 },
+ { "lgpl", I18N_NOOP("Use LGPL as license"), 0 },
+ { "classname <name>", I18N_NOOP("Name of class"), 0 },
+ { "filename <name>", I18N_NOOP("Name of file"), 0 },
+ { "namespace <name>", I18N_NOOP("Namespace"), 0 },
+ { "warning", I18N_NOOP("Create warning about code generation"), 0 },
+ { "qt-exception", I18N_NOOP("Add Qt exception to GPL"), 0 },
+ { "singleton", I18N_NOOP("Create a singleton class"), 0 },
+ { "protocol", I18N_NOOP("kioslave protocol"), 0 },
+ { "+[filename]", I18N_NOOP("Source code file name"), 0 },
+ KCmdLineLastOption
+};
+
+void addPropertyFunctions( QString &out, const QString &type,
+ const QString &name )
+{
+ // FIXME: Use KODE::Function
+
+ bool isReference = type.endsWith( "*" ) || type.endsWith( "&" );
+
+ QString argument;
+ QString upper = KODE::Style::upperFirst( name );
+ if ( !isReference ) {
+ argument = "const " + type + " &";
+ } else argument = type;
+
+ KODE::Code code;
+ code.setIndent( 4 );
+ code += "/**";
+ code += " Set .";
+ code += "*/";
+ code += "void set" + upper + "( " + argument + "v )";
+ code += "{";
+ code += " m" + upper + " = v;";
+ code += "}";
+
+ code += "/**";
+ code += " Get " + name + ". See set" + upper + "().";
+ code += "*/";
+ code += type + ( isReference ? "" : " " ) + name + "() const";
+ code += "{";
+ code += " return m" + upper + ";";
+ code += "}";
+
+ out += code.text();
+}
+
+void addPropertyVariable( QString &out, const QString &type,
+ const QString &name )
+{
+ QString upper = KODE::Style::upperFirst( name );
+ bool isReference = type.endsWith( "*" ) || type.endsWith( "&" );
+
+ KODE::Code code;
+ code.setIndent( 4 );
+ code += type + ( isReference ? "" : " " ) + "m" + upper + ";";
+
+ out += code.text();
+}
+
+// FIXME: Put addProperty in PropertyAdder class and add endReadAhead function.
+int addProperty( KCmdLineArgs *args )
+{
+ if ( args->count() != 3 ) {
+ std::cerr << "Usage: kode --add-property <class> <proprerty-type> "
+ << "<property-name>" << std::endl;
+ return 1;
+ }
+
+ QString className = args->arg( 0 );
+ QString type = args->arg( 1 );
+ QString name = args->arg( 2 );
+
+ kdDebug() << "Add property: class " << className << ": " << type << " " <<
+ name << endl;
+
+ QString headerFileName = className.lower() + ".h";
+
+ QFile headerFile( headerFileName );
+ if ( !headerFile.open( IO_ReadOnly ) ) {
+ std::cerr << "Unable to open file '" << headerFileName.utf8() << "'" <<
+ std::endl;
+ return 1;
+ }
+
+ QTextStream in( &headerFile );
+
+ enum State { FindClass, FindConstructor, FindProperties, FindPrivate,
+ FindVariables, Finish };
+ State state = FindClass;
+
+ QString accessor;
+ QString mutator;
+
+ QString out;
+
+ QString readAhead;
+
+ QString line;
+ while ( !( line = in.readLine() ).isNull() ) {
+// std::cout << line.utf8() << std::endl;
+ kdDebug() << state << " LINE: " << line << endl;
+ QString readAheadPrevious = readAhead;
+ readAhead += line + "\n";
+// out += line + "\n";
+ switch( state ) {
+ case FindClass:
+// if ( line.find( QRegExp( className ) ) >= 0 ) {
+ if ( line.find( QRegExp( "^\\s*class\\s+" + className ) ) >= 0 ) {
+ kdDebug() << " FOUND CLASS" << endl;
+ state = FindConstructor;
+ }
+ break;
+ case FindConstructor:
+ if ( line.find( QRegExp( "^\\s*" + className + "\\s*\\(" ) ) >= 0 ) {
+ kdDebug() << " FOUND CONSTRUCTOR" << endl;
+ out += readAhead;
+ readAhead = QString::null;
+ state = FindProperties;
+ }
+ break;
+ case FindProperties:
+ {
+ QRegExp re( "(\\w+)\\s*\\(" );
+ if ( re.search( line ) >= 0 ) {
+ QString function = re.cap( 1 ).lower();
+ if ( !function.isEmpty() ) {
+ kdDebug() << "Function: " << function << endl;
+ if ( function == className || function == "~" + className ) {
+ out += readAhead;
+ readAhead = QString::null;
+ } else {
+ if ( function.startsWith( "set" ) ) {
+ mutator = function.mid( 3 );
+ kdDebug() << "MUTATOR: " << mutator << endl;
+ } else {
+ if ( function == mutator ) {
+ accessor = function;
+ kdDebug() << "ACCESSOR: " << accessor << endl;
+ out += readAhead;
+ readAhead = QString::null;
+ } else {
+ kdDebug() << "CREATE PROPERTY" << endl;
+ out += readAheadPrevious;
+ addPropertyFunctions( out, type, name );
+ out += "\n";
+ readAhead = line + "\n";
+ state = FindPrivate;
+ }
+ }
+ }
+ }
+ } else if ( line.find( QRegExp( "\\s*protected" ) ) >= 0 ) {
+ state = FindPrivate;
+ } else if ( line.find( QRegExp( "\\s*private" ) ) >= 0 ) {
+ if ( accessor.isEmpty() ) {
+ addPropertyFunctions( out, type, name );
+ out += readAhead;
+ readAhead = QString::null;
+ addPropertyVariable( out, type, name );
+ state = Finish;
+ } else {
+ if ( accessor == mutator ) {
+ out += readAheadPrevious;
+ addPropertyFunctions( out, type, name );
+ out += "\n";
+ out += line + "\n";
+ readAhead = QString::null;
+ }
+ state = FindVariables;
+ }
+ }
+ }
+ break;
+ case FindPrivate:
+ if ( line.find( QRegExp( "\\s*private" ) ) >= 0 ) {
+ if ( accessor.isEmpty() ) {
+ out += readAhead;
+ readAhead = QString::null;
+ addPropertyVariable( out, type, name );
+ state = Finish;
+ } else {
+ state = FindVariables;
+ }
+ }
+ break;
+ case FindVariables:
+ {
+ if ( line.find( "m" + accessor.lower(), 0, false ) >= 0 ) {
+ out += readAhead;
+ readAhead = QString::null;
+ addPropertyVariable( out, type, name );
+ state = Finish;
+ }
+ }
+ break;
+ case Finish:
+ break;
+ }
+ }
+
+ headerFile.close();
+
+ out += readAhead;
+
+ if ( args->isSet( "inplace" ) ) {
+ QString headerFileNameOut = headerFileName + ".kodeorig" ;
+
+ KProcess proc;
+ proc << "cp" << QFile::encodeName( headerFileName ) <<
+ QFile::encodeName( headerFileNameOut );
+
+ if ( !proc.start( KProcess::Block ) ) {
+ kdError() << "Copy failed" << endl;
+ } else {
+ kdDebug() << "Write to original file." << endl;
+ if ( !headerFile.open( IO_WriteOnly ) ) {
+ kdError() << "Unable to open file '" << headerFileName <<
+ "' for writing." << endl;
+ return 1;
+ }
+ QTextStream o( &headerFile );
+ o << out << endl;
+ }
+ } else {
+ std::cout << out.utf8() << std::endl;
+ }
+
+ return 0;
+}
+
+int codify( KCmdLineArgs *args )
+{
+ if ( args->count() != 1 ) {
+ std::cerr << "Usage: kode --codify <sourcecodefile>" << std::endl;
+ return 1;
+ }
+
+ QString filename = args->arg( 0 );
+
+ QFile f( filename );
+ if ( !f.open( IO_ReadOnly ) ) {
+ kdError() << "Unable to open file '" << filename << "'." << endl;
+ return 1;
+ } else {
+ std::cout << "KODE::Code code;" << std::endl;
+ QTextStream ts( &f );
+ QString line;
+ while( !( line = ts.readLine() ).isNull() ) {
+ line.replace( "\\", "\\\\" );
+ line.replace( "\"", "\\\"" );
+ line = "code += \"" + line;
+ line.append( "\";" );
+ std::cout << line.local8Bit() << std::endl;
+ }
+ }
+
+ return 0;
+}
+
+int create( KCmdLineArgs *args )
+{
+ KODE::Printer p;
+ if ( args->isSet( "warning" ) ) p.setCreationWarning( true );
+
+ bool createKioslave = args->isSet( "create-kioslave" );
+ bool createMain = args->isSet( "create-main" );
+
+ QString filename = args->getOption( "filename" );
+
+ if ( createMain ) {
+ if ( filename.isEmpty() ) {
+ kdError() << "Error: No file name given." << endl;
+ return 1;
+ }
+
+ if ( filename.endsWith( ".cpp" ) ) {
+ filename = filename.left( filename.length() - 4 );
+ }
+ } else {
+ if ( !args->isSet( "classname" ) ) {
+ kdError() << "Error: No class name given." << endl;
+ return 1;
+ }
+ }
+
+ QString className = args->getOption( "classname" );
+
+ QString protocol;
+
+ if ( createKioslave ) {
+ if ( !args->isSet( "protocol" ) ) {
+ protocol = className.lower();
+ kdWarning() << "Warning: No protocol for kioslave given. Assuming '"
+ << protocol << "'" << endl;
+ } else {
+ protocol = args->getOption( "protocol" );
+ }
+ }
+
+ KODE::File file;
+
+ file.setProject( args->getOption( "project" ) );
+
+ QString authorEmail = args->getOption( "author-email" );
+ QString authorName;
+ KABC::Addressee a;
+ if ( authorEmail.isEmpty() ) {
+ a = KABC::StdAddressBook::self()->whoAmI();
+ authorEmail = a.preferredEmail();
+ } else {
+ KABC::Addressee::List as =
+ KABC::StdAddressBook::self()->findByEmail( authorEmail );
+ if ( as.isEmpty() ) {
+ kdDebug() << "Unable to find '" << authorEmail << "' in address book."
+ << endl;
+ } else {
+ a = as.first();
+ }
+ }
+ if ( !a.isEmpty() ) {
+ authorName = a.realName();
+ }
+ if ( !authorEmail.isEmpty() ) {
+ file.addCopyright( QDate::currentDate().year(), authorName, authorEmail );
+ }
+
+ KODE::License l;
+ if ( args->isSet( "gpl" ) ) l = KODE::License( KODE::License::GPL );
+ if ( args->isSet( "lgpl" ) ) l = KODE::License( KODE::License::LGPL );
+ l.setQtException( args->isSet( "qt-exception" ) );
+ file.setLicense( l );
+
+ file.setNameSpace( args->getOption( "namespace" ) );
+
+ if ( createMain ) {
+ file.addInclude( "kaboutdata.h" );
+ file.addInclude( "kapplication.h" );
+ file.addInclude( "kdebug" );
+ file.addInclude( "klocale" );
+ file.addInclude( "kcmdlineargs" );
+
+ KODE::Code code;
+ code += "static const KCmdLineOptions options[] =";
+ code += "{";
+ code += " { \"verbose\", \"Verbose output\", 0 },";
+ code += " KCmdLineLastOption";
+ code += "};";
+ file.addFileCode( code );
+
+ KODE::Function main( "main", "int" );
+ main.addArgument( "int argc" );
+ main.addArgument( "char **argv" );
+
+ code.clear();
+ code += "KAboutData aboutData(\"test\",\"Test\",\"0.1\");";
+ code += "KCmdLineArgs::init(argc,argv,&aboutData);";
+ code += "KCmdLineArgs::addCmdLineOptions( options );";
+ code += "";
+ code += "KApplication app;";
+ code += "";
+ code += "KCmdLineArgs *args = KCmdLineArgs::parsedArgs();";
+ code += "";
+ code += "Q_UNUSED( args );";
+ main.setBody( code );
+
+ file.addFileFunction( main );
+
+ file.setFilename( filename );
+
+ p.printImplementation( file, false );
+
+ return 0;
+ }
+
+ KODE::Class c( className );
+
+ if ( args->isSet( "create-dialog" ) ) {
+ c.addBaseClass( KODE::Class( "KDialogBase" ) );
+ c.addInclude( "kdialogbase.h" );
+ } else if ( createKioslave ) {
+ c.setDocs( "This class implements a kioslave for ..." );
+
+ c.addBaseClass( KODE::Class( "SlaveBase", "KIO" ) );
+ c.addHeaderInclude( "kio/slavebase.h" );
+
+ KODE::Function get( "get", "void" );
+ get.addArgument( "const KURL &url" );
+
+ KODE::Code code;
+
+ code += "kdDebug(7000) << \"" + className + "::get()\" << endl;";
+ code += "kdDebug(7000) << \" URL: \" << url.url() << endl;";
+ code += "#if 1";
+ code += "kdDebug(7000) << \" Path: \" << url.path() << endl;";
+ code += "kdDebug(7000) << \" Query: \" << url.query() << endl;";
+ code += "kdDebug(7000) << \" Protocol: \" << url.protocol() << endl;";
+ code += "kdDebug(7000) << \" Filename: \" << url.filename() << endl;";
+ code += "#endif";
+ code.newLine();
+
+ code += "mimeType( \"text/plain\" );";
+ code.newLine();
+
+ code += "QCString str( \"Hello!\" );";
+ code += "data( str );";
+ code.newLine();
+
+ code += "finished();";
+ code.newLine();
+
+ code += "kdDebug(7000) << \"" + className + "CgiProtocol::get() done\" << endl;";
+
+ get.setBody( code );
+
+ c.addFunction( get );
+
+
+ c.addInclude( "kinstance.h" );
+ c.addInclude( "kdebug.h" );
+ c.addInclude( "sys/types.h" );
+ c.addInclude( "unistd.h" );
+ c.addInclude( "stdlib.h" );
+
+ KODE::Function main( "kdemain", "int" );
+ main.addArgument( "int argc" );
+ main.addArgument( "char **argv" );
+
+ code.clear();
+
+ code += "KInstance instance( \"kio_" + protocol + "\" );";
+ code += "";
+ code += "kdDebug(7000) << \"Starting kio_" + protocol + "(pid: \" << getpid() << \")\" << endl;";
+ code += "";
+ code += "if (argc != 4) {";
+ code.indent();
+ code += "fprintf( stderr, \"Usage: kio_" + protocol + " protocol domain-socket1 domain-socket2\\n\");";
+ code += "exit( -1 );";
+ code.unindent();
+ code += "}";
+ code += "";
+ code += className + " slave( argv[2], argv[3] );";
+ code += "slave.dispatchLoop();";
+ code += "";
+ code += "return 0;";
+
+ main.setBody( code );
+
+ file.addFileFunction( main );
+
+ file.addExternCDeclaration( p.functionSignature( main ) );
+ }
+
+ KODE::Function constructor( className );
+
+ if ( args->isSet( "singleton" ) ) {
+ constructor.setAccess( KODE::Function::Private );
+
+ KODE::Function self( "self", className + " *" );
+ self.setStatic( true );
+
+ KODE::Code code;
+ code += "if ( !mSelf ) {";
+ code += " selfDeleter.setObject( mSelf, new " + className + "() );";
+ code += "}";
+ code += "return mSelf;";
+
+ self.setBody( code );
+
+ c.addFunction( self );
+
+ KODE::MemberVariable selfVar( "mSelf", className + " *", true );
+ selfVar.setInitializer( "0" );
+
+ c.addMemberVariable( selfVar );
+
+ KODE::Variable staticDeleter( "selfDeleter",
+ "KStaticDeleter<" + className + ">",
+ true );
+ file.addFileVariable( staticDeleter );
+ file.addInclude( "kstaticdeleter.h" );
+ }
+
+ if ( createKioslave ) {
+ constructor.addArgument( "const QCString &pool" );
+ constructor.addArgument( "const QCString &app" );
+
+ constructor.addInitializer( "SlaveBase( \"" + protocol + "\", pool, app )" );
+ }
+
+ c.addFunction( constructor );
+
+ file.insertClass( c );
+
+ p.printHeader( file );
+ p.printImplementation( file );
+
+ if ( createKioslave ) {
+ // Write automake Makefile
+ KODE::AutoMakefile am;
+
+ am.addEntry( "INCLUDES", "$(all_includes)" );
+ am.newLine();
+ am.addEntry( "noinst_HEADERS", className.lower() + ".h" );
+ am.newLine();
+ am.addEntry( "METASOURCES", "AUTO" );
+ am.newLine();
+ am.addEntry( "kdelnkdir", "$(kde_servicesdir)" );
+ am.addEntry( "kdelnk_DATA", protocol + ".protocol" );
+
+ KODE::AutoMakefile::Target t( "kde_module_LTLIBRARIES",
+ "kio_" + protocol + ".la" );
+ t.setSources( className.lower() + ".cpp" );
+ t.setLibAdd( "$(LIB_KIO)" );
+ t.setLdFlags( "$(all_libraries) -module $(KDE_PLUGIN)" );
+
+ am.addTarget( t );
+
+ p.printAutoMakefile( am );
+
+
+ // Write protocol file
+ QString protocolFilename = protocol + ".protocol";
+
+ QFileInfo fi( protocolFilename );
+ protocolFilename = fi.absFilePath();
+
+ KSaveFile::backupFile( protocolFilename, QString::null, ".backup" );
+
+ QFile::remove( protocolFilename );
+
+ KSimpleConfig protocolFile( protocolFilename );
+
+ protocolFile.setGroup( "Protocol" );
+ protocolFile.writeEntry( "exec", "kio_" + protocol );
+ protocolFile.writeEntry( "protocol", protocol );
+ protocolFile.writeEntry( "input", "none" );
+ protocolFile.writeEntry( "output", "filesystem" );
+ protocolFile.writeEntry( "reading", "true" );
+ protocolFile.writeEntry( "DocPath", "kioslave/" + protocol + ".html" );
+
+ protocolFile.sync();
+ }
+
+ return 0;
+}
+
+int main(int argc,char **argv)
+{
+ KAboutData aboutData( "kode", I18N_NOOP("KDE Code Generator"), "0.1" );
+ aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
+
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options );
+
+ KApplication app;
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+
+ if ( args->isSet( "create-class" ) || args->isSet( "create-dialog" ) ||
+ args->isSet( "create-kioslave" ) || args->isSet( "create-main" ) ) {
+ return create( args );
+ } else if ( args->isSet( "codify" ) ) {
+ return codify( args );
+ } else if ( args->isSet( "add-property" ) ) {
+ return addProperty( args );
+ } else {
+ std::cerr << "Error: No command given." << std::endl;
+ return 1;
+ }
+}