You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdebindings/korundum/rubylib/rbkconfig_compiler/rbkconfig_compiler.cpp

1331 lines
41 KiB

// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
/*
This file is part of KDE.
Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org>
Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
Copyright (c) 2003 Zack Rusin <zack@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 <tqfile.h>
#include <tqtextstream.h>
#include <tqdom.h>
#include <tqregexp.h>
#include <kaboutdata.h>
#include <kapplication.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <kglobal.h>
#include <kconfig.h>
#include <ksimpleconfig.h>
#include <kstandarddirs.h>
#include <iostream>
static const KCmdLineOptions options[] =
{
{ "d", 0, 0 },
{ "directory <dir>", I18N_NOOP("Directory to generate files in"), "." },
{ "+file.kcfg", I18N_NOOP("Input kcfg XML file"), 0 },
{ "+file.kcfgc", I18N_NOOP("Code generation options file"), 0 },
KCmdLineLastOption
};
bool globalEnums;
bool itemAccessors;
TTQStringList allNames;
TTQRegExp *validNameRegexp;
class CfgEntry
{
public:
struct Choice
{
TTQString name;
TTQString label;
TTQString whatsThis;
};
CfgEntry( const TTQString &group, const TTQString &type, const TTQString &key,
const TTQString &name, const TTQString &label,
const TTQString &whatsThis, const TTQString &code,
const TTQString &defaultValue, const TTQValueList<Choice> &choices,
bool hidden )
: mGroup( group ), mType( type ), mKey( key ), mName( name ),
mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
mDefaultValue( defaultValue ),
mChoices( choices ), mHidden( hidden )
{
}
void setGroup( const TTQString &group ) { mGroup = group; }
TTQString group() const { return mGroup; }
void setType( const TTQString &type ) { mType = type; }
TTQString type() const { return mType; }
void setKey( const TTQString &key ) { mKey = key; }
TTQString key() const { return mKey; }
void setName( const TTQString &name ) { mName = name; }
TTQString name() const { return mName; }
void setLabel( const TTQString &label ) { mLabel = label; }
TTQString label() const { return mLabel; }
void setWhatsThis( const TTQString &whatsThis ) { mWhatsThis = whatsThis; }
TTQString whatsThis() const { return mWhatsThis; }
void setDefaultValue( const TTQString &d ) { mDefaultValue = d; }
TTQString defaultValue() const { return mDefaultValue; }
void setCode( const TTQString &d ) { mCode = d; }
TTQString code() const { return mCode; }
void setMinValue( const TTQString &d ) { mMin = d; }
TTQString minValue() const { return mMin; }
void setMaxValue( const TTQString &d ) { mMax = d; }
TTQString maxValue() const { return mMax; }
void setParam( const TTQString &d ) { mParam = d; }
TTQString param() const { return mParam; }
void setParamName( const TTQString &d ) { mParamName = d; }
TTQString paramName() const { return mParamName; }
void setParamType( const TTQString &d ) { mParamType = d; }
TTQString paramType() const { return mParamType; }
void setChoices( const TTQValueList<Choice> &d ) { mChoices = d; }
TTQValueList<Choice> choices() const { return mChoices; }
void setParamValues( const TTQStringList &d ) { mParamValues = d; }
TTQStringList paramValues() const { return mParamValues; }
void setParamDefaultValues( const TTQStringList &d ) { mParamDefaultValues = d; }
TTQString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
void setParamMax( int d ) { mParamMax = d; }
int paramMax() const { return mParamMax; }
bool hidden() const { return mHidden; }
void dump() const
{
kdDebug() << "<entry>" << endl;
kdDebug() << " group: " << mGroup << endl;
kdDebug() << " type: " << mType << endl;
kdDebug() << " key: " << mKey << endl;
kdDebug() << " name: " << mName << endl;
kdDebug() << " label: " << mLabel << endl;
// whatsthis
kdDebug() << " code: " << mCode << endl;
// kdDebug() << " values: " << mValues.join(":") << endl;
if (!param().isEmpty())
{
kdDebug() << " param name: "<< mParamName << endl;
kdDebug() << " param type: "<< mParamType << endl;
kdDebug() << " paramvalues: " << mParamValues.join(":") << endl;
}
kdDebug() << " default: " << mDefaultValue << endl;
kdDebug() << " hidden: " << mHidden << endl;
kdDebug() << " min: " << mMin << endl;
kdDebug() << " max: " << mMax << endl;
kdDebug() << "</entry>" << endl;
}
private:
TTQString mGroup;
TTQString mType;
TTQString mKey;
TTQString mName;
TTQString mLabel;
TTQString mWhatsThis;
TTQString mCode;
TTQString mDefaultValue;
TTQString mParam;
TTQString mParamName;
TTQString mParamType;
TTQValueList<Choice> mChoices;
TTQStringList mParamValues;
TTQStringList mParamDefaultValues;
int mParamMax;
bool mHidden;
TTQString mMin;
TTQString mMax;
};
static TTQString varName(const TTQString &n)
{
TTQString result = "@"+n;
result[1] = result[1].lower();
return result;
}
static TTQString enumName(const TTQString &n)
{
TTQString result = "Enum"+n;
result[4] = result[4].upper();
return result;
}
static TTQString enumValue(const TTQString &n)
{
TTQString result = n;
result[0] = result[0].upper();
return result;
}
static TTQString setFunction(const TTQString &n)
{
TTQString result = "set"+n;
result[3] = result[3].upper();
return result;
}
static TTQString getFunction(const TTQString &n)
{
TTQString result = n;
result[0] = result[0].lower();
return result;
}
static void addQuotes( TTQString &s )
{
if ( s.left( 1 ) != "\"" ) s.prepend( "\"" );
if ( s.right( 1 ) != "\"" ) s.append( "\"" );
}
static TTQString quoteString( const TTQString &s )
{
TTQString r = s;
r.replace( "\\", "\\\\" );
r.replace( "\"", "\\\"" );
r.replace( "\r", "" );
r.replace( "\n", "\\n\"\n\"" );
return "\"" + r + "\"";
}
static TTQString literalString( const TTQString &s )
{
bool isAscii = true;
for(int i = s.length(); i--;)
if (s[i].unicode() > 127) isAscii = false;
return quoteString(s);
// if (isAscii)
// return "TTQString::fromLatin1( " + quoteString(s) + " )";
// else
// return "TTQString::fromUtf8( " + quoteString(s) + " )";
}
static TTQString dumpNode(const TTQDomNode &node)
{
TTQString msg;
TTQTextStream s(&msg, IO_WriteOnly );
node.save(s, 0);
msg = msg.simplifyWhiteSpace();
if (msg.length() > 40)
return msg.left(37)+"...";
return msg;
}
static TTQString filenameOnly(TTQString path)
{
int i = path.findRev('/');
if (i >= 0)
return path.mid(i+1);
return path;
}
static void preProcessDefault( TTQString &defaultValue, const TTQString &name,
const TTQString &type,
const TTQValueList<CfgEntry::Choice> &choices,
TTQString &code )
{
if ( type == "String" && !defaultValue.isEmpty() ) {
defaultValue = literalString(defaultValue);
} else if ( type == "Path" && !defaultValue.isEmpty() ) {
defaultValue = literalString( defaultValue );
} else if ( type == "StringList" && !defaultValue.isEmpty() ) {
TTQTextStream rb( &code, IO_WriteOnly | IO_Append );
if (!code.isEmpty())
rb << endl;
// rb << " TTQStringList default" << name << ";" << endl;
rb << " default" << name << " = []" << endl;
TTQStringList defaults = TTQStringList::split( ",", defaultValue );
TTQStringList::ConstIterator it;
for( it = defaults.begin(); it != defaults.end(); ++it ) {
rb << " default" << name << " << \"" << *it << "\""
<< endl;
}
defaultValue = "default" + name;
} else if ( type == "Color" && !defaultValue.isEmpty() ) {
TTQRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+");
if (colorRe.exactMatch(defaultValue))
{
defaultValue = "TQt::Color.new( " + defaultValue + " )";
}
else
{
defaultValue = "TQt::Color.new( \"" + defaultValue + "\" )";
}
} else if ( type == "Enum" ) {
if ( !globalEnums ) {
TTQValueList<CfgEntry::Choice>::ConstIterator it;
for( it = choices.begin(); it != choices.end(); ++it ) {
if ( (*it).name == defaultValue ) {
defaultValue.prepend( enumName(name) + "_");
break;
}
}
}
} else if ( type == "IntList" ) {
TTQTextStream rb( &code, IO_WriteOnly | IO_Append );
if (!code.isEmpty())
rb << endl;
rb << " default" << name << " = []" << endl;
TTQStringList defaults = TTQStringList::split( ",", defaultValue );
TTQStringList::ConstIterator it;
for( it = defaults.begin(); it != defaults.end(); ++it ) {
rb << " default" << name << " << " << *it << ""
<< endl;
}
defaultValue = "default" + name;
}
}
CfgEntry *parseEntry( const TTQString &group, const TTQDomElement &element )
{
bool defaultCode = false;
TTQString type = element.attribute( "type" );
TTQString name = element.attribute( "name" );
TTQString key = element.attribute( "key" );
TTQString hidden = element.attribute( "hidden" );
TTQString label;
TTQString whatsThis;
TTQString defaultValue;
TTQString code;
TTQString param;
TTQString paramName;
TTQString paramType;
TTQValueList<CfgEntry::Choice> choices;
TTQStringList paramValues;
TTQStringList paramDefaultValues;
TTQString minValue;
TTQString maxValue;
int paramMax = 0;
TTQDomNode n;
for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
TTQDomElement e = n.toElement();
TTQString tag = e.tagName();
if ( tag == "label" ) label = e.text();
else if ( tag == "whatsthis" ) whatsThis = e.text();
else if ( tag == "min" ) minValue = e.text();
else if ( tag == "max" ) maxValue = e.text();
else if ( tag == "code" ) code = e.text();
else if ( tag == "parameter" )
{
param = e.attribute( "name" );
paramType = e.attribute( "type" );
if ( param.isEmpty() ) {
kdError() << "Parameter must have a name: " << dumpNode(e) << endl;
return 0;
}
if ( paramType.isEmpty() ) {
kdError() << "Parameter must have a type: " << dumpNode(e) << endl;
return 0;
}
if ((paramType == "Int") || (paramType == "UInt"))
{
bool ok;
paramMax = e.attribute("max").toInt(&ok);
if (!ok)
{
kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
return 0;
}
}
else if (paramType == "Enum")
{
TTQDomNode n2;
for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
TTQDomElement e2 = n2.toElement();
if (e2.tagName() == "values")
{
TTQDomNode n3;
for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
TTQDomElement e3 = n3.toElement();
if (e3.tagName() == "value")
{
paramValues.append( e3.text() );
}
}
break;
}
}
if (paramValues.isEmpty())
{
kdError() << "No values specified for parameter '" << param << "'." << endl;
return 0;
}
paramMax = paramValues.count()-1;
}
else
{
kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl;
return 0;
}
}
else if ( tag == "default" )
{
if (e.attribute("param").isEmpty())
{
defaultValue = e.text();
if (e.attribute( "code" ) == "true")
defaultCode = true;
}
}
else if ( tag == "choices" ) {
TTQDomNode n2;
for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
TTQDomElement e2 = n2.toElement();
if ( e2.tagName() == "choice" ) {
TTQDomNode n3;
CfgEntry::Choice choice;
choice.name = e2.attribute( "name" );
if ( choice.name.isEmpty() ) {
kdError() << "Tag <choice> retquires attribute 'name'." << endl;
}
for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
TTQDomElement e3 = n3.toElement();
if ( e3.tagName() == "label" ) choice.label = e3.text();
if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
}
choices.append( choice );
}
}
}
}
bool nameIsEmpty = name.isEmpty();
if ( nameIsEmpty && key.isEmpty() ) {
kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl;
return 0;
}
if ( key.isEmpty() ) {
key = name;
}
if ( nameIsEmpty ) {
name = key;
name.replace( " ", TTQString::null );
} else if ( name.contains( ' ' ) ) {
kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl;
name.remove( ' ' );
}
if (name.contains("$("))
{
if (param.isEmpty())
{
kdError() << "Name may not be parameterized: " << name << endl;
return 0;
}
}
else
{
if (!param.isEmpty())
{
kdError() << "Name must contain '$(" << param << ")': " << name << endl;
return 0;
}
}
if ( label.isEmpty() ) {
label = key;
}
if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad
if (!param.isEmpty())
{
// Adjust name
paramName = name;
name.replace("$("+param+")", TTQString::null);
// Lookup defaults for indexed entries
for(int i = 0; i <= paramMax; i++)
{
paramDefaultValues.append(TTQString::null);
}
TTQDomNode n;
for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
TTQDomElement e = n.toElement();
TTQString tag = e.tagName();
if ( tag == "default" )
{
TTQString index = e.attribute("param");
if (index.isEmpty())
continue;
bool ok;
int i = index.toInt(&ok);
if (!ok)
{
i = paramValues.findIndex(index);
if (i == -1)
{
kdError() << "Index '" << index << "' for default value is unknown." << endl;
return 0;
}
}
if ((i < 0) || (i > paramMax))
{
kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
return 0;
}
TTQString tmpDefaultValue = e.text();
if (e.attribute( "code" ) != "true")
preProcessDefault(tmpDefaultValue, name, type, choices, code);
paramDefaultValues[i] = tmpDefaultValue;
}
}
}
if (!validNameRegexp->exactMatch(name))
{
if (nameIsEmpty)
kdError() << "The key '" << key << "' can not be used as name for the entry because "
"it is not a valid name. You need to specify a valid name for this entry." << endl;
else
kdError() << "The name '" << name << "' is not a valid name for an entry." << endl;
return 0;
}
if (allNames.contains(name))
{
if (nameIsEmpty)
kdError() << "The key '" << key << "' can not be used as name for the entry because "
"it does not result in a unique name. You need to specify a unique name for this entry." << endl;
else
kdError() << "The name '" << name << "' is not unique." << endl;
return 0;
}
allNames.append(name);
if (!defaultCode)
{
preProcessDefault(defaultValue, name, type, choices, code);
}
CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis,
code, defaultValue, choices,
hidden == "true" );
if (!param.isEmpty())
{
result->setParam(param);
result->setParamName(paramName);
result->setParamType(paramType);
result->setParamValues(paramValues);
result->setParamDefaultValues(paramDefaultValues);
result->setParamMax(paramMax);
}
result->setMinValue(minValue);
result->setMaxValue(maxValue);
return result;
}
/**
Return parameter declaration for given type.
*/
TTQString param( const TTQString &type )
{
if ( type == "String" ) return "const TTQString &";
else if ( type == "StringList" ) return "const TTQStringList &";
else if ( type == "Font" ) return "const TTQFont &";
else if ( type == "Rect" ) return "const TTQRect &";
else if ( type == "Size" ) return "const TTQSize &";
else if ( type == "Color" ) return "const TTQColor &";
else if ( type == "Point" ) return "const TTQPoint &";
else if ( type == "Int" ) return "int";
else if ( type == "UInt" ) return "uint";
else if ( type == "Bool" ) return "bool";
else if ( type == "Double" ) return "double";
else if ( type == "DateTime" ) return "const TTQDateTime &";
else if ( type == "Int64" ) return "Q_INT64";
else if ( type == "UInt64" ) return "Q_UINT64";
else if ( type == "IntList" ) return "const TTQValueList<int> &";
else if ( type == "Enum" ) return "int";
else if ( type == "Path" ) return "const TTQString &";
else if ( type == "Password" ) return "const TTQString &";
else {
kdError() <<"rbkconfig_compiler does not support type \""<< type <<"\""<<endl;
return "TTQString"; //For now, but an assert would be better
}
}
/**
Actual Ruby initializer value to give a type.
*/
TTQString rbType( const TTQString &type )
{
if ( type == "String" ) return "\"\"";
else if ( type == "StringList" ) return "[]";
else if ( type == "Font" ) return "TQt::Font.new";
else if ( type == "Rect" ) return "TQt::Rect.new";
else if ( type == "Size" ) return "TQt::Size.new";
else if ( type == "Color" ) return "TQt::Color.new";
else if ( type == "Point" ) return "TQt::Point.new";
else if ( type == "Int" ) return "0";
else if ( type == "UInt" ) return "0";
else if ( type == "Bool" ) return "false, 42";
else if ( type == "Double" ) return "0.0";
else if ( type == "DateTime" ) return "TQt::DateTime.new";
else if ( type == "Int64" ) return "0";
else if ( type == "UInt64" ) return "0";
else if ( type == "IntList" ) return "[]";
else if ( type == "Enum" ) return "0";
else if ( type == "Path" ) return "\"\"";
else if ( type == "Password" ) return "\"\"";
else {
kdError()<<"rbkconfig_compiler does not support type \""<< type <<"\""<<endl;
return "nil"; //For now, but an assert would be better
}
}
TTQString defaultValue( const TTQString &type )
{
if ( type == "String" ) return "\"\""; // Use empty string, not null string!
else if ( type == "StringList" ) return "[]";
else if ( type == "Font" ) return "KDE::GlobalSettings.generalFont()";
else if ( type == "Rect" ) return "TQt::Rect.new()";
else if ( type == "Size" ) return "TQt::Size.new()";
else if ( type == "Color" ) return "TQt::Color.new(128, 128, 128)";
else if ( type == "Point" ) return "TQt::Point.new()";
else if ( type == "Int" ) return "0";
else if ( type == "UInt" ) return "0";
else if ( type == "Bool" ) return "false";
else if ( type == "Double" ) return "0.0";
else if ( type == "DateTime" ) return "TQt::DateTime.new()";
else if ( type == "Int64" ) return "0";
else if ( type == "UInt64" ) return "0";
else if ( type == "IntList" ) return "[]";
else if ( type == "Enum" ) return "0";
else if ( type == "Path" ) return "\"\""; // Use empty string, not null string!
else if ( type == "Password" ) return "\"\""; // Use empty string, not null string!
else {
kdWarning()<<"Error, rbkconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl;
return "String"; //For now, but an assert would be better
}
}
TTQString itemType( const TTQString &type )
{
TTQString t;
t = type;
t.replace( 0, 1, t.left( 1 ).upper() );
return t;
}
static TTQString itemVar(const CfgEntry *e)
{
if (itemAccessors)
return varName( e->name() ) + "Item";
return "item" + e->name();
}
TTQString newItem( const TTQString &type, const TTQString &name, const TTQString &key,
const TTQString &defaultValue, const TTQString &param = TTQString::null)
{
TTQString t = "Item" + itemType( type ) +
".new( currentGroup(), " + key + ", " + varName( name ) + param;
if ( type == "Enum" ) {
t += ".toInt";
t += ", values" + name;
} else if ( type == "Path" ) {
t += ".toString";
} else if ( type == "Int64" ) {
t += ".toLongLong";
} else {
t += ".to" + itemType( type );
}
if ( !defaultValue.isEmpty() ) {
t += ", ";
if ( type == "String" ) t += defaultValue;
else t+= defaultValue;
}
t += " )";
return t;
}
TTQString addItem( const TTQString &type, const TTQString &name, const TTQString &key,
const TTQString &defaultValue, const TTQString &param = TTQString::null,
const TTQString &paramName = TTQString::null )
{
TTQString t = "addItem" + itemType( type ) +
"( " + key + ", " + varName( name ) + param;
if ( type == "Enum" ) t += ", values" + name;
if ( !defaultValue.isEmpty() ) {
t += ", ";
if ( type == "String" ) t += defaultValue;
else if ( type == "Enum" ) t += enumValue(defaultValue);
else t+= defaultValue;
}
if (!paramName.isNull()) {
t += ", \"" + paramName + "\"";
}
t += " )";
return t;
}
TTQString paramString(const TTQString &s, const CfgEntry *e, int i)
{
TTQString result = s;
TTQString needle = "$("+e->param()+")";
if (result.contains(needle))
{
TTQString tmp;
if (e->paramType() == "Enum")
{
tmp = e->paramValues()[i];
}
else
{
tmp = TTQString::number(i);
}
result.replace(needle, tmp);
}
return result;
}
TTQString paramString(const TTQString &group, const TTQStringList &parameters)
{
TTQString paramString = group;
TTQString arguments;
int i = 0;
for( TTQStringList::ConstIterator it = parameters.begin();
it != parameters.end(); ++it)
{
if (paramString.contains("$("+*it+")"))
{
i++;
paramString.replace("$("+*it+")", "%s");
if (i > 1) {
arguments += ", ";
}
arguments += " @param"+*it;
}
}
if (arguments.isEmpty())
return "\""+group+"\"";
if (i == 1) {
return "\""+paramString+"\" % "+arguments;
} else {
return "\""+paramString+"\" % ["+arguments+"]";
}
}
/* int i is the value of the parameter */
TTQString userTextsFunctions( CfgEntry *e, TTQString itemVarStr=TTQString::null, TTQString i=TTQString::null )
{
TTQString txt;
if (itemVarStr.isNull()) itemVarStr=itemVar(e);
if ( !e->label().isEmpty() ) {
txt += " " + itemVarStr + ".setLabel( i18n(";
if ( !e->param().isEmpty() )
txt += quoteString(e->label().replace("$("+e->param()+")", i));
else
txt+= quoteString(e->label());
txt+= ") )\n";
}
if ( !e->whatsThis().isEmpty() ) {
txt += " " + itemVarStr + ".setWhatsThis( i18n(";
if ( !e->param().isEmpty() )
txt += quoteString(e->whatsThis().replace("$("+e->param()+")", i));
else
txt+= quoteString(e->whatsThis());
txt+=") )\n";
}
return txt;
}
int main( int argc, char **argv )
{
KAboutData aboutData( "rbkconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3",
I18N_NOOP("Ruby KConfig Compiler") , KAboutData::License_LGPL );
aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" );
aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
aboutData.addCredit( "Reinhold Kainhofer", "Fix for parametrized entries",
"reinhold@kainhofer.com", "http://reinhold.kainhofer.com" );
aboutData.addCredit( "Richard Dale", "Ruby port",
"Richard_Dale@tipitina.demon.co.uk", "" );
KCmdLineArgs::init( argc, argv, &aboutData );
KCmdLineArgs::addCmdLineOptions( options );
KInstance app( &aboutData );
KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
if ( args->count() < 2 ) {
kdError() << "Too few arguments." << endl;
return 1;
}
if ( args->count() > 2 ) {
kdError() << "Too many arguments." << endl;
return 1;
}
validNameRegexp = new TTQRegExp("[a-zA-Z_][a-zA-Z0-9_]*");
TTQString baseDir = TTQFile::decodeName(args->getOption("directory"));
if (!baseDir.endsWith("/"))
baseDir.append("/");
TTQString inputFilename = args->url( 0 ).path();
TTQString codegenFilename = args->url( 1 ).path();
if (!codegenFilename.endsWith(".kcfgc"))
{
kdError() << "Codegen options file must have extension .kcfgc" << endl;
return 1;
}
TTQString baseName = args->url( 1 ).fileName();
baseName = baseName.left(baseName.length() - 6);
KSimpleConfig codegenConfig( codegenFilename, true );
TTQString nameSpace = codegenConfig.readEntry("NameSpace");
TTQString className = codegenConfig.readEntry("ClassName");
TTQString inherits = codegenConfig.readEntry("Inherits");
TTQString visibility = codegenConfig.readEntry("Visibility");
if (!visibility.isEmpty()) visibility+=" ";
bool singleton = codegenConfig.readBoolEntry("Singleton", false);
bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
TTQString memberVariables = codegenConfig.readEntry("MemberVariables");
TTQStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
TTQStringList mutators = codegenConfig.readListEntry("Mutators");
bool allMutators = false;
if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
allMutators = true;
itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
TTQFile input( inputFilename );
TTQDomDocument doc;
TTQString errorMsg;
int errorRow;
int errorCol;
if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
kdError() << "Unable to load document." << endl;
kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
return 1;
}
TTQDomElement cfgElement = doc.documentElement();
if ( cfgElement.isNull() ) {
kdError() << "No document in kcfg file" << endl;
return 1;
}
TTQString cfgFileName;
bool cfgFileNameArg = false;
TTQStringList parameters;
TTQStringList includes;
TTQPtrList<CfgEntry> entries;
entries.setAutoDelete( true );
TTQDomNode n;
for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
TTQDomElement e = n.toElement();
TTQString tag = e.tagName();
if ( tag == "include" ) {
TTQString includeFile = e.text();
if (!includeFile.isEmpty())
includes.append(includeFile);
} else if ( tag == "kcfgfile" ) {
cfgFileName = e.attribute( "name" );
cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
TTQDomNode n2;
for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
TTQDomElement e2 = n2.toElement();
if ( e2.tagName() == "parameter" ) {
parameters.append( e2.attribute( "name" ) );
}
}
} else if ( tag == "group" ) {
TTQString group = e.attribute( "name" );
if ( group.isEmpty() ) {
kdError() << "Group without name" << endl;
return 1;
}
TTQDomNode n2;
for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
TTQDomElement e2 = n2.toElement();
if ( e2.tagName() != "entry" ) continue;
CfgEntry *entry = parseEntry( group, e2 );
if ( entry ) entries.append( entry );
else {
kdError() << "Can't parse entry." << endl;
return 1;
}
}
}
}
if ( inherits.isEmpty() ) inherits = "KDE::ConfigSkeleton";
if ( className.isEmpty() ) {
kdError() << "Class name missing" << endl;
return 1;
}
if ( singleton && !parameters.isEmpty() ) {
kdError() << "Singleton class can not have parameters" << endl;
return 1;
}
if ( singleton && cfgFileNameArg)
{
kdError() << "Singleton class can not use filename as argument." << endl;
return 1;
}
if ( !cfgFileName.isEmpty() && cfgFileNameArg)
{
kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
return 1;
}
if ( entries.isEmpty() ) {
kdWarning() << "No entries." << endl;
}
#if 0
CfgEntry *cfg;
for( cfg = entries.first(); cfg; cfg = entries.next() ) {
cfg->dump();
}
#endif
TTQString implementationFileName = baseName + ".rb";
TTQFile implementation( baseDir + implementationFileName );
if ( !implementation.open( IO_WriteOnly ) ) {
kdError() << "Can't open '" << implementationFileName << "for writing." << endl;
return 1;
}
TTQTextStream rb( &implementation );
rb << "# This file is generated by rbkconfig_compiler from " << args->url(0).fileName() << "." << endl;
rb << "# All changes you do to this file will be lost." << endl;
rb << endl << "retquire 'Korundum'" << endl;
if (singleton) {
rb << "retquire 'singleton'" << endl;
}
rb << endl;
// rb << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
// << className.upper() << "_H" << endl;
// rb << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
// << className.upper() << "_H" << endl << endl;
// Includes
// TTQStringList::ConstIterator it;
// for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
// rb << "#include <" << *it << ">" << endl;
// }
if ( headerIncludes.count() > 0 ) rb << endl;
// rb << "#include <kconfigskeleton.h>" << endl << endl;
if ( !nameSpace.isEmpty() )
rb << "module " << nameSpace << endl << endl;
// Class declaration header
rb << "class " << className << " < " << inherits << endl;
if (singleton) {
rb << " include Singleton" << endl << endl;
}
// enums
CfgEntry *e;
for( e = entries.first(); e; e = entries.next() ) {
TTQValueList<CfgEntry::Choice> choices = e->choices();
if ( !choices.isEmpty() ) {
TTQStringList values;
TTQValueList<CfgEntry::Choice>::ConstIterator itChoice;
for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
if (globalEnums) {
values.append( enumValue((*itChoice).name) );
} else {
values.append( enumName(e->name()) + "_" + (*itChoice).name );
}
}
if (!globalEnums) {
values.append( enumName(e->name()) + "_COUNT" );
}
int count = 0;
for ( TTQStringList::Iterator it = values.begin(); it != values.end(); ++it, count++ ) {
rb << " " << *it << " = " << count << endl;
}
rb << endl;
}
TTQStringList values = e->paramValues();
if ( !values.isEmpty() ) {
int count = 0;
for ( TTQStringList::Iterator it = values.begin(); it != values.end(); ++it, count++ ) {
if (globalEnums) {
rb << " " << enumValue(*it) << " = " << count << endl;
} else {
rb << " " << enumName(e->param()) << "_" << *it << " = " << count << endl;
}
}
if (!globalEnums) {
rb << " " << enumName(e->param()) << "_COUNT = " << count << endl;
}
rb << endl;
rb << " def " << enumName(e->param()) << "ToString(i)" << endl;
rb << " [";
count = 0;
for ( TTQStringList::Iterator it = values.begin(); it != values.end(); ++it, count++ ) {
if (count > 0) {
rb << ", ";
}
rb << "\"" << *it << "\"";
}
rb << "].at(i)" << endl;
rb << " end" << endl;
}
}
rb << endl;
for( e = entries.first(); e; e = entries.next() ) {
TTQString n = e->name();
TTQString t = e->type();
// Manipulator
if (allMutators || mutators.contains(n))
{
rb << " #" << endl;
rb << " # Set " << e->label() << endl;
rb << " #" << endl;
rb << " def " << setFunction(n) << "( ";
if (!e->param().isEmpty())
rb << " i, ";
rb << " v )" << endl;
rb << " item = findItem( \"";
if (!e->param().isEmpty()) {
rb << e->paramName().replace("$("+e->param()+")", "%s") << "\" % ";
if ( e->paramType() == "Enum" ) {
rb << " ";
if (globalEnums)
rb << enumName(e->param()) << "ToString(i)";
else
rb << enumName(e->param()) << "ToString(i)";
} else {
rb << "i";
}
} else {
rb << n << "\"";
}
rb << " )" << endl;
rb << " if !item.immutable? " << endl;
rb << " item.property = " << varName(n);
if (!e->param().isEmpty())
rb << "[i]";
rb << " = TQt::Variant.new( v )" << endl;
rb << " end" << endl;
rb << " end" << endl << endl;
}
// Accessor
rb << " #" << endl;
rb << " # Get " << e->label() << endl;
rb << " #" << endl;
rb << " def " << getFunction(n) << "(";
if (!e->param().isEmpty())
rb << " " <<" i ";
rb << ")" << endl;
rb << " " << varName(n);
if (!e->param().isEmpty()) rb << "[i]";
rb << " = findItem( \"";
if (!e->param().isEmpty()) {
rb << e->paramName().replace("$("+e->param()+")", "%s") << "\" % ";
if ( e->paramType() == "Enum" ) {
rb << " ";
if (globalEnums)
rb << enumName(e->param()) << "ToString(i)";
else
rb << enumName(e->param()) << "ToString(i)";
} else {
rb << "i";
}
} else {
rb << n << "\"";
}
rb << " ).property" << endl;
rb << " return " << varName(n);
if (!e->param().isEmpty()) rb << "[i]";
if ( e->type() == "Enum" ) {
rb << ".toInt" << endl;
} else if ( e->type() == "Int64" ) {
rb << ".toLongLong" << endl;
} else if ( e->type() == "Path" ) {
rb << ".toString" << endl;
} else {
rb << ".to" << itemType( e->type() ) << endl;
}
rb << " end" << endl;
// Item accessor
if ( itemAccessors ) {
rb << endl;
rb << " #" << endl;
rb << " # Get Item object corresponding to " << n << "()"
<< endl;
rb << " #" << endl;
rb << " def "
<< getFunction( n ) << "Item(";
if (!e->param().isEmpty()) {
rb << " " << " i ";
}
rb << ")" << endl;
rb << " return " << itemVar(e);
if (!e->param().isEmpty()) rb << "[i]";
rb << endl << " end" << endl;
}
rb << endl;
}
if (customAddons)
{
rb << " # Include custom additions" << endl;
}
// Constructor
rb << " def initialize( ";
if (cfgFileNameArg)
rb << " config" << (parameters.isEmpty() ? " " : ", ");
for (TTQStringList::ConstIterator it = parameters.begin();
it != parameters.end(); ++it)
{
if (it != parameters.begin())
rb << ",";
rb << " " << *it;
}
rb << " )" << endl;
rb << " super(";
if ( !cfgFileName.isEmpty() ) rb << " \"" << cfgFileName << "\" ";
if ( cfgFileNameArg ) rb << " config ";
// if ( !cfgFileName.isEmpty() ) rb << ") ";
rb << ")" << endl;
// Store parameters
for (TTQStringList::ConstIterator it = parameters.begin();
it != parameters.end(); ++it)
{
rb << " @param" << *it << " = TQt::Variant.new( " << *it << " )" << endl;
}
TTQString group;
for( e = entries.first(); e; e = entries.next() ) {
if ( e->group() != group ) {
group = e->group();
rb << endl;
rb << " # " << group << endl;
}
if (e->param().isEmpty()) {
rb << " " << varName(e->name()) << " = TQt::Variant.new( " << rbType(e->type()) << " )";
} else {
rb << " " << varName(e->name()) << " = [ ";
for (int i = 0; i < e->paramMax()+1; i++) {
if (i > 0) {
rb << ", ";
}
rb << "TQt::Variant.new( " << rbType(e->type()) << " )";
}
rb << " ]";
}
rb << endl;
}
rb << endl;
group = TTQString::null;
for( e = entries.first(); e; e = entries.next() ) {
if ( e->group() != group ) {
if ( !group.isEmpty() ) rb << endl;
group = e->group();
rb << " setCurrentGroup( " << paramString(group, parameters) << " )" << endl << endl;
}
TTQString key = paramString(e->key(), parameters);
if ( !e->code().isEmpty())
{
rb << e->code() << endl;
}
if ( e->type() == "Enum" ) {
rb << " values"
<< e->name() << " = []" << endl;
TTQValueList<CfgEntry::Choice> choices = e->choices();
TTQValueList<CfgEntry::Choice>::ConstIterator it;
for( it = choices.begin(); it != choices.end(); ++it ) {
rb << " choice = ItemEnum::Choice.new" << endl;
rb << " choice.name = \"" << enumValue((*it).name) << "\" " << endl;
if ( setUserTexts ) {
if ( !(*it).label.isEmpty() )
rb << " choice.label = i18n(" << quoteString((*it).label) << ")" << endl;
if ( !(*it).whatsThis.isEmpty() )
rb << " choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ")" << endl;
}
rb << " values" << e->name() << " << choice" << endl;
}
}
if (e->param().isEmpty())
{
// Normal case
rb << " " << itemVar(e) << " = "
<< newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
rb << " " << itemVar(e) << ".property = " << varName(e->name()) << endl;
if ( !e->minValue().isEmpty() )
rb << " " << itemVar(e) << ".setMinValue(" << e->minValue() << ")" << endl;
if ( !e->maxValue().isEmpty() )
rb << " " << itemVar(e) << ".setMaxValue(" << e->maxValue() << ")" << endl;
if ( setUserTexts )
rb << userTextsFunctions( e );
rb << " addItem( " << itemVar(e);
TTQString quotedName = e->name();
addQuotes( quotedName );
if ( quotedName != key ) rb << ", \"" << e->name() << "\"";
rb << " )" << endl;
}
else
{
// Indexed
rb << " " << itemVar(e) << " = Array.new(" << e->paramMax()+1 << ")" << endl;
for(int i = 0; i <= e->paramMax(); i++)
{
TTQString defaultStr;
TTQString itemVarStr(itemVar(e)+TTQString("[%1]").arg(i));
if ( !e->paramDefaultValue(i).isEmpty() )
defaultStr = e->paramDefaultValue(i);
else if ( !e->defaultValue().isEmpty() )
defaultStr = paramString(e->defaultValue(), e, i);
else
defaultStr = defaultValue( e->type() );
rb << " " << itemVarStr << " = "
<< newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, TTQString("[%1]").arg(i) )
<< endl;
rb << " " << itemVarStr << ".property = " << varName(e->name())+TTQString("[%1]").arg(i) << endl;
if ( setUserTexts )
rb << userTextsFunctions( e, itemVarStr, e->paramName() );
// Make mutators for enum parameters work by adding them with $(..) replaced by the
// param name. The check for isImmutable in the set* functions doesn't have the param
// name available, just the corresponding enum value (int), so we need to store the
// param names in a separate static list!.
rb << " addItem( " << itemVarStr << ", \"";
if ( e->paramType()=="Enum" )
rb << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] );
else
rb << e->paramName().replace( "$("+e->param()+")", "%1").arg(i);
rb << "\" )" << endl;
}
}
}
rb << " end" << endl << endl;
rb << "end" << endl << endl;
if ( !nameSpace.isEmpty() ) rb << "end" << endl << endl;
implementation.close();
}