You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
368 lines
9.5 KiB
368 lines
9.5 KiB
15 years ago
|
/*
|
||
|
This file is part of the KDE libraries
|
||
|
Copyright (c) 1999 Preston Brown <pbrown@kde.org>
|
||
|
Copyright (C) 1997-1999 Matthias Kalle Dalheimer (kalle@kde.org)
|
||
|
|
||
|
This library is free software; you can redistribute it and/or
|
||
|
modify it under the terms of the GNU Library General Public
|
||
|
License as published by the Free Software Foundation; either
|
||
|
version 2 of the License, or (at your option) any later version.
|
||
|
|
||
|
This library is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
Library General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU Library General Public License
|
||
|
along with this library; see the file COPYING.LIB. If not, write to
|
||
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||
|
Boston, MA 02110-1301, USA.
|
||
|
*/
|
||
|
|
||
|
// $Id$
|
||
|
|
||
|
#include <config.h>
|
||
|
|
||
|
#ifdef HAVE_SYS_STAT_H
|
||
|
#include <sys/stat.h>
|
||
|
#endif
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
#include <qfileinfo.h>
|
||
|
|
||
|
#include <kapplication.h>
|
||
|
#include "kconfigbackend.h"
|
||
|
|
||
|
#include "kconfig.h"
|
||
|
#include "kglobal.h"
|
||
|
#include "kstandarddirs.h"
|
||
|
#include "kstaticdeleter.h"
|
||
|
#include <qtimer.h>
|
||
|
|
||
|
KConfig::KConfig( const QString& fileName,
|
||
|
bool bReadOnly, bool bUseKderc, const char *resType )
|
||
|
: KConfigBase(), bGroupImmutable(false), bFileImmutable(false),
|
||
|
bForceGlobal(false)
|
||
|
{
|
||
|
// set the object's read-only status.
|
||
|
setReadOnly(bReadOnly);
|
||
|
|
||
|
// for right now we will hardcode that we are using the INI
|
||
|
// back end driver. In the future this should be converted over to
|
||
|
// a object factory of some sorts.
|
||
|
KConfigINIBackEnd *aBackEnd = new KConfigINIBackEnd(this,
|
||
|
fileName,
|
||
|
resType,
|
||
|
bUseKderc);
|
||
|
|
||
|
// set the object's back end pointer to this new backend
|
||
|
backEnd = aBackEnd;
|
||
|
|
||
|
// read initial information off disk
|
||
|
reparseConfiguration();
|
||
|
|
||
|
// we let KStandardDirs add custom user config files. It will do
|
||
|
// this only once. So only the first call ever to this constructor
|
||
|
// will anything else than return here We have to reparse here as
|
||
|
// configuration files may appear after customized directories have
|
||
|
// been added. and the info they contain needs to be inserted into the
|
||
|
// config object.
|
||
|
// Since this makes only sense for config directories, addCustomized
|
||
|
// returns true only if new config directories appeared.
|
||
|
if (KGlobal::dirs()->addCustomized(this))
|
||
|
reparseConfiguration();
|
||
|
}
|
||
|
|
||
|
KConfig::KConfig(KConfigBackEnd *aBackEnd, bool bReadOnly)
|
||
|
: bGroupImmutable(false), bFileImmutable(false),
|
||
|
bForceGlobal(false)
|
||
|
{
|
||
|
setReadOnly(bReadOnly);
|
||
|
backEnd = aBackEnd;
|
||
|
reparseConfiguration();
|
||
|
}
|
||
|
|
||
|
KConfig::~KConfig()
|
||
|
{
|
||
|
sync();
|
||
|
|
||
|
delete backEnd;
|
||
|
}
|
||
|
|
||
|
void KConfig::rollback(bool bDeep)
|
||
|
{
|
||
|
KConfigBase::rollback(bDeep);
|
||
|
|
||
|
if (!bDeep)
|
||
|
return; // object's bDeep flag is set in KConfigBase method
|
||
|
|
||
|
// clear any dirty flags that entries might have set
|
||
|
for (KEntryMapIterator aIt = aEntryMap.begin();
|
||
|
aIt != aEntryMap.end(); ++aIt)
|
||
|
(*aIt).bDirty = false;
|
||
|
}
|
||
|
|
||
|
QStringList KConfig::groupList() const
|
||
|
{
|
||
|
QStringList retList;
|
||
|
|
||
|
KEntryMapConstIterator aIt = aEntryMap.begin();
|
||
|
KEntryMapConstIterator aEnd = aEntryMap.end();
|
||
|
for (; aIt != aEnd; ++aIt)
|
||
|
{
|
||
|
while(aIt.key().mKey.isEmpty())
|
||
|
{
|
||
|
QCString group = aIt.key().mGroup;
|
||
|
++aIt;
|
||
|
while (true)
|
||
|
{
|
||
|
if (aIt == aEnd)
|
||
|
return retList; // done
|
||
|
|
||
|
if (aIt.key().mKey.isEmpty())
|
||
|
break; // Group is empty, next group
|
||
|
|
||
|
if (!aIt.key().bDefault && !(*aIt).bDeleted)
|
||
|
{
|
||
|
if (group != "$Version") // Special case!
|
||
|
retList.append(QString::fromUtf8(group));
|
||
|
break; // Group is non-empty, added, next group
|
||
|
}
|
||
|
++aIt;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return retList;
|
||
|
}
|
||
|
|
||
|
QMap<QString, QString> KConfig::entryMap(const QString &pGroup) const
|
||
|
{
|
||
|
QCString pGroup_utf = pGroup.utf8();
|
||
|
KEntryKey groupKey( pGroup_utf, 0 );
|
||
|
QMap<QString, QString> tmpMap;
|
||
|
|
||
|
KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
|
||
|
if (aIt == aEntryMap.end())
|
||
|
return tmpMap;
|
||
|
++aIt; // advance past special group entry marker
|
||
|
for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
|
||
|
{
|
||
|
// Leave the default values out && leave deleted entries out
|
||
|
if (!aIt.key().bDefault && !(*aIt).bDeleted)
|
||
|
tmpMap.insert(QString::fromUtf8(aIt.key().mKey), QString::fromUtf8((*aIt).mValue.data(), (*aIt).mValue.length()));
|
||
|
}
|
||
|
|
||
|
return tmpMap;
|
||
|
}
|
||
|
|
||
|
void KConfig::reparseConfiguration()
|
||
|
{
|
||
|
// Don't lose pending changes
|
||
|
if (!isReadOnly() && backEnd && bDirty)
|
||
|
backEnd->sync();
|
||
|
|
||
|
aEntryMap.clear();
|
||
|
|
||
|
// add the "default group" marker to the map
|
||
|
KEntryKey groupKey("<default>", 0);
|
||
|
aEntryMap.insert(groupKey, KEntry());
|
||
|
|
||
|
bFileImmutable = false;
|
||
|
parseConfigFiles();
|
||
|
bFileImmutable = bReadOnly;
|
||
|
}
|
||
|
|
||
|
KEntryMap KConfig::internalEntryMap(const QString &pGroup) const
|
||
|
{
|
||
|
QCString pGroup_utf = pGroup.utf8();
|
||
|
KEntry aEntry;
|
||
|
KEntryMapConstIterator aIt;
|
||
|
KEntryKey aKey(pGroup_utf, 0);
|
||
|
KEntryMap tmpEntryMap;
|
||
|
|
||
|
aIt = aEntryMap.find(aKey);
|
||
|
if (aIt == aEntryMap.end()) {
|
||
|
// the special group key is not in the map,
|
||
|
// so it must be an invalid group. Return
|
||
|
// an empty map.
|
||
|
return tmpEntryMap;
|
||
|
}
|
||
|
// we now have a pointer to the nodes we want to copy.
|
||
|
for (; aIt.key().mGroup == pGroup_utf && aIt != aEntryMap.end(); ++aIt)
|
||
|
{
|
||
|
tmpEntryMap.insert(aIt.key(), *aIt);
|
||
|
}
|
||
|
|
||
|
return tmpEntryMap;
|
||
|
}
|
||
|
|
||
|
void KConfig::putData(const KEntryKey &_key, const KEntry &_data, bool _checkGroup)
|
||
|
{
|
||
|
if (bFileImmutable && !_key.bDefault)
|
||
|
return;
|
||
|
|
||
|
// check to see if the special group key is present,
|
||
|
// and if not, put it in.
|
||
|
if (_checkGroup)
|
||
|
{
|
||
|
KEntryKey groupKey( _key.mGroup, 0);
|
||
|
KEntry &entry = aEntryMap[groupKey];
|
||
|
bGroupImmutable = entry.bImmutable;
|
||
|
}
|
||
|
if (bGroupImmutable && !_key.bDefault)
|
||
|
return;
|
||
|
|
||
|
// now either add or replace the data
|
||
|
KEntry &entry = aEntryMap[_key];
|
||
|
bool immutable = entry.bImmutable;
|
||
|
if (immutable && !_key.bDefault)
|
||
|
return;
|
||
|
|
||
|
entry = _data;
|
||
|
entry.bImmutable |= immutable;
|
||
|
entry.bGlobal |= bForceGlobal; // force to kdeglobals
|
||
|
|
||
|
if (_key.bDefault)
|
||
|
{
|
||
|
// We have added the data as default value,
|
||
|
// add it as normal value as well.
|
||
|
KEntryKey key(_key);
|
||
|
key.bDefault = false;
|
||
|
aEntryMap[key] = _data;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
KEntry KConfig::lookupData(const KEntryKey &_key) const
|
||
|
{
|
||
|
KEntryMapConstIterator aIt = aEntryMap.find(_key);
|
||
|
if (aIt != aEntryMap.end())
|
||
|
{
|
||
|
const KEntry &entry = *aIt;
|
||
|
if (entry.bDeleted)
|
||
|
return KEntry();
|
||
|
else
|
||
|
return entry;
|
||
|
}
|
||
|
else {
|
||
|
return KEntry();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool KConfig::internalHasGroup(const QCString &group) const
|
||
|
{
|
||
|
KEntryKey groupKey( group, 0);
|
||
|
|
||
|
KEntryMapConstIterator aIt = aEntryMap.find(groupKey);
|
||
|
KEntryMapConstIterator aEnd = aEntryMap.end();
|
||
|
|
||
|
if (aIt == aEnd)
|
||
|
return false;
|
||
|
++aIt;
|
||
|
for(; (aIt != aEnd); ++aIt)
|
||
|
{
|
||
|
if (aIt.key().mKey.isEmpty())
|
||
|
break;
|
||
|
|
||
|
if (!aIt.key().bDefault && !(*aIt).bDeleted)
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
void KConfig::setFileWriteMode(int mode)
|
||
|
{
|
||
|
backEnd->setFileWriteMode(mode);
|
||
|
}
|
||
|
|
||
|
KLockFile::Ptr KConfig::lockFile(bool bGlobal)
|
||
|
{
|
||
|
KConfigINIBackEnd *aBackEnd = dynamic_cast<KConfigINIBackEnd*>(backEnd);
|
||
|
if (!aBackEnd) return 0;
|
||
|
return aBackEnd->lockFile(bGlobal);
|
||
|
}
|
||
|
|
||
|
void KConfig::checkUpdate(const QString &id, const QString &updateFile)
|
||
|
{
|
||
|
QString oldGroup = group();
|
||
|
setGroup("$Version");
|
||
|
QString cfg_id = updateFile+":"+id;
|
||
|
QStringList ids = readListEntry("update_info");
|
||
|
if (!ids.contains(cfg_id))
|
||
|
{
|
||
|
QStringList args;
|
||
|
args << "--check" << updateFile;
|
||
|
KApplication::kdeinitExecWait("kconf_update", args);
|
||
|
reparseConfiguration();
|
||
|
}
|
||
|
setGroup(oldGroup);
|
||
|
}
|
||
|
|
||
|
KConfig* KConfig::copyTo(const QString &file, KConfig *config) const
|
||
|
{
|
||
|
if (!config)
|
||
|
config = new KConfig(QString::null, false, false);
|
||
|
config->backEnd->changeFileName(file, "config", false);
|
||
|
config->setReadOnly(false);
|
||
|
config->bFileImmutable = false;
|
||
|
config->backEnd->mConfigState = ReadWrite;
|
||
|
|
||
|
QStringList groups = groupList();
|
||
|
for(QStringList::ConstIterator it = groups.begin();
|
||
|
it != groups.end(); ++it)
|
||
|
{
|
||
|
QMap<QString, QString> map = entryMap(*it);
|
||
|
config->setGroup(*it);
|
||
|
for (QMap<QString,QString>::Iterator it2 = map.begin();
|
||
|
it2 != map.end(); ++it2)
|
||
|
{
|
||
|
config->writeEntry(it2.key(), it2.data());
|
||
|
}
|
||
|
|
||
|
}
|
||
|
return config;
|
||
|
}
|
||
|
|
||
|
void KConfig::virtual_hook( int id, void* data )
|
||
|
{ KConfigBase::virtual_hook( id, data ); }
|
||
|
|
||
|
static KStaticDeleter< QValueList<KSharedConfig*> > sd;
|
||
|
QValueList<KSharedConfig*> *KSharedConfig::s_list = 0;
|
||
|
|
||
|
KSharedConfig::Ptr KSharedConfig::openConfig(const QString& fileName, bool readOnly, bool useKDEGlobals )
|
||
|
{
|
||
|
if (s_list)
|
||
|
{
|
||
|
for(QValueList<KSharedConfig*>::ConstIterator it = s_list->begin();
|
||
|
it != s_list->end(); ++it)
|
||
|
{
|
||
|
if ((*it)->backEnd->fileName() == fileName &&
|
||
|
(*it)->bReadOnly == readOnly &&
|
||
|
(*it)->backEnd->useKDEGlobals == useKDEGlobals )
|
||
|
return (*it);
|
||
|
}
|
||
|
}
|
||
|
return new KSharedConfig(fileName, readOnly, useKDEGlobals);
|
||
|
}
|
||
|
|
||
|
KSharedConfig::KSharedConfig( const QString& fileName, bool readonly, bool usekdeglobals)
|
||
|
: KConfig(fileName, readonly, usekdeglobals)
|
||
|
{
|
||
|
if (!s_list)
|
||
|
{
|
||
|
sd.setObject(s_list, new QValueList<KSharedConfig*>);
|
||
|
}
|
||
|
|
||
|
s_list->append(this);
|
||
|
}
|
||
|
|
||
|
KSharedConfig::~KSharedConfig()
|
||
|
{
|
||
|
if ( s_list )
|
||
|
s_list->remove(this);
|
||
|
}
|
||
|
|
||
|
#include "kconfig.moc"
|