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