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 if ( e2.tagName() != "entry" ) continue;
00813 CfgEntry *entry = parseEntry( group, e2 );
00814 if ( entry ) entries.append( entry );
00815 else {
00816 kdError() << "Can't parse entry." << endl;
00817 return 1;
00818 }
00819 }
00820 }
00821 }
00822
00823 if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
00824
00825 if ( className.isEmpty() ) {
00826 kdError() << "Class name missing" << endl;
00827 return 1;
00828 }
00829
00830 if ( singleton && !parameters.isEmpty() ) {
00831 kdError() << "Singleton class can not have parameters" << endl;
00832 return 1;
00833 }
00834
00835 if ( singleton && cfgFileNameArg)
00836 {
00837 kdError() << "Singleton class can not use filename as argument." << endl;
00838 return 1;
00839 }
00840
00841 if ( !cfgFileName.isEmpty() && cfgFileNameArg)
00842 {
00843 kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
00844 return 1;
00845 }
00846
00847 if ( entries.isEmpty() ) {
00848 kdWarning() << "No entries." << endl;
00849 }
00850
00851 #if 0
00852 CfgEntry *cfg;
00853 for( cfg = entries.first(); cfg; cfg = entries.next() ) {
00854 cfg->dump();
00855 }
00856 #endif
00857
00858 QString headerFileName = baseName + ".h";
00859 QString implementationFileName = baseName + ".cpp";
00860
00861 QFile header( baseDir + headerFileName );
00862 if ( !header.open( IO_WriteOnly ) ) {
00863 kdError() << "Can't open '" << headerFileName << "for writing." << endl;
00864 return 1;
00865 }
00866
00867 QTextStream h( &header );
00868
00869 h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
00870 h << "// All changes you do to this file will be lost." << endl;
00871
00872 h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00873 << className.upper() << "_H" << endl;
00874 h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00875 << className.upper() << "_H" << endl << endl;
00876
00877
00878 QStringList::ConstIterator it;
00879 for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
00880 h << "#include <" << *it << ">" << endl;
00881 }
00882
00883 if ( headerIncludes.count() > 0 ) h << endl;
00884
00885 h << "#include <kconfigskeleton.h>" << endl << endl;
00886
00887 if ( !nameSpace.isEmpty() )
00888 h << "namespace " << nameSpace << " {" << endl << endl;
00889
00890
00891 h << "class " << className << " : public " << inherits << endl;
00892 h << "{" << endl;
00893 h << " public:" << endl;
00894
00895
00896 CfgEntry *e;
00897 for( e = entries.first(); e; e = entries.next() ) {
00898 QValueList<CfgEntry::Choice> choices = e->choices();
00899 if ( !choices.isEmpty() ) {
00900 QStringList values;
00901 QValueList<CfgEntry::Choice>::ConstIterator itChoice;
00902 for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
00903 values.append( (*itChoice).name );
00904 }
00905 if ( globalEnums ) {
00906 h << " enum { " << values.join( ", " ) << " };" << endl;
00907 } else {
00908 h << " class " << enumName(e->name()) << endl;
00909 h << " {" << endl;
00910 h << " public:" << endl;
00911 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00912 h << " };" << endl;
00913 }
00914 }
00915 QStringList values = e->paramValues();
00916 if ( !values.isEmpty() ) {
00917 h << " class " << enumName(e->param()) << endl;
00918 h << " {" << endl;
00919 h << " public:" << endl;
00920 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00921 h << " };" << endl;
00922 }
00923 }
00924
00925 h << endl;
00926
00927
00928 if ( !singleton ) {
00929 h << " " << className << "(";
00930 if (cfgFileNameArg)
00931 h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
00932 for (QStringList::ConstIterator it = parameters.begin();
00933 it != parameters.end(); ++it)
00934 {
00935 if (it != parameters.begin())
00936 h << ",";
00937 h << " const QString &" << *it;
00938 }
00939 h << " );" << endl;
00940 } else {
00941 h << " static " << className << " *self();" << endl;
00942 }
00943
00944
00945 h << " ~" << className << "();" << endl << endl;
00946
00947 QString This;
00948 QString Const;
00949 if (staticAccessors)
00950 This = "self()->";
00951 else
00952 Const = " const";
00953
00954 for( e = entries.first(); e; e = entries.next() ) {
00955 QString n = e->name();
00956 QString t = e->type();
00957
00958
00959 if (allMutators || mutators.contains(n))
00960 {
00961 h << " /**" << endl;
00962 h << " Set " << e->label() << endl;
00963 h << " */" << endl;
00964 if (staticAccessors)
00965 h << " static" << endl;
00966 h << " void " << setFunction(n) << "( ";
00967 if (!e->param().isEmpty())
00968 h << cppType(e->paramType()) << " i, ";
00969 h << param( t ) << " v )" << endl;
00970 h << " {" << endl;
00971 h << " if (!" << This << "isImmutable( \"" << n << "\" ))" << endl;
00972 h << " " << This << varName(n);
00973 if (!e->param().isEmpty())
00974 h << "[i]";
00975 h << " = v;" << endl;
00976 h << " }" << endl << endl;
00977 }
00978
00979
00980 h << " /**" << endl;
00981 h << " Get " << e->label() << endl;
00982 h << " */" << endl;
00983 if (staticAccessors)
00984 h << " static" << endl;
00985 h << " " << cppType(t) << " " << getFunction(n) << "(";
00986 if (!e->param().isEmpty())
00987 h << " " << cppType(e->paramType()) <<" i ";
00988 h << ")" << Const << endl;
00989 h << " {" << endl;
00990 h << " return " << This << varName(n);
00991 if (!e->param().isEmpty())
00992 h << "[i]";
00993 h << ";" << endl;
00994 h << " }" << endl;
00995
00996
00997 if ( itemAccessors ) {
00998 h << endl;
00999 h << " /**" << endl;
01000 h << " Get Item object corresponding to " << n << "()"
01001 << endl;
01002 h << " */" << endl;
01003 h << " Item" << itemType( e->type() ) << " *"
01004 << getFunction( n ) << "Item()" << endl;
01005 h << " {" << endl;
01006 h << " return " << itemVar(e) << ";" << endl;
01007 h << " }" << endl;
01008 }
01009
01010 h << endl;
01011 }
01012
01013
01014 if ( singleton ) {
01015 h << " static" << endl;
01016 h << " void writeConfig()" << endl;
01017 h << " {" << endl;
01018 h << " static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
01019 h << " }" << endl;
01020 }
01021
01022 h << " protected:" << endl;
01023
01024
01025 if ( singleton ) {
01026 h << " " << className << "();" << endl;
01027 h << " static " << className << " *mSelf;" << endl << endl;
01028 }
01029
01030
01031 if ( !memberVariables.isEmpty() && memberVariables != "private" ) {
01032 h << " " << memberVariables << ":" << endl;
01033 }
01034
01035
01036 for (QStringList::ConstIterator it = parameters.begin();
01037 it != parameters.end(); ++it)
01038 {
01039 h << " QString mParam" << *it << ";" << endl;
01040 }
01041
01042 QString group;
01043 for( e = entries.first(); e; e = entries.next() ) {
01044 if ( e->group() != group ) {
01045 group = e->group();
01046 h << endl;
01047 h << " // " << group << endl;
01048 }
01049 h << " " << cppType(e->type()) << " " << varName(e->name());
01050 if (!e->param().isEmpty())
01051 {
01052 h << QString("[%1]").arg(e->paramMax()+1);
01053 }
01054 h << ";" << endl;
01055 }
01056
01057 h << endl << " private:" << endl;
01058 if ( itemAccessors ) {
01059 for( e = entries.first(); e; e = entries.next() ) {
01060 h << " Item" << itemType( e->type() ) << " *" << itemVar( e ) << ";" << endl;
01061 }
01062 }
01063
01064 if (customAddons)
01065 {
01066 h << " // Include custom additions" << endl;
01067 h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01068 }
01069
01070 h << "};" << endl << endl;
01071
01072 if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
01073
01074 h << "#endif" << endl;
01075
01076
01077 header.close();
01078
01079 QFile implementation( baseDir + implementationFileName );
01080 if ( !implementation.open( IO_WriteOnly ) ) {
01081 kdError() << "Can't open '" << implementationFileName << "for writing."
01082 << endl;
01083 return 1;
01084 }
01085
01086 QTextStream cpp( &implementation );
01087
01088
01089 cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01090 cpp << "// All changes you do to this file will be lost." << endl << endl;
01091
01092 cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01093
01094 if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01095
01096
01097 for( it = includes.begin(); it != includes.end(); ++it ) {
01098 cpp << "#include <" << *it << ">" << endl;
01099 }
01100
01101
01102 if ( singleton )
01103 cpp << "#include <kstaticdeleter.h>" << endl << endl;
01104
01105 if ( !nameSpace.isEmpty() )
01106 cpp << "using namespace " << nameSpace << ";" << endl << endl;
01107
01108
01109 if ( singleton ) {
01110 cpp << className << " *" << className << "::mSelf = 0;" << endl;
01111 cpp << "static KStaticDeleter<" << className << "> staticDeleter;" << endl << endl;
01112
01113 cpp << className << " *" << className << "::self()" << endl;
01114 cpp << "{" << endl;
01115 cpp << " if ( !mSelf ) {" << endl;
01116 cpp << " staticDeleter.setObject( mSelf, new " << className << "() );" << endl;
01117 cpp << " mSelf->readConfig();" << endl;
01118 cpp << " }" << endl << endl;
01119 cpp << " return mSelf;" << endl;
01120 cpp << "}" << endl << endl;
01121 }
01122
01123
01124 cpp << className << "::" << className << "( ";
01125 if (cfgFileNameArg)
01126 cpp << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
01127 for (QStringList::ConstIterator it = parameters.begin();
01128 it != parameters.end(); ++it)
01129 {
01130 if (it != parameters.begin())
01131 cpp << ",";
01132 cpp << " const QString &" << *it;
01133 }
01134 cpp << " )" << endl;
01135
01136 cpp << " : " << inherits << "(";
01137 if ( !cfgFileName.isEmpty() ) cpp << " \"" << cfgFileName << "\" ";
01138 if ( cfgFileNameArg ) cpp << " config ";
01139 cpp << ")" << endl;
01140
01141
01142 for (QStringList::ConstIterator it = parameters.begin();
01143 it != parameters.end(); ++it)
01144 {
01145 cpp << " , mParam" << *it << "(" << *it << ")" << endl;
01146 }
01147
01148 cpp << "{" << endl;
01149
01150
01151
01152 if ( singleton )
01153 cpp << " mSelf = this;" << endl;
01154
01155 group = QString::null;
01156 for( e = entries.first(); e; e = entries.next() ) {
01157 if ( e->group() != group ) {
01158 if ( !group.isEmpty() ) cpp << endl;
01159 group = e->group();
01160 cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
01161 }
01162
01163 QString key = paramString(e->key(), parameters);
01164 if ( !e->code().isEmpty())
01165 {
01166 cpp << e->code() << endl;
01167 }
01168 if ( e->type() == "Enum" ) {
01169 cpp << " QValueList<KConfigSkeleton::ItemEnum::Choice> values"
01170 << e->name() << ";" << endl;
01171 QValueList<CfgEntry::Choice> choices = e->choices();
01172 QValueList<CfgEntry::Choice>::ConstIterator it;
01173 for( it = choices.begin(); it != choices.end(); ++it ) {
01174 cpp << " {" << endl;
01175 cpp << " KConfigSkeleton::ItemEnum::Choice choice;" << endl;
01176 cpp << " choice.name = \"" << (*it).name << "\";" << endl;
01177 if ( setUserTexts ) {
01178 if ( !(*it).label.isEmpty() )
01179 cpp << " choice.label = i18n(\"" << (*it).label << "\");" << endl;
01180 if ( !(*it).whatsThis.isEmpty() )
01181 cpp << " choice.whatsThis = i18n(\"" << (*it).whatsThis << "\");" << endl;
01182 }
01183 cpp << " values" << e->name() << ".append( choice );" << endl;
01184 cpp << " }" << endl;
01185 }
01186 }
01187 cpp << itemDeclaration(e);
01188 if (e->param().isEmpty())
01189 {
01190
01191 cpp << " " << itemVar(e) << " = "
01192 << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
01193
01194 if ( !e->minValue().isEmpty() )
01195 cpp << " " << itemVar(e) << "->setMinValue(" << e->minValue() << ");" << endl;
01196 if ( !e->maxValue().isEmpty() )
01197 cpp << " " << itemVar(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
01198
01199 if ( setUserTexts )
01200 cpp << userTextsFunctions( e );
01201
01202 cpp << " addItem( " << itemVar(e);
01203 QString quotedName = e->name();
01204 addQuotes( quotedName );
01205 if ( quotedName != key ) cpp << ", \"" << e->name() << "\"";
01206 cpp << " );" << endl;
01207 }
01208 else
01209 {
01210
01211
01212
01213 for(int i = 0; i <= e->paramMax(); i++)
01214 {
01215 QString defaultStr;
01216 if ( !e->paramDefaultValue(i).isEmpty() )
01217 defaultStr = e->paramDefaultValue(i);
01218 else if ( !e->defaultValue().isEmpty() )
01219 defaultStr = paramString(e->defaultValue(), e, i);
01220 else
01221 defaultStr = defaultValue( e->type() );
01222
01223 cpp << " " << itemVar(e) << " = "
01224 << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
01225 << endl;
01226
01227 if ( setUserTexts )
01228 cpp << userTextsFunctions( e );
01229
01230 cpp << " addItem( " << itemVar( e ) << ", \""
01231 << paramString(e->paramName(), e, i) << "\" );" << endl;
01232 }
01233 }
01234 }
01235
01236 cpp << "}" << endl << endl;
01237
01238
01239 cpp << className << "::~" << className << "()" << endl;
01240 cpp << "{" << endl;
01241 if ( singleton ) {
01242 cpp << " if ( mSelf == this )" << endl;
01243 cpp << " staticDeleter.setObject( mSelf, 0, false );" << endl;
01244 }
01245 cpp << "}" << endl << endl;
01246
01247 implementation.close();
01248 }