qsettings: Simplify confFiles logic

Use a QVector to hold the QConfFile(s) to allow more configuration
files than the statically defined number -> this will allow considering
multiple system-wide configuration files if needed.

To use a dynamic container we get rid of use QScopedSharedPointer, which
actually wasn't needed anyway, as the "deref" logic was/is done manually
in the QConfFileSettingsPrivate destructor.

Change-Id: Ie9341da2cbe2e2b1379f9e2538cb4c9ebbd6fc97
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Palo Kisa 2016-08-24 02:14:32 +02:00
parent 99b6eb4382
commit ee35fbbf52
3 changed files with 85 additions and 118 deletions

View File

@ -228,7 +228,7 @@ void QConfFile::clearCache()
// QSettingsPrivate // QSettingsPrivate
QSettingsPrivate::QSettingsPrivate(QSettings::Format format) QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
: format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), spec(0), fallbacks(true), : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
pendingChanges(false), status(QSettings::NoError) pendingChanges(false), status(QSettings::NoError)
{ {
} }
@ -236,7 +236,7 @@ QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope, QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
const QString &organization, const QString &application) const QString &organization, const QString &application)
: format(format), scope(scope), organizationName(organization), applicationName(application), : format(format), scope(scope), organizationName(organization), applicationName(application),
iniCodec(0), spec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError) iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
{ {
} }
@ -944,7 +944,7 @@ void QConfFileSettingsPrivate::initFormat()
void QConfFileSettingsPrivate::initAccess() void QConfFileSettingsPrivate::initAccess()
{ {
if (confFiles[spec]) { if (!confFiles.isEmpty()) {
if (format > QSettings::IniFormat) { if (format > QSettings::IniFormat) {
if (!readFunc) if (!readFunc)
setStatus(QSettings::AccessError); setStatus(QSettings::AccessError);
@ -1105,7 +1105,6 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
: QSettingsPrivate(format, scope, organization, application), : QSettingsPrivate(format, scope, organization, application),
nextPosition(0x40000000) // big positive number nextPosition(0x40000000) // big positive number
{ {
int i;
initFormat(); initFormat();
QString org = organization; QString org = organization;
@ -1120,21 +1119,14 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
if (scope == QSettings::UserScope) { if (scope == QSettings::UserScope) {
QString userPath = getPath(format, QSettings::UserScope); QString userPath = getPath(format, QSettings::UserScope);
if (!application.isEmpty()) if (!application.isEmpty())
confFiles[F_User | F_Application].reset(QConfFile::fromName(userPath + appFile, true)); confFiles.append(QConfFile::fromName(userPath + appFile, true));
confFiles[F_User | F_Organization].reset(QConfFile::fromName(userPath + orgFile, true)); confFiles.append(QConfFile::fromName(userPath + orgFile, true));
} }
QString systemPath = getPath(format, QSettings::SystemScope); QString systemPath = getPath(format, QSettings::SystemScope);
if (!application.isEmpty()) if (!application.isEmpty())
confFiles[F_System | F_Application].reset(QConfFile::fromName(systemPath + appFile, false)); confFiles.append(QConfFile::fromName(systemPath + appFile, false));
confFiles[F_System | F_Organization].reset(QConfFile::fromName(systemPath + orgFile, false)); confFiles.append(QConfFile::fromName(systemPath + orgFile, false));
for (i = 0; i < NumConfFiles; ++i) {
if (confFiles[i]) {
spec = i;
break;
}
}
initAccess(); initAccess();
} }
@ -1146,7 +1138,7 @@ QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
{ {
initFormat(); initFormat();
confFiles[0].reset(QConfFile::fromName(fileName, true)); confFiles.append(QConfFile::fromName(fileName, true));
initAccess(); initAccess();
} }
@ -1157,40 +1149,39 @@ QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
ConfFileHash *usedHash = usedHashFunc(); ConfFileHash *usedHash = usedHashFunc();
ConfFileCache *unusedCache = unusedCacheFunc(); ConfFileCache *unusedCache = unusedCacheFunc();
for (int i = 0; i < NumConfFiles; ++i) { for (auto conf_file : qAsConst(confFiles)) {
if (confFiles[i] && !confFiles[i]->ref.deref()) { if (!conf_file->ref.deref()) {
if (confFiles[i]->size == 0) { if (conf_file->size == 0) {
delete confFiles[i].take(); delete conf_file;
} else { } else {
if (usedHash) if (usedHash)
usedHash->remove(confFiles[i]->name); usedHash->remove(conf_file->name);
if (unusedCache) { if (unusedCache) {
QT_TRY { QT_TRY {
// compute a better size? // compute a better size?
unusedCache->insert(confFiles[i]->name, confFiles[i].data(), unusedCache->insert(conf_file->name, conf_file,
10 + (confFiles[i]->originalKeys.size() / 4)); 10 + (conf_file->originalKeys.size() / 4));
confFiles[i].take();
} QT_CATCH(...) { } QT_CATCH(...) {
// out of memory. Do not cache the file. // out of memory. Do not cache the file.
delete confFiles[i].take(); delete conf_file;
} }
} else { } else {
// unusedCache is gone - delete the entry to prevent a memory leak // unusedCache is gone - delete the entry to prevent a memory leak
delete confFiles[i].take(); delete conf_file;
} }
} }
} }
// prevent the ScopedPointer to deref it again.
confFiles[i].take();
} }
} }
void QConfFileSettingsPrivate::remove(const QString &key) void QConfFileSettingsPrivate::remove(const QString &key)
{ {
QConfFile *confFile = confFiles[spec].data(); if (confFiles.isEmpty())
if (!confFile)
return; return;
// Note: First config file is always the most specific.
QConfFile *confFile = confFiles.at(0);
QSettingsKey theKey(key, caseSensitivity); QSettingsKey theKey(key, caseSensitivity);
QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity); QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
QMutexLocker locker(&confFile->mutex); QMutexLocker locker(&confFile->mutex);
@ -1214,10 +1205,12 @@ void QConfFileSettingsPrivate::remove(const QString &key)
void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value) void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
{ {
QConfFile *confFile = confFiles[spec].data(); if (confFiles.isEmpty())
if (!confFile)
return; return;
// Note: First config file is always the most specific.
QConfFile *confFile = confFiles.at(0);
QSettingsKey theKey(key, caseSensitivity, nextPosition++); QSettingsKey theKey(key, caseSensitivity, nextPosition++);
QMutexLocker locker(&confFile->mutex); QMutexLocker locker(&confFile->mutex);
confFile->removedKeys.remove(theKey); confFile->removedKeys.remove(theKey);
@ -1230,29 +1223,27 @@ bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
ParsedSettingsMap::const_iterator j; ParsedSettingsMap::const_iterator j;
bool found = false; bool found = false;
for (int i = 0; i < NumConfFiles; ++i) { for (auto confFile : qAsConst(confFiles)) {
if (QConfFile *confFile = confFiles[i].data()) { QMutexLocker locker(&confFile->mutex);
QMutexLocker locker(&confFile->mutex);
if (!confFile->addedKeys.isEmpty()) { if (!confFile->addedKeys.isEmpty()) {
j = confFile->addedKeys.constFind(theKey); j = confFile->addedKeys.constFind(theKey);
found = (j != confFile->addedKeys.constEnd()); found = (j != confFile->addedKeys.constEnd());
}
if (!found) {
ensureSectionParsed(confFile, theKey);
j = confFile->originalKeys.constFind(theKey);
found = (j != confFile->originalKeys.constEnd()
&& !confFile->removedKeys.contains(theKey));
}
if (found && value)
*value = *j;
if (found)
return true;
if (!fallbacks)
break;
} }
if (!found) {
ensureSectionParsed(confFile, theKey);
j = confFile->originalKeys.constFind(theKey);
found = (j != confFile->originalKeys.constEnd()
&& !confFile->removedKeys.contains(theKey));
}
if (found && value)
*value = *j;
if (found)
return true;
if (!fallbacks)
break;
} }
return false; return false;
} }
@ -1265,34 +1256,31 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
QSettingsKey thePrefix(prefix, caseSensitivity); QSettingsKey thePrefix(prefix, caseSensitivity);
int startPos = prefix.size(); int startPos = prefix.size();
for (int i = 0; i < NumConfFiles; ++i) { for (auto confFile : qAsConst(confFiles)) {
if (QConfFile *confFile = confFiles[i].data()) { QMutexLocker locker(&confFile->mutex);
QMutexLocker locker(&confFile->mutex);
if (thePrefix.isEmpty()) { if (thePrefix.isEmpty())
ensureAllSectionsParsed(confFile); ensureAllSectionsParsed(confFile);
} else { else
ensureSectionParsed(confFile, thePrefix); ensureSectionParsed(confFile, thePrefix);
}
j = const_cast<const ParsedSettingsMap *>( j = const_cast<const ParsedSettingsMap *>(
&confFile->originalKeys)->lowerBound( thePrefix); &confFile->originalKeys)->lowerBound( thePrefix);
while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) { while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
if (!confFile->removedKeys.contains(j.key())) if (!confFile->removedKeys.contains(j.key()))
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
++j;
}
j = const_cast<const ParsedSettingsMap *>(
&confFile->addedKeys)->lowerBound(thePrefix);
while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
processChild(j.key().originalCaseKey().midRef(startPos), spec, result); processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
++j; ++j;
}
if (!fallbacks)
break;
} }
j = const_cast<const ParsedSettingsMap *>(
&confFile->addedKeys)->lowerBound(thePrefix);
while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
++j;
}
if (!fallbacks)
break;
} }
std::sort(result.begin(), result.end()); std::sort(result.begin(), result.end());
result.erase(std::unique(result.begin(), result.end()), result.erase(std::unique(result.begin(), result.end()),
@ -1302,10 +1290,12 @@ QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec
void QConfFileSettingsPrivate::clear() void QConfFileSettingsPrivate::clear()
{ {
QConfFile *confFile = confFiles[spec].data(); if (confFiles.isEmpty())
if (!confFile)
return; return;
// Note: First config file is always the most specific.
QConfFile *confFile = confFiles.at(0);
QMutexLocker locker(&confFile->mutex); QMutexLocker locker(&confFile->mutex);
ensureAllSectionsParsed(confFile); ensureAllSectionsParsed(confFile);
confFile->addedKeys.clear(); confFile->addedKeys.clear();
@ -1317,12 +1307,9 @@ void QConfFileSettingsPrivate::sync()
// people probably won't be checking the status a whole lot, so in case of // people probably won't be checking the status a whole lot, so in case of
// error we just try to go on and make the best of it // error we just try to go on and make the best of it
for (int i = 0; i < NumConfFiles; ++i) { for (auto confFile : qAsConst(confFiles)) {
QConfFile *confFile = confFiles[i].data(); QMutexLocker locker(&confFile->mutex);
if (confFile) { syncConfFile(confFile);
QMutexLocker locker(&confFile->mutex);
syncConfFile(i);
}
} }
} }
@ -1333,10 +1320,11 @@ void QConfFileSettingsPrivate::flush()
QString QConfFileSettingsPrivate::fileName() const QString QConfFileSettingsPrivate::fileName() const
{ {
QConfFile *confFile = confFiles[spec].data(); if (confFiles.isEmpty())
if (!confFile)
return QString(); return QString();
return confFile->name;
// Note: First config file is always the most specific.
return confFiles.at(0)->name;
} }
bool QConfFileSettingsPrivate::isWritable() const bool QConfFileSettingsPrivate::isWritable() const
@ -1344,16 +1332,14 @@ bool QConfFileSettingsPrivate::isWritable() const
if (format > QSettings::IniFormat && !writeFunc) if (format > QSettings::IniFormat && !writeFunc)
return false; return false;
QConfFile *confFile = confFiles[spec].data(); if (confFiles.isEmpty())
if (!confFile)
return false; return false;
return confFile->isWritable(); return confFiles.at(0)->isWritable();
} }
void QConfFileSettingsPrivate::syncConfFile(int confFileNo) void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
{ {
QConfFile *confFile = confFiles[confFileNo].data();
bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty(); bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
/* /*

View File

@ -419,20 +419,15 @@ QMacSettingsPrivate::QMacSettingsPrivate(QSettings::Scope scope, const QString &
javaPackageName.prepend(QLatin1String("com.")); javaPackageName.prepend(QLatin1String("com."));
suiteId = javaPackageName; suiteId = javaPackageName;
if (scope == QSettings::SystemScope) if (!application.isEmpty()) {
spec |= F_System;
if (application.isEmpty()) {
spec |= F_Organization;
} else {
javaPackageName += QLatin1Char('.'); javaPackageName += QLatin1Char('.');
javaPackageName += application; javaPackageName += application;
applicationId = javaPackageName; applicationId = javaPackageName;
} }
numDomains = 0; numDomains = 0;
for (int i = (spec & F_System) ? 1 : 0; i < 2; ++i) { for (int i = (scope == QSettings::SystemScope) ? 1 : 0; i < 2; ++i) {
for (int j = (spec & F_Organization) ? 1 : 0; j < 3; ++j) { for (int j = (application.isEmpty()) ? 1 : 0; j < 3; ++j) {
SearchDomain &domain = domains[numDomains++]; SearchDomain &domain = domains[numDomains++];
domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser; domain.userName = (i == 0) ? kCFPreferencesCurrentUser : kCFPreferencesAnyUser;
if (j == 0) if (j == 0)
@ -573,7 +568,7 @@ bool QMacSettingsPrivate::isWritable() const
QString QMacSettingsPrivate::fileName() const QString QMacSettingsPrivate::fileName() const
{ {
QString result; QString result;
if ((spec & F_System) == 0) if (scope == QSettings::UserScope)
result = QDir::homePath(); result = QDir::homePath();
result += QLatin1String("/Library/Preferences/"); result += QLatin1String("/Library/Preferences/");
result += QCFString::toQString(domains[0].applicationOrSuiteId); result += QCFString::toQString(domains[0].applicationOrSuiteId);

View File

@ -236,19 +236,6 @@ public:
QTextCodec *codec); QTextCodec *codec);
static QStringList splitArgs(const QString &s, int idx); static QStringList splitArgs(const QString &s, int idx);
/*
The numeric values of these enums define their search order. For example,
F_User | F_Organization is searched before F_System | F_Application,
because their values are respectively 1 and 2.
*/
enum {
F_Application = 0x0,
F_Organization = 0x1,
F_User = 0x0,
F_System = 0x2,
NumConfFiles = 4
};
QSettings::Format format; QSettings::Format format;
QSettings::Scope scope; QSettings::Scope scope;
QString organizationName; QString organizationName;
@ -258,7 +245,6 @@ public:
protected: protected:
QStack<QSettingsGroup> groupStack; QStack<QSettingsGroup> groupStack;
QString groupPrefix; QString groupPrefix;
int spec;
bool fallbacks; bool fallbacks;
bool pendingChanges; bool pendingChanges;
mutable QSettings::Status status; mutable QSettings::Status status;
@ -293,7 +279,7 @@ public:
private: private:
void initFormat(); void initFormat();
void initAccess(); void initAccess();
void syncConfFile(int confFileNo); void syncConfFile(QConfFile *confFile);
bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map); bool writeIniFile(QIODevice &device, const ParsedSettingsMap &map);
#ifdef Q_OS_MAC #ifdef Q_OS_MAC
bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const; bool readPlistFile(const QByteArray &data, ParsedSettingsMap *map) const;
@ -302,7 +288,7 @@ private:
void ensureAllSectionsParsed(QConfFile *confFile) const; void ensureAllSectionsParsed(QConfFile *confFile) const;
void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const; void ensureSectionParsed(QConfFile *confFile, const QSettingsKey &key) const;
QScopedSharedPointer<QConfFile> confFiles[NumConfFiles]; QVector<QConfFile *> confFiles;
QSettings::ReadFunc readFunc; QSettings::ReadFunc readFunc;
QSettings::WriteFunc writeFunc; QSettings::WriteFunc writeFunc;
QString extension; QString extension;