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 QString visibility = codegenConfig.readEntry("Visibility");
00777 if (!visibility.isEmpty()) visibility+=" ";
00778 bool singleton = codegenConfig.readBoolEntry("Singleton", false);
00779 bool staticAccessors = singleton;
00780 bool customAddons = codegenConfig.readBoolEntry("CustomAdditions");
00781 QString memberVariables = codegenConfig.readEntry("MemberVariables");
00782 QStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles");
00783 QStringList mutators = codegenConfig.readListEntry("Mutators");
00784 bool allMutators = false;
00785 if ((mutators.count() == 1) && (mutators[0].lower() == "true"))
00786 allMutators = true;
00787 itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false );
00788 bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false );
00789
00790 globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false );
00791
00792 QFile input( inputFilename );
00793
00794 QDomDocument doc;
00795 QString errorMsg;
00796 int errorRow;
00797 int errorCol;
00798 if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) {
00799 kdError() << "Unable to load document." << endl;
00800 kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl;
00801 return 1;
00802 }
00803
00804 QDomElement cfgElement = doc.documentElement();
00805
00806 if ( cfgElement.isNull() ) {
00807 kdError() << "No document in kcfg file" << endl;
00808 return 1;
00809 }
00810
00811 QString cfgFileName;
00812 bool cfgFileNameArg = false;
00813 QStringList parameters;
00814 QStringList includes;
00815
00816 QPtrList<CfgEntry> entries;
00817 entries.setAutoDelete( true );
00818
00819 QDomNode n;
00820 for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) {
00821 QDomElement e = n.toElement();
00822
00823 QString tag = e.tagName();
00824
00825 if ( tag == "include" ) {
00826 QString includeFile = e.text();
00827 if (!includeFile.isEmpty())
00828 includes.append(includeFile);
00829
00830 } else if ( tag == "kcfgfile" ) {
00831 cfgFileName = e.attribute( "name" );
00832 cfgFileNameArg = e.attribute( "arg" ).lower() == "true";
00833 QDomNode n2;
00834 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00835 QDomElement e2 = n2.toElement();
00836 if ( e2.tagName() == "parameter" ) {
00837 parameters.append( e2.attribute( "name" ) );
00838 }
00839 }
00840
00841 } else if ( tag == "group" ) {
00842 QString group = e.attribute( "name" );
00843 if ( group.isEmpty() ) {
00844 kdError() << "Group without name" << endl;
00845 return 1;
00846 }
00847 QDomNode n2;
00848 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) {
00849 QDomElement e2 = n2.toElement();
00850 if ( e2.tagName() != "entry" ) continue;
00851 CfgEntry *entry = parseEntry( group, e2 );
00852 if ( entry ) entries.append( entry );
00853 else {
00854 kdError() << "Can't parse entry." << endl;
00855 return 1;
00856 }
00857 }
00858 }
00859 }
00860
00861 if ( inherits.isEmpty() ) inherits = "KConfigSkeleton";
00862
00863 if ( className.isEmpty() ) {
00864 kdError() << "Class name missing" << endl;
00865 return 1;
00866 }
00867
00868 if ( singleton && !parameters.isEmpty() ) {
00869 kdError() << "Singleton class can not have parameters" << endl;
00870 return 1;
00871 }
00872
00873 if ( singleton && cfgFileNameArg)
00874 {
00875 kdError() << "Singleton class can not use filename as argument." << endl;
00876 return 1;
00877 }
00878
00879 if ( !cfgFileName.isEmpty() && cfgFileNameArg)
00880 {
00881 kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl;
00882 return 1;
00883 }
00884
00885 if ( entries.isEmpty() ) {
00886 kdWarning() << "No entries." << endl;
00887 }
00888
00889 #if 0
00890 CfgEntry *cfg;
00891 for( cfg = entries.first(); cfg; cfg = entries.next() ) {
00892 cfg->dump();
00893 }
00894 #endif
00895
00896 QString headerFileName = baseName + ".h";
00897 QString implementationFileName = baseName + ".cpp";
00898 QString cppPreamble;
00899
00900 QFile header( baseDir + headerFileName );
00901 if ( !header.open( IO_WriteOnly ) ) {
00902 kdError() << "Can't open '" << headerFileName << "for writing." << endl;
00903 return 1;
00904 }
00905
00906 QTextStream h( &header );
00907
00908 h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
00909 h << "// All changes you do to this file will be lost." << endl;
00910
00911 h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00912 << className.upper() << "_H" << endl;
00913 h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" )
00914 << className.upper() << "_H" << endl << endl;
00915
00916
00917 QStringList::ConstIterator it;
00918 for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) {
00919 h << "#include <" << *it << ">" << endl;
00920 }
00921
00922 if ( headerIncludes.count() > 0 ) h << endl;
00923
00924 h << "#include <kconfigskeleton.h>" << endl << endl;
00925
00926 if ( !nameSpace.isEmpty() )
00927 h << "namespace " << nameSpace << " {" << endl << endl;
00928
00929
00930 h << "class " << visibility << className << " : public " << inherits << endl;
00931 h << "{" << endl;
00932 h << " public:" << endl;
00933
00934
00935 CfgEntry *e;
00936 for( e = entries.first(); e; e = entries.next() ) {
00937 QValueList<CfgEntry::Choice> choices = e->choices();
00938 if ( !choices.isEmpty() ) {
00939 QStringList values;
00940 QValueList<CfgEntry::Choice>::ConstIterator itChoice;
00941 for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) {
00942 values.append( (*itChoice).name );
00943 }
00944 if ( globalEnums ) {
00945 h << " enum { " << values.join( ", " ) << " };" << endl;
00946 } else {
00947 h << " class " << enumName(e->name()) << endl;
00948 h << " {" << endl;
00949 h << " public:" << endl;
00950 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00951 h << " };" << endl;
00952 }
00953 }
00954 QStringList values = e->paramValues();
00955 if ( !values.isEmpty() ) {
00956 if ( globalEnums ) {
00957 h << " enum { " << values.join( ", " ) << " };" << endl;
00958 h << " static const char* const " << enumName(e->param()) << "ToString[];" << endl;
00959 cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "ToString[] = " +
00960 "{ \"" + values.join( "\", \"" ) + "\" };\n";
00961 } else {
00962 h << " class " << enumName(e->param()) << endl;
00963 h << " {" << endl;
00964 h << " public:" << endl;
00965 h << " enum { " << values.join( ", " ) << ", COUNT };" << endl;
00966 h << " static const char* const enumToString[];" << endl;
00967 h << " };" << endl;
00968 cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "::enumToString[] = " +
00969 "{ \"" + values.join( "\", \"" ) + "\" };\n";
00970 }
00971 }
00972 }
00973
00974 h << endl;
00975
00976
00977 if ( !singleton ) {
00978 h << " " << className << "(";
00979 if (cfgFileNameArg)
00980 h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
00981 for (QStringList::ConstIterator it = parameters.begin();
00982 it != parameters.end(); ++it)
00983 {
00984 if (it != parameters.begin())
00985 h << ",";
00986 h << " const QString &" << *it;
00987 }
00988 h << " );" << endl;
00989 } else {
00990 h << " static " << className << " *self();" << endl;
00991 }
00992
00993
00994 h << " ~" << className << "();" << endl << endl;
00995
00996 QString This;
00997 QString Const;
00998 if (staticAccessors)
00999 This = "self()->";
01000 else
01001 Const = " const";
01002
01003 for( e = entries.first(); e; e = entries.next() ) {
01004 QString n = e->name();
01005 QString t = e->type();
01006
01007
01008 if (allMutators || mutators.contains(n))
01009 {
01010 h << " /**" << endl;
01011 h << " Set " << e->label() << endl;
01012 h << " */" << endl;
01013 if (staticAccessors)
01014 h << " static" << endl;
01015 h << " void " << setFunction(n) << "( ";
01016 if (!e->param().isEmpty())
01017 h << cppType(e->paramType()) << " i, ";
01018 h << param( t ) << " v )" << endl;
01019 h << " {" << endl;
01020 h << " if (!" << This << "isImmutable( QString::fromLatin1( \"";
01021 if (!e->param().isEmpty()) {
01022 h << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( ";
01023 if ( e->paramType() == "Enum" ) {
01024 h << "QString::fromLatin1( ";
01025 if (globalEnums)
01026 h << enumName(e->name()) << "ToString[i]";
01027 else
01028 h << enumName(e->param()) << "::enumToString[i]";
01029 h << " )";
01030 } else {
01031 h << "i";
01032 }
01033 h << " )";
01034 } else
01035 h << n << "\" )";
01036 h << " ))" << endl;
01037 h << " " << This << varName(n);
01038 if (!e->param().isEmpty())
01039 h << "[i]";
01040 h << " = v;" << endl;
01041 h << " }" << endl << endl;
01042 }
01043
01044
01045 h << " /**" << endl;
01046 h << " Get " << e->label() << endl;
01047 h << " */" << endl;
01048 if (staticAccessors)
01049 h << " static" << endl;
01050 h << " " << cppType(t) << " " << getFunction(n) << "(";
01051 if (!e->param().isEmpty())
01052 h << " " << cppType(e->paramType()) <<" i ";
01053 h << ")" << Const << endl;
01054 h << " {" << endl;
01055 h << " return " << This << varName(n);
01056 if (!e->param().isEmpty()) h << "[i]";
01057 h << ";" << endl;
01058 h << " }" << endl;
01059
01060
01061 if ( itemAccessors ) {
01062 h << endl;
01063 h << " /**" << endl;
01064 h << " Get Item object corresponding to " << n << "()"
01065 << endl;
01066 h << " */" << endl;
01067 h << " Item" << itemType( e->type() ) << " *"
01068 << getFunction( n ) << "Item(";
01069 if (!e->param().isEmpty()) {
01070 h << " " << cppType(e->paramType()) << " i ";
01071 }
01072 h << ")" << endl;
01073 h << " {" << endl;
01074 h << " return " << itemVar(e);
01075 if (!e->param().isEmpty()) h << "[i]";
01076 h << ";" << endl;
01077 h << " }" << endl;
01078 }
01079
01080 h << endl;
01081 }
01082
01083
01084 if ( singleton ) {
01085 h << " static" << endl;
01086 h << " void writeConfig()" << endl;
01087 h << " {" << endl;
01088 h << " static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl;
01089 h << " }" << endl;
01090 }
01091
01092 h << " protected:" << endl;
01093
01094
01095 if ( singleton ) {
01096 h << " " << className << "();" << endl;
01097 h << " static " << className << " *mSelf;" << endl << endl;
01098 }
01099
01100
01101 if ( !memberVariables.isEmpty() && memberVariables != "private" ) {
01102 h << " " << memberVariables << ":" << endl;
01103 }
01104
01105
01106 for (QStringList::ConstIterator it = parameters.begin();
01107 it != parameters.end(); ++it)
01108 {
01109 h << " QString mParam" << *it << ";" << endl;
01110 }
01111
01112 QString group;
01113 for( e = entries.first(); e; e = entries.next() ) {
01114 if ( e->group() != group ) {
01115 group = e->group();
01116 h << endl;
01117 h << " // " << group << endl;
01118 }
01119 h << " " << cppType(e->type()) << " " << varName(e->name());
01120 if (!e->param().isEmpty())
01121 {
01122 h << QString("[%1]").arg(e->paramMax()+1);
01123 }
01124 h << ";" << endl;
01125 }
01126
01127 h << endl << " private:" << endl;
01128 if ( itemAccessors ) {
01129 for( e = entries.first(); e; e = entries.next() ) {
01130 h << " Item" << itemType( e->type() ) << " *" << itemVar( e );
01131 if (!e->param().isEmpty() ) h << QString("[%1]").arg( e->paramMax()+1 );
01132 h << ";" << endl;
01133 }
01134 }
01135
01136 if (customAddons)
01137 {
01138 h << " // Include custom additions" << endl;
01139 h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl;
01140 }
01141
01142 h << "};" << endl << endl;
01143
01144 if ( !nameSpace.isEmpty() ) h << "}" << endl << endl;
01145
01146 h << "#endif" << endl;
01147
01148
01149 header.close();
01150
01151 QFile implementation( baseDir + implementationFileName );
01152 if ( !implementation.open( IO_WriteOnly ) ) {
01153 kdError() << "Can't open '" << implementationFileName << "for writing."
01154 << endl;
01155 return 1;
01156 }
01157
01158 QTextStream cpp( &implementation );
01159
01160
01161 cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl;
01162 cpp << "// All changes you do to this file will be lost." << endl << endl;
01163
01164 cpp << "#include \"" << headerFileName << "\"" << endl << endl;
01165
01166 if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl;
01167
01168
01169 for( it = includes.begin(); it != includes.end(); ++it ) {
01170 cpp << "#include <" << *it << ">" << endl;
01171 }
01172
01173
01174 if ( singleton )
01175 cpp << "#include <kstaticdeleter.h>" << endl << endl;
01176
01177 if ( !nameSpace.isEmpty() )
01178 cpp << "using namespace " << nameSpace << ";" << endl << endl;
01179
01180
01181 if ( singleton ) {
01182 cpp << className << " *" << className << "::mSelf = 0;" << endl;
01183 cpp << "static KStaticDeleter<" << className << "> static" << className << "Deleter;" << endl << endl;
01184
01185 cpp << className << " *" << className << "::self()" << endl;
01186 cpp << "{" << endl;
01187 cpp << " if ( !mSelf ) {" << endl;
01188 cpp << " static" << className << "Deleter.setObject( mSelf, new " << className << "() );" << endl;
01189 cpp << " mSelf->readConfig();" << endl;
01190 cpp << " }" << endl << endl;
01191 cpp << " return mSelf;" << endl;
01192 cpp << "}" << endl << endl;
01193 }
01194
01195 if ( !cppPreamble.isEmpty() )
01196 cpp << cppPreamble << endl;
01197
01198
01199 cpp << className << "::" << className << "( ";
01200 if (cfgFileNameArg)
01201 cpp << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " " : ", ");
01202 for (QStringList::ConstIterator it = parameters.begin();
01203 it != parameters.end(); ++it)
01204 {
01205 if (it != parameters.begin())
01206 cpp << ",";
01207 cpp << " const QString &" << *it;
01208 }
01209 cpp << " )" << endl;
01210
01211 cpp << " : " << inherits << "(";
01212 if ( !cfgFileName.isEmpty() ) cpp << " QString::fromLatin1( \"" << cfgFileName << "\" ";
01213 if ( cfgFileNameArg ) cpp << " config ";
01214 if ( !cfgFileName.isEmpty() ) cpp << ") ";
01215 cpp << ")" << endl;
01216
01217
01218 for (QStringList::ConstIterator it = parameters.begin();
01219 it != parameters.end(); ++it)
01220 {
01221 cpp << " , mParam" << *it << "(" << *it << ")" << endl;
01222 }
01223
01224 cpp << "{" << endl;
01225
01226
01227
01228 if ( singleton )
01229 cpp << " mSelf = this;" << endl;
01230
01231 group = QString::null;
01232 for( e = entries.first(); e; e = entries.next() ) {
01233 if ( e->group() != group ) {
01234 if ( !group.isEmpty() ) cpp << endl;
01235 group = e->group();
01236 cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl;
01237 }
01238
01239 QString key = paramString(e->key(), parameters);
01240 if ( !e->code().isEmpty())
01241 {
01242 cpp << e->code() << endl;
01243 }
01244 if ( e->type() == "Enum" ) {
01245 cpp << " QValueList<KConfigSkeleton::ItemEnum::Choice> values"
01246 << e->name() << ";" << endl;
01247 QValueList<CfgEntry::Choice> choices = e->choices();
01248 QValueList<CfgEntry::Choice>::ConstIterator it;
01249 for( it = choices.begin(); it != choices.end(); ++it ) {
01250 cpp << " {" << endl;
01251 cpp << " KConfigSkeleton::ItemEnum::Choice choice;" << endl;
01252 cpp << " choice.name = QString::fromLatin1( \"" << (*it).name << "\" );" << endl;
01253 if ( setUserTexts ) {
01254 if ( !(*it).label.isEmpty() )
01255 cpp << " choice.label = i18n(" << quoteString((*it).label) << ");" << endl;
01256 if ( !(*it).whatsThis.isEmpty() )
01257 cpp << " choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ");" << endl;
01258 }
01259 cpp << " values" << e->name() << ".append( choice );" << endl;
01260 cpp << " }" << endl;
01261 }
01262 }
01263 cpp << itemDeclaration(e);
01264 if (e->param().isEmpty())
01265 {
01266
01267 cpp << " " << itemVar(e) << " = "
01268 << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl;
01269
01270 if ( !e->minValue().isEmpty() )
01271 cpp << " " << itemVar(e) << "->setMinValue(" << e->minValue() << ");" << endl;
01272 if ( !e->maxValue().isEmpty() )
01273 cpp << " " << itemVar(e) << "->setMaxValue(" << e->maxValue() << ");" << endl;
01274
01275 if ( setUserTexts )
01276 cpp << userTextsFunctions( e );
01277
01278 cpp << " addItem( " << itemVar(e);
01279 QString quotedName = e->name();
01280 addQuotes( quotedName );
01281 if ( quotedName != key ) cpp << ", QString::fromLatin1( \"" << e->name() << "\" )";
01282 cpp << " );" << endl;
01283 }
01284 else
01285 {
01286
01287 for(int i = 0; i <= e->paramMax(); i++)
01288 {
01289 QString defaultStr;
01290 QString itemVarStr(itemVar(e)+QString("[%1]").arg(i));
01291
01292 if ( !e->paramDefaultValue(i).isEmpty() )
01293 defaultStr = e->paramDefaultValue(i);
01294 else if ( !e->defaultValue().isEmpty() )
01295 defaultStr = paramString(e->defaultValue(), e, i);
01296 else
01297 defaultStr = defaultValue( e->type() );
01298
01299 cpp << " " << itemVarStr << " = "
01300 << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, QString("[%1]").arg(i) )
01301 << endl;
01302
01303 if ( setUserTexts )
01304 cpp << userTextsFunctions( e, itemVarStr, e->paramName() );
01305
01306
01307
01308
01309
01310 cpp << " addItem( " << itemVarStr << ", QString::fromLatin1( \"";
01311 if ( e->paramType()=="Enum" )
01312 cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] );
01313 else
01314 cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(i);
01315 cpp << "\" ) );" << endl;
01316 }
01317 }
01318 }
01319
01320 cpp << "}" << endl << endl;
01321
01322
01323 cpp << className << "::~" << className << "()" << endl;
01324 cpp << "{" << endl;
01325 if ( singleton ) {
01326 cpp << " if ( mSelf == this )" << endl;
01327 cpp << " static" << className << "Deleter.setObject( mSelf, 0, false );" << endl;
01328 }
01329 cpp << "}" << endl << endl;
01330
01331 implementation.close();
01332 }