kdecore Library API Documentation

kconfig_compiler.cpp

00001 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; -*- 00002 /* 00003 This file is part of KDE. 00004 00005 Copyright (c) 2003 Cornelius Schumacher <schumacher@kde.org> 00006 Copyright (c) 2003 Waldo Bastian <bastian@kde.org> 00007 Copyright (c) 2003 Zack Rusin <zack@kde.org> 00008 00009 This library is free software; you can redistribute it and/or 00010 modify it under the terms of the GNU Library General Public 00011 License as published by the Free Software Foundation; either 00012 version 2 of the License, or (at your option) any later version. 00013 00014 This library is distributed in the hope that it will be useful, 00015 but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 Library General Public License for more details. 00018 00019 You should have received a copy of the GNU Library General Public License 00020 along with this library; see the file COPYING.LIB. If not, write to 00021 the Free Software Foundation, Inc., 59 Temple Place - Suite 330, 00022 Boston, MA 02111-1307, USA. 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 // whatsthis 00137 kdDebug() << " code: " << mCode << endl; 00138 // kdDebug() << " values: " << mValues.join(":") << endl; 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"; // XXX : implicit type might be bad 00442 00443 if (!param.isEmpty()) 00444 { 00445 // Adjust name 00446 paramName = name; 00447 name.replace("$("+param+")", QString::null); 00448 // Lookup defaults for indexed entries 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"; //For now, but an assert would be better 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"; //For now, but an assert would be better 00570 } 00571 } 00572 00573 QString defaultValue( const QString &type ) 00574 { 00575 if ( type == "String" ) return "\"\""; // Use empty string, not null string! 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 "\"\""; // Use empty string, not null string! 00592 else if ( type == "Password" ) return "\"\""; // Use empty string, not null string! 00593 else { 00594 kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl; 00595 return "QString"; //For now, but an assert would be better 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 &param = 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 &parameters) 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 // Includes 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 // Class declaration header 00891 h << "class " << className << " : public " << inherits << endl; 00892 h << "{" << endl; 00893 h << " public:" << endl; 00894 00895 // enums 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 // Constructor or singleton accessor 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 // Destructor 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 // Manipulator 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 // Accessor 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 // Item accessor 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 // Static writeConfig method for singleton 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 // Private constructor for singleton 01025 if ( singleton ) { 01026 h << " " << className << "();" << endl; 01027 h << " static " << className << " *mSelf;" << endl << endl; 01028 } 01029 01030 // Member variables 01031 if ( !memberVariables.isEmpty() && memberVariables != "private" ) { 01032 h << " " << memberVariables << ":" << endl; 01033 } 01034 01035 // Class Parameters 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 << 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 // Includes 01097 for( it = includes.begin(); it != includes.end(); ++it ) { 01098 cpp << "#include <" << *it << ">" << endl; 01099 } 01100 01101 // Header required by singleton implementation 01102 if ( singleton ) 01103 cpp << "#include <kstaticdeleter.h>" << endl << endl; 01104 01105 if ( !nameSpace.isEmpty() ) 01106 cpp << "using namespace " << nameSpace << ";" << endl << endl; 01107 01108 // Singleton implementation 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 // Constructor 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 // Store parameters 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 // Needed in case the singleton class is used as baseclass for 01151 // another singleton. 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 // Normal case 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 // TODO: itemAccessors don't work with parameterized entries 01211 // TODO: itemVar(e) should be an array in that case 01212 // Indexed 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 // Destructor 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 }
KDE Logo
This file is part of the documentation for kdecore Library Version 3.2.3.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Mon Aug 30 22:53:30 2004 by doxygen 1.3.8 written by Dimitri van Heesch, © 1997-2003