summaryrefslogtreecommitdiffstats
path: root/kdecore/kconfigbackend.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kdecore/kconfigbackend.cpp')
-rw-r--r--kdecore/kconfigbackend.cpp1186
1 files changed, 0 insertions, 1186 deletions
diff --git a/kdecore/kconfigbackend.cpp b/kdecore/kconfigbackend.cpp
deleted file mode 100644
index 633458d41..000000000
--- a/kdecore/kconfigbackend.cpp
+++ /dev/null
@@ -1,1186 +0,0 @@
-/*
- 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.
-*/
-
-#include <config.h>
-
-#include <unistd.h>
-#include <ctype.h>
-#ifdef HAVE_SYS_MMAN_H
-#include <sys/mman.h>
-#endif
-#include <sys/types.h>
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#include <fcntl.h>
-#include <signal.h>
-#include <setjmp.h>
-
-#include <tqdir.h>
-#include <tqfileinfo.h>
-#include <tqtextcodec.h>
-#include <tqtextstream.h>
-
-#include "kconfigbackend.h"
-#include "kconfigbase.h"
-#include <kapplication.h>
-#include <kglobal.h>
-#include <kprocess.h>
-#include <klocale.h>
-#include <kstandarddirs.h>
-#include <ksavefile.h>
-#include <kurl.h>
-#include <kde_file.h>
-
-extern bool checkAccess(const TQString& pathname, int mode);
-/* translate escaped escape sequences to their actual values. */
-static TQCString printableToString(const char *str, int l)
-{
- // Strip leading white-space.
- while((l>0) &&
- ((*str == ' ') || (*str == '\t') || (*str == '\r')))
- {
- str++; l--;
- }
-
- // Strip trailing white-space.
- while((l>0) &&
- ((str[l-1] == ' ') || (str[l-1] == '\t') || (str[l-1] == '\r')))
- {
- l--;
- }
-
- TQCString result(l + 1);
- char *r = result.data();
-
- for(int i = 0; i < l;i++, str++)
- {
- if (*str == '\\')
- {
- i++, str++;
- if (i >= l) // End of line. (Line ends with single slash)
- {
- *r++ = '\\';
- break;
- }
- switch(*str)
- {
- case 's':
- *r++ = ' ';
- break;
- case 't':
- *r++ = '\t';
- break;
- case 'n':
- *r++ = '\n';
- break;
- case 'r':
- *r++ = '\r';
- break;
- case '\\':
- *r++ = '\\';
- break;
- default:
- *r++ = '\\';
- *r++ = *str;
- }
- }
- else
- {
- *r++ = *str;
- }
- }
- result.truncate(r-result.data());
- return result;
-}
-
-static TQCString stringToPrintable(const TQCString& str){
- TQCString result(str.length()*2); // Maximum 2x as long as source string
- register char *r = const_cast<TQCString&>(result).data();
- register char *s = const_cast<TQCString&>(str).data();
-
- if (!s) return TQCString("");
-
- // Escape leading space
- if (*s == ' ')
- {
- *r++ = '\\'; *r++ = 's';
- s++;
- }
-
- if (*s)
- {
- while(*s)
- {
- if (*s == '\n')
- {
- *r++ = '\\'; *r++ = 'n';
- }
- else if (*s == '\t')
- {
- *r++ = '\\'; *r++ = 't';
- }
- else if (*s == '\r')
- {
- *r++ = '\\'; *r++ = 'r';
- }
- else if (*s == '\\')
- {
- *r++ = '\\'; *r++ = '\\';
- }
- else
- {
- *r++ = *s;
- }
- s++;
- }
- // Escape trailing space
- if (*(r-1) == ' ')
- {
- *(r-1) = '\\'; *r++ = 's';
- }
- }
-
- result.truncate(r - result.data());
- return result;
-}
-
-static TQCString decodeGroup(const char*s, int l)
-{
- TQCString result(l);
- register char *r = result.data();
-
- l--; // Correct for trailing \0
- while(l)
- {
- if ((*s == '[') && (l > 1))
- {
- if ((*(s+1) == '['))
- {
- l--;
- s++;
- }
- }
- if ((*s == ']') && (l > 1))
- {
- if ((*(s+1) == ']'))
- {
- l--;
- s++;
- }
- }
- *r++ = *s++;
- l--;
- }
- result.truncate(r - result.data());
- return result;
-}
-
-static TQCString encodeGroup(const TQCString &str)
-{
- int l = str.length();
- TQCString result(l*2+1);
- register char *r = const_cast<TQCString&>(result).data();
- register char *s = const_cast<TQCString&>(str).data();
- while(l)
- {
- if ((*s == '[') || (*s == ']'))
- *r++ = *s;
- *r++ = *s++;
- l--;
- }
- result.truncate(r - result.data());
- return result;
-}
-
-static TQCString encodeKey(const char* key)
-{
- TQCString newKey(key);
-
- newKey.replace('[', "%5b");
- newKey.replace(']', "%5d");
-
- return newKey;
-}
-
-static TQCString decodeKey(const char* key)
-{
- TQCString newKey(key);
-
- newKey.replace("%5b", "[");
- newKey.replace("%5d", "]");
-
- return newKey;
-}
-
-class KConfigBackEnd::KConfigBackEndPrivate
-{
-public:
- TQDateTime localLastModified;
- uint localLastSize;
- KLockFile::Ptr localLockFile;
- KLockFile::Ptr globalLockFile;
-};
-
-void KConfigBackEnd::changeFileName(const TQString &_fileName,
- const char * _resType,
- bool _useKDEGlobals)
-{
- mfileName = _fileName;
- resType = _resType;
- useKDEGlobals = _useKDEGlobals;
- if (mfileName.isEmpty())
- mLocalFileName = TQString::null;
- else if (!TQDir::isRelativePath(mfileName))
- mLocalFileName = mfileName;
- else
- mLocalFileName = KGlobal::dirs()->saveLocation(resType) + mfileName;
-
- if (useKDEGlobals)
- mGlobalFileName = KGlobal::dirs()->saveLocation("config") +
- TQString::tqfromLatin1("kdeglobals");
- else
- mGlobalFileName = TQString::null;
-
- d->localLastModified = TQDateTime();
- d->localLastSize = 0;
- d->localLockFile = 0;
- d->globalLockFile = 0;
-}
-
-KLockFile::Ptr KConfigBackEnd::lockFile(bool bGlobal)
-{
- if (bGlobal)
- {
- if (d->globalLockFile)
- return d->globalLockFile;
-
- if (!mGlobalFileName.isEmpty())
- {
- d->globalLockFile = new KLockFile(mGlobalFileName+".lock");
- return d->globalLockFile;
- }
- }
- else
- {
- if (d->localLockFile)
- return d->localLockFile;
-
- if (!mLocalFileName.isEmpty())
- {
- d->localLockFile = new KLockFile(mLocalFileName+".lock");
- return d->localLockFile;
- }
- }
- return 0;
-}
-
-KConfigBackEnd::KConfigBackEnd(KConfigBase *_config,
- const TQString &_fileName,
- const char * _resType,
- bool _useKDEGlobals)
- : pConfig(_config), bFileImmutable(false), mConfigState(KConfigBase::NoAccess), mFileMode(-1)
-{
- d = new KConfigBackEndPrivate;
- changeFileName(_fileName, _resType, _useKDEGlobals);
-}
-
-KConfigBackEnd::~KConfigBackEnd()
-{
- delete d;
-}
-
-void KConfigBackEnd::setFileWriteMode(int mode)
-{
- mFileMode = mode;
-}
-
-bool KConfigINIBackEnd::parseConfigFiles()
-{
- // Check if we can write to the local file.
- mConfigState = KConfigBase::ReadOnly;
- if (!mLocalFileName.isEmpty() && !pConfig->isReadOnly())
- {
- if (checkAccess(mLocalFileName, W_OK))
- {
- mConfigState = KConfigBase::ReadWrite;
- }
- else
- {
- // Create the containing dir, maybe it wasn't there
- KURL path;
- path.setPath(mLocalFileName);
- TQString dir=path.directory();
- KStandardDirs::makeDir(dir);
-
- if (checkAccess(mLocalFileName, W_OK))
- {
- mConfigState = KConfigBase::ReadWrite;
- }
- }
- TQFileInfo info(mLocalFileName);
- d->localLastModified = info.lastModified();
- d->localLastSize = info.size();
- }
-
- // Parse all desired files from the least to the most specific.
- bFileImmutable = false;
-
- // Parse the general config files
- if (useKDEGlobals) {
- TQStringList kdercs = KGlobal::dirs()->
- findAllResources("config", TQString::tqfromLatin1("kdeglobals"));
-
-#ifdef Q_WS_WIN
- TQString etc_kderc = TQFile::decodeName( TQCString(getenv("WINDIR")) + "\\kderc" );
-#else
- TQString etc_kderc = TQString::tqfromLatin1("/etc/kderc");
-#endif
-
- if (checkAccess(etc_kderc, R_OK))
- kdercs += etc_kderc;
-
- kdercs += KGlobal::dirs()->
- findAllResources("config", TQString::tqfromLatin1("system.kdeglobals"));
-
- TQStringList::ConstIterator it;
-
- for (it = kdercs.fromLast(); it != kdercs.end(); --it) {
-
- TQFile aConfigFile( *it );
- if (!aConfigFile.open( IO_ReadOnly ))
- continue;
- parseSingleConfigFile( aConfigFile, 0L, true, (*it != mGlobalFileName) );
- aConfigFile.close();
- if (bFileImmutable)
- break;
- }
- }
-
- bool bReadFile = !mfileName.isEmpty();
- while(bReadFile) {
- bReadFile = false;
- TQString bootLanguage;
- if (useKDEGlobals && localeString.isEmpty() && !KGlobal::_locale) {
- // Boot strap language
- bootLanguage = KLocale::_initLanguage(pConfig);
- setLocaleString(bootLanguage.utf8());
- }
-
- bFileImmutable = false;
- TQStringList list;
- if ( !TQDir::isRelativePath(mfileName) )
- list << mfileName;
- else
- list = KGlobal::dirs()->findAllResources(resType, mfileName);
-
- TQStringList::ConstIterator it;
-
- for (it = list.fromLast(); it != list.end(); --it) {
-
- TQFile aConfigFile( *it );
- // we can already be sure that this file exists
- bool bIsLocal = (*it == mLocalFileName);
- if (aConfigFile.open( IO_ReadOnly )) {
- parseSingleConfigFile( aConfigFile, 0L, false, !bIsLocal );
- aConfigFile.close();
- if (bFileImmutable)
- break;
- }
- }
- if (KGlobal::dirs()->isRestrictedResource(resType, mfileName))
- bFileImmutable = true;
- TQString currentLanguage;
- if (!bootLanguage.isEmpty())
- {
- currentLanguage = KLocale::_initLanguage(pConfig);
- // If the file changed the language, we need to read the file again
- // with the new language setting.
- if (bootLanguage != currentLanguage)
- {
- bReadFile = true;
- setLocaleString(currentLanguage.utf8());
- }
- }
- }
- if (bFileImmutable)
- mConfigState = KConfigBase::ReadOnly;
-
- return true;
-}
-
-#ifdef HAVE_MMAP
-#ifdef SIGBUS
-static sigjmp_buf mmap_jmpbuf;
-struct sigaction mmap_old_sigact;
-
-extern "C" {
- static void mmap_sigbus_handler(int)
- {
- siglongjmp (mmap_jmpbuf, 1);
- }
-}
-#endif
-#endif
-
-extern bool kde_kiosk_exception;
-
-void KConfigINIBackEnd::parseSingleConfigFile(TQFile &rFile,
- KEntryMap *pWriteBackMap,
- bool bGlobal, bool bDefault)
-{
- const char *s; // May get clobbered by sigsetjump, but we don't use them afterwards.
- const char *eof; // May get clobbered by sigsetjump, but we don't use them afterwards.
- TQByteArray data;
-
- if (!rFile.isOpen()) // come back, if you have real work for us ;->
- return;
-
- //using kdDebug() here leads to an infinite loop
- //remove this for the release, aleXXX
- //qWarning("Parsing %s, global = %s default = %s",
- // rFile.name().latin1(), bGlobal ? "true" : "false", bDefault ? "true" : "false");
-
- TQCString aCurrentGroup("<default>");
-
- unsigned int ll = localeString.length();
-
-#ifdef HAVE_MMAP
- static volatile const char *map;
- map = ( const char* ) mmap(0, rFile.size(), PROT_READ, MAP_PRIVATE,
- rFile.handle(), 0);
-
- if ( map != MAP_FAILED )
- {
- s = (const char*) map;
- eof = s + rFile.size();
-
-#ifdef SIGBUS
- struct sigaction act;
- act.sa_handler = mmap_sigbus_handler;
- sigemptyset( &act.sa_mask );
-#ifdef SA_ONESHOT
- act.sa_flags = SA_ONESHOT;
-#else
- act.sa_flags = SA_RESETHAND;
-#endif
- sigaction( SIGBUS, &act, &mmap_old_sigact );
-
- if (sigsetjmp (mmap_jmpbuf, 1))
- {
-qWarning("SIGBUS while reading %s", rFile.name().latin1());
- munmap(( char* )map, rFile.size());
- sigaction (SIGBUS, &mmap_old_sigact, 0);
- return;
- }
-#endif
- }
- else
-#endif
- {
- rFile.tqat(0);
- data = rFile.readAll();
- s = data.data();
- eof = s + data.size();
- }
-
- bool fileOptionImmutable = false;
- bool groupOptionImmutable = false;
- bool groupSkip = false;
- bool foundGettextDomain = false;
- TQCString gettextDomain;
-
- int line = 0;
- for(; s < eof; s++)
- {
- line++;
-
- while((s < eof) && isspace(*s) && (*s != '\n'))
- s++; //skip leading whitespace, shouldn't happen too often
-
- //skip empty lines, lines starting with #
- if ((s < eof) && ((*s == '\n') || (*s == '#')))
- {
- sktoeol: //skip till end-of-line
- while ((s < eof) && (*s != '\n'))
- s++;
- continue; // Empty or comment or no keyword
- }
- const char *startLine = s;
-
- if (*s == '[') //group
- {
- // In a group [[ and ]] have a special meaning
- while ((s < eof) && (*s != '\n'))
- {
- if (*s == ']')
- {
- if ((s+1 < eof) && (*(s+1) == ']'))
- s++; // Skip "]]"
- else
- break;
- }
-
- s++; // Search till end of group
- }
- const char *e = s;
- while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
- if ((e >= eof) || (*e != ']'))
- {
- fprintf(stderr, "Invalid group header at %s:%d\n", rFile.name().latin1(), line);
- continue;
- }
- // group found; get the group name by taking everything in
- // between the brackets
- if ((e-startLine == 3) &&
- (startLine[1] == '$') &&
- (startLine[2] == 'i'))
- {
- if (!kde_kiosk_exception)
- fileOptionImmutable = true;
- continue;
- }
-
- aCurrentGroup = decodeGroup(startLine + 1, e - startLine);
- //cout<<"found group ["<<aCurrentGroup<<"]"<<endl;
-
- // Backwards compatibility
- if (aCurrentGroup == "KDE Desktop Entry")
- aCurrentGroup = "Desktop Entry";
-
- groupOptionImmutable = fileOptionImmutable;
-
- e++;
- if ((e+2 < eof) && (*e++ == '[') && (*e++ == '$')) // Option follows
- {
- if ((*e == 'i') && !kde_kiosk_exception)
- {
- groupOptionImmutable = true;
- }
- }
-
- KEntryKey groupKey(aCurrentGroup, 0);
- KEntry entry = pConfig->lookupData(groupKey);
- groupSkip = entry.bImmutable;
-
- if (groupSkip && !bDefault)
- continue;
-
- entry.bImmutable |= groupOptionImmutable;
- pConfig->putData(groupKey, entry, false);
-
- if (pWriteBackMap)
- {
- // add the special group key indicator
- (*pWriteBackMap)[groupKey] = entry;
- }
-
- continue;
- }
- if (groupSkip && !bDefault)
- goto sktoeol; // Skip entry
-
-
- bool optionImmutable = groupOptionImmutable;
- bool optionDeleted = false;
- bool optionExpand = false;
- const char *endOfKey = 0, *locale = 0, *elocale = 0;
- for (; (s < eof) && (*s != '\n'); s++)
- {
- if (*s == '=') //find the equal sign
- {
- if (!endOfKey)
- endOfKey = s;
- goto haveeq;
- }
- if (*s == '[') //find the locale or options.
- {
- const char *option;
- const char *eoption;
- endOfKey = s;
- option = ++s;
- for (;; s++)
- {
- if ((s >= eof) || (*s == '\n') || (*s == '=')) {
- fprintf(stderr, "Invalid entry (missing ']') at %s:%d\n", rFile.name().latin1(), line);
- goto sktoeol;
- }
- if (*s == ']')
- break;
- }
- eoption = s;
- if (*option != '$')
- {
- // Locale
- if (locale) {
- fprintf(stderr, "Invalid entry (second locale!?) at %s:%d\n", rFile.name().latin1(), line);
- goto sktoeol;
- }
- locale = option;
- elocale = eoption;
- }
- else
- {
- // Option
- while (option < eoption)
- {
- option++;
- if ((*option == 'i') && !kde_kiosk_exception)
- optionImmutable = true;
- else if (*option == 'e')
- optionExpand = true;
- else if (*option == 'd')
- {
- optionDeleted = true;
- goto haveeq;
- }
- else if (*option == ']')
- break;
- }
- }
- }
- }
- fprintf(stderr, "Invalid entry (missing '=') at %s:%d\n", rFile.name().latin1(), line);
- continue;
-
- haveeq:
- for (endOfKey--; ; endOfKey--)
- {
- if (endOfKey < startLine)
- {
- fprintf(stderr, "Invalid entry (empty key) at %s:%d\n", rFile.name().latin1(), line);
- goto sktoeol;
- }
- if (!isspace(*endOfKey))
- break;
- }
-
- const char *st = ++s;
- while ((s < eof) && (*s != '\n')) s++; // Search till end of line / end of file
-
- if (locale) {
- unsigned int cl = static_cast<unsigned int>(elocale - locale);
- if ((ll != cl) || memcmp(locale, localeString.data(), ll))
- {
- // backward compatibility. C == en_US
- if ( cl != 1 || ll != 5 || *locale != 'C' || memcmp(localeString.data(), "en_US", 5)) {
- //cout<<"mismatched locale '"<<TQCString(locale, elocale-locale +1)<<"'"<<endl;
- // We can ignore this one
- if (!pWriteBackMap)
- continue; // We just ignore it
- // We just store it as is to be able to write it back later.
- endOfKey = elocale;
- locale = 0;
- }
- }
- }
-
- // insert the key/value line
- TQCString key(startLine, endOfKey - startLine + 2);
- TQCString val = printableToString(st, s - st);
- //qDebug("found key '%s' with value '%s'", key.data(), val.data());
-
- if (TQString(key.data()) == "X-Ubuntu-Gettext-Domain") {
- gettextDomain = val.data();
- foundGettextDomain = true;
- }
-
- KEntryKey aEntryKey(aCurrentGroup, decodeKey(key));
- aEntryKey.bLocal = (locale != 0);
- aEntryKey.bDefault = bDefault;
-
- KEntry aEntry;
- aEntry.mValue = val;
- aEntry.bGlobal = bGlobal;
- aEntry.bImmutable = optionImmutable;
- aEntry.bDeleted = optionDeleted;
- aEntry.bExpand = optionExpand;
- aEntry.bNLS = (locale != 0);
-
- if (pWriteBackMap) {
- // don't insert into the config object but into the temporary
- // scratchpad map
- pWriteBackMap->insert(aEntryKey, aEntry);
- } else {
- // directly insert value into config object
- // no need to specify localization; if the key we just
- // retrieved was localized already, no need to localize it again.
- pConfig->putData(aEntryKey, aEntry, false);
- }
- }
- // Look up translations using KLocale
- // https://launchpad.net/distros/ubuntu/+spec/langpacks-desktopfiles-kde
- // This calls KLocale up to 10 times for each config file (and each KConfig has up to 4 files)
- // so I'll see how much of a performance hit it is
- // it also only acts on the last group in a file
- // Ideas: only translate most important fields, only translate "Desktop Entry" files,
- // do translation per KConfig not per single file
- if (!pWriteBackMap) {
- TQFile file("file.txt");
- if (foundGettextDomain) {
-
- KLocale locale(gettextDomain);
-
- TQString language = locale.language();
- translateKey(locale, aCurrentGroup, TQCString("Name"));
- translateKey(locale, aCurrentGroup, TQCString("Comment"));
- translateKey(locale, aCurrentGroup, TQCString("Language"));
- translateKey(locale, aCurrentGroup, TQCString("Keywords"));
- translateKey(locale, aCurrentGroup, TQCString("About"));
- translateKey(locale, aCurrentGroup, TQCString("Description"));
- translateKey(locale, aCurrentGroup, TQCString("GenericName"));
- translateKey(locale, aCurrentGroup, TQCString("Query"));
- translateKey(locale, aCurrentGroup, TQCString("ExtraNames"));
- translateKey(locale, aCurrentGroup, TQCString("X-KDE-Submenu"));
- }
- }
-
-
- if (fileOptionImmutable)
- bFileImmutable = true;
-
-#ifdef HAVE_MMAP
- if (map)
- {
- munmap(( char* )map, rFile.size());
-#ifdef SIGBUS
- sigaction (SIGBUS, &mmap_old_sigact, 0);
-#endif
- }
-#endif
-}
-
-void KConfigINIBackEnd::translateKey(KLocale& locale, TQCString currentGroup, TQCString key) {
- KEntryKey entryKey = KEntryKey(currentGroup, key);
- KEntry entry = pConfig->lookupData(entryKey);
- if (TQString(entry.mValue) != "") {
- TQString orig = key + "=" + entry.mValue;
- TQString translate = locale.translate(key + "=" + entry.mValue);
- if (TQString::compare(orig, translate) != 0) {
- translate = translate.mid(key.length() + 1);
- entry.mValue = translate.utf8();
- entryKey.bLocal = true;
- entry.bNLS = true;
- pConfig->putData(entryKey, entry, false);
- }
- }
-}
-
-void KConfigINIBackEnd::sync(bool bMerge)
-{
- // write-sync is only necessary if there are dirty entries
- if (!pConfig->isDirty())
- return;
-
- bool bEntriesLeft = true;
-
- // find out the file to write to (most specific writable file)
- // try local app-specific file first
-
- if (!mfileName.isEmpty()) {
- // Create the containing dir if needed
- if ((resType!="config") && !TQDir::isRelativePath(mLocalFileName))
- {
- KURL path;
- path.setPath(mLocalFileName);
- TQString dir=path.directory();
- KStandardDirs::makeDir(dir);
- }
-
- // Can we allow the write? We can, if the program
- // doesn't run SUID. But if it runs SUID, we must
- // check if the user would be allowed to write if
- // it wasn't SUID.
- if (checkAccess(mLocalFileName, W_OK)) {
- // File is writable
- KLockFile::Ptr lf;
-
- bool mergeLocalFile = bMerge;
- // Check if the file has been updated since.
- if (mergeLocalFile)
- {
- lf = lockFile(false); // Lock file for local file
- if (lf && lf->isLocked())
- lf = 0; // Already locked, we don't need to lock/unlock again
-
- if (lf)
- {
- lf->lock( KLockFile::LockForce );
- // But what if the locking failed? Ignore it for now...
- }
-
- TQFileInfo info(mLocalFileName);
- if ((d->localLastSize == info.size()) &&
- (d->localLastModified == info.lastModified()))
- {
- // Not changed, don't merge.
- mergeLocalFile = false;
- }
- else
- {
- // Changed...
- d->localLastModified = TQDateTime();
- d->localLastSize = 0;
- }
- }
-
- bEntriesLeft = writeConfigFile( mLocalFileName, false, mergeLocalFile );
-
- // Only if we didn't have to merge anything can we use our in-memory state
- // the next time around. Otherwise the config-file may contain entries
- // that are different from our in-memory state which means we will have to
- // do a merge from then on.
- // We do not automatically update the in-memory state with the on-disk
- // state when writing the config to disk. We only do so when
- // KCOnfig::reparseConfiguration() is called.
- // For KDE 4.0 we may wish to reconsider that.
- if (!mergeLocalFile)
- {
- TQFileInfo info(mLocalFileName);
- d->localLastModified = info.lastModified();
- d->localLastSize = info.size();
- }
- if (lf) lf->unlock();
- }
- }
-
- // only write out entries to the kdeglobals file if there are any
- // entries marked global (indicated by bEntriesLeft) and
- // the useKDEGlobals flag is set.
- if (bEntriesLeft && useKDEGlobals) {
-
- // can we allow the write? (see above)
- if (checkAccess ( mGlobalFileName, W_OK )) {
- KLockFile::Ptr lf = lockFile(true); // Lock file for global file
- if (lf && lf->isLocked())
- lf = 0; // Already locked, we don't need to lock/unlock again
-
- if (lf)
- {
- lf->lock( KLockFile::LockForce );
- // But what if the locking failed? Ignore it for now...
- }
- writeConfigFile( mGlobalFileName, true, bMerge ); // Always merge
- if (lf) lf->unlock();
- }
- }
-
-}
-
-static void writeEntries(FILE *pStream, const KEntryMap& entryMap, bool defaultGroup, bool &firstEntry, const TQCString &localeString)
-{
- // now write out all other groups.
- TQCString currentGroup;
- for (KEntryMapConstIterator aIt = entryMap.begin();
- aIt != entryMap.end(); ++aIt)
- {
- const KEntryKey &key = aIt.key();
-
- // Either proces the default group or all others
- if ((key.mGroup != "<default>") == defaultGroup)
- continue; // Skip
-
- // Skip default values and group headers.
- if ((key.bDefault) || key.mKey.isEmpty())
- continue; // Skip
-
- const KEntry &currentEntry = *aIt;
-
- KEntryMapConstIterator aTestIt = aIt;
- ++aTestIt;
- bool hasDefault = (aTestIt != entryMap.end());
- if (hasDefault)
- {
- const KEntryKey &defaultKey = aTestIt.key();
- if ((!defaultKey.bDefault) ||
- (defaultKey.mKey != key.mKey) ||
- (defaultKey.mGroup != key.mGroup) ||
- (defaultKey.bLocal != key.bLocal))
- hasDefault = false;
- }
-
-
- if (hasDefault)
- {
- // Entry had a default value
- if ((currentEntry.mValue == (*aTestIt).mValue) &&
- (currentEntry.bDeleted == (*aTestIt).bDeleted))
- continue; // Same as default, don't write.
- }
- else
- {
- // Entry had no default value.
- if (currentEntry.bDeleted)
- continue; // Don't write deleted entries if there is no default.
- }
-
- if (!defaultGroup && (currentGroup != key.mGroup)) {
- if (!firstEntry)
- fprintf(pStream, "\n");
- currentGroup = key.mGroup;
- fprintf(pStream, "[%s]\n", encodeGroup(currentGroup).data());
- }
-
- firstEntry = false;
- // it is data for a group
- fputs(encodeKey(key.mKey.data()), pStream); // Key
-
- if ( currentEntry.bNLS )
- {
- fputc('[', pStream);
- fputs(localeString.data(), pStream);
- fputc(']', pStream);
- }
-
- if (currentEntry.bDeleted)
- {
- fputs("[$d]\n", pStream); // Deleted
- }
- else
- {
- if (currentEntry.bImmutable || currentEntry.bExpand)
- {
- fputc('[', pStream);
- fputc('$', pStream);
- if (currentEntry.bImmutable)
- fputc('i', pStream);
- if (currentEntry.bExpand)
- fputc('e', pStream);
-
- fputc(']', pStream);
- }
- fputc('=', pStream);
- fputs(stringToPrintable(currentEntry.mValue).data(), pStream);
- fputc('\n', pStream);
- }
- } // for loop
-}
-
-bool KConfigINIBackEnd::getEntryMap(KEntryMap &aTempMap, bool bGlobal,
- TQFile *mergeFile)
-{
- bool bEntriesLeft = false;
- bFileImmutable = false;
-
- // Read entries from disk
- if (mergeFile && mergeFile->open(IO_ReadOnly))
- {
- // fill the temporary structure with entries from the file
- parseSingleConfigFile(*mergeFile, &aTempMap, bGlobal, false );
-
- if (bFileImmutable) // File has become immutable on disk
- return bEntriesLeft;
- }
-
- KEntryMap aMap = pConfig->internalEntryMap();
-
- // augment this structure with the dirty entries from the config object
- for (KEntryMapIterator aIt = aMap.begin();
- aIt != aMap.end(); ++aIt)
- {
- const KEntry &currentEntry = *aIt;
- if(aIt.key().bDefault)
- {
- aTempMap.replace(aIt.key(), currentEntry);
- continue;
- }
-
- if (mergeFile && !currentEntry.bDirty)
- continue;
-
- // only write back entries that have the same
- // "globality" as the file
- if (currentEntry.bGlobal != bGlobal)
- {
- // wrong "globality" - might have to be saved later
- bEntriesLeft = true;
- continue;
- }
-
- // put this entry from the config object into the
- // temporary map, possibly replacing an existing entry
- KEntryMapIterator aIt2 = aTempMap.find(aIt.key());
- if (aIt2 != aTempMap.end() && (*aIt2).bImmutable)
- continue; // Bail out if the on-disk entry is immutable
-
- aTempMap.insert(aIt.key(), currentEntry, true);
- } // loop
-
- return bEntriesLeft;
-}
-
-/* antlarr: KDE 4.0: make the first parameter "const TQString &" */
-bool KConfigINIBackEnd::writeConfigFile(TQString filename, bool bGlobal,
- bool bMerge)
-{
- // is the config object read-only?
- if (pConfig->isReadOnly())
- return true; // pretend we wrote it
-
- KEntryMap aTempMap;
- TQFile *mergeFile = (bMerge ? new TQFile(filename) : 0);
- bool bEntriesLeft = getEntryMap(aTempMap, bGlobal, mergeFile);
- delete mergeFile;
- if (bFileImmutable)
- return true; // pretend we wrote it
-
- // OK now the temporary map should be full of ALL entries.
- // write it out to disk.
-
- // Check if file exists:
- int fileMode = -1;
- bool createNew = true;
-
- KDE_struct_stat buf;
- if (KDE_stat(TQFile::encodeName(filename), &buf) == 0)
- {
- if (buf.st_uid == getuid())
- {
- // Preserve file mode if file exists and is owned by user.
- fileMode = buf.st_mode & 0777;
- }
- else
- {
- // File is not owned by user:
- // Don't create new file but write to existing file instead.
- createNew = false;
- }
- }
-
- KSaveFile *pConfigFile = 0;
- FILE *pStream = 0;
-
- if (createNew)
- {
- pConfigFile = new KSaveFile( filename, 0600 );
-
- if (pConfigFile->status() != 0)
- {
- delete pConfigFile;
- return bEntriesLeft;
- }
-
- if (!bGlobal && (fileMode == -1))
- fileMode = mFileMode;
-
- if (fileMode != -1)
- {
- fchmod(pConfigFile->handle(), fileMode);
- }
-
- pStream = pConfigFile->fstream();
- }
- else
- {
- // Open existing file.
- // We use open() to ensure that we call without O_CREAT.
- int fd = KDE_open( TQFile::encodeName(filename), O_WRONLY | O_TRUNC );
- if (fd < 0)
- {
- return bEntriesLeft;
- }
- pStream = KDE_fdopen( fd, "w");
- if (!pStream)
- {
- close(fd);
- return bEntriesLeft;
- }
- }
-
- writeEntries(pStream, aTempMap);
-
- if (pConfigFile)
- {
- bool bEmptyFile = (ftell(pStream) == 0);
- if ( bEmptyFile && ((fileMode == -1) || (fileMode == 0600)) )
- {
- // File is empty and doesn't have special permissions: delete it.
- ::unlink(TQFile::encodeName(filename));
- pConfigFile->abort();
- }
- else
- {
- // Normal case: Close the file
- pConfigFile->close();
- }
- delete pConfigFile;
- }
- else
- {
- fclose(pStream);
- }
-
- return bEntriesLeft;
-}
-
-void KConfigINIBackEnd::writeEntries(FILE *pStream, const KEntryMap &aTempMap)
-{
- bool firstEntry = true;
-
- // Write default group
- ::writeEntries(pStream, aTempMap, true, firstEntry, localeString);
-
- // Write all other groups
- ::writeEntries(pStream, aTempMap, false, firstEntry, localeString);
-}
-
-void KConfigBackEnd::virtual_hook( int, void* )
-{ /*BASE::virtual_hook( id, data );*/ }
-
-void KConfigINIBackEnd::virtual_hook( int id, void* data )
-{ KConfigBackEnd::virtual_hook( id, data ); }
-
-bool KConfigBackEnd::checkConfigFilesWritable(bool warnUser)
-{
- // WARNING: Do NOT use the event loop as it may not exist at this time.
- bool allWritable = true;
- TQString errorMsg;
- if ( !mLocalFileName.isEmpty() && !bFileImmutable && !checkAccess(mLocalFileName,W_OK) )
- {
- errorMsg = i18n("Will not save configuration.\n");
- allWritable = false;
- errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mLocalFileName);
- }
- // We do not have an immutability flag for kdeglobals. However, making kdeglobals mutable while making
- // the local config file immutable is senseless.
- if ( !mGlobalFileName.isEmpty() && useKDEGlobals && !bFileImmutable && !checkAccess(mGlobalFileName,W_OK) )
- {
- if ( errorMsg.isEmpty() )
- errorMsg = i18n("Will not save configuration.\n");
- errorMsg += i18n("Configuration file \"%1\" not writable.\n").arg(mGlobalFileName);
- allWritable = false;
- }
-
- if (warnUser && !allWritable)
- {
- // Note: We don't ask the user if we should not ask this question again because we can't save the answer.
- errorMsg += i18n("Please contact your system administrator.");
- TQString cmdToExec = KStandardDirs::findExe(TQString("kdialog"));
- KApplication *app = kapp;
- if (!cmdToExec.isEmpty() && app)
- {
- KProcess lprocess;
- lprocess << cmdToExec << "--title" << app->instanceName() << "--msgbox" << TQCString(errorMsg.local8Bit());
- lprocess.start( KProcess::Block );
- }
- }
- return allWritable;
-}