00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <qfile.h>
00026 #include <qtextstream.h>
00027 #include <qdom.h>
00028 #include <qregexp.h>
00029
00030 #include <kaboutdata.h>
00031 #include <kapplication.h>
00032 #include <kdebug.h>
00033 #include <klocale.h>
00034 #include <kcmdlineargs.h>
00035 #include <kglobal.h>
00036 #include <kconfig.h>
00037 #include <ksimpleconfig.h>
00038 #include <kstandarddirs.h>
00039
00040 static const KCmdLineOptions options[] =
00041 {
00042 { "d", 0, 0 },
00043 { "directory <dir>", I18N_NOOP("Directory to generate files in"), "." },
00044 { "+file.kfcg", I18N_NOOP("Input kcfg XML file."), 0 },
00045 { "+file.kcfgc", I18N_NOOP("Code generation options file."), 0 },
00046 KCmdLineLastOption
00047 };
00048
00049
00050 bool globalEnums;
00051 bool itemAccessors;
00052
00053 class CfgEntry
00054 {
00055 public:
00056 struct Choice
00057 {
00058 QString name;
00059 QString label;
00060 QString whatsThis;
00061 };
00062
00063 CfgEntry( const QString &group, const QString &type, const QString &key,
00064 const QString &name, const QString &label,
00065 const QString &whatsThis, const QString &code,
00066 const QString &defaultValue, const QValueList<Choice> &choices,
00067 bool hidden )
00068 : mGroup( group ), mType( type ), mKey( key ), mName( name ),
00069 mLabel( label ), mWhatsThis( whatsThis ), mCode( code ),
00070 mDefaultValue( defaultValue ),
00071 mChoices( choices ), mHidden( hidden )
00072 {
00073 }
00074
00075 void setGroup( const QString &group ) { mGroup = group; }
00076 QString group() const { return mGroup; }
00077
00078 void setType( const QString &type ) { mType = type; }
00079 QString type() const { return mType; }
00080
00081 void setKey( const QString &key ) { mKey = key; }
00082 QString key() const { return mKey; }
00083
00084 void setName( const QString &name ) { mName = name; }
00085 QString name() const { return mName; }
00086
00087 void setLabel( const QString &label ) { mLabel = label; }
00088 QString label() const { return mLabel; }
00089
00090 void setWhatsThis( const QString &whatsThis ) { mWhatsThis = whatsThis; }
00091 QString whatsThis() const { return mWhatsThis; }
00092
00093 void setDefaultValue( const QString &d ) { mDefaultValue = d; }
00094 QString defaultValue() const { return mDefaultValue; }
00095
00096 void setCode( const QString &d ) { mCode = d; }
00097 QString code() const { return mCode; }
00098
00099 void setMinValue( const QString &d ) { mMin = d; }
00100 QString minValue() const { return mMin; }
00101
00102 void setMaxValue( const QString &d ) { mMax = d; }
00103 QString maxValue() const { return mMax; }
00104
00105 void setParam( const QString &d ) { mParam = d; }
00106 QString param() const { return mParam; }
00107
00108 void setParamName( const QString &d ) { mParamName = d; }
00109 QString paramName() const { return mParamName; }
00110
00111 void setParamType( const QString &d ) { mParamType = d; }
00112 QString paramType() const { return mParamType; }
00113
00114 void setChoices( const QValueList<Choice> &d ) { mChoices = d; }
00115 QValueList<Choice> choices() const { return mChoices; }
00116
00117 void setParamValues( const QStringList &d ) { mParamValues = d; }
00118 QStringList paramValues() const { return mParamValues; }
00119
00120 void setParamDefaultValues( const QStringList &d ) { mParamDefaultValues = d; }
00121 QString paramDefaultValue(int i) const { return mParamDefaultValues[i]; }
00122
00123 void setParamMax( int d ) { mParamMax = d; }
00124 int paramMax() const { return mParamMax; }
00125
00126 bool hidden() const { return mHidden; }
00127
00128 void dump() const
00129 {
00130 kdDebug() << "<entry>" << endl;
00131 kdDebug() << " group: " << mGroup << endl;
00132 kdDebug() << " type: " << mType << endl;
00133 kdDebug() << " key: " << mKey << endl;
00134 kdDebug() << " name: " << mName << endl;
00135 kdDebug() << " label: " << mLabel << endl;
00136
00137 kdDebug() << " code: " << mCode << endl;
00138
00139 kdDebug() << " paramvalues: " << mParamValues.join(":") << endl;
00140 kdDebug() << " default: " << mDefaultValue << endl;
00141 kdDebug() << " hidden: " << mHidden << endl;
00142 kdDebug() << " min: " << mMin << endl;
00143 kdDebug() << " max: " << mMax << endl;
00144 kdDebug() << "</entry>" << endl;
00145 }
00146
00147 private:
00148 QString mGroup;
00149 QString mType;
00150 QString mKey;
00151 QString mName;
00152 QString mLabel;
00153 QString mWhatsThis;
00154 QString mCode;
00155 QString mDefaultValue;
00156 QString mParam;
00157 QString mParamName;
00158 QString mParamType;
00159 QValueList<Choice> mChoices;
00160 QStringList mParamValues;
00161 QStringList mParamDefaultValues;
00162 int mParamMax;
00163 bool mHidden;
00164 QString mMin;
00165 QString mMax;
00166 };
00167
00168
00169 static QString varName(const QString &n)
00170 {
00171 QString result = "m"+n;
00172 result[1] = result[1].upper();
00173 return result;
00174 }
00175
00176 static QString enumName(const QString &n)
00177 {
00178 QString result = "Enum"+n;
00179 result[4] = result[4].upper();
00180 return result;
00181 }
00182
00183 static QString setFunction(const QString &n)
00184 {
00185 QString result = "set"+n;
00186 result[3] = result[3].upper();
00187 return result;
00188 }
00189
00190
00191 static QString getFunction(const QString &n)
00192 {
00193 QString result = n;
00194 result[0] = result[0].lower();
00195 return result;
00196 }
00197
00198
00199 static void addQuotes( QString &s )
00200 {
00201 if ( s.left( 1 ) != "\"" ) s.prepend( "\"" );
00202 if ( s.right( 1 ) != "\"" ) s.append( "\"" );
00203 }
00204
00205 static QString dumpNode(const QDomNode &node)
00206 {
00207 QString msg;
00208 QTextStream s(&msg, IO_WriteOnly );
00209 node.save(s, 0);
00210
00211 msg = msg.simplifyWhiteSpace();
00212 if (msg.length() > 40)
00213 return msg.left(37)+"...";
00214 return msg;
00215 }
00216
00217 static QString filenameOnly(QString path)
00218 {
00219 int i = path.findRev('/');
00220 if (i >= 0)
00221 return path.mid(i+1);
00222 return path;
00223 }
00224
00225 static void preProcessDefault( QString &defaultValue, const QString &name,
00226 const QString &type,
00227 const QValueList<CfgEntry::Choice> &choices,
00228 QString &code )
00229 {
00230 if ( type == "String" && !defaultValue.isEmpty() ) {
00231 addQuotes( defaultValue );
00232
00233 } else if ( type == "Path" && !defaultValue.isEmpty() ) {
00234 addQuotes( defaultValue );
00235
00236 } else if ( type == "StringList" && !defaultValue.isEmpty() ) {
00237 QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00238 if (!code.isEmpty())
00239 cpp << endl;
00240
00241 cpp << " QStringList default" << name << ";" << endl;
00242 QStringList defaults = QStringList::split( ",", defaultValue );
00243 QStringList::ConstIterator it;
00244 for( it = defaults.begin(); it != defaults.end(); ++it ) {
00245 cpp << " default" << name << ".append( \"" << *it << "\" );"
00246 << endl;
00247 }
00248 defaultValue = "default" + name;
00249
00250 } else if ( type == "Color" && !defaultValue.isEmpty() ) {
00251 QRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+");
00252 if (colorRe.exactMatch(defaultValue))
00253 {
00254 defaultValue = "QColor( " + defaultValue + " )";
00255 }
00256 else
00257 {
00258 defaultValue = "QColor( \"" + defaultValue + "\" )";
00259 }
00260
00261 } else if ( type == "Enum" ) {
00262 if ( !globalEnums ) {
00263 QValueList<CfgEntry::Choice>::ConstIterator it;
00264 for( it = choices.begin(); it != choices.end(); ++it ) {
00265 if ( (*it).name == defaultValue ) {
00266 defaultValue.prepend( enumName(name) + "::");
00267 break;
00268 }
00269 }
00270 }
00271
00272 } else if ( type == "IntList" ) {
00273 QTextStream cpp( &code, IO_WriteOnly | IO_Append );
00274 if (!code.isEmpty())
00275 cpp << endl;
00276
00277 cpp << " QValueList<int> default" << name << ";" << endl;
00278 QStringList defaults = QStringList::split( ",", defaultValue );
00279 QStringList::ConstIterator it;
00280 for( it = defaults.begin(); it != defaults.end(); ++it ) {
00281 cpp << " default" << name << ".append( " << *it << " );"
00282 << endl;
00283 }
00284 defaultValue = "default" + name;
00285 }
00286 }
00287
00288
00289 CfgEntry *parseEntry( const QString &group, const QDomElement &element )
00290 {
00291 bool defaultCode = false;
00292 QString type = element.attribute( "type" );
00293 QString name = element.attribute( "name" );
00294 QString key = element.attribute( "key" );
00295 QString hidden = element.attribute( "hidden" );
00296 QString label;
00297 QString whatsThis;
00298 QString defaultValue;
00299 QString code;
00300 QString param;
00301 QString paramName;
00302 QString paramType;
00303 QValueList<CfgEntry::Choice> choices;
00304 QStringList paramValues;
00305 QStringList paramDefaultValues;
00306 QString minValue;
00307 QString maxValue;
00308 int paramMax = 0;
00309
00310 QDomNode n;
00311 for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00312 QDomElement e = n.toElement();
00313 QString tag = e.tagName();
00314 if ( tag == "label" ) label = e.text();
00315 else if ( tag == "whatsthis" ) whatsThis = e.text();
00316 else if ( tag == "min" ) minValue = e.text();
00317 else if ( tag == "max" ) maxValue = e.text();
00318 else if ( tag == "code" ) code = e.text();
00319 else if ( tag == "parameter" )
00320 {
00321 param = e.attribute( "name" );
00322 paramType = e.attribute( "type" );
00323 if ( param.isEmpty() ) {
00324 kdError() << "Parameter must have a name: " << dumpNode(e) << endl;
00325 return 0;
00326 }
00327 if ( paramType.isEmpty() ) {
00328 kdError() << "Parameter must have a type: " << dumpNode(e) << endl;
00329 return 0;
00330 }
00331 if ((paramType == "Int") || (paramType == "UInt"))
00332 {
00333 bool ok;
00334 paramMax = e.attribute("max").toInt(&ok);
00335 if (!ok)
00336 {
00337 kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl;
00338 return 0;
00339 }
00340 }
00341 else if (paramType == "Enum")
00342 {
00343 QDomNode n2;
00344 for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00345 QDomElement e2 = n2.toElement();
00346 if (e2.tagName() == "values")
00347 {
00348 QDomNode n3;
00349 for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00350 QDomElement e3 = n3.toElement();
00351 if (e3.tagName() == "value")
00352 {
00353 paramValues.append( e3.text() );
00354 }
00355 }
00356 break;
00357 }
00358 }
00359 if (paramValues.isEmpty())
00360 {
00361 kdError() << "No values specified for parameter '" << param << "'." << endl;
00362 return 0;
00363 }
00364 paramMax = paramValues.count()-1;
00365 }
00366 else
00367 {
00368 kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl;
00369 return 0;
00370 }
00371 }
00372 else if ( tag == "default" )
00373 {
00374 if (e.attribute("param").isEmpty())
00375 {
00376 defaultValue = e.text();
00377 if (e.attribute( "code" ) == "true")
00378 defaultCode = true;
00379 }
00380 }
00381 else if ( tag == "choices" ) {
00382 QDomNode n2;
00383 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00384 QDomElement e2 = n2.toElement();
00385 if ( e2.tagName() == "choice" ) {
00386 QDomNode n3;
00387 CfgEntry::Choice choice;
00388 choice.name = e2.attribute( "name" );
00389 if ( choice.name.isEmpty() ) {
00390 kdError() << "Tag <choice> requires attribute 'name'." << endl;
00391 }
00392 for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) {
00393 QDomElement e3 = n3.toElement();
00394 if ( e3.tagName() == "label" ) choice.label = e3.text();
00395 if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text();
00396 }
00397 choices.append( choice );
00398 }
00399 }
00400 }
00401 }
00402
00403 if ( name.isEmpty() && key.isEmpty() ) {
00404 kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl;
00405 return 0;
00406 }
00407
00408 if ( key.isEmpty() ) {
00409 key = name;
00410 }
00411
00412 if ( name.isEmpty() ) {
00413 name = key;
00414 name.replace( " ", "" );
00415 } else if ( name.contains( ' ' ) ) {
00416 kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl;
00417 name.remove( ' ' );
00418 }
00419
00420 if (name.contains("$("))
00421 {
00422 if (param.isEmpty())
00423 {
00424 kdError() << "Name may not be parameterized: " << name << endl;
00425 return 0;
00426 }
00427 }
00428 else
00429 {
00430 if (!param.isEmpty())
00431 {
00432 kdError() << "Name must contain '$(" << param << ")': " << name << endl;
00433 return 0;
00434 }
00435 }
00436
00437 if ( label.isEmpty() ) {
00438 label = key;
00439 }
00440
00441 if ( type.isEmpty() ) type = "String";
00442
00443 if (!param.isEmpty())
00444 {
00445
00446 paramName = name;
00447 name.replace("$("+param+")", QString::null);
00448
00449 for(int i = 0; i <= paramMax; i++)
00450 {
00451 paramDefaultValues.append(QString::null);
00452 }
00453
00454 QDomNode n;
00455 for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00456 QDomElement e = n.toElement();
00457 QString tag = e.tagName();
00458 if ( tag == "default" )
00459 {
00460 QString index = e.attribute("param");
00461 if (index.isEmpty())
00462 continue;
00463
00464 bool ok;
00465 int i = index.toInt(&ok);
00466 if (!ok)
00467 {
00468 i = paramValues.findIndex(index);
00469 if (i == -1)
00470 {
00471 kdError() << "Index '" << index << "' for default value is unknown." << endl;
00472 return 0;
00473 }
00474 }
00475
00476 if ((i < 0) || (i > paramMax))
00477 {
00478 kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl;
00479 return 0;
00480 }
00481
00482 QString tmpDefaultValue = e.text();
00483
00484 if (e.attribute( "code" ) != "true")
00485 preProcessDefault(tmpDefaultValue, name, type, choices, code);
00486
00487 paramDefaultValues[i] = tmpDefaultValue;
00488 }
00489 }
00490 }
00491
00492 if (!defaultCode)
00493 {
00494 preProcessDefault(defaultValue, name, type, choices, code);
00495 }
00496
00497 CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis,
00498 code, defaultValue, choices,
00499 hidden == "true" );
00500 if (!param.isEmpty())
00501 {
00502 result->setParam(param);
00503 result->setParamName(paramName);
00504 result->setParamType(paramType);
00505 result->setParamValues(paramValues);
00506 result->setParamDefaultValues(paramDefaultValues);
00507 result->setParamMax(paramMax);
00508 }
00509 result->setMinValue(minValue);
00510 result->setMaxValue(maxValue);
00511
00512 return result;
00513 }
00514
00518 QString param( const QString &type )
00519 {
00520 if ( type == "String" ) return "const QString &";
00521 else if ( type == "StringList" ) return "const QStringList &";
00522 else if ( type == "Font" ) return "const QFont &";
00523 else if ( type == "Rect" ) return "const QRect &";
00524 else if ( type == "Size" ) return "const QSize &";
00525 else if ( type == "Color" ) return "const QColor &";
00526 else if ( type == "Point" ) return "const QPoint &";
00527 else if ( type == "Int" ) return "int";
00528 else if ( type == "UInt" ) return "uint";
00529 else if ( type == "Bool" ) return "bool";
00530 else if ( type == "Double" ) return "double";
00531 else if ( type == "DateTime" ) return "const QDateTime &";
00532 else if ( type == "Int64" ) return "Q_INT64";
00533 else if ( type == "UInt64" ) return "Q_UINT64";
00534 else if ( type == "IntList" ) return "const QValueList<int> &";
00535 else if ( type == "Enum" ) return "int";
00536 else if ( type == "Path" ) return "const QString &";
00537 else if ( type == "Password" ) return "const QString &";
00538 else {
00539 kdError() <<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00540 return "QString";
00541 }
00542 }
00543
00547 QString cppType( const QString &type )
00548 {
00549 if ( type == "String" ) return "QString";
00550 else if ( type == "StringList" ) return "QStringList";
00551 else if ( type == "Font" ) return "QFont";
00552 else if ( type == "Rect" ) return "QRect";
00553 else if ( type == "Size" ) return "QSize";
00554 else if ( type == "Color" ) return "QColor";
00555 else if ( type == "Point" ) return "QPoint";
00556 else if ( type == "Int" ) return "int";
00557 else if ( type == "UInt" ) return "uint";
00558 else if ( type == "Bool" ) return "bool";
00559 else if ( type == "Double" ) return "double";
00560 else if ( type == "DateTime" ) return "QDateTime";
00561 else if ( type == "Int64" ) return "Q_INT64";
00562 else if ( type == "UInt64" ) return "Q_UINT64";
00563 else if ( type == "IntList" ) return "QValueList<int>";
00564 else if ( type == "Enum" ) return "int";
00565 else if ( type == "Path" ) return "QString";
00566 else if ( type == "Password" ) return "QString";
00567 else {
00568 kdError()<<"kconfig_compiler does not support type \""<< type <<"\""<<endl;
00569 return "QString";
00570 }
00571 }
00572
00573 QString defaultValue( const QString &type )
00574 {
00575 if ( type == "String" ) return "\"\"";
00576 else if ( type == "StringList" ) return "QStringList()";
00577 else if ( type == "Font" ) return "KGlobalSettings::generalFont()";
00578 else if ( type == "Rect" ) return "QRect()";
00579 else if ( type == "Size" ) return "QSize()";
00580 else if ( type == "Color" ) return "QColor(128, 128, 128)";
00581 else if ( type == "Point" ) return "QPoint()";
00582 else if ( type == "Int" ) return "0";
00583 else if ( type == "UInt" ) return "0";
00584 else if ( type == "Bool" ) return "false";
00585 else if ( type == "Double" ) return "0.0";
00586 else if ( type == "DateTime" ) return "QDateTime()";
00587 else if ( type == "Int64" ) return "0";
00588 else if ( type == "UInt64" ) return "0";
00589 else if ( type == "IntList" ) return "QValueList<int>()";
00590 else if ( type == "Enum" ) return "0";
00591 else if ( type == "Path" ) return "\"\"";
00592 else if ( type == "Password" ) return "\"\"";
00593 else {
00594 kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl;
00595 return "QString";
00596 }
00597 }
00598
00599 QString itemType( const QString &type )
00600 {
00601 QString t;
00602
00603 t = type;
00604 t.replace( 0, 1, t.left( 1 ).upper() );
00605
00606 return t;
00607 }
00608
00609 static QString itemDeclaration(const CfgEntry *e)
00610 {
00611 if (itemAccessors)
00612 return QString::null;
00613
00614 return " KConfigSkeleton::Item"+itemType( e->type() ) +
00615 " *item" + e->name() + ";\n";
00616 }
00617
00618 static QString itemVar(const CfgEntry *e)
00619 {
00620 if (itemAccessors)
00621 return varName( e->name() ) + "Item";
00622
00623 return "item" + e->name();
00624
00625 }
00626
00627 QString newItem( const QString &type, const QString &name, const QString &key,
00628 const QString &defaultValue, const QString ¶m = QString::null)
00629 {
00630 QString t = "new KConfigSkeleton::Item" + itemType( type ) +
00631 "( currentGroup(), " + key + ", " + varName( name ) + param;
00632 if ( type == "Enum" ) t += ", values" + name;
00633 if ( !defaultValue.isEmpty() ) t += ", " + defaultValue;
00634 t += " );";
00635
00636 return t;
00637 }
00638
00639 QString paramString(const QString &s, const CfgEntry *e, int i)
00640 {
00641 QString result = s;
00642 QString needle = "$("+e->param()+")";
00643 if (result.contains(needle))
00644 {
00645 QString tmp;
00646 if (e->paramType() == "Enum")
00647 {
00648 tmp = e->paramValues()[i];
00649 }
00650 else
00651 {
00652 tmp = QString("%1").arg(i);
00653 }
00654
00655 result.replace(needle, tmp);
00656 }
00657 return result;
00658 }
00659
00660 QString paramString(const QString &group, const QStringList ¶meters)
00661 {
00662 QString paramString = group;
00663 QString arguments;
00664 int i = 1;
00665 for( QStringList::ConstIterator it = parameters.begin();
00666 it != parameters.end(); ++it)
00667 {
00668 if (paramString.contains("$("+*it+")"))
00669 {
00670 QString tmp;
00671 tmp.sprintf("%%%d", i++);
00672 paramString.replace("$("+*it+")", tmp);
00673 arguments += ".arg( mParam"+*it+" )";
00674 }
00675 }
00676 if (arguments.isEmpty())
00677 return "\""+group+"\"";
00678
00679 return "QString(\""+paramString+"\")"+arguments;
00680 }
00681
00682 QString userTextsFunctions( CfgEntry *e )
00683 {
00684 QString txt;
00685 if ( !e->label().isEmpty() ) {
00686 txt += " " + itemVar(e) + "->setLabel( i18n(\"" +
00687 e->label() + "\") );\n";
00688 }
00689 if ( !e->whatsThis().isEmpty() ) {
00690 txt += " " + itemVar(e) + "->setWhatsThis( i18n(\"" +
00691 e->whatsThis() + "\") );\n";
00692 }
00693 return txt;
00694 }
00695
00696 int main( int argc, char **argv )
00697 {
00698 KAboutData aboutData( "kconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3",
00699 I18N_NOOP("KConfig Compiler") , KAboutData::License_LGPL );
00700 aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" );
00701 aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" );
00702 aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" );
00703
00704 KCmdLineArgs::init( argc, argv, &aboutData );
00705 KCmdLineArgs::addCmdLineOptions( options );
00706
00707 KInstance app( &aboutData );
00708
00709 KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
00710
00711 if ( args->count() < 2 ) {
00712 kdError() << "Too few arguments." << endl;
00713 return 1;
00714 }
00715 if ( args->count() > 2 ) {
00716 kdError() << "Too many arguments." << endl;
00717 return 1;
00718 }
00719
00720 QString baseDir = QFile::decodeName(args->getOption("directory"));
00721 if (!baseDir.endsWith("/"))
00722 baseDir.append("/");
00723
00724 QString inputFilename = args->url( 0 ).path();
00725 QString codegenFilename = args->url( 1 ).path();
00726
00727 if (!codegenFilename.endsWith(".kcfgc"))
00728 {
00729 kdError() << "Codegen options file must have extension .kcfgc" << endl;
00730 return 1;
00731 }
00732 QString baseName = args->url( 1 ).fileName();
00733 baseName = baseName.left(baseName.length() - 6);
00734
00735 KSimpleConfig codegenConfig( codegenFilename, true );
00736
00737 QString nameSpace = codegenConfig.readEntry("NameSpace");
00738 QString className = codegenConfig.readEntry("ClassName");
00739 QString inherits = codegenConfig.readEntry("Inherits");
00740 bool singleton = codegenConfig.readBoolEntry("Singleton", false);
00741 bool staticAccessors = singleton;
00742 bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
00743 QString memberVariables = codegenConfig.readEntry("MemberVariables");
00744 QStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
00745 QStringList mutators = codegenConfig.readListEntry("Mutators");
00746 bool allMutators = false;
00747 if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
00748 allMutators = true;
00749 itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
00750 bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
00751
00752 globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
00753
00754 QFile input( inputFilename );
00755
00756 QDomDocument doc;
00757 QString errorMsg;
00758 int errorRow;
00759 int errorCol;
00760 if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
00761 kdError() << "Unable to load document." << endl;
00762 kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
00763 return 1;
00764 }
00765
00766 QDomElement cfgElement = doc.documentElement();
00767
00768 if ( cfgElement.isNull() ) {
00769 kdError() << "No document in kcfg file" << endl;
00770 return 1;
00771 }
00772
00773 QString cfgFileName;
00774 bool cfgFileNameArg = false;
00775 QStringList parameters;
00776 QStringList includes;
00777
00778 QPtrList<CfgEntry> entries;
00779 entries.setAutoDelete( true );
00780
00781 QDomNode n;
00782 for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00783 QDomElement e = n.toElement();
00784
00785 QString tag = e.tagName();
00786
00787 if ( tag == "include" ) {
00788 QString includeFile = e.text();
00789 if (!includeFile.isEmpty())
00790 includes.append(includeFile);
00791
00792 } else if ( tag == "kcfgfile" ) {
00793 cfgFileName = e.attribute( "name" );
00794 cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
00795 QDomNode n2;
00796 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00797 QDomElement e2 = n2.toElement();
00798 if ( e2.tagName() == "parameter" ) {
00799 parameters.append( e2.attribute( "name" ) );
00800 }
00801 }
00802
00803 } else if ( tag == "group" ) {
00804 QString group = e.attribute( "name" );
00805 if ( group.isEmpty() ) {
00806 kdError() << "Group without name" << endl;
00807 return 1;
00808 }
00809 QDomNode n2;
00810 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00811 QDomElement e2 = n2.toElement();
00812 CfgEntry *entry = parseEntry( group, e2 );
00813 if ( entry ) entries.append( entry );
00814 else {
00815 kdError() << "Can't parse entry." << endl;
00816 return 1;
00817 }
00818 }
00819 }
00820 }
00821
00822 if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
00823
00824 if ( className.isEmpty() ) {
00825 kdError() << "Class name missing" << endl;
00826 return 1;
00827 }
00828
00829 if ( singleton && !parameters.isEmpty() ) {
00830 kdError() << "Singleton class can not have parameters" << endl;
00831 return 1;
00832 }
00833
00834 if ( singleton && cfgFileNameArg)
00835 {
00836 kdError() << "Singleton class can not use filename as argument." << endl;
00837 return 1;
00838 }
00839
00840 if ( !cfgFileName.isEmpty() && cfgFileNameArg)
00841 {
00842 kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
00843 return 1;
00844 }
00845
00846 if ( entries.isEmpty() ) {
00847 kdWarning() << "No entries." << endl;
00848 }
00849
00850 #if 0
00851 CfgEntry *cfg;
00852 for( cfg = entries.first(); cfg; cfg = entries.next() ) {
00853 cfg->dump();
00854 }
00855 #endif
00856
00857 QString headerFileName = baseName + ".h";
00858 QString implementationFileName = baseName + ".cpp";
00859
00860 QFile header( baseDir + headerFileName );
00861 if ( !header.open( IO_WriteOnly ) ) {
00862 kdError() << "Can't open '" << headerFileName << "for writing." << endl;
00863 return 1;
00864 }
00865
00866 QTextStream h( &header );
00867
00868 h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
00869 h << "// All changes you do to this file will be lost." << endl;
00870
00871 h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00872 << className.upper() << "_H" << endl;
00873 h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00874 << className.upper() << "_H" << endl << endl;
00875
00876
00877 QStringList::ConstIterator it;
00878 for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
00879 h << "#include <" << *it << ">" << endl;
00880 }
00881
00882 if ( headerIncludes.count() > 0 ) h << endl;
00883
00884 h << "#include <kconfigskeleton.h>" << endl << endl;
00885
00886 if ( !nameSpace.isEmpty() )
00887 h << "namespace " << nameSpace << " {" << endl << endl;
00888
00889
00890 h << "class " << className << " : public " << inherits << endl;
00891 h << "{" << endl;
00892 h << " public:" << endl;
00893
00894
00895 CfgEntry *e;
00896 for( e = entries.first(); e; e = entries.next() ) {
00897 QValueList<CfgEntry::Choice> choices = e->choices();
00898 if ( !choices.isEmpty() ) {
00899 QStringList values;
00900 QValueList<CfgEntry::Choice>::ConstIterator itChoice;
00901 for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
00902 values.append( (*itChoice).name );
00903 }
00904 if ( globalEnums ) {
00905 h << " enum { " << values.join( ", " ) << " };" << endl;
00906 } else {
00907 h << " class " << enumName(e->name()) << endl;
00908 h << " {" << endl;
00909 h << " public:" << endl;
00910 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00911 h << " };" << endl;
00912 }
00913 }
00914 QStringList values = e->paramValues();
00915 if ( !values.isEmpty() ) {
00916 h << " class " << enumName(e->param()) << endl;
00917 h << " {" << endl;
00918 h << " public:" << endl;
00919 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00920 h << " };" << endl;
00921 }
00922 }
00923
00924 h << endl;
00925
00926
00927 if ( !singleton ) {
00928 h << " " << className << "(";
00929 if (cfgFileNameArg)
00930 h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
00931 for (QStringList::ConstIterator it = parameters.begin();
00932 it != parameters.end(); ++it)
00933 {
00934 if (it != parameters.begin())
00935 h << ",";
00936 h << " const QString &" << *it;
00937 }
00938 h << " );" << endl;
00939 } else {
00940 h << " static " << className << " *self();" << endl;
00941 }
00942
00943
00944 h << " ~" << className << "();" << endl << endl;
00945
00946 QString This;
00947 QString Const;
00948 if (staticAccessors)
00949 This = "self()->";
00950 else
00951 Const = " const";
00952
00953 for( e = entries.first(); e; e = entries.next() ) {
00954 QString n = e->name();
00955 QString t = e->type();
00956
00957
00958 if (allMutators || mutators.contains(n))
00959 {
00960 h << " /**" << endl;
00961 h << " Set " << e->label() << endl;
00962 h << " */" << endl;
00963 if (staticAccessors)
00964 h << " static" << endl;
00965 h << " void " << setFunction(n) << "( ";
00966 if (!e->param().isEmpty())
00967 h << cppType(e->paramType()) << " i, ";
00968 h << param( t ) << " v )" << endl;
00969 h << " {" << endl;
00970 h << " if (!" << This << "isImmutable( \"" << n << "\" ))" << endl;
00971 h << " " << This << varName(n);
00972 if (!e->param().isEmpty())
00973 h << "[i]";
00974 h << " = v;" << endl;
00975 h << " }" << endl << endl;
00976 }
00977
00978
00979 h << " /**" << endl;
00980 h << " Get " << e->label() << endl;
00981 h << " */" << endl;
00982 if (staticAccessors)
00983 h << " static" << endl;
00984 h << " " << cppType(t) << " " << getFunction(n) << "(";
00985 if (!e->param().isEmpty())
00986 h << " " << cppType(e->paramType()) <<" i ";
00987 h << ")" << Const << endl;
00988 h << " {" << endl;
00989 h << " return " << This << varName(n);
00990 if (!e->param().isEmpty())
00991 h << "[i]";
00992 h << ";" << endl;
00993 h << " }" << endl;
00994
00995
00996 if ( itemAccessors ) {
00997 h << endl;
00998 h << " /**" << endl;
00999 h << " Get Item object corresponding to " << n << "()"
01000 << endl;
01001 h << " */" << endl;
01002 h << " Item" << itemType( e->type() ) << " *"
01003 << getFunction( n ) << "Item()" << endl;
01004 h << " {" << endl;
01005 h << " return " << itemVar(e) << ";" << endl;
01006 h << " }" << endl;
01007 }
01008
01009 h << endl;
01010 }
01011
01012
01013 if ( singleton ) {
01014 h << " static" << endl;
01015 h << " void writeConfig()" << endl;
01016 h << " {" << endl;
01017 h << " static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
01018 h << " }" << endl;
01019 }
01020
01021 h << " protected:" << endl;
01022
01023
01024 if ( singleton ) {
01025 h << " " << className << "();" << endl;
01026 h << " static " << className << " *mSelf;" << endl << endl;
01027 }
01028
01029
01030 if ( !memberVariables.isEmpty() && memberVariables != "private" ) {
01031 h << " " << memberVariables << ":" << endl;
01032 }
01033
01034
01035 for (QStringList::ConstIterator it = parameters.begin();
01036 it != parameters.end(); ++it)
01037 {
01038 h << " QString mParam" << *it << ";" << endl;
01039 }
01040
01041 QString group;
01042 for( e = entries.first(); e; e = entries.next() ) {
01043 if ( e->group() != group ) {
01044 group = e->group();
01045 h << endl;
01046 h << " // " << group << endl;
01047 }
01048 h << " " << cppType(e->type()) << " " << varName(e->name());
01049 if (!e->param().isEmpty())
01050 {
01051 h << QString("[%1]").arg(e->paramMax()+1);
01052 }
01053 h << ";" << endl;
01054 }
01055
01056 h << endl << " private:" << endl;
01057 if ( itemAccessors ) {
01058 for( e = entries.first(); e; e = entries.next() ) {
01059 h << " Item" << itemType( e->type() ) << " *" << itemVar( e ) << ";" << endl;
01060 }
01061 }
01062
01063 if (customAddons)
01064 {
01065 h << " // Include custom additions" << endl;
01066 h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01067 }
01068
01069 h << "};" << endl << endl;
01070
01071 if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
01072
01073 h << "#endif" << endl;
01074
01075
01076 header.close();
01077
01078 QFile implementation( baseDir + implementationFileName );
01079 if ( !implementation.open( IO_WriteOnly ) ) {
01080 kdError() << "Can't open '" << implementationFileName << "for writing."
01081 << endl;
01082 return 1;
01083 }
01084
01085 QTextStream cpp( &implementation );
01086
01087
01088 cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01089 cpp << "// All changes you do to this file will be lost." << endl << endl;
01090
01091 cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01092
01093 if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01094
01095
01096 for( it = includes.begin(); it != includes.end(); ++it ) {
01097 cpp << "#include <" << *it << ">" << endl;
01098 }
01099
01100
01101 if ( singleton )
01102 cpp << "#include <kstaticdeleter.h>" << endl << endl;
01103
01104 if ( !nameSpace.isEmpty() )
01105 cpp << "using namespace " << nameSpace << ";" << endl << endl;
01106
01107
01108 if ( singleton ) {
01109 cpp << className << " *" << className << "::mSelf = 0;" << endl;
01110 cpp << "static KStaticDeleter<" << className << "> staticDeleter;" << endl << endl;
01111
01112 cpp << className << " *" << className << "::self()" << endl;
01113 cpp << "{" << endl;
01114 cpp << " if ( !mSelf ) {" << endl;
01115 cpp << " staticDeleter.setObject( mSelf, new " << className << "() );" << endl;
01116 cpp << " mSelf->readConfig();" << endl;
01117 cpp << " }" << endl << endl;
01118 cpp << " return mSelf;" << endl;
01119 cpp << "}" << endl << endl;
01120 }
01121
01122
01123 cpp << className << "::" << className << "( ";
01124 if (cfgFileNameArg)
01125 cpp << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
01126 for (QStringList::ConstIterator it = parameters.begin();
01127 it != parameters.end(); ++it)
01128 {
01129 if (it != parameters.begin())
01130 cpp << ",";
01131 cpp << " const QString &" << *it;
01132 }
01133 cpp << " )" << endl;
01134
01135 cpp << " : " << inherits << "(";
01136 if ( !cfgFileName.isEmpty() ) cpp << " \"" << cfgFileName << "\" ";
01137 if ( cfgFileNameArg ) cpp << " config ";
01138 cpp << ")" << endl;
01139
01140
01141 for (QStringList::ConstIterator it = parameters.begin();
01142 it != parameters.end(); ++it)
01143 {
01144 cpp << " , mParam" << *it << "(" << *it << ")" << endl;
01145 }
01146
01147 cpp << "{" << endl;
01148
01149
01150
01151 if ( singleton )
01152 cpp << " mSelf = this;" << endl;
01153
01154 group = QString::null;
01155 for( e = entries.first(); e; e = entries.next() ) {
01156 if ( e->group() != group ) {
01157 if ( !group.isEmpty() ) cpp << endl;
01158 group = e->group();
01159 cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
01160 }
01161
01162 QString key = paramString(e->key(), parameters);
01163 if ( !e->code().isEmpty())
01164 {
01165 cpp << e->code() << endl;
01166 }
01167 if ( e->type() == "Enum" ) {
01168 cpp << " QValueList<KConfigSkeleton::ItemEnum::Choice> values"
01169 << e->name() << ";" << endl;
01170 QValueList<CfgEntry::Choice> choices = e->choices();
01171 QValueList<CfgEntry::Choice>::ConstIterator it;
01172 for( it = choices.begin(); it != choices.end(); ++it ) {
01173 cpp << " {" << endl;
01174 cpp << " KConfigSkeleton::ItemEnum::Choice choice;" << endl;
01175 cpp << " choice.name = \"" << (*it).name << "\";" << endl;
01176 if ( setUserTexts ) {
01177 if ( !(*it).label.isEmpty() )
01178 cpp << " choice.label = i18n(\"" << (*it).label << "\");" << endl;
01179 if ( !(*it).whatsThis.isEmpty() )
01180 cpp << " choice.whatsThis = i18n(\"" << (*it).whatsThis << "\");" << endl;
01181 }
01182 cpp << " values" << e->name() << ".append( choice );" << endl;
01183 cpp << " }" << endl;
01184 }
01185 }
01186 cpp << itemDeclaration(e);
01187 if (e->param().isEmpty())
01188 {
01189
01190 cpp << " " << itemVar(e) << " = "
01191 << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
01192
01193 if ( !e->minValue().isEmpty() )
01194 cpp << " " << itemVar(e) << "->setMinValue(" << e->minValue() << ");" << endl;
01195 if ( !e->maxValue().isEmpty() )
01196 cpp << " " << itemVar(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
01197
01198 if ( setUserTexts )
01199 cpp << userTextsFunctions( e );
01200
01201 cpp << " addItem( " << itemVar(e);
01202 QString quotedName = e->name();
01203 addQuotes( quotedName );
01204 if ( quotedName != key ) cpp << ", \"" << e->name() << "\"";
01205 cpp << " );" << endl;
01206 }
01207 else
01208 {
01209
01210
01211
01212 for(int i = 0; i <= e->paramMax(); i++)
01213 {
01214 QString defaultStr;
01215 if ( !e->paramDefaultValue(i).isEmpty() )
01216 defaultStr = e->paramDefaultValue(i);
01217 else if ( !e->defaultValue().isEmpty() )
01218 defaultStr = paramString(e->defaultValue(), e, i);
01219 else
01220 defaultStr = defaultValue( e->type() );
01221
01222 cpp << " " << itemVar(e) << " = "
01223 << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
01224 << endl;
01225
01226 if ( setUserTexts )
01227 cpp << userTextsFunctions( e );
01228
01229 cpp << " addItem( " << itemVar( e ) << ", \""
01230 << paramString(e->paramName(), e, i) << "\" );" << endl;
01231 }
01232 }
01233 }
01234
01235 cpp << "}" << endl << endl;
01236
01237
01238 cpp << className << "::~" << className << "()" << endl;
01239 cpp << "{" << endl;
01240 if ( singleton ) {
01241 cpp << " if ( mSelf == this )" << endl;
01242 cpp << " staticDeleter.setObject( mSelf, 0, false );" << endl;
01243 }
01244 cpp << "}" << endl << endl;
01245
01246 implementation.close();
01247 }