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., 51 Franklin Street, Fifth Floor, 00022 Boston, MA 02110-1301, USA. 00023 */ 00024 00025 #include <tqfile.h> 00026 #include <tqtextstream.h> 00027 #include <tqdom.h> 00028 #include <tqregexp.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 bool dpointer; 00055 TQStringList allNames; 00056 TQRegExp *validNameRegexp; 00057 TQString This; 00058 TQString Const; 00059 00060 class CfgEntry 00061 { 00062 public: 00063 struct Choice 00064 { 00065 TQString name; 00066 TQString label; 00067 TQString whatsThis; 00068 }; 00069 00070 CfgEntry( const TQString &group, const TQString &type, const TQString &key, 00071 const TQString &name, const TQString &label, 00072 const TQString &whatsThis, const TQString &code, 00073 const TQString &defaultValue, const TQValueList<Choice> &choices, 00074 bool hidden ) 00075 : mGroup( group ), mType( type ), mKey( key ), mName( name ), 00076 mLabel( label ), mWhatsThis( whatsThis ), mCode( code ), 00077 mDefaultValue( defaultValue ), 00078 mChoices( choices ), mHidden( hidden ) 00079 { 00080 } 00081 00082 void setGroup( const TQString &group ) { mGroup = group; } 00083 TQString group() const { return mGroup; } 00084 00085 void setType( const TQString &type ) { mType = type; } 00086 TQString type() const { return mType; } 00087 00088 void setKey( const TQString &key ) { mKey = key; } 00089 TQString key() const { return mKey; } 00090 00091 void setName( const TQString &name ) { mName = name; } 00092 TQString name() const { return mName; } 00093 00094 void setLabel( const TQString &label ) { mLabel = label; } 00095 TQString label() const { return mLabel; } 00096 00097 void setWhatsThis( const TQString &whatsThis ) { mWhatsThis = whatsThis; } 00098 TQString whatsThis() const { return mWhatsThis; } 00099 00100 void setDefaultValue( const TQString &d ) { mDefaultValue = d; } 00101 TQString defaultValue() const { return mDefaultValue; } 00102 00103 void setCode( const TQString &d ) { mCode = d; } 00104 TQString code() const { return mCode; } 00105 00106 void setMinValue( const TQString &d ) { mMin = d; } 00107 TQString minValue() const { return mMin; } 00108 00109 void setMaxValue( const TQString &d ) { mMax = d; } 00110 TQString maxValue() const { return mMax; } 00111 00112 void setParam( const TQString &d ) { mParam = d; } 00113 TQString param() const { return mParam; } 00114 00115 void setParamName( const TQString &d ) { mParamName = d; } 00116 TQString paramName() const { return mParamName; } 00117 00118 void setParamType( const TQString &d ) { mParamType = d; } 00119 TQString paramType() const { return mParamType; } 00120 00121 void setChoices( const TQValueList<Choice> &d ) { mChoices = d; } 00122 TQValueList<Choice> choices() const { return mChoices; } 00123 00124 void setParamValues( const TQStringList &d ) { mParamValues = d; } 00125 TQStringList paramValues() const { return mParamValues; } 00126 00127 void setParamDefaultValues( const TQStringList &d ) { mParamDefaultValues = d; } 00128 TQString paramDefaultValue(int i) const { return mParamDefaultValues[i]; } 00129 00130 void setParamMax( int d ) { mParamMax = d; } 00131 int paramMax() const { return mParamMax; } 00132 00133 bool hidden() const { return mHidden; } 00134 00135 void dump() const 00136 { 00137 kdDebug() << "<entry>" << endl; 00138 kdDebug() << " group: " << mGroup << endl; 00139 kdDebug() << " type: " << mType << endl; 00140 kdDebug() << " key: " << mKey << endl; 00141 kdDebug() << " name: " << mName << endl; 00142 kdDebug() << " label: " << mLabel << endl; 00143 // whatsthis 00144 kdDebug() << " code: " << mCode << endl; 00145 // kdDebug() << " values: " << mValues.join(":") << endl; 00146 00147 if (!param().isEmpty()) 00148 { 00149 kdDebug() << " param name: "<< mParamName << endl; 00150 kdDebug() << " param type: "<< mParamType << endl; 00151 kdDebug() << " paramvalues: " << mParamValues.join(":") << endl; 00152 } 00153 kdDebug() << " default: " << mDefaultValue << endl; 00154 kdDebug() << " hidden: " << mHidden << endl; 00155 kdDebug() << " min: " << mMin << endl; 00156 kdDebug() << " max: " << mMax << endl; 00157 kdDebug() << "</entry>" << endl; 00158 } 00159 00160 private: 00161 TQString mGroup; 00162 TQString mType; 00163 TQString mKey; 00164 TQString mName; 00165 TQString mLabel; 00166 TQString mWhatsThis; 00167 TQString mCode; 00168 TQString mDefaultValue; 00169 TQString mParam; 00170 TQString mParamName; 00171 TQString mParamType; 00172 TQValueList<Choice> mChoices; 00173 TQStringList mParamValues; 00174 TQStringList mParamDefaultValues; 00175 int mParamMax; 00176 bool mHidden; 00177 TQString mMin; 00178 TQString mMax; 00179 }; 00180 00181 class Param { 00182 public: 00183 TQString name; 00184 TQString type; 00185 }; 00186 00187 // returns the name of an member variable 00188 // use itemPath to know the full path 00189 // like using d-> in case of dpointer 00190 static TQString varName(const TQString &n) 00191 { 00192 TQString result; 00193 if ( !dpointer ) { 00194 result = "m"+n; 00195 result[1] = result[1].upper(); 00196 } 00197 else { 00198 result = n; 00199 result[0] = result[0].lower(); 00200 } 00201 return result; 00202 } 00203 00204 static TQString varPath(const TQString &n) 00205 { 00206 TQString result; 00207 if ( dpointer ) { 00208 result = "d->"+varName(n); 00209 } 00210 else { 00211 result = varName(n); 00212 } 00213 return result; 00214 } 00215 00216 static TQString enumName(const TQString &n) 00217 { 00218 TQString result = "Enum"+n; 00219 result[4] = result[4].upper(); 00220 return result; 00221 } 00222 00223 static TQString setFunction(const TQString &n, const TQString &className = TQString()) 00224 { 00225 TQString result = "set"+n; 00226 result[3] = result[3].upper(); 00227 00228 if ( !className.isEmpty() ) 00229 result = className + "::" + result; 00230 return result; 00231 } 00232 00233 00234 static TQString getFunction(const TQString &n, const TQString &className = TQString()) 00235 { 00236 TQString result = n; 00237 result[0] = result[0].lower(); 00238 00239 if ( !className.isEmpty() ) 00240 result = className + "::" + result; 00241 return result; 00242 } 00243 00244 00245 static void addQuotes( TQString &s ) 00246 { 00247 if ( s.left( 1 ) != "\"" ) s.prepend( "\"" ); 00248 if ( s.right( 1 ) != "\"" ) s.append( "\"" ); 00249 } 00250 00251 static TQString quoteString( const TQString &s ) 00252 { 00253 TQString r = s; 00254 r.replace( "\\", "\\\\" ); 00255 r.replace( "\"", "\\\"" ); 00256 r.replace( "\r", "" ); 00257 r.replace( "\n", "\\n\"\n\"" ); 00258 return "\"" + r + "\""; 00259 } 00260 00261 static TQString literalString( const TQString &s ) 00262 { 00263 bool isAscii = true; 00264 for(int i = s.length(); i--;) 00265 if (s[i].unicode() > 127) isAscii = false; 00266 00267 if (isAscii) 00268 return "TQString::fromLatin1( " + quoteString(s) + " )"; 00269 else 00270 return "TQString::fromUtf8( " + quoteString(s) + " )"; 00271 } 00272 00273 static TQString dumpNode(const TQDomNode &node) 00274 { 00275 TQString msg; 00276 TQTextStream s(&msg, IO_WriteOnly ); 00277 node.save(s, 0); 00278 00279 msg = msg.simplifyWhiteSpace(); 00280 if (msg.length() > 40) 00281 return msg.left(37)+"..."; 00282 return msg; 00283 } 00284 00285 static TQString filenameOnly(TQString path) 00286 { 00287 int i = path.findRev('/'); 00288 if (i >= 0) 00289 return path.mid(i+1); 00290 return path; 00291 } 00292 00293 static void preProcessDefault( TQString &defaultValue, const TQString &name, 00294 const TQString &type, 00295 const TQValueList<CfgEntry::Choice> &choices, 00296 TQString &code ) 00297 { 00298 if ( type == "String" && !defaultValue.isEmpty() ) { 00299 defaultValue = literalString(defaultValue); 00300 00301 } else if ( type == "Path" && !defaultValue.isEmpty() ) { 00302 defaultValue = literalString( defaultValue ); 00303 00304 } else if ( (type == "StringList" || type == "PathList") && !defaultValue.isEmpty() ) { 00305 TQTextStream cpp( &code, IO_WriteOnly | IO_Append ); 00306 if (!code.isEmpty()) 00307 cpp << endl; 00308 00309 cpp << " TQStringList default" << name << ";" << endl; 00310 TQStringList defaults = TQStringList::split( ",", defaultValue ); 00311 TQStringList::ConstIterator it; 00312 for( it = defaults.begin(); it != defaults.end(); ++it ) { 00313 cpp << " default" << name << ".append( TQString::fromUtf8( \"" << *it << "\" ) );" 00314 << endl; 00315 } 00316 defaultValue = "default" + name; 00317 00318 } else if ( type == "Color" && !defaultValue.isEmpty() ) { 00319 TQRegExp colorRe("\\d+,\\s*\\d+,\\s*\\d+"); 00320 if (colorRe.exactMatch(defaultValue)) 00321 { 00322 defaultValue = "TQColor( " + defaultValue + " )"; 00323 } 00324 else 00325 { 00326 defaultValue = "TQColor( \"" + defaultValue + "\" )"; 00327 } 00328 00329 } else if ( type == "Enum" ) { 00330 if ( !globalEnums ) { 00331 TQValueList<CfgEntry::Choice>::ConstIterator it; 00332 for( it = choices.begin(); it != choices.end(); ++it ) { 00333 if ( (*it).name == defaultValue ) { 00334 defaultValue.prepend( enumName(name) + "::"); 00335 break; 00336 } 00337 } 00338 } 00339 00340 } else if ( type == "IntList" ) { 00341 TQTextStream cpp( &code, IO_WriteOnly | IO_Append ); 00342 if (!code.isEmpty()) 00343 cpp << endl; 00344 00345 cpp << " TQValueList<int> default" << name << ";" << endl; 00346 TQStringList defaults = TQStringList::split( ",", defaultValue ); 00347 TQStringList::ConstIterator it; 00348 for( it = defaults.begin(); it != defaults.end(); ++it ) { 00349 cpp << " default" << name << ".append( " << *it << " );" 00350 << endl; 00351 } 00352 defaultValue = "default" + name; 00353 } 00354 } 00355 00356 00357 CfgEntry *parseEntry( const TQString &group, const TQDomElement &element ) 00358 { 00359 bool defaultCode = false; 00360 TQString type = element.attribute( "type" ); 00361 TQString name = element.attribute( "name" ); 00362 TQString key = element.attribute( "key" ); 00363 TQString hidden = element.attribute( "hidden" ); 00364 TQString label; 00365 TQString whatsThis; 00366 TQString defaultValue; 00367 TQString code; 00368 TQString param; 00369 TQString paramName; 00370 TQString paramType; 00371 TQValueList<CfgEntry::Choice> choices; 00372 TQStringList paramValues; 00373 TQStringList paramDefaultValues; 00374 TQString minValue; 00375 TQString maxValue; 00376 int paramMax = 0; 00377 00378 TQDomNode n; 00379 for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { 00380 TQDomElement e = n.toElement(); 00381 TQString tag = e.tagName(); 00382 if ( tag == "label" ) label = e.text(); 00383 else if ( tag == "whatsthis" ) whatsThis = e.text(); 00384 else if ( tag == "min" ) minValue = e.text(); 00385 else if ( tag == "max" ) maxValue = e.text(); 00386 else if ( tag == "code" ) code = e.text(); 00387 else if ( tag == "parameter" ) 00388 { 00389 param = e.attribute( "name" ); 00390 paramType = e.attribute( "type" ); 00391 if ( param.isEmpty() ) { 00392 kdError() << "Parameter must have a name: " << dumpNode(e) << endl; 00393 return 0; 00394 } 00395 if ( paramType.isEmpty() ) { 00396 kdError() << "Parameter must have a type: " << dumpNode(e) << endl; 00397 return 0; 00398 } 00399 if ((paramType == "Int") || (paramType == "UInt")) 00400 { 00401 bool ok; 00402 paramMax = e.attribute("max").toInt(&ok); 00403 if (!ok) 00404 { 00405 kdError() << "Integer parameter must have a maximum (e.g. max=\"0\"): " << dumpNode(e) << endl; 00406 return 0; 00407 } 00408 } 00409 else if (paramType == "Enum") 00410 { 00411 TQDomNode n2; 00412 for ( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) { 00413 TQDomElement e2 = n2.toElement(); 00414 if (e2.tagName() == "values") 00415 { 00416 TQDomNode n3; 00417 for ( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) { 00418 TQDomElement e3 = n3.toElement(); 00419 if (e3.tagName() == "value") 00420 { 00421 paramValues.append( e3.text() ); 00422 } 00423 } 00424 break; 00425 } 00426 } 00427 if (paramValues.isEmpty()) 00428 { 00429 kdError() << "No values specified for parameter '" << param << "'." << endl; 00430 return 0; 00431 } 00432 paramMax = paramValues.count()-1; 00433 } 00434 else 00435 { 00436 kdError() << "Parameter '" << param << "' has type " << paramType << " but must be of type int, uint or Enum." << endl; 00437 return 0; 00438 } 00439 } 00440 else if ( tag == "default" ) 00441 { 00442 if (e.attribute("param").isEmpty()) 00443 { 00444 defaultValue = e.text(); 00445 if (e.attribute( "code" ) == "true") 00446 defaultCode = true; 00447 } 00448 } 00449 else if ( tag == "choices" ) { 00450 TQDomNode n2; 00451 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) { 00452 TQDomElement e2 = n2.toElement(); 00453 if ( e2.tagName() == "choice" ) { 00454 TQDomNode n3; 00455 CfgEntry::Choice choice; 00456 choice.name = e2.attribute( "name" ); 00457 if ( choice.name.isEmpty() ) { 00458 kdError() << "Tag <choice> requires attribute 'name'." << endl; 00459 } 00460 for( n3 = e2.firstChild(); !n3.isNull(); n3 = n3.nextSibling() ) { 00461 TQDomElement e3 = n3.toElement(); 00462 if ( e3.tagName() == "label" ) choice.label = e3.text(); 00463 if ( e3.tagName() == "whatsthis" ) choice.whatsThis = e3.text(); 00464 } 00465 choices.append( choice ); 00466 } 00467 } 00468 } 00469 } 00470 00471 bool nameIsEmpty = name.isEmpty(); 00472 if ( nameIsEmpty && key.isEmpty() ) { 00473 kdError() << "Entry must have a name or a key: " << dumpNode(element) << endl; 00474 return 0; 00475 } 00476 00477 if ( key.isEmpty() ) { 00478 key = name; 00479 } 00480 00481 if ( nameIsEmpty ) { 00482 name = key; 00483 name.replace( " ", TQString() ); 00484 } else if ( name.contains( ' ' ) ) { 00485 kdWarning()<<"Entry '"<<name<<"' contains spaces! <name> elements can't contain speces!"<<endl; 00486 name.remove( ' ' ); 00487 } 00488 00489 if (name.contains("$(")) 00490 { 00491 if (param.isEmpty()) 00492 { 00493 kdError() << "Name may not be parameterized: " << name << endl; 00494 return 0; 00495 } 00496 } 00497 else 00498 { 00499 if (!param.isEmpty()) 00500 { 00501 kdError() << "Name must contain '$(" << param << ")': " << name << endl; 00502 return 0; 00503 } 00504 } 00505 00506 if ( label.isEmpty() ) { 00507 label = key; 00508 } 00509 00510 if ( type.isEmpty() ) type = "String"; // XXX : implicit type might be bad 00511 00512 if (!param.isEmpty()) 00513 { 00514 // Adjust name 00515 paramName = name; 00516 name.replace("$("+param+")", TQString()); 00517 // Lookup defaults for indexed entries 00518 for(int i = 0; i <= paramMax; i++) 00519 { 00520 paramDefaultValues.append(TQString()); 00521 } 00522 00523 TQDomNode n; 00524 for ( n = element.firstChild(); !n.isNull(); n = n.nextSibling() ) { 00525 TQDomElement e = n.toElement(); 00526 TQString tag = e.tagName(); 00527 if ( tag == "default" ) 00528 { 00529 TQString index = e.attribute("param"); 00530 if (index.isEmpty()) 00531 continue; 00532 00533 bool ok; 00534 int i = index.toInt(&ok); 00535 if (!ok) 00536 { 00537 i = paramValues.findIndex(index); 00538 if (i == -1) 00539 { 00540 kdError() << "Index '" << index << "' for default value is unknown." << endl; 00541 return 0; 00542 } 00543 } 00544 00545 if ((i < 0) || (i > paramMax)) 00546 { 00547 kdError() << "Index '" << i << "' for default value is out of range [0, "<< paramMax<<"]." << endl; 00548 return 0; 00549 } 00550 00551 TQString tmpDefaultValue = e.text(); 00552 00553 if (e.attribute( "code" ) != "true") 00554 preProcessDefault(tmpDefaultValue, name, type, choices, code); 00555 00556 paramDefaultValues[i] = tmpDefaultValue; 00557 } 00558 } 00559 } 00560 00561 if (!validNameRegexp->exactMatch(name)) 00562 { 00563 if (nameIsEmpty) 00564 kdError() << "The key '" << key << "' can not be used as name for the entry because " 00565 "it is not a valid name. You need to specify a valid name for this entry." << endl; 00566 else 00567 kdError() << "The name '" << name << "' is not a valid name for an entry." << endl; 00568 return 0; 00569 } 00570 00571 if (allNames.contains(name)) 00572 { 00573 if (nameIsEmpty) 00574 kdError() << "The key '" << key << "' can not be used as name for the entry because " 00575 "it does not result in a unique name. You need to specify a unique name for this entry." << endl; 00576 else 00577 kdError() << "The name '" << name << "' is not unique." << endl; 00578 return 0; 00579 } 00580 allNames.append(name); 00581 00582 if (!defaultCode) 00583 { 00584 preProcessDefault(defaultValue, name, type, choices, code); 00585 } 00586 00587 CfgEntry *result = new CfgEntry( group, type, key, name, label, whatsThis, 00588 code, defaultValue, choices, 00589 hidden == "true" ); 00590 if (!param.isEmpty()) 00591 { 00592 result->setParam(param); 00593 result->setParamName(paramName); 00594 result->setParamType(paramType); 00595 result->setParamValues(paramValues); 00596 result->setParamDefaultValues(paramDefaultValues); 00597 result->setParamMax(paramMax); 00598 } 00599 result->setMinValue(minValue); 00600 result->setMaxValue(maxValue); 00601 00602 return result; 00603 } 00604 00608 TQString param( const TQString &type ) 00609 { 00610 if ( type == "String" ) return "const TQString &"; 00611 else if ( type == "StringList" ) return "const TQStringList &"; 00612 else if ( type == "Font" ) return "const TQFont &"; 00613 else if ( type == "Rect" ) return "const TQRect &"; 00614 else if ( type == "Size" ) return "const TQSize &"; 00615 else if ( type == "Color" ) return "const TQColor &"; 00616 else if ( type == "Point" ) return "const TQPoint &"; 00617 else if ( type == "Int" ) return "int"; 00618 else if ( type == "UInt" ) return "uint"; 00619 else if ( type == "Bool" ) return "bool"; 00620 else if ( type == "Double" ) return "double"; 00621 else if ( type == "DateTime" ) return "const TQDateTime &"; 00622 else if ( type == "Int64" ) return "TQ_INT64"; 00623 else if ( type == "UInt64" ) return "TQ_UINT64"; 00624 else if ( type == "IntList" ) return "const TQValueList<int> &"; 00625 else if ( type == "Enum" ) return "int"; 00626 else if ( type == "Path" ) return "const TQString &"; 00627 else if ( type == "PathList" ) return "const TQStringList &"; 00628 else if ( type == "Password" ) return "const TQString &"; 00629 else { 00630 kdError() <<"kconfig_compiler does not support type \""<< type <<"\""<<endl; 00631 return "TQString"; //For now, but an assert would be better 00632 } 00633 } 00634 00638 TQString cppType( const TQString &type ) 00639 { 00640 if ( type == "String" ) return "TQString"; 00641 else if ( type == "StringList" ) return "TQStringList"; 00642 else if ( type == "Font" ) return "TQFont"; 00643 else if ( type == "Rect" ) return "TQRect"; 00644 else if ( type == "Size" ) return "TQSize"; 00645 else if ( type == "Color" ) return "TQColor"; 00646 else if ( type == "Point" ) return "TQPoint"; 00647 else if ( type == "Int" ) return "int"; 00648 else if ( type == "UInt" ) return "uint"; 00649 else if ( type == "Bool" ) return "bool"; 00650 else if ( type == "Double" ) return "double"; 00651 else if ( type == "DateTime" ) return "TQDateTime"; 00652 else if ( type == "Int64" ) return "TQ_INT64"; 00653 else if ( type == "UInt64" ) return "TQ_UINT64"; 00654 else if ( type == "IntList" ) return "TQValueList<int>"; 00655 else if ( type == "Enum" ) return "int"; 00656 else if ( type == "Path" ) return "TQString"; 00657 else if ( type == "PathList" ) return "TQStringList"; 00658 else if ( type == "Password" ) return "TQString"; 00659 else { 00660 kdError()<<"kconfig_compiler does not support type \""<< type <<"\""<<endl; 00661 return "TQString"; //For now, but an assert would be better 00662 } 00663 } 00664 00665 TQString defaultValue( const TQString &type ) 00666 { 00667 if ( type == "String" ) return "\"\""; // Use empty string, not null string! 00668 else if ( type == "StringList" ) return "TQStringList()"; 00669 else if ( type == "Font" ) return "KGlobalSettings::generalFont()"; 00670 else if ( type == "Rect" ) return "TQRect()"; 00671 else if ( type == "Size" ) return "TQSize()"; 00672 else if ( type == "Color" ) return "TQColor(128, 128, 128)"; 00673 else if ( type == "Point" ) return "TQPoint()"; 00674 else if ( type == "Int" ) return "0"; 00675 else if ( type == "UInt" ) return "0"; 00676 else if ( type == "Bool" ) return "false"; 00677 else if ( type == "Double" ) return "0.0"; 00678 else if ( type == "DateTime" ) return "TQDateTime()"; 00679 else if ( type == "Int64" ) return "0"; 00680 else if ( type == "UInt64" ) return "0"; 00681 else if ( type == "IntList" ) return "TQValueList<int>()"; 00682 else if ( type == "Enum" ) return "0"; 00683 else if ( type == "Path" ) return "\"\""; // Use empty string, not null string! 00684 else if ( type == "PathList" ) return "TQStringList()"; 00685 else if ( type == "Password" ) return "\"\""; // Use empty string, not null string! 00686 else { 00687 kdWarning()<<"Error, kconfig_compiler doesn't support the \""<< type <<"\" type!"<<endl; 00688 return "TQString"; //For now, but an assert would be better 00689 } 00690 } 00691 00692 TQString itemType( const TQString &type ) 00693 { 00694 TQString t; 00695 00696 t = type; 00697 t.replace( 0, 1, t.left( 1 ).upper() ); 00698 00699 return t; 00700 } 00701 00702 static TQString itemDeclaration(const CfgEntry *e) 00703 { 00704 if (itemAccessors) 00705 return TQString(); 00706 00707 TQString fCap = e->name(); 00708 fCap[0] = fCap[0].upper(); 00709 return " KConfigSkeleton::Item"+itemType( e->type() ) + 00710 " *item" + fCap + 00711 ( (!e->param().isEmpty())?(TQString("[%1]").arg(e->paramMax()+1)) : TQString()) + 00712 ";\n"; 00713 } 00714 00715 // returns the name of an item variable 00716 // use itemPath to know the full path 00717 // like using d-> in case of dpointer 00718 static TQString itemVar(const CfgEntry *e) 00719 { 00720 TQString result; 00721 if (itemAccessors) 00722 { 00723 if ( !dpointer ) 00724 { 00725 result = "m" + e->name() + "Item"; 00726 result[1] = result[1].upper(); 00727 } 00728 else 00729 { 00730 result = e->name() + "Item"; 00731 result[0] = result[0].lower(); 00732 } 00733 } 00734 else 00735 { 00736 result = "item" + e->name(); 00737 result[4] = result[4].upper(); 00738 } 00739 return result; 00740 } 00741 00742 static TQString itemPath(const CfgEntry *e) 00743 { 00744 TQString result; 00745 if ( dpointer ) { 00746 result = "d->"+itemVar(e); 00747 } 00748 else { 00749 result = itemVar(e); 00750 } 00751 return result; 00752 } 00753 00754 TQString newItem( const TQString &type, const TQString &name, const TQString &key, 00755 const TQString &defaultValue, const TQString ¶m = TQString()) 00756 { 00757 TQString t = "new KConfigSkeleton::Item" + itemType( type ) + 00758 "( currentGroup(), " + key + ", " + varPath( name ) + param; 00759 if ( type == "Enum" ) t += ", values" + name; 00760 if ( !defaultValue.isEmpty() ) { 00761 t += ", "; 00762 if ( type == "String" ) t += defaultValue; 00763 else t+= defaultValue; 00764 } 00765 t += " );"; 00766 00767 return t; 00768 } 00769 00770 TQString paramString(const TQString &s, const CfgEntry *e, int i) 00771 { 00772 TQString result = s; 00773 TQString needle = "$("+e->param()+")"; 00774 if (result.contains(needle)) 00775 { 00776 TQString tmp; 00777 if (e->paramType() == "Enum") 00778 { 00779 tmp = e->paramValues()[i]; 00780 } 00781 else 00782 { 00783 tmp = TQString::number(i); 00784 } 00785 00786 result.replace(needle, tmp); 00787 } 00788 return result; 00789 } 00790 00791 TQString paramString(const TQString &group, const TQValueList<Param> ¶meters) 00792 { 00793 TQString paramString = group; 00794 TQString arguments; 00795 int i = 1; 00796 for (TQValueList<Param>::ConstIterator it = parameters.begin(); 00797 it != parameters.end(); ++it) 00798 { 00799 if (paramString.contains("$("+(*it).name+")")) 00800 { 00801 TQString tmp; 00802 tmp.sprintf("%%%d", i++); 00803 paramString.replace("$("+(*it).name+")", tmp); 00804 arguments += ".arg( mParam"+(*it).name+" )"; 00805 } 00806 } 00807 if (arguments.isEmpty()) 00808 return "TQString::fromLatin1( \""+group+"\" )"; 00809 00810 return "TQString::fromLatin1( \""+paramString+"\" )"+arguments; 00811 } 00812 00813 /* int i is the value of the parameter */ 00814 TQString userTextsFunctions( CfgEntry *e, TQString itemVarStr=TQString(), TQString i=TQString() ) 00815 { 00816 TQString txt; 00817 if (itemVarStr.isNull()) itemVarStr=itemPath(e); 00818 if ( !e->label().isEmpty() ) { 00819 txt += " " + itemVarStr + "->setLabel( i18n("; 00820 if ( !e->param().isEmpty() ) 00821 txt += quoteString(e->label().replace("$("+e->param()+")", i)); 00822 else 00823 txt+= quoteString(e->label()); 00824 txt+= ") );\n"; 00825 } 00826 if ( !e->whatsThis().isEmpty() ) { 00827 txt += " " + itemVarStr + "->setWhatsThis( i18n("; 00828 if ( !e->param().isEmpty() ) 00829 txt += quoteString(e->whatsThis().replace("$("+e->param()+")", i)); 00830 else 00831 txt+= quoteString(e->whatsThis()); 00832 txt+=") );\n"; 00833 } 00834 return txt; 00835 } 00836 00837 // returns the member accesor implementation 00838 // which should go in the h file if inline 00839 // or the cpp file if not inline 00840 TQString memberAccessorBody( CfgEntry *e ) 00841 { 00842 TQString result; 00843 TQTextStream out(&result, IO_WriteOnly); 00844 TQString n = e->name(); 00845 TQString t = e->type(); 00846 00847 out << "return " << This << varPath(n); 00848 if (!e->param().isEmpty()) out << "[i]"; 00849 out << ";" << endl; 00850 00851 return result; 00852 } 00853 00854 // returns the member mutator implementation 00855 // which should go in the h file if inline 00856 // or the cpp file if not inline 00857 TQString memberMutatorBody( CfgEntry *e ) 00858 { 00859 TQString result; 00860 TQTextStream out(&result, IO_WriteOnly); 00861 TQString n = e->name(); 00862 TQString t = e->type(); 00863 00864 if (!e->minValue().isEmpty()) 00865 { 00866 out << "if (v < " << e->minValue() << ")" << endl; 00867 out << "{" << endl; 00868 out << " kdDebug() << \"" << setFunction(n); 00869 out << ": value \" << v << \" is less than the minimum value of "; 00870 out << e->minValue()<< "\" << endl;" << endl; 00871 out << " v = " << e->minValue() << ";" << endl; 00872 out << "}" << endl; 00873 } 00874 00875 if (!e->maxValue().isEmpty()) 00876 { 00877 out << endl << "if (v > " << e->maxValue() << ")" << endl; 00878 out << "{" << endl; 00879 out << " kdDebug() << \"" << setFunction(n); 00880 out << ": value \" << v << \" is greater than the maximum value of "; 00881 out << e->maxValue()<< "\" << endl;" << endl; 00882 out << " v = " << e->maxValue() << ";" << endl; 00883 out << "}" << endl << endl; 00884 } 00885 00886 out << "if (!" << This << "isImmutable( TQString::fromLatin1( \""; 00887 if (!e->param().isEmpty()) 00888 { 00889 out << e->paramName().replace("$("+e->param()+")", "%1") << "\" ).arg( "; 00890 if ( e->paramType() == "Enum" ) { 00891 out << "TQString::fromLatin1( "; 00892 00893 if (globalEnums) 00894 out << enumName(e->param()) << "ToString[i]"; 00895 else 00896 out << enumName(e->param()) << "::enumToString[i]"; 00897 00898 out << " )"; 00899 } 00900 else 00901 { 00902 out << "i"; 00903 } 00904 out << " )"; 00905 } 00906 else 00907 { 00908 out << n << "\" )"; 00909 } 00910 out << " ))" << endl; 00911 out << " " << This << varPath(n); 00912 if (!e->param().isEmpty()) 00913 out << "[i]"; 00914 out << " = v;" << endl; 00915 00916 return result; 00917 } 00918 00919 // returns the item accesor implementation 00920 // which should go in the h file if inline 00921 // or the cpp file if not inline 00922 TQString itemAccessorBody( CfgEntry *e ) 00923 { 00924 TQString result; 00925 TQTextStream out(&result, IO_WriteOnly); 00926 00927 out << "return " << itemPath(e); 00928 if (!e->param().isEmpty()) out << "[i]"; 00929 out << ";" << endl; 00930 00931 return result; 00932 } 00933 00934 //indents text adding X spaces per line 00935 TQString indent(TQString text, int spaces) 00936 { 00937 TQString result; 00938 TQTextStream out(&result, IO_WriteOnly); 00939 TQTextStream in(&text, IO_ReadOnly); 00940 TQString currLine; 00941 while ( !in.atEnd() ) 00942 { 00943 currLine = in.readLine(); 00944 if (!currLine.isEmpty()) 00945 for (int i=0; i < spaces; i++) 00946 out << " "; 00947 out << currLine << endl; 00948 } 00949 return result; 00950 } 00951 00952 00953 int main( int argc, char **argv ) 00954 { 00955 KAboutData aboutData( "kconfig_compiler", I18N_NOOP("KDE .kcfg compiler"), "0.3", 00956 I18N_NOOP("KConfig Compiler") , KAboutData::License_LGPL ); 00957 aboutData.addAuthor( "Cornelius Schumacher", 0, "schumacher@kde.org" ); 00958 aboutData.addAuthor( "Waldo Bastian", 0, "bastian@kde.org" ); 00959 aboutData.addAuthor( "Zack Rusin", 0, "zack@kde.org" ); 00960 aboutData.addCredit( "Reinhold Kainhofer", "Fix for parametrized entries", 00961 "reinhold@kainhofer.com", "http://reinhold.kainhofer.com" ); 00962 aboutData.addCredit( "Duncan Mac-Vicar P.", "dpointer support", 00963 "duncan@kde.org", "http://www.mac-vicar.com/~duncan" ); 00964 00965 KCmdLineArgs::init( argc, argv, &aboutData ); 00966 KCmdLineArgs::addCmdLineOptions( options ); 00967 00968 KInstance app( &aboutData ); 00969 00970 KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); 00971 00972 if ( args->count() < 2 ) { 00973 kdError() << "Too few arguments." << endl; 00974 return 1; 00975 } 00976 if ( args->count() > 2 ) { 00977 kdError() << "Too many arguments." << endl; 00978 return 1; 00979 } 00980 00981 validNameRegexp = new TQRegExp("[a-zA-Z_][a-zA-Z0-9_]*"); 00982 00983 TQString baseDir = TQFile::decodeName(args->getOption("directory")); 00984 if (!baseDir.endsWith("/")) 00985 baseDir.append("/"); 00986 00987 TQString inputFilename = args->url( 0 ).path(); 00988 TQString codegenFilename = args->url( 1 ).path(); 00989 00990 if (!codegenFilename.endsWith(".kcfgc")) 00991 { 00992 kdError() << "Codegen options file must have extension .kcfgc" << endl; 00993 return 1; 00994 } 00995 TQString baseName = args->url( 1 ).fileName(); 00996 baseName = baseName.left(baseName.length() - 6); 00997 00998 KSimpleConfig codegenConfig( codegenFilename, true ); 00999 01000 TQString nameSpace = codegenConfig.readEntry("NameSpace"); 01001 TQString className = codegenConfig.readEntry("ClassName"); 01002 TQString inherits = codegenConfig.readEntry("Inherits"); 01003 TQString visibility = codegenConfig.readEntry("Visibility"); 01004 if (!visibility.isEmpty()) visibility+=" "; 01005 bool singleton = codegenConfig.readBoolEntry("Singleton", false); 01006 bool staticAccessors = singleton; 01007 //bool useDPointer = codegenConfig.readBoolEntry("DPointer", false); 01008 bool customAddons = codegenConfig.readBoolEntry("CustomAdditions"); 01009 TQString memberVariables = codegenConfig.readEntry("MemberVariables"); 01010 TQStringList headerIncludes = codegenConfig.readListEntry("IncludeFiles"); 01011 TQStringList mutators = codegenConfig.readListEntry("Mutators"); 01012 bool allMutators = false; 01013 if ((mutators.count() == 1) && (mutators[0].lower() == "true")) 01014 allMutators = true; 01015 itemAccessors = codegenConfig.readBoolEntry( "ItemAccessors", false ); 01016 bool setUserTexts = codegenConfig.readBoolEntry( "SetUserTexts", false ); 01017 01018 globalEnums = codegenConfig.readBoolEntry( "GlobalEnums", false ); 01019 01020 dpointer = (memberVariables == "dpointer"); 01021 01022 TQFile input( inputFilename ); 01023 01024 TQDomDocument doc; 01025 TQString errorMsg; 01026 int errorRow; 01027 int errorCol; 01028 if ( !doc.setContent( &input, &errorMsg, &errorRow, &errorCol ) ) { 01029 kdError() << "Unable to load document." << endl; 01030 kdError() << "Parse error in " << args->url( 0 ).fileName() << ", line " << errorRow << ", col " << errorCol << ": " << errorMsg << endl; 01031 return 1; 01032 } 01033 01034 TQDomElement cfgElement = doc.documentElement(); 01035 01036 if ( cfgElement.isNull() ) { 01037 kdError() << "No document in kcfg file" << endl; 01038 return 1; 01039 } 01040 01041 TQString cfgFileName; 01042 bool cfgFileNameArg = false; 01043 TQValueList<Param> parameters; 01044 TQStringList includes; 01045 01046 TQPtrList<CfgEntry> entries; 01047 entries.setAutoDelete( true ); 01048 01049 TQDomNode n; 01050 for ( n = cfgElement.firstChild(); !n.isNull(); n = n.nextSibling() ) { 01051 TQDomElement e = n.toElement(); 01052 01053 TQString tag = e.tagName(); 01054 01055 if ( tag == "include" ) { 01056 TQString includeFile = e.text(); 01057 if (!includeFile.isEmpty()) 01058 includes.append(includeFile); 01059 01060 } else if ( tag == "kcfgfile" ) { 01061 cfgFileName = e.attribute( "name" ); 01062 cfgFileNameArg = e.attribute( "arg" ).lower() == "true"; 01063 TQDomNode n2; 01064 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) { 01065 TQDomElement e2 = n2.toElement(); 01066 if ( e2.tagName() == "parameter" ) { 01067 Param p; 01068 p.name = e2.attribute( "name" ); 01069 p.type = e2.attribute( "type" ); 01070 if (p.type.isEmpty()) 01071 p.type = "String"; 01072 parameters.append( p ); 01073 } 01074 } 01075 01076 } else if ( tag == "group" ) { 01077 TQString group = e.attribute( "name" ); 01078 if ( group.isEmpty() ) { 01079 kdError() << "Group without name" << endl; 01080 return 1; 01081 } 01082 TQDomNode n2; 01083 for( n2 = e.firstChild(); !n2.isNull(); n2 = n2.nextSibling() ) { 01084 TQDomElement e2 = n2.toElement(); 01085 if ( e2.tagName() != "entry" ) continue; 01086 CfgEntry *entry = parseEntry( group, e2 ); 01087 if ( entry ) entries.append( entry ); 01088 else { 01089 kdError() << "Can't parse entry." << endl; 01090 return 1; 01091 } 01092 } 01093 } 01094 } 01095 01096 if ( inherits.isEmpty() ) inherits = "KConfigSkeleton"; 01097 01098 if ( className.isEmpty() ) { 01099 kdError() << "Class name missing" << endl; 01100 return 1; 01101 } 01102 01103 if ( singleton && !parameters.isEmpty() ) { 01104 kdError() << "Singleton class can not have parameters" << endl; 01105 return 1; 01106 } 01107 01108 if ( !cfgFileName.isEmpty() && cfgFileNameArg) 01109 { 01110 kdError() << "Having both a fixed filename and a filename as argument is not possible." << endl; 01111 return 1; 01112 } 01113 01114 if ( entries.isEmpty() ) { 01115 kdWarning() << "No entries." << endl; 01116 } 01117 01118 #if 0 01119 CfgEntry *cfg; 01120 for( cfg = entries.first(); cfg; cfg = entries.next() ) { 01121 cfg->dump(); 01122 } 01123 #endif 01124 01125 TQString headerFileName = baseName + ".h"; 01126 TQString implementationFileName = baseName + ".cpp"; 01127 TQString cppPreamble; // code to be inserted at the beginnin of the cpp file, e.g. initialization of static values 01128 01129 TQFile header( baseDir + headerFileName ); 01130 if ( !header.open( IO_WriteOnly ) ) { 01131 kdError() << "Can't open '" << headerFileName << "' for writing." << endl; 01132 return 1; 01133 } 01134 01135 TQTextStream h( &header ); 01136 01137 h << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl; 01138 h << "// All changes you do to this file will be lost." << endl; 01139 01140 h << "#ifndef " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" ) 01141 << className.upper() << "_H" << endl; 01142 h << "#define " << ( !nameSpace.isEmpty() ? nameSpace.upper() + "_" : "" ) 01143 << className.upper() << "_H" << endl << endl; 01144 01145 // Includes 01146 TQStringList::ConstIterator it; 01147 for( it = headerIncludes.begin(); it != headerIncludes.end(); ++it ) { 01148 h << "#include <" << *it << ">" << endl; 01149 } 01150 01151 if ( headerIncludes.count() > 0 ) h << endl; 01152 01153 if ( !singleton && cfgFileNameArg && parameters.isEmpty() ) 01154 h << "#include <kglobal.h>" << endl; 01155 01156 h << "#include <kconfigskeleton.h>" << endl; 01157 h << "#include <kdebug.h>" << endl << endl; 01158 01159 // Includes 01160 for( it = includes.begin(); it != includes.end(); ++it ) { 01161 h << "#include <" << *it << ">" << endl; 01162 } 01163 01164 01165 if ( !nameSpace.isEmpty() ) 01166 h << "namespace " << nameSpace << " {" << endl << endl; 01167 01168 // Private class declaration 01169 if ( dpointer ) 01170 h << "class " << className << "Private;" << endl << endl; 01171 01172 // Class declaration header 01173 h << "class " << visibility << className << " : public " << inherits << endl; 01174 h << "{" << endl; 01175 h << " public:" << endl; 01176 01177 // enums 01178 CfgEntry *e; 01179 for( e = entries.first(); e; e = entries.next() ) { 01180 TQValueList<CfgEntry::Choice> choices = e->choices(); 01181 if ( !choices.isEmpty() ) { 01182 TQStringList values; 01183 TQValueList<CfgEntry::Choice>::ConstIterator itChoice; 01184 for( itChoice = choices.begin(); itChoice != choices.end(); ++itChoice ) { 01185 values.append( (*itChoice).name ); 01186 } 01187 if ( globalEnums ) { 01188 h << " enum { " << values.join( ", " ) << " };" << endl; 01189 } else { 01190 h << " class " << enumName(e->name()) << endl; 01191 h << " {" << endl; 01192 h << " public:" << endl; 01193 h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl; 01194 h << " };" << endl; 01195 } 01196 } 01197 TQStringList values = e->paramValues(); 01198 if ( !values.isEmpty() ) { 01199 if ( globalEnums ) { 01200 h << " enum { " << values.join( ", " ) << " };" << endl; 01201 h << " static const char* const " << enumName(e->param()) << "ToString[];" << endl; 01202 cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "ToString[] = " + 01203 "{ \"" + values.join( "\", \"" ) + "\" };\n"; 01204 } else { 01205 h << " class " << enumName(e->param()) << endl; 01206 h << " {" << endl; 01207 h << " public:" << endl; 01208 h << " enum type { " << values.join( ", " ) << ", COUNT };" << endl; 01209 h << " static const char* const enumToString[];" << endl; 01210 h << " };" << endl; 01211 cppPreamble += "const char* const " + className + "::" + enumName(e->param()) + "::enumToString[] = " + 01212 "{ \"" + values.join( "\", \"" ) + "\" };\n"; 01213 } 01214 } 01215 } 01216 01217 h << endl; 01218 01219 // Constructor or singleton accessor 01220 if ( !singleton ) { 01221 h << " " << className << "("; 01222 if (cfgFileNameArg) 01223 h << " KSharedConfig::Ptr config" << (parameters.isEmpty() ? " = KGlobal::sharedConfig()" : ", "); 01224 for (TQValueList<Param>::ConstIterator it = parameters.begin(); 01225 it != parameters.end(); ++it) 01226 { 01227 if (it != parameters.begin()) 01228 h << ","; 01229 h << " " << param((*it).type) << " " << (*it).name; 01230 } 01231 h << " );" << endl; 01232 } else { 01233 h << " static " << className << " *self();" << endl; 01234 if (cfgFileNameArg) 01235 h << " static void instance(const char * cfgfilename);" << endl; 01236 } 01237 01238 // Destructor 01239 h << " ~" << className << "();" << endl << endl; 01240 01241 // global variables 01242 if (staticAccessors) 01243 This = "self()->"; 01244 else 01245 Const = " const"; 01246 01247 for( e = entries.first(); e; e = entries.next() ) { 01248 TQString n = e->name(); 01249 TQString t = e->type(); 01250 01251 // Manipulator 01252 if (allMutators || mutators.contains(n)) 01253 { 01254 h << " /**" << endl; 01255 h << " Set " << e->label() << endl; 01256 h << " */" << endl; 01257 if (staticAccessors) 01258 h << " static" << endl; 01259 h << " void " << setFunction(n) << "( "; 01260 if (!e->param().isEmpty()) 01261 h << cppType(e->paramType()) << " i, "; 01262 h << param( t ) << " v )"; 01263 // function body inline only if not using dpointer 01264 // for BC mode 01265 if ( !dpointer ) 01266 { 01267 h << endl << " {" << endl; 01268 h << indent(memberMutatorBody(e), 6 ); 01269 h << " }" << endl; 01270 } 01271 else 01272 { 01273 h << ";" << endl; 01274 } 01275 } 01276 h << endl; 01277 // Accessor 01278 h << " /**" << endl; 01279 h << " Get " << e->label() << endl; 01280 h << " */" << endl; 01281 if (staticAccessors) 01282 h << " static" << endl; 01283 h << " " << cppType(t) << " " << getFunction(n) << "("; 01284 if (!e->param().isEmpty()) 01285 h << " " << cppType(e->paramType()) <<" i "; 01286 h << ")" << Const; 01287 // function body inline only if not using dpointer 01288 // for BC mode 01289 if ( !dpointer ) 01290 { 01291 h << endl << " {" << endl; 01292 h << indent(memberAccessorBody(e), 6 ); 01293 h << " }" << endl; 01294 } 01295 else 01296 { 01297 h << ";" << endl; 01298 } 01299 01300 // Item accessor 01301 if ( itemAccessors ) { 01302 h << endl; 01303 h << " /**" << endl; 01304 h << " Get Item object corresponding to " << n << "()" 01305 << endl; 01306 h << " */" << endl; 01307 h << " Item" << itemType( e->type() ) << " *" 01308 << getFunction( n ) << "Item("; 01309 if (!e->param().isEmpty()) { 01310 h << " " << cppType(e->paramType()) << " i "; 01311 } 01312 h << ")"; 01313 if (! dpointer ) 01314 { 01315 h << endl << " {" << endl; 01316 h << indent( itemAccessorBody(e), 6); 01317 h << " }" << endl; 01318 } 01319 else 01320 { 01321 h << ";" << endl; 01322 } 01323 } 01324 01325 h << endl; 01326 } 01327 01328 // Static writeConfig method for singleton 01329 if ( singleton ) { 01330 h << " static" << endl; 01331 h << " void writeConfig()" << endl; 01332 h << " {" << endl; 01333 h << " static_cast<KConfigSkeleton*>(self())->writeConfig();" << endl; 01334 h << " }" << endl; 01335 } 01336 01337 h << " protected:" << endl; 01338 01339 // Private constructor for singleton 01340 if ( singleton ) { 01341 h << " " << className << "("; 01342 if ( cfgFileNameArg ) 01343 h << "const char *arg"; 01344 h << ");" << endl; 01345 h << " static " << className << " *mSelf;" << endl << endl; 01346 } 01347 01348 // Member variables 01349 if ( !memberVariables.isEmpty() && memberVariables != "private" && memberVariables != "dpointer") { 01350 h << " " << memberVariables << ":" << endl; 01351 } 01352 01353 // Class Parameters 01354 for (TQValueList<Param>::ConstIterator it = parameters.begin(); 01355 it != parameters.end(); ++it) 01356 { 01357 h << " " << cppType((*it).type) << " mParam" << (*it).name << ";" << endl; 01358 } 01359 01360 if ( memberVariables != "dpointer" ) 01361 { 01362 TQString group; 01363 for( e = entries.first(); e; e = entries.next() ) { 01364 if ( e->group() != group ) { 01365 group = e->group(); 01366 h << endl; 01367 h << " // " << group << endl; 01368 } 01369 h << " " << cppType(e->type()) << " " << varName(e->name()); 01370 if (!e->param().isEmpty()) 01371 { 01372 h << TQString("[%1]").arg(e->paramMax()+1); 01373 } 01374 h << ";" << endl; 01375 } 01376 01377 h << endl << " private:" << endl; 01378 if ( itemAccessors ) { 01379 for( e = entries.first(); e; e = entries.next() ) { 01380 h << " Item" << itemType( e->type() ) << " *" << itemVar( e ); 01381 if (!e->param().isEmpty() ) h << TQString("[%1]").arg( e->paramMax()+1 ); 01382 h << ";" << endl; 01383 } 01384 } 01385 01386 } 01387 else 01388 { 01389 // use a private class for both member variables and items 01390 h << " private:" << endl; 01391 h << " " + className + "Private *d;" << endl; 01392 } 01393 01394 if (customAddons) 01395 { 01396 h << " // Include custom additions" << endl; 01397 h << " #include \"" << filenameOnly(baseName) << "_addons.h\"" <<endl; 01398 } 01399 01400 h << "};" << endl << endl; 01401 01402 if ( !nameSpace.isEmpty() ) h << "}" << endl << endl; 01403 01404 h << "#endif" << endl << endl; 01405 01406 01407 header.close(); 01408 01409 TQFile implementation( baseDir + implementationFileName ); 01410 if ( !implementation.open( IO_WriteOnly ) ) { 01411 kdError() << "Can't open '" << implementationFileName << "' for writing." 01412 << endl; 01413 return 1; 01414 } 01415 01416 TQTextStream cpp( &implementation ); 01417 01418 01419 cpp << "// This file is generated by kconfig_compiler from " << args->url(0).fileName() << "." << endl; 01420 cpp << "// All changes you do to this file will be lost." << endl << endl; 01421 01422 cpp << "#include \"" << headerFileName << "\"" << endl << endl; 01423 01424 if ( setUserTexts ) cpp << "#include <klocale.h>" << endl << endl; 01425 01426 // Header required by singleton implementation 01427 if ( singleton ) 01428 cpp << "#include <kstaticdeleter.h>" << endl << endl; 01429 if ( singleton && cfgFileNameArg ) 01430 cpp << "#include <kdebug.h>" << endl << endl; 01431 01432 if ( !nameSpace.isEmpty() ) 01433 cpp << "using namespace " << nameSpace << ";" << endl << endl; 01434 01435 TQString group; 01436 01437 // private class implementation 01438 if ( dpointer ) 01439 { 01440 cpp << "class " << className << "Private" << endl; 01441 cpp << "{" << endl; 01442 cpp << " public:" << endl; 01443 for( e = entries.first(); e; e = entries.next() ) { 01444 if ( e->group() != group ) { 01445 group = e->group(); 01446 cpp << endl; 01447 cpp << " // " << group << endl; 01448 } 01449 cpp << " " << cppType(e->type()) << " " << varName(e->name()); 01450 if (!e->param().isEmpty()) 01451 { 01452 cpp << TQString("[%1]").arg(e->paramMax()+1); 01453 } 01454 cpp << ";" << endl; 01455 } 01456 cpp << endl << " // items" << endl; 01457 for( e = entries.first(); e; e = entries.next() ) { 01458 cpp << " KConfigSkeleton::Item" << itemType( e->type() ) << " *" << itemVar( e ); 01459 if (!e->param().isEmpty() ) cpp << TQString("[%1]").arg( e->paramMax()+1 ); 01460 cpp << ";" << endl; 01461 } 01462 01463 cpp << "};" << endl << endl; 01464 } 01465 01466 // Singleton implementation 01467 if ( singleton ) { 01468 cpp << className << " *" << className << "::mSelf = 0;" << endl; 01469 cpp << "static KStaticDeleter<" << className << "> static" << className << "Deleter;" << endl << endl; 01470 01471 cpp << className << " *" << className << "::self()" << endl; 01472 cpp << "{" << endl; 01473 if ( cfgFileNameArg ) { 01474 cpp << " if (!mSelf)" << endl; 01475 cpp << " kdFatal() << \"you need to call " << className << "::instance before using\" << endl;" << endl; 01476 } else { 01477 cpp << " if ( !mSelf ) {" << endl; 01478 cpp << " static" << className << "Deleter.setObject( mSelf, new " << className << "() );" << endl; 01479 cpp << " mSelf->readConfig();" << endl; 01480 cpp << " }" << endl << endl; 01481 } 01482 cpp << " return mSelf;" << endl; 01483 cpp << "}" << endl << endl; 01484 01485 if ( cfgFileNameArg ) { 01486 cpp << "void " << className << "::instance(const char *cfgfilename)" << endl; 01487 cpp << "{" << endl; 01488 cpp << " if (mSelf) {" << endl; 01489 cpp << " kdError() << \"" << className << "::instance called after the first use - ignoring\" << endl;" << endl; 01490 cpp << " return;" << endl; 01491 cpp << " }" << endl; 01492 cpp << " static" << className << "Deleter.setObject( mSelf, new " << className << "(cfgfilename) );" << endl; 01493 cpp << " mSelf->readConfig();" << endl; 01494 cpp << "}" << endl << endl; 01495 } 01496 } 01497 01498 if ( !cppPreamble.isEmpty() ) 01499 cpp << cppPreamble << endl; 01500 01501 // Constructor 01502 cpp << className << "::" << className << "( "; 01503 if ( cfgFileNameArg ) { 01504 if ( !singleton ) 01505 cpp << " KSharedConfig::Ptr config"; 01506 else 01507 cpp << " const char *config"; 01508 cpp << (parameters.isEmpty() ? " " : ", "); 01509 } 01510 01511 for (TQValueList<Param>::ConstIterator it = parameters.begin(); 01512 it != parameters.end(); ++it) 01513 { 01514 if (it != parameters.begin()) 01515 cpp << ","; 01516 cpp << " " << param((*it).type) << " " << (*it).name; 01517 } 01518 cpp << " )" << endl; 01519 01520 cpp << " : " << inherits << "("; 01521 if ( !cfgFileName.isEmpty() ) cpp << " TQString::fromLatin1( \"" << cfgFileName << "\" "; 01522 if ( cfgFileNameArg ) cpp << " config "; 01523 if ( !cfgFileName.isEmpty() ) cpp << ") "; 01524 cpp << ")" << endl; 01525 01526 // Store parameters 01527 for (TQValueList<Param>::ConstIterator it = parameters.begin(); 01528 it != parameters.end(); ++it) 01529 { 01530 cpp << " , mParam" << (*it).name << "(" << (*it).name << ")" << endl; 01531 } 01532 01533 cpp << "{" << endl; 01534 01535 if (dpointer) 01536 cpp << " d = new " + className + "Private;" << endl; 01537 // Needed in case the singleton class is used as baseclass for 01538 // another singleton. 01539 if ( singleton ) 01540 cpp << " mSelf = this;" << endl; 01541 01542 group = TQString(); 01543 for( e = entries.first(); e; e = entries.next() ) { 01544 if ( e->group() != group ) { 01545 if ( !group.isEmpty() ) cpp << endl; 01546 group = e->group(); 01547 cpp << " setCurrentGroup( " << paramString(group, parameters) << " );" << endl << endl; 01548 } 01549 01550 TQString key = paramString(e->key(), parameters); 01551 if ( !e->code().isEmpty()) 01552 { 01553 cpp << e->code() << endl; 01554 } 01555 if ( e->type() == "Enum" ) { 01556 cpp << " TQValueList<KConfigSkeleton::ItemEnum::Choice> values" 01557 << e->name() << ";" << endl; 01558 TQValueList<CfgEntry::Choice> choices = e->choices(); 01559 TQValueList<CfgEntry::Choice>::ConstIterator it; 01560 for( it = choices.begin(); it != choices.end(); ++it ) { 01561 cpp << " {" << endl; 01562 cpp << " KConfigSkeleton::ItemEnum::Choice choice;" << endl; 01563 cpp << " choice.name = TQString::fromLatin1( \"" << (*it).name << "\" );" << endl; 01564 if ( setUserTexts ) { 01565 if ( !(*it).label.isEmpty() ) 01566 cpp << " choice.label = i18n(" << quoteString((*it).label) << ");" << endl; 01567 if ( !(*it).whatsThis.isEmpty() ) 01568 cpp << " choice.whatsThis = i18n(" << quoteString((*it).whatsThis) << ");" << endl; 01569 } 01570 cpp << " values" << e->name() << ".append( choice );" << endl; 01571 cpp << " }" << endl; 01572 } 01573 } 01574 01575 if (!dpointer) 01576 cpp << itemDeclaration(e); 01577 01578 if (e->param().isEmpty()) 01579 { 01580 // Normal case 01581 cpp << " " << itemPath(e) << " = " 01582 << newItem( e->type(), e->name(), key, e->defaultValue() ) << endl; 01583 01584 if ( !e->minValue().isEmpty() ) 01585 cpp << " " << itemPath(e) << "->setMinValue(" << e->minValue() << ");" << endl; 01586 if ( !e->maxValue().isEmpty() ) 01587 cpp << " " << itemPath(e) << "->setMaxValue(" << e->maxValue() << ");" << endl; 01588 01589 if ( setUserTexts ) 01590 cpp << userTextsFunctions( e ); 01591 01592 cpp << " addItem( " << itemPath(e); 01593 TQString quotedName = e->name(); 01594 addQuotes( quotedName ); 01595 if ( quotedName != key ) cpp << ", TQString::fromLatin1( \"" << e->name() << "\" )"; 01596 cpp << " );" << endl; 01597 } 01598 else 01599 { 01600 // Indexed 01601 for(int i = 0; i <= e->paramMax(); i++) 01602 { 01603 TQString defaultStr; 01604 TQString itemVarStr(itemPath(e)+TQString("[%1]").arg(i)); 01605 01606 if ( !e->paramDefaultValue(i).isEmpty() ) 01607 defaultStr = e->paramDefaultValue(i); 01608 else if ( !e->defaultValue().isEmpty() ) 01609 defaultStr = paramString(e->defaultValue(), e, i); 01610 else 01611 defaultStr = defaultValue( e->type() ); 01612 01613 cpp << " " << itemVarStr << " = " 01614 << newItem( e->type(), e->name(), paramString(key, e, i), defaultStr, TQString("[%1]").arg(i) ) 01615 << endl; 01616 01617 if ( setUserTexts ) 01618 cpp << userTextsFunctions( e, itemVarStr, e->paramName() ); 01619 01620 // Make mutators for enum parameters work by adding them with $(..) replaced by the 01621 // param name. The check for isImmutable in the set* functions doesn't have the param 01622 // name available, just the corresponding enum value (int), so we need to store the 01623 // param names in a separate static list!. 01624 cpp << " addItem( " << itemVarStr << ", TQString::fromLatin1( \""; 01625 if ( e->paramType()=="Enum" ) 01626 cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(e->paramValues()[i] ); 01627 else 01628 cpp << e->paramName().replace( "$("+e->param()+")", "%1").arg(i); 01629 cpp << "\" ) );" << endl; 01630 } 01631 } 01632 } 01633 01634 cpp << "}" << endl << endl; 01635 01636 if (dpointer) 01637 { 01638 // setters and getters go in Cpp if in dpointer mode 01639 for( e = entries.first(); e; e = entries.next() ) 01640 { 01641 TQString n = e->name(); 01642 TQString t = e->type(); 01643 01644 // Manipulator 01645 if (allMutators || mutators.contains(n)) 01646 { 01647 cpp << "void " << setFunction(n, className) << "( "; 01648 if (!e->param().isEmpty()) 01649 cpp << cppType(e->paramType()) << " i, "; 01650 cpp << param( t ) << " v )" << endl; 01651 // function body inline only if not using dpointer 01652 // for BC mode 01653 cpp << "{" << endl; 01654 cpp << indent(memberMutatorBody(e), 6); 01655 cpp << "}" << endl << endl; 01656 } 01657 01658 // Accessor 01659 cpp << cppType(t) << " " << getFunction(n, className) << "("; 01660 if (!e->param().isEmpty()) 01661 cpp << " " << cppType(e->paramType()) <<" i "; 01662 cpp << ")" << Const << endl; 01663 // function body inline only if not using dpointer 01664 // for BC mode 01665 cpp << "{" << endl; 01666 cpp << indent(memberAccessorBody(e), 2); 01667 cpp << "}" << endl << endl; 01668 01669 // Item accessor 01670 if ( itemAccessors ) 01671 { 01672 cpp << endl; 01673 cpp << "KConfigSkeleton::Item" << itemType( e->type() ) << " *" 01674 << getFunction( n, className ) << "Item("; 01675 if (!e->param().isEmpty()) { 01676 cpp << " " << cppType(e->paramType()) << " i "; 01677 } 01678 cpp << ")" << endl; 01679 cpp << "{" << endl; 01680 cpp << indent(itemAccessorBody(e), 2); 01681 cpp << "}" << endl; 01682 } 01683 01684 cpp << endl; 01685 } 01686 } 01687 01688 // Destructor 01689 cpp << className << "::~" << className << "()" << endl; 01690 cpp << "{" << endl; 01691 if ( singleton ) { 01692 if ( dpointer ) 01693 cpp << " delete d;" << endl; 01694 cpp << " if ( mSelf == this )" << endl; 01695 cpp << " static" << className << "Deleter.setObject( mSelf, 0, false );" << endl; 01696 } 01697 cpp << "}" << endl << endl; 01698 01699 implementation.close(); 01700 }