kconfig.cpp

00001 /*
00002   This file is part of the KDE libraries
00003   Copyright (c) 1999 Preston Brown <pbrown@kde.org>
00004   Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
00005 
00006   This library is free software; you can redistribute it and/or
00007   modify it under the terms of the GNU Library General Public
00008   License as published by the Free Software Foundation; either
00009   version 2 of the License, or (at your option) any later version.
00010 
00011   This library is distributed in the hope that it will be useful,
00012   but WITHOUT ANY WARRANTY; without even the implied warranty of
00013   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014   Library General Public License for more details.
00015 
00016   You should have received a copy of the GNU Library General Public License
00017   along with this library; see the file COPYING.LIB.  If not, write to
00018   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019   Boston, MA 02110-1301, USA.
00020 */
00021 
00022 // $Id$
00023 
00024 #include <config.h>
00025 
00026 #ifdef HAVE_SYS_STAT_H
00027 #include <sys/stat.h>
00028 #endif
00029 
00030 #include <stdlib.h>
00031 #include <unistd.h>
00032 
00033 #include <qfileinfo.h>
00034 
00035 #include <kapplication.h>
00036 #include "kconfigbackend.h"
00037 #include "kconfigldapbackend.h"
00038 
00039 #include "kconfig.h"
00040 #include "kglobal.h"
00041 #include "kstandarddirs.h"
00042 #include "kstaticdeleter.h"
00043 #include <qtimer.h>
00044 
00045 KConfig::KConfig( const QString& fileName,
00046                  bool bReadOnly, bool bUseKderc, const char *resType )
00047   : KConfigBase(), bGroupImmutable(false), bFileImmutable(false),
00048     bForceGlobal(false)
00049 {
00050   // set the object's read-only status.
00051   setReadOnly(bReadOnly);
00052 
00053   QString ldapenv( getenv( "KDELDAP" ) );
00054 
00055   if ( ! ldapenv.isEmpty() )
00056   {
00057       // for right now we will hardcode that we are using the INI & LDAP
00058       // back end driver.  In the future this should be converted over to
00059       // a object factory of some sorts.
00060       // and to configure precedence and exclusion
00061       KConfigLDAPBackEnd *ldapBackEnd = new KConfigLDAPBackEnd(this,
00062               fileName,
00063               resType,
00064               bUseKderc);
00065       
00066       m_Private->backEnds.append(ldapBackEnd);
00067   }
00068 
00069   KConfigINIBackEnd *iniBackEnd = new KConfigINIBackEnd(this,
00070                               fileName,
00071                               resType,
00072                               bUseKderc);
00073 
00074   m_Private->backEnds.append(iniBackEnd);
00075           
00076   // set the object's back end pointer to this new backend
00077   backEnd = iniBackEnd;
00078   
00079   // read initial information off disk
00080   reparseConfiguration();
00081 
00082   // we let KStandardDirs add custom user config files. It will do
00083   // this only once. So only the first call ever to this constructor
00084   // will anything else than return here We have to reparse here as
00085   // configuration files may appear after customized directories have
00086   // been added. and the info they contain needs to be inserted into the
00087   // config object.
00088   // Since this makes only sense for config directories, addCustomized
00089   // returns true only if new config directories appeared.
00090   if (KGlobal::dirs()->addCustomized(this))
00091       reparseConfiguration();
00092 }
00093 
00094 KConfig::KConfig(KConfigBackEnd *aBackEnd, bool bReadOnly)
00095     : bGroupImmutable(false), bFileImmutable(false),
00096     bForceGlobal(false)
00097 {
00098   setReadOnly(bReadOnly);
00099   backEnd = aBackEnd;
00100   reparseConfiguration();
00101 }
00102 
00103 KConfig::~KConfig()
00104 {
00105   sync();
00106 
00107   // delete taken care of by destruction of kconfibase's private class
00108   //delete backEnd;
00109 }
00110 
00111 void KConfig::rollback(bool bDeep)
00112 {
00113   KConfigBase::rollback(bDeep);
00114 
00115   if (!bDeep)
00116     return; // object's bDeep flag is set in KConfigBase method
00117 
00118   // clear any dirty flags that entries might have set
00119   for (KEntryMapIterator aIt = aEntryMap.begin();
00120        aIt != aEntryMap.end(); ++aIt)
00121     (*aIt).bDirty = false;
00122 }
00123 
00124 QStringList KConfig::groupList() const
00125 {
00126   QStringList retList;
00127 
00128   KEntryMapConstIterator aIt = aEntryMap.begin();
00129   KEntryMapConstIterator aEnd = aEntryMap.end();
00130   for (; aIt != aEnd; ++aIt)
00131   {
00132     while(aIt.key().mKey.isEmpty())
00133     {
00134       QCString group = aIt.key().mGroup;
00135       ++aIt;
00136       while (true)
00137       {
00138          if (aIt == aEnd)
00139             return retList; // done
00140 
00141          if (aIt.key().mKey.isEmpty())
00142             break; // Group is empty, next group
00143 
00144          if (!aIt.key().bDefault && !(*aIt).bDeleted)
00145          {
00146             if (group != "$Version") // Special case!
00147                retList.append(QString::fromUtf8(group));
00148             break; // Group is non-empty, added, next group
00149          }
00150          ++aIt;
00151       }
00152     }
00153   }
00154 
00155   return retList;
00156 }
00157 
00158 QMap<QString, QString> KConfig::entryMap(const QString &pGroup) const
00159 {
00160   QCString pGroup_utf = pGroup.utf8();
00161   KEntryKey groupKey( pGroup_utf, 0 );
00162   QMap<QString, QString> tmpMap;
00163 
00164   KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
00165   if (aIt == aEntryMap.end())
00166      return tmpMap;
00167   ++aIt; // advance past special group entry marker
00168   for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
00169   {
00170     // Leave the default values out && leave deleted entries out
00171     if (!aIt.key().bDefault && !(*aIt).bDeleted)
00172       tmpMap.insert(QString::fromUtf8(aIt.key().mKey), QString::fromUtf8((*aIt).mValue.data(), (*aIt).mValue.length()));
00173   }
00174 
00175   return tmpMap;
00176 }
00177 
00178 void KConfig::reparseConfiguration()
00179 {
00180   // Don't lose pending changes
00181   if (!isReadOnly() && backEnd && bDirty)
00182     backEnd->sync();
00183 
00184   aEntryMap.clear();
00185 
00186   // add the "default group" marker to the map
00187   KEntryKey groupKey("<default>", 0);
00188   aEntryMap.insert(groupKey, KEntry());
00189 
00190   bFileImmutable = false;
00191   parseConfigFiles();
00192   bFileImmutable = bReadOnly;
00193 }
00194 
00195 KEntryMap KConfig::internalEntryMap(const QString &pGroup) const
00196 {
00197   QCString pGroup_utf = pGroup.utf8();
00198   KEntry aEntry;
00199   KEntryMapConstIterator aIt;
00200   KEntryKey aKey(pGroup_utf, 0);
00201   KEntryMap tmpEntryMap;
00202 
00203   aIt = aEntryMap.find(aKey);
00204   if (aIt == aEntryMap.end()) {
00205     // the special group key is not in the map,
00206     // so it must be an invalid group.  Return
00207     // an empty map.
00208     return tmpEntryMap;
00209   }
00210   // we now have a pointer to the nodes we want to copy.
00211   for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
00212   {
00213     tmpEntryMap.insert(aIt.key(), *aIt);
00214   }
00215 
00216   return tmpEntryMap;
00217 }
00218 
00219 void KConfig::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup)
00220 {
00221   if (bFileImmutable && !_key.bDefault)
00222     return;
00223 
00224   // check to see if the special group key is present,
00225   // and if not, put it in.
00226   if (_checkGroup)
00227   {
00228     KEntryKey groupKey( _key.mGroup, 0);
00229     KEntry &entry = aEntryMap[groupKey];
00230     bGroupImmutable = entry.bImmutable;
00231   }
00232   if (bGroupImmutable && !_key.bDefault)
00233     return;
00234 
00235   // now either add or replace the data
00236   KEntry &entry = aEntryMap[_key];
00237   bool immutable = entry.bImmutable;
00238   if (immutable && !_key.bDefault)
00239     return;
00240 
00241   entry = _data;
00242   entry.bImmutable |= immutable;
00243   entry.bGlobal |= bForceGlobal; // force to kdeglobals
00244 
00245   if (_key.bDefault)
00246   {
00247      // We have added the data as default value,
00248      // add it as normal value as well.
00249      KEntryKey key(_key);
00250      key.bDefault = false;
00251      aEntryMap[key] = _data;
00252   }
00253 }
00254 
00255 KEntry KConfig::lookupData(const KEntryKey &_key) const
00256 {
00257   KEntryMapConstIterator aIt = aEntryMap.find(_key);
00258   if (aIt != aEntryMap.end())
00259   {
00260     const KEntry &entry = *aIt;
00261     if (entry.bDeleted)
00262        return KEntry();
00263     else
00264        return entry;
00265   }
00266   else {
00267     return KEntry();
00268   }
00269 }
00270 
00271 bool KConfig::internalHasGroup(const QCString &group) const
00272 {
00273   KEntryKey groupKey( group, 0);
00274 
00275   KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
00276   KEntryMapConstIterator aEnd = aEntryMap.end();
00277 
00278   if (aIt == aEnd)
00279      return false;
00280   ++aIt;
00281   for(; (aIt != aEnd); ++aIt)
00282   {
00283      if (aIt.key().mKey.isEmpty())
00284         break;
00285 
00286      if (!aIt.key().bDefault && !(*aIt).bDeleted)
00287         return true;
00288   }
00289   return false;
00290 }
00291 
00292 void KConfig::setFileWriteMode(int mode)
00293 {
00294   backEnd->setFileWriteMode(mode);
00295 }
00296 
00297 KLockFile::Ptr KConfig::lockFile(bool bGlobal)
00298 {
00299   KConfigINIBackEnd *aBackEnd = dynamic_cast<KConfigINIBackEnd*>(backEnd);
00300   if (!aBackEnd) return 0;
00301   return aBackEnd->lockFile(bGlobal);
00302 }
00303 
00304 void KConfig::checkUpdate(const QString &id, const QString &updateFile)
00305 {
00306   QString oldGroup = group();
00307   setGroup("$Version");
00308   QString cfg_id = updateFile+":"+id;
00309   QStringList ids = readListEntry("update_info");
00310   if (!ids.contains(cfg_id))
00311   {
00312      QStringList args;
00313      args << "--check" << updateFile;
00314      KApplication::kdeinitExecWait("kconf_update", args);
00315      reparseConfiguration();
00316   }
00317   setGroup(oldGroup);
00318 }
00319 
00320 KConfig* KConfig::copyTo(const QString &file, KConfig *config) const
00321 {
00322   if (!config)
00323      config = new KConfig(QString::null, false, false);
00324   config->backEnd->changeFileName(file, "config", false);
00325   config->setReadOnly(false);
00326   config->bFileImmutable = false;
00327   config->backEnd->mConfigState = ReadWrite;
00328 
00329   QStringList groups = groupList();
00330   for(QStringList::ConstIterator it = groups.begin();
00331       it != groups.end(); ++it)
00332   {
00333      QMap<QString, QString> map = entryMap(*it);
00334      config->setGroup(*it);
00335      for (QMap<QString,QString>::Iterator it2  = map.begin();
00336           it2 != map.end(); ++it2)
00337      {
00338         config->writeEntry(it2.key(), it2.data());
00339      }
00340 
00341   }
00342   return config;
00343 }
00344 
00345 void KConfig::virtual_hook( int id, void* data )
00346 { KConfigBase::virtual_hook( id, data ); }
00347 
00348 static KStaticDeleter< QValueList<KSharedConfig*> > sd;
00349 QValueList<KSharedConfig*> *KSharedConfig::s_list = 0;
00350 
00351 KSharedConfig::Ptr KSharedConfig::openConfig(const QString& fileName, bool readOnly, bool useKDEGlobals )
00352 {
00353   if (s_list)
00354   {
00355      for(QValueList<KSharedConfig*>::ConstIterator it = s_list->begin();
00356          it != s_list->end(); ++it)
00357      {
00358         if ((*it)->backEnd->fileName() == fileName &&
00359                 (*it)->bReadOnly == readOnly &&
00360                 (*it)->backEnd->useKDEGlobals == useKDEGlobals )
00361            return (*it);
00362      }
00363   }
00364   return new KSharedConfig(fileName, readOnly, useKDEGlobals);
00365 }
00366 
00367 KSharedConfig::KSharedConfig( const QString& fileName, bool readonly, bool usekdeglobals)
00368  : KConfig(fileName, readonly, usekdeglobals)
00369 {
00370   if (!s_list)
00371   {
00372     sd.setObject(s_list, new QValueList<KSharedConfig*>);
00373   }
00374 
00375   s_list->append(this);
00376 }
00377 
00378 KSharedConfig::~KSharedConfig()
00379 {
00380   if ( s_list )
00381     s_list->remove(this);
00382 }
00383 
00384 #include "kconfig.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys