1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <qdebug.h>
41#include "qplatformdefs.h"
42#include "qsettings.h"
43
44#include "qsettings_p.h"
45#include "qcache.h"
46#include "qfile.h"
47#include "qdir.h"
48#include "qfileinfo.h"
49#include "qmutex.h"
50#include "qlibraryinfo.h"
51#include "qtemporaryfile.h"
52#include "qstandardpaths.h"
53#include <qdatastream.h>
54
55#if QT_CONFIG(textcodec)
56# include "qtextcodec.h"
57#endif
58
59#ifndef QT_NO_GEOM_VARIANT
60#include "qsize.h"
61#include "qpoint.h"
62#include "qrect.h"
63#endif // !QT_NO_GEOM_VARIANT
64
65#ifndef QT_BUILD_QMAKE
66# include "qcoreapplication.h"
67#endif
68
69#ifndef QT_BOOTSTRAPPED
70#include "qsavefile.h"
71#include "qlockfile.h"
72#endif
73
74#ifdef Q_OS_VXWORKS
75# include <ioLib.h>
76#endif
77
78#ifdef Q_OS_WASM
79#include <emscripten.h>
80#endif
81
82#include <algorithm>
83#include <stdlib.h>
84
85#ifdef Q_OS_WIN // for homedirpath reading from registry
86# include <qt_windows.h>
87# ifndef Q_OS_WINRT
88# include <shlobj.h>
89# endif
90#endif
91
92#ifdef Q_OS_WINRT
93#include <wrl.h>
94#include <windows.foundation.h>
95#include <windows.storage.h>
96using namespace Microsoft::WRL;
97using namespace Microsoft::WRL::Wrappers;
98using namespace ABI::Windows::Foundation;
99using namespace ABI::Windows::Storage;
100#endif
101
102#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC) && !defined(Q_OS_ANDROID)
103#define Q_XDG_PLATFORM
104#endif
105
106#if !defined(QT_NO_STANDARDPATHS) && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT))
107#define QSETTINGS_USE_QSTANDARDPATHS
108#endif
109
110// ************************************************************************
111// QConfFile
112
113/*
114 QConfFile objects are explicitly shared within the application.
115 This ensures that modification to the settings done through one
116 QSettings object are immediately reflected in other setting
117 objects of the same application.
118*/
119
120QT_BEGIN_NAMESPACE
121
122struct QConfFileCustomFormat
123{
124 QString extension;
125 QSettings::ReadFunc readFunc;
126 QSettings::WriteFunc writeFunc;
127 Qt::CaseSensitivity caseSensitivity;
128};
129Q_DECLARE_TYPEINFO(QConfFileCustomFormat, Q_MOVABLE_TYPE);
130
131typedef QHash<QString, QConfFile *> ConfFileHash;
132typedef QCache<QString, QConfFile> ConfFileCache;
133namespace {
134 struct Path
135 {
136 // Note: Defining constructors explicitly because of buggy C++11
137 // implementation in MSVC (uniform initialization).
138 Path() {}
139 Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
140 QString path;
141 bool userDefined; //!< true - user defined, overridden by setPath
142 };
143}
144typedef QHash<int, Path> PathHash;
145typedef QVector<QConfFileCustomFormat> CustomFormatVector;
146
147Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
148Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
149Q_GLOBAL_STATIC(PathHash, pathHashFunc)
150Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
151
152static QBasicMutex settingsGlobalMutex;
153
154static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
155
156QConfFile::QConfFile(const QString &fileName, bool _userPerms)
157 : name(fileName), size(0), ref(1), userPerms(_userPerms)
158{
159 usedHashFunc()->insert(name, this);
160}
161
162QConfFile::~QConfFile()
163{
164 if (usedHashFunc())
165 usedHashFunc()->remove(name);
166}
167
168ParsedSettingsMap QConfFile::mergedKeyMap() const
169{
170 ParsedSettingsMap result = originalKeys;
171 ParsedSettingsMap::const_iterator i;
172
173 for (i = removedKeys.begin(); i != removedKeys.end(); ++i)
174 result.remove(i.key());
175 for (i = addedKeys.begin(); i != addedKeys.end(); ++i)
176 result.insert(i.key(), i.value());
177 return result;
178}
179
180bool QConfFile::isWritable() const
181{
182 QFileInfo fileInfo(name);
183
184#ifndef QT_NO_TEMPORARYFILE
185 if (fileInfo.exists()) {
186#endif
187 QFile file(name);
188 return file.open(QFile::ReadWrite);
189#ifndef QT_NO_TEMPORARYFILE
190 } else {
191 // Create the directories to the file.
192 QDir dir(fileInfo.absolutePath());
193 if (!dir.exists()) {
194 if (!dir.mkpath(dir.absolutePath()))
195 return false;
196 }
197
198 // we use a temporary file to avoid race conditions
199 QTemporaryFile file(name);
200 return file.open();
201 }
202#endif
203}
204
205QConfFile *QConfFile::fromName(const QString &fileName, bool _userPerms)
206{
207 QString absPath = QFileInfo(fileName).absoluteFilePath();
208
209 ConfFileHash *usedHash = usedHashFunc();
210 ConfFileCache *unusedCache = unusedCacheFunc();
211
212 QConfFile *confFile = 0;
213 QMutexLocker locker(&settingsGlobalMutex);
214
215 if (!(confFile = usedHash->value(absPath))) {
216 if ((confFile = unusedCache->take(absPath)))
217 usedHash->insert(absPath, confFile);
218 }
219 if (confFile) {
220 confFile->ref.ref();
221 return confFile;
222 }
223 return new QConfFile(absPath, _userPerms);
224}
225
226void QConfFile::clearCache()
227{
228 QMutexLocker locker(&settingsGlobalMutex);
229 unusedCacheFunc()->clear();
230}
231
232// ************************************************************************
233// QSettingsPrivate
234
235QSettingsPrivate::QSettingsPrivate(QSettings::Format format)
236 : format(format), scope(QSettings::UserScope /* nothing better to put */), iniCodec(0), fallbacks(true),
237 pendingChanges(false), status(QSettings::NoError)
238{
239}
240
241QSettingsPrivate::QSettingsPrivate(QSettings::Format format, QSettings::Scope scope,
242 const QString &organization, const QString &application)
243 : format(format), scope(scope), organizationName(organization), applicationName(application),
244 iniCodec(0), fallbacks(true), pendingChanges(false), status(QSettings::NoError)
245{
246}
247
248QSettingsPrivate::~QSettingsPrivate()
249{
250}
251
252QString QSettingsPrivate::actualKey(const QString &key) const
253{
254 QString n = normalizedKey(key);
255 Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
256 return groupPrefix + n;
257}
258
259/*
260 Returns a string that never starts nor ends with a slash (or an
261 empty string). Examples:
262
263 "foo" becomes "foo"
264 "/foo//bar///" becomes "foo/bar"
265 "///" becomes ""
266
267 This function is optimized to avoid a QString deep copy in the
268 common case where the key is already normalized.
269*/
270QString QSettingsPrivate::normalizedKey(const QString &key)
271{
272 QString result = key;
273
274 int i = 0;
275 while (i < result.size()) {
276 while (result.at(i) == QLatin1Char('/')) {
277 result.remove(i, 1);
278 if (i == result.size())
279 goto after_loop;
280 }
281 while (result.at(i) != QLatin1Char('/')) {
282 ++i;
283 if (i == result.size())
284 return result;
285 }
286 ++i; // leave the slash alone
287 }
288
289after_loop:
290 if (!result.isEmpty())
291 result.truncate(i - 1); // remove the trailing slash
292 return result;
293}
294
295// see also qsettings_win.cpp, qsettings_winrt.cpp and qsettings_mac.cpp
296
297#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
298QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
299 const QString &organization, const QString &application)
300{
301 return new QConfFileSettingsPrivate(format, scope, organization, application);
302}
303#endif
304
305#if !defined(Q_OS_WIN)
306QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
307{
308 return new QConfFileSettingsPrivate(fileName, format);
309}
310#endif
311
312void QSettingsPrivate::processChild(QStringRef key, ChildSpec spec, QStringList &result)
313{
314 if (spec != AllKeys) {
315 int slashPos = key.indexOf(QLatin1Char('/'));
316 if (slashPos == -1) {
317 if (spec != ChildKeys)
318 return;
319 } else {
320 if (spec != ChildGroups)
321 return;
322 key.truncate(slashPos);
323 }
324 }
325 result.append(key.toString());
326}
327
328void QSettingsPrivate::beginGroupOrArray(const QSettingsGroup &group)
329{
330 groupStack.push(group);
331 const QString name = group.name();
332 if (!name.isEmpty())
333 groupPrefix += name + QLatin1Char('/');
334}
335
336/*
337 We only set an error if there isn't one set already. This way the user always gets the
338 first error that occurred. We always allow clearing errors.
339*/
340
341void QSettingsPrivate::setStatus(QSettings::Status status) const
342{
343 if (status == QSettings::NoError || this->status == QSettings::NoError)
344 this->status = status;
345}
346
347void QSettingsPrivate::update()
348{
349 flush();
350 pendingChanges = false;
351}
352
353void QSettingsPrivate::requestUpdate()
354{
355 if (!pendingChanges) {
356 pendingChanges = true;
357#ifndef QT_NO_QOBJECT
358 Q_Q(QSettings);
359 QCoreApplication::postEvent(q, new QEvent(QEvent::UpdateRequest));
360#else
361 update();
362#endif
363 }
364}
365
366QStringList QSettingsPrivate::variantListToStringList(const QVariantList &l)
367{
368 QStringList result;
369 result.reserve(l.count());
370 QVariantList::const_iterator it = l.constBegin();
371 for (; it != l.constEnd(); ++it)
372 result.append(variantToString(*it));
373 return result;
374}
375
376QVariant QSettingsPrivate::stringListToVariantList(const QStringList &l)
377{
378 QStringList outStringList = l;
379 for (int i = 0; i < outStringList.count(); ++i) {
380 const QString &str = outStringList.at(i);
381
382 if (str.startsWith(QLatin1Char('@'))) {
383 if (str.length() >= 2 && str.at(1) == QLatin1Char('@')) {
384 outStringList[i].remove(0, 1);
385 } else {
386 QVariantList variantList;
387 const int stringCount = l.count();
388 variantList.reserve(stringCount);
389 for (int j = 0; j < stringCount; ++j)
390 variantList.append(stringToVariant(l.at(j)));
391 return variantList;
392 }
393 }
394 }
395 return outStringList;
396}
397
398QString QSettingsPrivate::variantToString(const QVariant &v)
399{
400 QString result;
401
402 switch (v.type()) {
403 case QVariant::Invalid:
404 result = QLatin1String("@Invalid()");
405 break;
406
407 case QVariant::ByteArray: {
408 QByteArray a = v.toByteArray();
409 result = QLatin1String("@ByteArray(")
410 + QLatin1String(a.constData(), a.size())
411 + QLatin1Char(')');
412 break;
413 }
414
415 case QVariant::String:
416 case QVariant::LongLong:
417 case QVariant::ULongLong:
418 case QVariant::Int:
419 case QVariant::UInt:
420 case QVariant::Bool:
421 case QVariant::Double:
422 case QVariant::KeySequence: {
423 result = v.toString();
424 if (result.contains(QChar::Null))
425 result = QLatin1String("@String(") + result + QLatin1Char(')');
426 else if (result.startsWith(QLatin1Char('@')))
427 result.prepend(QLatin1Char('@'));
428 break;
429 }
430#ifndef QT_NO_GEOM_VARIANT
431 case QVariant::Rect: {
432 QRect r = qvariant_cast<QRect>(v);
433 result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
434 break;
435 }
436 case QVariant::Size: {
437 QSize s = qvariant_cast<QSize>(v);
438 result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
439 break;
440 }
441 case QVariant::Point: {
442 QPoint p = qvariant_cast<QPoint>(v);
443 result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
444 break;
445 }
446#endif // !QT_NO_GEOM_VARIANT
447
448 default: {
449#ifndef QT_NO_DATASTREAM
450 QDataStream::Version version;
451 const char *typeSpec;
452 if (v.type() == QVariant::DateTime) {
453 version = QDataStream::Qt_5_6;
454 typeSpec = "@DateTime(";
455 } else {
456 version = QDataStream::Qt_4_0;
457 typeSpec = "@Variant(";
458 }
459 QByteArray a;
460 {
461 QDataStream s(&a, QIODevice::WriteOnly);
462 s.setVersion(version);
463 s << v;
464 }
465
466 result = QLatin1String(typeSpec)
467 + QLatin1String(a.constData(), a.size())
468 + QLatin1Char(')');
469#else
470 Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
471#endif
472 break;
473 }
474 }
475
476 return result;
477}
478
479
480QVariant QSettingsPrivate::stringToVariant(const QString &s)
481{
482 if (s.startsWith(QLatin1Char('@'))) {
483 if (s.endsWith(QLatin1Char(')'))) {
484 if (s.startsWith(QLatin1String("@ByteArray("))) {
485 return QVariant(s.midRef(11, s.size() - 12).toLatin1());
486 } else if (s.startsWith(QLatin1String("@String("))) {
487 return QVariant(s.midRef(8, s.size() - 9).toString());
488 } else if (s.startsWith(QLatin1String("@Variant("))
489 || s.startsWith(QLatin1String("@DateTime("))) {
490#ifndef QT_NO_DATASTREAM
491 QDataStream::Version version;
492 int offset;
493 if (s.at(1) == QLatin1Char('D')) {
494 version = QDataStream::Qt_5_6;
495 offset = 10;
496 } else {
497 version = QDataStream::Qt_4_0;
498 offset = 9;
499 }
500 QByteArray a = s.midRef(offset).toLatin1();
501 QDataStream stream(&a, QIODevice::ReadOnly);
502 stream.setVersion(version);
503 QVariant result;
504 stream >> result;
505 return result;
506#else
507 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
508#endif
509#ifndef QT_NO_GEOM_VARIANT
510 } else if (s.startsWith(QLatin1String("@Rect("))) {
511 QStringList args = QSettingsPrivate::splitArgs(s, 5);
512 if (args.size() == 4)
513 return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
514 } else if (s.startsWith(QLatin1String("@Size("))) {
515 QStringList args = QSettingsPrivate::splitArgs(s, 5);
516 if (args.size() == 2)
517 return QVariant(QSize(args[0].toInt(), args[1].toInt()));
518 } else if (s.startsWith(QLatin1String("@Point("))) {
519 QStringList args = QSettingsPrivate::splitArgs(s, 6);
520 if (args.size() == 2)
521 return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
522#endif
523 } else if (s == QLatin1String("@Invalid()")) {
524 return QVariant();
525 }
526
527 }
528 if (s.startsWith(QLatin1String("@@")))
529 return QVariant(s.mid(1));
530 }
531
532 return QVariant(s);
533}
534
535static const char hexDigits[] = "0123456789ABCDEF";
536
537void QSettingsPrivate::iniEscapedKey(const QString &key, QByteArray &result)
538{
539 result.reserve(result.length() + key.length() * 3 / 2);
540 for (int i = 0; i < key.size(); ++i) {
541 uint ch = key.at(i).unicode();
542
543 if (ch == '/') {
544 result += '\\';
545 } else if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
546 || ch == '_' || ch == '-' || ch == '.') {
547 result += (char)ch;
548 } else if (ch <= 0xFF) {
549 result += '%';
550 result += hexDigits[ch / 16];
551 result += hexDigits[ch % 16];
552 } else {
553 result += "%U";
554 QByteArray hexCode;
555 for (int i = 0; i < 4; ++i) {
556 hexCode.prepend(hexDigits[ch % 16]);
557 ch >>= 4;
558 }
559 result += hexCode;
560 }
561 }
562}
563
564bool QSettingsPrivate::iniUnescapedKey(const QByteArray &key, int from, int to, QString &result)
565{
566 bool lowercaseOnly = true;
567 int i = from;
568 result.reserve(result.length() + (to - from));
569 while (i < to) {
570 int ch = (uchar)key.at(i);
571
572 if (ch == '\\') {
573 result += QLatin1Char('/');
574 ++i;
575 continue;
576 }
577
578 if (ch != '%' || i == to - 1) {
579 if (uint(ch - 'A') <= 'Z' - 'A') // only for ASCII
580 lowercaseOnly = false;
581 result += QLatin1Char(ch);
582 ++i;
583 continue;
584 }
585
586 int numDigits = 2;
587 int firstDigitPos = i + 1;
588
589 ch = key.at(i + 1);
590 if (ch == 'U') {
591 ++firstDigitPos;
592 numDigits = 4;
593 }
594
595 if (firstDigitPos + numDigits > to) {
596 result += QLatin1Char('%');
597 // ### missing U
598 ++i;
599 continue;
600 }
601
602 bool ok;
603 ch = key.mid(firstDigitPos, numDigits).toInt(&ok, 16);
604 if (!ok) {
605 result += QLatin1Char('%');
606 // ### missing U
607 ++i;
608 continue;
609 }
610
611 QChar qch(ch);
612 if (qch.isUpper())
613 lowercaseOnly = false;
614 result += qch;
615 i = firstDigitPos + numDigits;
616 }
617 return lowercaseOnly;
618}
619
620void QSettingsPrivate::iniEscapedString(const QString &str, QByteArray &result, QTextCodec *codec)
621{
622 bool needsQuotes = false;
623 bool escapeNextIfDigit = false;
624 bool useCodec = codec && !str.startsWith(QLatin1String("@ByteArray("))
625 && !str.startsWith(QLatin1String("@Variant("));
626
627 int i;
628 int startPos = result.size();
629
630 result.reserve(startPos + str.size() * 3 / 2);
631 const QChar *unicode = str.unicode();
632 for (i = 0; i < str.size(); ++i) {
633 uint ch = unicode[i].unicode();
634 if (ch == ';' || ch == ',' || ch == '=')
635 needsQuotes = true;
636
637 if (escapeNextIfDigit
638 && ((ch >= '0' && ch <= '9')
639 || (ch >= 'a' && ch <= 'f')
640 || (ch >= 'A' && ch <= 'F'))) {
641 result += "\\x" + QByteArray::number(ch, 16);
642 continue;
643 }
644
645 escapeNextIfDigit = false;
646
647 switch (ch) {
648 case '\0':
649 result += "\\0";
650 escapeNextIfDigit = true;
651 break;
652 case '\a':
653 result += "\\a";
654 break;
655 case '\b':
656 result += "\\b";
657 break;
658 case '\f':
659 result += "\\f";
660 break;
661 case '\n':
662 result += "\\n";
663 break;
664 case '\r':
665 result += "\\r";
666 break;
667 case '\t':
668 result += "\\t";
669 break;
670 case '\v':
671 result += "\\v";
672 break;
673 case '"':
674 case '\\':
675 result += '\\';
676 result += (char)ch;
677 break;
678 default:
679 if (ch <= 0x1F || (ch >= 0x7F && !useCodec)) {
680 result += "\\x" + QByteArray::number(ch, 16);
681 escapeNextIfDigit = true;
682#if QT_CONFIG(textcodec)
683 } else if (useCodec) {
684 // slow
685 result += codec->fromUnicode(&unicode[i], 1);
686#endif
687 } else {
688 result += (char)ch;
689 }
690 }
691 }
692
693 if (needsQuotes
694 || (startPos < result.size() && (result.at(startPos) == ' '
695 || result.at(result.size() - 1) == ' '))) {
696 result.insert(startPos, '"');
697 result += '"';
698 }
699}
700
701inline static void iniChopTrailingSpaces(QString &str, int limit)
702{
703 int n = str.size() - 1;
704 QChar ch;
705 while (n >= limit && ((ch = str.at(n)) == QLatin1Char(' ') || ch == QLatin1Char('\t')))
706 str.truncate(n--);
707}
708
709void QSettingsPrivate::iniEscapedStringList(const QStringList &strs, QByteArray &result, QTextCodec *codec)
710{
711 if (strs.isEmpty()) {
712 /*
713 We need to distinguish between empty lists and one-item
714 lists that contain an empty string. Ideally, we'd have a
715 @EmptyList() symbol but that would break compatibility
716 with Qt 4.0. @Invalid() stands for QVariant(), and
717 QVariant().toStringList() returns an empty QStringList,
718 so we're in good shape.
719 */
720 result += "@Invalid()";
721 } else {
722 for (int i = 0; i < strs.size(); ++i) {
723 if (i != 0)
724 result += ", ";
725 iniEscapedString(strs.at(i), result, codec);
726 }
727 }
728}
729
730bool QSettingsPrivate::iniUnescapedStringList(const QByteArray &str, int from, int to,
731 QString &stringResult, QStringList &stringListResult,
732 QTextCodec *codec)
733{
734 static const char escapeCodes[][2] =
735 {
736 { 'a', '\a' },
737 { 'b', '\b' },
738 { 'f', '\f' },
739 { 'n', '\n' },
740 { 'r', '\r' },
741 { 't', '\t' },
742 { 'v', '\v' },
743 { '"', '"' },
744 { '?', '?' },
745 { '\'', '\'' },
746 { '\\', '\\' }
747 };
748 static const int numEscapeCodes = sizeof(escapeCodes) / sizeof(escapeCodes[0]);
749
750 bool isStringList = false;
751 bool inQuotedString = false;
752 bool currentValueIsQuoted = false;
753 int escapeVal = 0;
754 int i = from;
755 char ch;
756
757StSkipSpaces:
758 while (i < to && ((ch = str.at(i)) == ' ' || ch == '\t'))
759 ++i;
760 // fallthrough
761
762StNormal:
763 int chopLimit = stringResult.length();
764 while (i < to) {
765 switch (str.at(i)) {
766 case '\\':
767 ++i;
768 if (i >= to)
769 goto end;
770
771 ch = str.at(i++);
772 for (int j = 0; j < numEscapeCodes; ++j) {
773 if (ch == escapeCodes[j][0]) {
774 stringResult += QLatin1Char(escapeCodes[j][1]);
775 goto StNormal;
776 }
777 }
778
779 if (ch == 'x') {
780 escapeVal = 0;
781
782 if (i >= to)
783 goto end;
784
785 ch = str.at(i);
786 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F') || (ch >= 'a' && ch <= 'f'))
787 goto StHexEscape;
788 } else if (ch >= '0' && ch <= '7') {
789 escapeVal = ch - '0';
790 goto StOctEscape;
791 } else if (ch == '\n' || ch == '\r') {
792 if (i < to) {
793 char ch2 = str.at(i);
794 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
795 if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
796 ++i;
797 }
798 } else {
799 // the character is skipped
800 }
801 chopLimit = stringResult.length();
802 break;
803 case '"':
804 ++i;
805 currentValueIsQuoted = true;
806 inQuotedString = !inQuotedString;
807 if (!inQuotedString)
808 goto StSkipSpaces;
809 break;
810 case ',':
811 if (!inQuotedString) {
812 if (!currentValueIsQuoted)
813 iniChopTrailingSpaces(stringResult, chopLimit);
814 if (!isStringList) {
815 isStringList = true;
816 stringListResult.clear();
817 stringResult.squeeze();
818 }
819 stringListResult.append(stringResult);
820 stringResult.clear();
821 currentValueIsQuoted = false;
822 ++i;
823 goto StSkipSpaces;
824 }
825 Q_FALLTHROUGH();
826 default: {
827 int j = i + 1;
828 while (j < to) {
829 ch = str.at(j);
830 if (ch == '\\' || ch == '"' || ch == ',')
831 break;
832 ++j;
833 }
834
835#if !QT_CONFIG(textcodec)
836 Q_UNUSED(codec)
837#else
838 if (codec) {
839 stringResult += codec->toUnicode(str.constData() + i, j - i);
840 } else
841#endif
842 {
843 int n = stringResult.size();
844 stringResult.resize(n + (j - i));
845 QChar *resultData = stringResult.data() + n;
846 for (int k = i; k < j; ++k)
847 *resultData++ = QLatin1Char(str.at(k));
848 }
849 i = j;
850 }
851 }
852 }
853 if (!currentValueIsQuoted)
854 iniChopTrailingSpaces(stringResult, chopLimit);
855 goto end;
856
857StHexEscape:
858 if (i >= to) {
859 stringResult += QChar(escapeVal);
860 goto end;
861 }
862
863 ch = str.at(i);
864 if (ch >= 'a')
865 ch -= 'a' - 'A';
866 if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'F')) {
867 escapeVal <<= 4;
868 escapeVal += strchr(hexDigits, ch) - hexDigits;
869 ++i;
870 goto StHexEscape;
871 } else {
872 stringResult += QChar(escapeVal);
873 goto StNormal;
874 }
875
876StOctEscape:
877 if (i >= to) {
878 stringResult += QChar(escapeVal);
879 goto end;
880 }
881
882 ch = str.at(i);
883 if (ch >= '0' && ch <= '7') {
884 escapeVal <<= 3;
885 escapeVal += ch - '0';
886 ++i;
887 goto StOctEscape;
888 } else {
889 stringResult += QChar(escapeVal);
890 goto StNormal;
891 }
892
893end:
894 if (isStringList)
895 stringListResult.append(stringResult);
896 return isStringList;
897}
898
899QStringList QSettingsPrivate::splitArgs(const QString &s, int idx)
900{
901 int l = s.length();
902 Q_ASSERT(l > 0);
903 Q_ASSERT(s.at(idx) == QLatin1Char('('));
904 Q_ASSERT(s.at(l - 1) == QLatin1Char(')'));
905
906 QStringList result;
907 QString item;
908
909 for (++idx; idx < l; ++idx) {
910 QChar c = s.at(idx);
911 if (c == QLatin1Char(')')) {
912 Q_ASSERT(idx == l - 1);
913 result.append(item);
914 } else if (c == QLatin1Char(' ')) {
915 result.append(item);
916 item.clear();
917 } else {
918 item.append(c);
919 }
920 }
921
922 return result;
923}
924
925// ************************************************************************
926// QConfFileSettingsPrivate
927
928void QConfFileSettingsPrivate::initFormat()
929{
930 extension = (format == QSettings::NativeFormat) ? QLatin1String(".conf") : QLatin1String(".ini");
931 readFunc = 0;
932 writeFunc = 0;
933#if defined(Q_OS_MAC)
934 caseSensitivity = (format == QSettings::NativeFormat) ? Qt::CaseSensitive : IniCaseSensitivity;
935#else
936 caseSensitivity = IniCaseSensitivity;
937#endif
938
939 if (format > QSettings::IniFormat) {
940 QMutexLocker locker(&settingsGlobalMutex);
941 const CustomFormatVector *customFormatVector = customFormatVectorFunc();
942
943 int i = (int)format - (int)QSettings::CustomFormat1;
944 if (i >= 0 && i < customFormatVector->size()) {
945 QConfFileCustomFormat info = customFormatVector->at(i);
946 extension = info.extension;
947 readFunc = info.readFunc;
948 writeFunc = info.writeFunc;
949 caseSensitivity = info.caseSensitivity;
950 }
951 }
952}
953
954void QConfFileSettingsPrivate::initAccess()
955{
956 if (!confFiles.isEmpty()) {
957 if (format > QSettings::IniFormat) {
958 if (!readFunc)
959 setStatus(QSettings::AccessError);
960 }
961 }
962
963 sync(); // loads the files the first time
964}
965
966#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT)
967static QString windowsConfigPath(const KNOWNFOLDERID &type)
968{
969 QString result;
970
971 PWSTR path = nullptr;
972 if (SHGetKnownFolderPath(type, KF_FLAG_DONT_VERIFY, NULL, &path) == S_OK) {
973 result = QString::fromWCharArray(path);
974 CoTaskMemFree(path);
975 }
976
977 if (result.isEmpty()) {
978 if (type == FOLDERID_ProgramData) {
979 result = QLatin1String("C:\\temp\\qt-common");
980 } else if (type == FOLDERID_RoamingAppData) {
981 result = QLatin1String("C:\\temp\\qt-user");
982 }
983 }
984
985 return result;
986}
987#elif defined(Q_OS_WINRT) // Q_OS_WIN && !Q_OS_WINRT
988
989enum ConfigPathType {
990 ConfigPath_CommonAppData,
991 ConfigPath_UserAppData
992};
993
994static QString windowsConfigPath(ConfigPathType type)
995{
996 static QString result;
997 while (result.isEmpty()) {
998 ComPtr<IApplicationDataStatics> applicationDataStatics;
999 if (FAILED(GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics)))
1000 return result;
1001 ComPtr<IApplicationData> applicationData;
1002 if (FAILED(applicationDataStatics->get_Current(&applicationData)))
1003 return result;
1004 ComPtr<IStorageFolder> localFolder;
1005 if (FAILED(applicationData->get_LocalFolder(&localFolder)))
1006 return result;
1007 ComPtr<IStorageItem> localFolderItem;
1008 if (FAILED(localFolder.As(&localFolderItem)))
1009 return result;
1010 HString path;
1011 if (FAILED(localFolderItem->get_Path(path.GetAddressOf())))
1012 return result;
1013 result = QString::fromWCharArray(path.GetRawBuffer(nullptr));
1014 }
1015
1016 switch (type) {
1017 case ConfigPath_CommonAppData:
1018 return result + QLatin1String("\\qt-common");
1019 case ConfigPath_UserAppData:
1020 return result + QLatin1String("\\qt-user");
1021 }
1022 return result;
1023}
1024#endif // Q_OS_WINRT
1025
1026static inline int pathHashKey(QSettings::Format format, QSettings::Scope scope)
1027{
1028 return int((uint(format) << 1) | uint(scope == QSettings::SystemScope));
1029}
1030
1031#ifndef Q_OS_WIN
1032static QString make_user_path()
1033{
1034 static Q_CONSTEXPR QChar sep = QLatin1Char('/');
1035#ifndef QSETTINGS_USE_QSTANDARDPATHS
1036 // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
1037 // for some time now. Moving away from that would require migrating existing settings.
1038 QByteArray env = qgetenv("XDG_CONFIG_HOME");
1039 if (env.isEmpty()) {
1040 return QDir::homePath() + QLatin1String("/.config/");
1041 } else if (env.startsWith('/')) {
1042 return QFile::decodeName(env) + sep;
1043 } else {
1044 return QDir::homePath() + sep + QFile::decodeName(env) + sep;
1045 }
1046#else
1047 // When using a proper XDG platform, use QStandardPaths rather than the above hand-written code;
1048 // it makes the use of test mode from unit tests possible.
1049 // Ideally all platforms should use this, but see above for the migration issue.
1050 return QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation) + sep;
1051#endif
1052}
1053#endif // !Q_OS_WIN
1054
1055static void initDefaultPaths(QMutexLocker *locker)
1056{
1057 PathHash *pathHash = pathHashFunc();
1058
1059 locker->unlock();
1060
1061 /*
1062 QLibraryInfo::location() uses QSettings, so in order to
1063 avoid a dead-lock, we can't hold the global mutex while
1064 calling it.
1065 */
1066 QString systemPath = QLibraryInfo::location(QLibraryInfo::SettingsPath) + QLatin1Char('/');
1067
1068 locker->relock();
1069 if (pathHash->isEmpty()) {
1070 /*
1071 Lazy initialization of pathHash. We initialize the
1072 IniFormat paths and (on Unix) the NativeFormat paths.
1073 (The NativeFormat paths are not configurable for the
1074 Windows registry and the Mac CFPreferences.)
1075 */
1076#ifdef Q_OS_WIN
1077
1078# ifdef Q_OS_WINRT
1079 const QString roamingAppDataFolder = windowsConfigPath(ConfigPath_UserAppData);
1080 const QString programDataFolder = windowsConfigPath(ConfigPath_CommonAppData);
1081# else
1082 const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1083 const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1084# endif
1085 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope),
1086 Path(roamingAppDataFolder + QDir::separator(), false));
1087 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope),
1088 Path(programDataFolder + QDir::separator(), false));
1089#else
1090 const QString userPath = make_user_path();
1091 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1092 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1093#ifndef Q_OS_MAC
1094 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::UserScope), Path(userPath, false));
1095 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1096#endif
1097#endif // Q_OS_WIN
1098 }
1099}
1100
1101static Path getPath(QSettings::Format format, QSettings::Scope scope)
1102{
1103 Q_ASSERT((int)QSettings::NativeFormat == 0);
1104 Q_ASSERT((int)QSettings::IniFormat == 1);
1105
1106 QMutexLocker locker(&settingsGlobalMutex);
1107 PathHash *pathHash = pathHashFunc();
1108 if (pathHash->isEmpty())
1109 initDefaultPaths(&locker);
1110
1111 Path result = pathHash->value(pathHashKey(format, scope));
1112 if (!result.path.isEmpty())
1113 return result;
1114
1115 // fall back on INI path
1116 return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1117}
1118
1119#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1120// Note: Suitable only for autotests.
1121void Q_AUTOTEST_EXPORT clearDefaultPaths()
1122{
1123 QMutexLocker locker(&settingsGlobalMutex);
1124 pathHashFunc()->clear();
1125}
1126#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1127
1128QConfFileSettingsPrivate::QConfFileSettingsPrivate(QSettings::Format format,
1129 QSettings::Scope scope,
1130 const QString &organization,
1131 const QString &application)
1132 : QSettingsPrivate(format, scope, organization, application),
1133 nextPosition(0x40000000) // big positive number
1134{
1135 initFormat();
1136
1137 QString org = organization;
1138 if (org.isEmpty()) {
1139 setStatus(QSettings::AccessError);
1140 org = QLatin1String("Unknown Organization");
1141 }
1142
1143 QString appFile = org + QDir::separator() + application + extension;
1144 QString orgFile = org + extension;
1145
1146 if (scope == QSettings::UserScope) {
1147 Path userPath = getPath(format, QSettings::UserScope);
1148 if (!application.isEmpty())
1149 confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1150 confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1151 }
1152
1153 Path systemPath = getPath(format, QSettings::SystemScope);
1154#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1155 // check if the systemPath wasn't overridden by QSettings::setPath()
1156 if (!systemPath.userDefined) {
1157 // Note: We can't use QStandardPaths::locateAll() as we need all the
1158 // possible files (not just the existing ones) and there is no way
1159 // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1160 QStringList dirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation);
1161 // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1162 if (!dirs.isEmpty())
1163 dirs.takeFirst();
1164 QStringList paths;
1165 if (!application.isEmpty()) {
1166 paths.reserve(dirs.size() * 2);
1167 for (const auto &dir : qAsConst(dirs))
1168 paths.append(dir + QLatin1Char('/') + appFile);
1169 } else {
1170 paths.reserve(dirs.size());
1171 }
1172 for (const auto &dir : qAsConst(dirs))
1173 paths.append(dir + QLatin1Char('/') + orgFile);
1174
1175 // Note: No check for existence of files is done intentionaly.
1176 for (const auto &path : qAsConst(paths))
1177 confFiles.append(QConfFile::fromName(path, false));
1178 } else
1179#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1180 {
1181 if (!application.isEmpty())
1182 confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1183 confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1184 }
1185
1186 initAccess();
1187}
1188
1189QConfFileSettingsPrivate::QConfFileSettingsPrivate(const QString &fileName,
1190 QSettings::Format format)
1191 : QSettingsPrivate(format),
1192 nextPosition(0x40000000) // big positive number
1193{
1194 initFormat();
1195
1196 confFiles.append(QConfFile::fromName(fileName, true));
1197
1198 initAccess();
1199}
1200
1201QConfFileSettingsPrivate::~QConfFileSettingsPrivate()
1202{
1203 QMutexLocker locker(&settingsGlobalMutex);
1204 ConfFileHash *usedHash = usedHashFunc();
1205 ConfFileCache *unusedCache = unusedCacheFunc();
1206
1207 for (auto conf_file : qAsConst(confFiles)) {
1208 if (!conf_file->ref.deref()) {
1209 if (conf_file->size == 0) {
1210 delete conf_file;
1211 } else {
1212 if (usedHash)
1213 usedHash->remove(conf_file->name);
1214 if (unusedCache) {
1215 QT_TRY {
1216 // compute a better size?
1217 unusedCache->insert(conf_file->name, conf_file,
1218 10 + (conf_file->originalKeys.size() / 4));
1219 } QT_CATCH(...) {
1220 // out of memory. Do not cache the file.
1221 delete conf_file;
1222 }
1223 } else {
1224 // unusedCache is gone - delete the entry to prevent a memory leak
1225 delete conf_file;
1226 }
1227 }
1228 }
1229 }
1230}
1231
1232void QConfFileSettingsPrivate::remove(const QString &key)
1233{
1234 if (confFiles.isEmpty())
1235 return;
1236
1237 // Note: First config file is always the most specific.
1238 QConfFile *confFile = confFiles.at(0);
1239
1240 QSettingsKey theKey(key, caseSensitivity);
1241 QSettingsKey prefix(key + QLatin1Char('/'), caseSensitivity);
1242 QMutexLocker locker(&confFile->mutex);
1243
1244 ensureSectionParsed(confFile, theKey);
1245 ensureSectionParsed(confFile, prefix);
1246
1247 ParsedSettingsMap::iterator i = confFile->addedKeys.lowerBound(prefix);
1248 while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1249 i = confFile->addedKeys.erase(i);
1250 confFile->addedKeys.remove(theKey);
1251
1252 ParsedSettingsMap::const_iterator j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1253 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1254 confFile->removedKeys.insert(j.key(), QVariant());
1255 ++j;
1256 }
1257 if (confFile->originalKeys.contains(theKey))
1258 confFile->removedKeys.insert(theKey, QVariant());
1259}
1260
1261void QConfFileSettingsPrivate::set(const QString &key, const QVariant &value)
1262{
1263 if (confFiles.isEmpty())
1264 return;
1265
1266 // Note: First config file is always the most specific.
1267 QConfFile *confFile = confFiles.at(0);
1268
1269 QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1270 QMutexLocker locker(&confFile->mutex);
1271 confFile->removedKeys.remove(theKey);
1272 confFile->addedKeys.insert(theKey, value);
1273}
1274
1275bool QConfFileSettingsPrivate::get(const QString &key, QVariant *value) const
1276{
1277 QSettingsKey theKey(key, caseSensitivity);
1278 ParsedSettingsMap::const_iterator j;
1279 bool found = false;
1280
1281 for (auto confFile : qAsConst(confFiles)) {
1282 QMutexLocker locker(&confFile->mutex);
1283
1284 if (!confFile->addedKeys.isEmpty()) {
1285 j = confFile->addedKeys.constFind(theKey);
1286 found = (j != confFile->addedKeys.constEnd());
1287 }
1288 if (!found) {
1289 ensureSectionParsed(confFile, theKey);
1290 j = confFile->originalKeys.constFind(theKey);
1291 found = (j != confFile->originalKeys.constEnd()
1292 && !confFile->removedKeys.contains(theKey));
1293 }
1294
1295 if (found && value)
1296 *value = *j;
1297
1298 if (found)
1299 return true;
1300 if (!fallbacks)
1301 break;
1302 }
1303 return false;
1304}
1305
1306QStringList QConfFileSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
1307{
1308 QStringList result;
1309 ParsedSettingsMap::const_iterator j;
1310
1311 QSettingsKey thePrefix(prefix, caseSensitivity);
1312 int startPos = prefix.size();
1313
1314 for (auto confFile : qAsConst(confFiles)) {
1315 QMutexLocker locker(&confFile->mutex);
1316
1317 if (thePrefix.isEmpty())
1318 ensureAllSectionsParsed(confFile);
1319 else
1320 ensureSectionParsed(confFile, thePrefix);
1321
1322 j = const_cast<const ParsedSettingsMap *>(
1323 &confFile->originalKeys)->lowerBound( thePrefix);
1324 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
1325 if (!confFile->removedKeys.contains(j.key()))
1326 processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1327 ++j;
1328 }
1329
1330 j = const_cast<const ParsedSettingsMap *>(
1331 &confFile->addedKeys)->lowerBound(thePrefix);
1332 while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
1333 processChild(j.key().originalCaseKey().midRef(startPos), spec, result);
1334 ++j;
1335 }
1336
1337 if (!fallbacks)
1338 break;
1339 }
1340 std::sort(result.begin(), result.end());
1341 result.erase(std::unique(result.begin(), result.end()),
1342 result.end());
1343 return result;
1344}
1345
1346void QConfFileSettingsPrivate::clear()
1347{
1348 if (confFiles.isEmpty())
1349 return;
1350
1351 // Note: First config file is always the most specific.
1352 QConfFile *confFile = confFiles.at(0);
1353
1354 QMutexLocker locker(&confFile->mutex);
1355 ensureAllSectionsParsed(confFile);
1356 confFile->addedKeys.clear();
1357 confFile->removedKeys = confFile->originalKeys;
1358}
1359
1360void QConfFileSettingsPrivate::sync()
1361{
1362 // people probably won't be checking the status a whole lot, so in case of
1363 // error we just try to go on and make the best of it
1364
1365 for (auto confFile : qAsConst(confFiles)) {
1366 QMutexLocker locker(&confFile->mutex);
1367 syncConfFile(confFile);
1368 }
1369}
1370
1371void QConfFileSettingsPrivate::flush()
1372{
1373 sync();
1374}
1375
1376QString QConfFileSettingsPrivate::fileName() const
1377{
1378 if (confFiles.isEmpty())
1379 return QString();
1380
1381 // Note: First config file is always the most specific.
1382 return confFiles.at(0)->name;
1383}
1384
1385bool QConfFileSettingsPrivate::isWritable() const
1386{
1387 if (format > QSettings::IniFormat && !writeFunc)
1388 return false;
1389
1390 if (confFiles.isEmpty())
1391 return false;
1392
1393 return confFiles.at(0)->isWritable();
1394}
1395
1396void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1397{
1398 bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1399
1400 /*
1401 We can often optimize the read-only case, if the file on disk
1402 hasn't changed.
1403 */
1404 if (readOnly && confFile->size > 0) {
1405 QFileInfo fileInfo(confFile->name);
1406 if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified())
1407 return;
1408 }
1409
1410 if (!readOnly && !confFile->isWritable()) {
1411 setStatus(QSettings::AccessError);
1412 return;
1413 }
1414
1415#ifndef QT_BOOTSTRAPPED
1416 /*
1417 Use a lockfile in order to protect us against other QSettings instances
1418 trying to write the same settings at the same time.
1419
1420 We only need to lock if we are actually writing as only concurrent writes are a problem.
1421 Concurrent read and write are not a problem because the writing operation is atomic.
1422 */
1423 QLockFile lockFile(confFile->name + QLatin1String(".lock"));
1424 if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1425 setStatus(QSettings::AccessError);
1426 return;
1427 }
1428#endif
1429
1430 /*
1431 We hold the lock. Let's reread the file if it has changed
1432 since last time we read it.
1433 */
1434 QFileInfo fileInfo(confFile->name);
1435 bool mustReadFile = true;
1436 bool createFile = !fileInfo.exists();
1437
1438 if (!readOnly)
1439 mustReadFile = (confFile->size != fileInfo.size()
1440 || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified()));
1441
1442 if (mustReadFile) {
1443 confFile->unparsedIniSections.clear();
1444 confFile->originalKeys.clear();
1445
1446 QFile file(confFile->name);
1447 if (!createFile && !file.open(QFile::ReadOnly)) {
1448 setStatus(QSettings::AccessError);
1449 return;
1450 }
1451
1452 /*
1453 Files that we can't read (because of permissions or
1454 because they don't exist) are treated as empty files.
1455 */
1456 if (file.isReadable() && file.size() != 0) {
1457 bool ok = false;
1458#ifdef Q_OS_MAC
1459 if (format == QSettings::NativeFormat) {
1460 QByteArray data = file.readAll();
1461 ok = readPlistFile(data, &confFile->originalKeys);
1462 } else
1463#endif
1464 if (format <= QSettings::IniFormat) {
1465 QByteArray data = file.readAll();
1466 ok = readIniFile(data, &confFile->unparsedIniSections);
1467 } else if (readFunc) {
1468 QSettings::SettingsMap tempNewKeys;
1469 ok = readFunc(file, tempNewKeys);
1470
1471 if (ok) {
1472 QSettings::SettingsMap::const_iterator i = tempNewKeys.constBegin();
1473 while (i != tempNewKeys.constEnd()) {
1474 confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1475 i.value());
1476 ++i;
1477 }
1478 }
1479 }
1480
1481 if (!ok)
1482 setStatus(QSettings::FormatError);
1483 }
1484
1485 confFile->size = fileInfo.size();
1486 confFile->timeStamp = fileInfo.lastModified();
1487 }
1488
1489 /*
1490 We also need to save the file. We still hold the file lock,
1491 so everything is under control.
1492 */
1493 if (!readOnly) {
1494 bool ok = false;
1495 ensureAllSectionsParsed(confFile);
1496 ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1497
1498#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1499 QSaveFile sf(confFile->name);
1500 sf.setDirectWriteFallback(!atomicSyncOnly);
1501#else
1502 QFile sf(confFile->name);
1503#endif
1504 if (!sf.open(QIODevice::WriteOnly)) {
1505 setStatus(QSettings::AccessError);
1506 return;
1507 }
1508
1509#ifdef Q_OS_MAC
1510 if (format == QSettings::NativeFormat) {
1511 ok = writePlistFile(sf, mergedKeys);
1512 } else
1513#endif
1514 if (format <= QSettings::IniFormat) {
1515 ok = writeIniFile(sf, mergedKeys);
1516 } else if (writeFunc) {
1517 QSettings::SettingsMap tempOriginalKeys;
1518
1519 ParsedSettingsMap::const_iterator i = mergedKeys.constBegin();
1520 while (i != mergedKeys.constEnd()) {
1521 tempOriginalKeys.insert(i.key(), i.value());
1522 ++i;
1523 }
1524 ok = writeFunc(sf, tempOriginalKeys);
1525 }
1526
1527#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1528 if (ok)
1529 ok = sf.commit();
1530#endif
1531
1532 if (ok) {
1533 confFile->unparsedIniSections.clear();
1534 confFile->originalKeys = mergedKeys;
1535 confFile->addedKeys.clear();
1536 confFile->removedKeys.clear();
1537
1538 QFileInfo fileInfo(confFile->name);
1539 confFile->size = fileInfo.size();
1540 confFile->timeStamp = fileInfo.lastModified();
1541
1542 // If we have created the file, apply the file perms
1543 if (createFile) {
1544 QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1545 if (!confFile->userPerms)
1546 perms |= QFile::ReadGroup | QFile::ReadOther;
1547 QFile(confFile->name).setPermissions(perms);
1548 }
1549#ifdef Q_OS_WASM
1550 EM_ASM(
1551 // Sync sandbox filesystem to persistent database filesystem. See QTBUG-70002
1552 FS.syncfs(false, function(err) {
1553 });
1554 );
1555#endif
1556 } else {
1557 setStatus(QSettings::AccessError);
1558 }
1559 }
1560}
1561
1562enum { Space = 0x1, Special = 0x2 };
1563
1564static const char charTraits[256] =
1565{
1566 // Space: '\t', '\n', '\r', ' '
1567 // Special: '\n', '\r', '"', ';', '=', '\\'
1568
1569 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1570 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1571 Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1572 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1573 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1574 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0,
1575 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1576 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1577
1578 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1579 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1580 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1581 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1582 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1583 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1584 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1585 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1586};
1587
1588bool QConfFileSettingsPrivate::readIniLine(const QByteArray &data, int &dataPos,
1589 int &lineStart, int &lineLen, int &equalsPos)
1590{
1591 int dataLen = data.length();
1592 bool inQuotes = false;
1593
1594 equalsPos = -1;
1595
1596 lineStart = dataPos;
1597 while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1598 ++lineStart;
1599
1600 int i = lineStart;
1601 while (i < dataLen) {
1602 char ch = data.at(i);
1603 while (!(charTraits[uchar(ch)] & Special)) {
1604 if (++i == dataLen)
1605 goto break_out_of_outer_loop;
1606 ch = data.at(i);
1607 }
1608
1609 ++i;
1610 if (ch == '=') {
1611 if (!inQuotes && equalsPos == -1)
1612 equalsPos = i - 1;
1613 } else if (ch == '\n' || ch == '\r') {
1614 if (i == lineStart + 1) {
1615 ++lineStart;
1616 } else if (!inQuotes) {
1617 --i;
1618 goto break_out_of_outer_loop;
1619 }
1620 } else if (ch == '\\') {
1621 if (i < dataLen) {
1622 char ch = data.at(i++);
1623 if (i < dataLen) {
1624 char ch2 = data.at(i);
1625 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1626 if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1627 ++i;
1628 }
1629 }
1630 } else if (ch == '"') {
1631 inQuotes = !inQuotes;
1632 } else {
1633 Q_ASSERT(ch == ';');
1634
1635 if (i == lineStart + 1) {
1636 while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1637 ++i;
1638 while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1639 ++i;
1640 lineStart = i;
1641 } else if (!inQuotes) {
1642 --i;
1643 goto break_out_of_outer_loop;
1644 }
1645 }
1646 }
1647
1648break_out_of_outer_loop:
1649 dataPos = i;
1650 lineLen = i - lineStart;
1651 return lineLen > 0;
1652}
1653
1654/*
1655 Returns \c false on parse error. However, as many keys are read as
1656 possible, so if the user doesn't check the status he will get the
1657 most out of the file anyway.
1658*/
1659bool QConfFileSettingsPrivate::readIniFile(const QByteArray &data,
1660 UnparsedSettingsMap *unparsedIniSections)
1661{
1662#define FLUSH_CURRENT_SECTION() \
1663 { \
1664 QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection, \
1665 IniCaseSensitivity, \
1666 sectionPosition)]; \
1667 if (!sectionData.isEmpty()) \
1668 sectionData.append('\n'); \
1669 sectionData += data.mid(currentSectionStart, lineStart - currentSectionStart); \
1670 sectionPosition = ++position; \
1671 }
1672
1673 QString currentSection;
1674 int currentSectionStart = 0;
1675 int dataPos = 0;
1676 int lineStart;
1677 int lineLen;
1678 int equalsPos;
1679 int position = 0;
1680 int sectionPosition = 0;
1681 bool ok = true;
1682
1683#if QT_CONFIG(textcodec)
1684 // detect utf8 BOM
1685 const uchar *dd = (const uchar *)data.constData();
1686 if (data.size() >= 3 && dd[0] == 0xef && dd[1] == 0xbb && dd[2] == 0xbf) {
1687 iniCodec = QTextCodec::codecForName("UTF-8");
1688 dataPos = 3;
1689 }
1690#endif
1691
1692 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1693 char ch = data.at(lineStart);
1694 if (ch == '[') {
1695 FLUSH_CURRENT_SECTION();
1696
1697 // this is a section
1698 QByteArray iniSection;
1699 int idx = data.indexOf(']', lineStart);
1700 if (idx == -1 || idx >= lineStart + lineLen) {
1701 ok = false;
1702 iniSection = data.mid(lineStart + 1, lineLen - 1);
1703 } else {
1704 iniSection = data.mid(lineStart + 1, idx - lineStart - 1);
1705 }
1706
1707 iniSection = iniSection.trimmed();
1708
1709 if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1710 currentSection.clear();
1711 } else {
1712 if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1713 currentSection = QLatin1String(iniSection.constData() + 1);
1714 } else {
1715 currentSection.clear();
1716 iniUnescapedKey(iniSection, 0, iniSection.size(), currentSection);
1717 }
1718 currentSection += QLatin1Char('/');
1719 }
1720 currentSectionStart = dataPos;
1721 }
1722 ++position;
1723 }
1724
1725 Q_ASSERT(lineStart == data.length());
1726 FLUSH_CURRENT_SECTION();
1727
1728 return ok;
1729
1730#undef FLUSH_CURRENT_SECTION
1731}
1732
1733bool QConfFileSettingsPrivate::readIniSection(const QSettingsKey &section, const QByteArray &data,
1734 ParsedSettingsMap *settingsMap, QTextCodec *codec)
1735{
1736 QStringList strListValue;
1737 bool sectionIsLowercase = (section == section.originalCaseKey());
1738 int equalsPos;
1739
1740 bool ok = true;
1741 int dataPos = 0;
1742 int lineStart;
1743 int lineLen;
1744 int position = section.originalKeyPosition();
1745
1746 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1747 char ch = data.at(lineStart);
1748 Q_ASSERT(ch != '[');
1749
1750 if (equalsPos == -1) {
1751 if (ch != ';')
1752 ok = false;
1753 continue;
1754 }
1755
1756 int keyEnd = equalsPos;
1757 while (keyEnd > lineStart && ((ch = data.at(keyEnd - 1)) == ' ' || ch == '\t'))
1758 --keyEnd;
1759 int valueStart = equalsPos + 1;
1760
1761 QString key = section.originalCaseKey();
1762 bool keyIsLowercase = (iniUnescapedKey(data, lineStart, keyEnd, key) && sectionIsLowercase);
1763
1764 QString strValue;
1765 strValue.reserve(lineLen - (valueStart - lineStart));
1766 bool isStringList = iniUnescapedStringList(data, valueStart, lineStart + lineLen,
1767 strValue, strListValue, codec);
1768 QVariant variant;
1769 if (isStringList) {
1770 variant = stringListToVariantList(strListValue);
1771 } else {
1772 variant = stringToVariant(strValue);
1773 }
1774
1775 /*
1776 We try to avoid the expensive toLower() call in
1777 QSettingsKey by passing Qt::CaseSensitive when the
1778 key is already in lowercase.
1779 */
1780 settingsMap->insert(QSettingsKey(key, keyIsLowercase ? Qt::CaseSensitive
1781 : IniCaseSensitivity,
1782 position),
1783 variant);
1784 ++position;
1785 }
1786
1787 return ok;
1788}
1789
1790class QSettingsIniKey : public QString
1791{
1792public:
1793 inline QSettingsIniKey() : position(-1) {}
1794 inline QSettingsIniKey(const QString &str, int pos = -1) : QString(str), position(pos) {}
1795
1796 int position;
1797};
1798Q_DECLARE_TYPEINFO(QSettingsIniKey, Q_MOVABLE_TYPE);
1799
1800static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1801{
1802 if (k1.position != k2.position)
1803 return k1.position < k2.position;
1804 return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1805}
1806
1807typedef QMap<QSettingsIniKey, QVariant> IniKeyMap;
1808
1809struct QSettingsIniSection
1810{
1811 int position;
1812 IniKeyMap keyMap;
1813
1814 inline QSettingsIniSection() : position(-1) {}
1815};
1816
1817Q_DECLARE_TYPEINFO(QSettingsIniSection, Q_MOVABLE_TYPE);
1818
1819typedef QMap<QString, QSettingsIniSection> IniMap;
1820
1821/*
1822 This would be more straightforward if we didn't try to remember the original
1823 key order in the .ini file, but we do.
1824*/
1825bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1826{
1827 IniMap iniMap;
1828 IniMap::const_iterator i;
1829
1830#ifdef Q_OS_WIN
1831 const char * const eol = "\r\n";
1832#else
1833 const char eol = '\n';
1834#endif
1835
1836 for (ParsedSettingsMap::const_iterator j = map.constBegin(); j != map.constEnd(); ++j) {
1837 QString section;
1838 QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1839 int slashPos;
1840
1841 if ((slashPos = key.indexOf(QLatin1Char('/'))) != -1) {
1842 section = key.left(slashPos);
1843 key.remove(0, slashPos + 1);
1844 }
1845
1846 QSettingsIniSection &iniSection = iniMap[section];
1847
1848 // -1 means infinity
1849 if (uint(key.position) < uint(iniSection.position))
1850 iniSection.position = key.position;
1851 iniSection.keyMap[key] = j.value();
1852 }
1853
1854 const int sectionCount = iniMap.size();
1855 QVector<QSettingsIniKey> sections;
1856 sections.reserve(sectionCount);
1857 for (i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1858 sections.append(QSettingsIniKey(i.key(), i.value().position));
1859 std::sort(sections.begin(), sections.end());
1860
1861 bool writeError = false;
1862 for (int j = 0; !writeError && j < sectionCount; ++j) {
1863 i = iniMap.constFind(sections.at(j));
1864 Q_ASSERT(i != iniMap.constEnd());
1865
1866 QByteArray realSection;
1867
1868 iniEscapedKey(i.key(), realSection);
1869
1870 if (realSection.isEmpty()) {
1871 realSection = "[General]";
1872 } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1873 realSection = "[%General]";
1874 } else {
1875 realSection.prepend('[');
1876 realSection.append(']');
1877 }
1878
1879 if (j != 0)
1880 realSection.prepend(eol);
1881 realSection += eol;
1882
1883 device.write(realSection);
1884
1885 const IniKeyMap &ents = i.value().keyMap;
1886 for (IniKeyMap::const_iterator j = ents.constBegin(); j != ents.constEnd(); ++j) {
1887 QByteArray block;
1888 iniEscapedKey(j.key(), block);
1889 block += '=';
1890
1891 const QVariant &value = j.value();
1892
1893 /*
1894 The size() != 1 trick is necessary because
1895 QVariant(QString("foo")).toList() returns an empty
1896 list, not a list containing "foo".
1897 */
1898 if (value.type() == QVariant::StringList
1899 || (value.type() == QVariant::List && value.toList().size() != 1)) {
1900 iniEscapedStringList(variantListToStringList(value.toList()), block, iniCodec);
1901 } else {
1902 iniEscapedString(variantToString(value), block, iniCodec);
1903 }
1904 block += eol;
1905 if (device.write(block) == -1) {
1906 writeError = true;
1907 break;
1908 }
1909 }
1910 }
1911 return !writeError;
1912}
1913
1914void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1915{
1916 UnparsedSettingsMap::const_iterator i = confFile->unparsedIniSections.constBegin();
1917 const UnparsedSettingsMap::const_iterator end = confFile->unparsedIniSections.constEnd();
1918
1919 for (; i != end; ++i) {
1920 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1921 setStatus(QSettings::FormatError);
1922 }
1923 confFile->unparsedIniSections.clear();
1924}
1925
1926void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1927 const QSettingsKey &key) const
1928{
1929 if (confFile->unparsedIniSections.isEmpty())
1930 return;
1931
1932 UnparsedSettingsMap::iterator i;
1933
1934 int indexOfSlash = key.indexOf(QLatin1Char('/'));
1935 if (indexOfSlash != -1) {
1936 i = confFile->unparsedIniSections.upperBound(key);
1937 if (i == confFile->unparsedIniSections.begin())
1938 return;
1939 --i;
1940 if (i.key().isEmpty() || !key.startsWith(i.key()))
1941 return;
1942 } else {
1943 i = confFile->unparsedIniSections.begin();
1944 if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1945 return;
1946 }
1947
1948 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys, iniCodec))
1949 setStatus(QSettings::FormatError);
1950 confFile->unparsedIniSections.erase(i);
1951}
1952
1953/*!
1954 \class QSettings
1955 \inmodule QtCore
1956 \brief The QSettings class provides persistent platform-independent application settings.
1957
1958 \ingroup io
1959
1960 \reentrant
1961
1962 Users normally expect an application to remember its settings
1963 (window sizes and positions, options, etc.) across sessions. This
1964 information is often stored in the system registry on Windows,
1965 and in property list files on \macos and iOS. On Unix systems, in the
1966 absence of a standard, many applications (including the KDE
1967 applications) use INI text files.
1968
1969 QSettings is an abstraction around these technologies, enabling
1970 you to save and restore application settings in a portable
1971 manner. It also supports \l{registerFormat()}{custom storage
1972 formats}.
1973
1974 QSettings's API is based on QVariant, allowing you to save
1975 most value-based types, such as QString, QRect, and QImage,
1976 with the minimum of effort.
1977
1978 If all you need is a non-persistent memory-based structure,
1979 consider using QMap<QString, QVariant> instead.
1980
1981 \tableofcontents section1
1982
1983 \section1 Basic Usage
1984
1985 When creating a QSettings object, you must pass the name of your
1986 company or organization as well as the name of your application.
1987 For example, if your product is called Star Runner and your
1988 company is called MySoft, you would construct the QSettings
1989 object as follows:
1990
1991 \snippet settings/settings.cpp 0
1992
1993 QSettings objects can be created either on the stack or on
1994 the heap (i.e. using \c new). Constructing and destroying a
1995 QSettings object is very fast.
1996
1997 If you use QSettings from many places in your application, you
1998 might want to specify the organization name and the application
1999 name using QCoreApplication::setOrganizationName() and
2000 QCoreApplication::setApplicationName(), and then use the default
2001 QSettings constructor:
2002
2003 \snippet settings/settings.cpp 1
2004 \snippet settings/settings.cpp 2
2005 \snippet settings/settings.cpp 3
2006 \dots
2007 \snippet settings/settings.cpp 4
2008
2009 (Here, we also specify the organization's Internet domain. When
2010 the Internet domain is set, it is used on \macos and iOS instead of the
2011 organization name, since \macos and iOS applications conventionally use
2012 Internet domains to identify themselves. If no domain is set, a
2013 fake domain is derived from the organization name. See the
2014 \l{Platform-Specific Notes} below for details.)
2015
2016 QSettings stores settings. Each setting consists of a QString
2017 that specifies the setting's name (the \e key) and a QVariant
2018 that stores the data associated with the key. To write a setting,
2019 use setValue(). For example:
2020
2021 \snippet settings/settings.cpp 5
2022
2023 If there already exists a setting with the same key, the existing
2024 value is overwritten by the new value. For efficiency, the
2025 changes may not be saved to permanent storage immediately. (You
2026 can always call sync() to commit your changes.)
2027
2028 You can get a setting's value back using value():
2029
2030 \snippet settings/settings.cpp 6
2031
2032 If there is no setting with the specified name, QSettings
2033 returns a null QVariant (which can be converted to the integer 0).
2034 You can specify another default value by passing a second
2035 argument to value():
2036
2037 \snippet settings/settings.cpp 7
2038
2039 To test whether a given key exists, call contains(). To remove
2040 the setting associated with a key, call remove(). To obtain the
2041 list of all keys, call allKeys(). To remove all keys, call
2042 clear().
2043
2044 \section1 QVariant and GUI Types
2045
2046 Because QVariant is part of the Qt Core module, it cannot provide
2047 conversion functions to data types such as QColor, QImage, and
2048 QPixmap, which are part of Qt GUI. In other words, there is no
2049 \c toColor(), \c toImage(), or \c toPixmap() functions in QVariant.
2050
2051 Instead, you can use the QVariant::value() or the qVariantValue()
2052 template function. For example:
2053
2054 \snippet code/src_corelib_io_qsettings.cpp 0
2055
2056 The inverse conversion (e.g., from QColor to QVariant) is
2057 automatic for all data types supported by QVariant, including
2058 GUI-related types:
2059
2060 \snippet code/src_corelib_io_qsettings.cpp 1
2061
2062 Custom types registered using qRegisterMetaType() and
2063 qRegisterMetaTypeStreamOperators() can be stored using QSettings.
2064
2065 \section1 Section and Key Syntax
2066
2067 Setting keys can contain any Unicode characters. The Windows
2068 registry and INI files use case-insensitive keys, whereas the
2069 CFPreferences API on \macos and iOS uses case-sensitive keys. To
2070 avoid portability problems, follow these simple rules:
2071
2072 \list 1
2073 \li Always refer to the same key using the same case. For example,
2074 if you refer to a key as "text fonts" in one place in your
2075 code, don't refer to it as "Text Fonts" somewhere else.
2076
2077 \li Avoid key names that are identical except for the case. For
2078 example, if you have a key called "MainWindow", don't try to
2079 save another key as "mainwindow".
2080
2081 \li Do not use slashes ('/' and '\\') in section or key names; the
2082 backslash character is used to separate sub keys (see below). On
2083 windows '\\' are converted by QSettings to '/', which makes
2084 them identical.
2085 \endlist
2086
2087 You can form hierarchical keys using the '/' character as a
2088 separator, similar to Unix file paths. For example:
2089
2090 \snippet settings/settings.cpp 8
2091 \snippet settings/settings.cpp 9
2092 \snippet settings/settings.cpp 10
2093
2094 If you want to save or restore many settings with the same
2095 prefix, you can specify the prefix using beginGroup() and call
2096 endGroup() at the end. Here's the same example again, but this
2097 time using the group mechanism:
2098
2099 \snippet settings/settings.cpp 11
2100 \codeline
2101 \snippet settings/settings.cpp 12
2102
2103 If a group is set using beginGroup(), the behavior of most
2104 functions changes consequently. Groups can be set recursively.
2105
2106 In addition to groups, QSettings also supports an "array"
2107 concept. See beginReadArray() and beginWriteArray() for details.
2108
2109 \section1 Fallback Mechanism
2110
2111 Let's assume that you have created a QSettings object with the
2112 organization name MySoft and the application name Star Runner.
2113 When you look up a value, up to four locations are searched in
2114 that order:
2115
2116 \list 1
2117 \li a user-specific location for the Star Runner application
2118 \li a user-specific location for all applications by MySoft
2119 \li a system-wide location for the Star Runner application
2120 \li a system-wide location for all applications by MySoft
2121 \endlist
2122
2123 (See \l{Platform-Specific Notes} below for information on what
2124 these locations are on the different platforms supported by Qt.)
2125
2126 If a key cannot be found in the first location, the search goes
2127 on in the second location, and so on. This enables you to store
2128 system-wide or organization-wide settings and to override them on
2129 a per-user or per-application basis. To turn off this mechanism,
2130 call setFallbacksEnabled(false).
2131
2132 Although keys from all four locations are available for reading,
2133 only the first file (the user-specific location for the
2134 application at hand) is accessible for writing. To write to any
2135 of the other files, omit the application name and/or specify
2136 QSettings::SystemScope (as opposed to QSettings::UserScope, the
2137 default).
2138
2139 Let's see with an example:
2140
2141 \snippet settings/settings.cpp 13
2142 \snippet settings/settings.cpp 14
2143
2144 The table below summarizes which QSettings objects access
2145 which location. "\b{X}" means that the location is the main
2146 location associated to the QSettings object and is used both
2147 for reading and for writing; "o" means that the location is used
2148 as a fallback when reading.
2149
2150 \table
2151 \header \li Locations \li \c{obj1} \li \c{obj2} \li \c{obj3} \li \c{obj4}
2152 \row \li 1. User, Application \li \b{X} \li \li \li
2153 \row \li 2. User, Organization \li o \li \b{X} \li \li
2154 \row \li 3. System, Application \li o \li \li \b{X} \li
2155 \row \li 4. System, Organization \li o \li o \li o \li \b{X}
2156 \endtable
2157
2158 The beauty of this mechanism is that it works on all platforms
2159 supported by Qt and that it still gives you a lot of flexibility,
2160 without requiring you to specify any file names or registry
2161 paths.
2162
2163 If you want to use INI files on all platforms instead of the
2164 native API, you can pass QSettings::IniFormat as the first
2165 argument to the QSettings constructor, followed by the scope, the
2166 organization name, and the application name:
2167
2168 \snippet settings/settings.cpp 15
2169
2170 The \l{tools/settingseditor}{Settings Editor} example lets you
2171 experiment with different settings location and with fallbacks
2172 turned on or off.
2173
2174 \section1 Restoring the State of a GUI Application
2175
2176 QSettings is often used to store the state of a GUI
2177 application. The following example illustrates how to use QSettings
2178 to save and restore the geometry of an application's main window.
2179
2180 \snippet settings/settings.cpp 16
2181 \codeline
2182 \snippet settings/settings.cpp 17
2183
2184 See \l{Window Geometry} for a discussion on why it is better to
2185 call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry()
2186 to restore a window's geometry.
2187
2188 The \c readSettings() and \c writeSettings() functions must be
2189 called from the main window's constructor and close event handler
2190 as follows:
2191
2192 \snippet settings/settings.cpp 18
2193 \dots
2194 \snippet settings/settings.cpp 19
2195 \snippet settings/settings.cpp 20
2196 \codeline
2197 \snippet settings/settings.cpp 21
2198
2199 See the \l{mainwindows/application}{Application} example for a
2200 self-contained example that uses QSettings.
2201
2202 \section1 Accessing Settings from Multiple Threads or Processes Simultaneously
2203
2204 QSettings is \l{reentrant}. This means that you can use
2205 distinct QSettings object in different threads
2206 simultaneously. This guarantee stands even when the QSettings
2207 objects refer to the same files on disk (or to the same entries
2208 in the system registry). If a setting is modified through one
2209 QSettings object, the change will immediately be visible in
2210 any other QSettings objects that operate on the same location
2211 and that live in the same process.
2212
2213 QSettings can safely be used from different processes (which can
2214 be different instances of your application running at the same
2215 time or different applications altogether) to read and write to
2216 the same system locations, provided certain conditions are met. For
2217 QSettings::IniFormat, it uses advisory file locking and a smart merging
2218 algorithm to ensure data integrity. The condition for that to work is that
2219 the writeable configuration file must be a regular file and must reside in
2220 a directory that the current user can create new, temporary files in. If
2221 that is not the case, then one must use setAtomicSyncRequired() to turn the
2222 safety off.
2223
2224 Note that sync() imports changes made by other processes (in addition to
2225 writing the changes from this QSettings).
2226
2227 \section1 Platform-Specific Notes
2228
2229 \section2 Locations Where Application Settings Are Stored
2230
2231 As mentioned in the \l{Fallback Mechanism} section, QSettings
2232 stores settings for an application in up to four locations,
2233 depending on whether the settings are user-specific or
2234 system-wide and whether the settings are application-specific
2235 or organization-wide. For simplicity, we're assuming the
2236 organization is called MySoft and the application is called Star
2237 Runner.
2238
2239 On Unix systems, if the file format is NativeFormat, the
2240 following files are used by default:
2241
2242 \list 1
2243 \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
2244 \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
2245 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
2246 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
2247 \endlist
2248 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2249
2250 On \macos versions 10.2 and 10.3, these files are used by
2251 default:
2252
2253 \list 1
2254 \li \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist}
2255 \li \c{$HOME/Library/Preferences/com.MySoft.plist}
2256 \li \c{/Library/Preferences/com.MySoft.Star Runner.plist}
2257 \li \c{/Library/Preferences/com.MySoft.plist}
2258 \endlist
2259
2260 On Windows, NativeFormat settings are stored in the following
2261 registry paths:
2262
2263 \list 1
2264 \li \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner}
2265 \li \c{HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults}
2266 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner}
2267 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults}
2268 \endlist
2269
2270 \note On Windows, for 32-bit programs running in WOW64 mode, settings are
2271 stored in the following registry path:
2272 \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}.
2273
2274 If the file format is NativeFormat, this is "Settings/MySoft/Star Runner.conf"
2275 in the application's home directory.
2276
2277 If the file format is IniFormat, the following files are
2278 used on Unix, \macos, and iOS:
2279
2280 \list 1
2281 \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
2282 \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
2283 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
2284 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
2285 \endlist
2286 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2287
2288 On Windows, the following files are used:
2289
2290 \list 1
2291 \li \c{FOLDERID_RoamingAppData\MySoft\Star Runner.ini}
2292 \li \c{FOLDERID_RoamingAppData\MySoft.ini}
2293 \li \c{FOLDERID_ProgramData\MySoft\Star Runner.ini}
2294 \li \c{FOLDERID_ProgramData\MySoft.ini}
2295 \endlist
2296
2297 The identifiers prefixed by \c{FOLDERID_} are special item ID lists to be passed
2298 to the Win32 API function \c{SHGetKnownFolderPath()} to obtain the
2299 corresponding path.
2300
2301 \c{FOLDERID_RoamingAppData} usually points to \tt{C:\\Users\\\e{User Name}\\AppData\\Roaming},
2302 also shown by the environment variable \c{%APPDATA%}.
2303
2304 \c{FOLDERID_ProgramData} usually points to \tt{C:\\ProgramData}.
2305
2306 If the file format is IniFormat, this is "Settings/MySoft/Star Runner.ini"
2307 in the application's home directory.
2308
2309 The paths for the \c .ini and \c .conf files can be changed using
2310 setPath(). On Unix, \macos, and iOS the user can override them by
2311 setting the \c XDG_CONFIG_HOME environment variable; see
2312 setPath() for details.
2313
2314 \section2 Accessing INI and .plist Files Directly
2315
2316 Sometimes you do want to access settings stored in a specific
2317 file or registry path. On all platforms, if you want to read an
2318 INI file directly, you can use the QSettings constructor that
2319 takes a file name as first argument and pass QSettings::IniFormat
2320 as second argument. For example:
2321
2322 \snippet code/src_corelib_io_qsettings.cpp 2
2323
2324 You can then use the QSettings object to read and write settings
2325 in the file.
2326
2327 On \macos and iOS, you can access property list \c .plist files by passing
2328 QSettings::NativeFormat as second argument. For example:
2329
2330 \snippet code/src_corelib_io_qsettings.cpp 3
2331
2332 \section2 Accessing the Windows Registry Directly
2333
2334 On Windows, QSettings lets you access settings that have been
2335 written with QSettings (or settings in a supported format, e.g., string
2336 data) in the system registry. This is done by constructing a QSettings
2337 object with a path in the registry and QSettings::NativeFormat.
2338
2339 For example:
2340
2341 \snippet code/src_corelib_io_qsettings.cpp 4
2342
2343 All the registry entries that appear under the specified path can
2344 be read or written through the QSettings object as usual (using
2345 forward slashes instead of backslashes). For example:
2346
2347 \snippet code/src_corelib_io_qsettings.cpp 5
2348
2349 Note that the backslash character is, as mentioned, used by
2350 QSettings to separate subkeys. As a result, you cannot read or
2351 write windows registry entries that contain slashes or
2352 backslashes; you should use a native windows API if you need to do
2353 so.
2354
2355 \section2 Accessing Common Registry Settings on Windows
2356
2357 On Windows, it is possible for a key to have both a value and subkeys.
2358 Its default value is accessed by using "Default" or "." in
2359 place of a subkey:
2360
2361 \snippet code/src_corelib_io_qsettings.cpp 6
2362
2363 On other platforms than Windows, "Default" and "." would be
2364 treated as regular subkeys.
2365
2366 \section2 Platform Limitations
2367
2368 While QSettings attempts to smooth over the differences between
2369 the different supported platforms, there are still a few
2370 differences that you should be aware of when porting your
2371 application:
2372
2373 \list
2374 \li The Windows system registry has the following limitations: A
2375 subkey may not exceed 255 characters, an entry's value may
2376 not exceed 16,383 characters, and all the values of a key may
2377 not exceed 65,535 characters. One way to work around these
2378 limitations is to store the settings using the IniFormat
2379 instead of the NativeFormat.
2380
2381 \li On Windows, when the Windows system registry is used, QSettings
2382 does not preserve the original type of the value. Therefore,
2383 the type of the value might change when a new value is set. For
2384 example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ.
2385
2386 \li On \macos and iOS, allKeys() will return some extra keys for global
2387 settings that apply to all applications. These keys can be
2388 read using value() but cannot be changed, only shadowed.
2389 Calling setFallbacksEnabled(false) will hide these global
2390 settings.
2391
2392 \li On \macos and iOS, the CFPreferences API used by QSettings expects
2393 Internet domain names rather than organization names. To
2394 provide a uniform API, QSettings derives a fake domain name
2395 from the organization name (unless the organization name
2396 already is a domain name, e.g. OpenOffice.org). The algorithm
2397 appends ".com" to the company name and replaces spaces and
2398 other illegal characters with hyphens. If you want to specify
2399 a different domain name, call
2400 QCoreApplication::setOrganizationDomain(),
2401 QCoreApplication::setOrganizationName(), and
2402 QCoreApplication::setApplicationName() in your \c main()
2403 function and then use the default QSettings constructor.
2404 Another solution is to use preprocessor directives, for
2405 example:
2406
2407 \snippet code/src_corelib_io_qsettings.cpp 7
2408
2409 \li On \macos, permissions to access settings not belonging to the
2410 current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to
2411 that version, users having admin rights could access these. For 10.7 and
2412 10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
2413 that rule again but only for the native format (plist files).
2414
2415 \endlist
2416
2417 \sa QVariant, QSessionManager, {Settings Editor Example}, {Application Example}
2418*/
2419
2420/*! \enum QSettings::Status
2421
2422 The following status values are possible:
2423
2424 \value NoError No error occurred.
2425 \value AccessError An access error occurred (e.g. trying to write to a read-only file).
2426 \value FormatError A format error occurred (e.g. loading a malformed INI file).
2427
2428 \sa status()
2429*/
2430
2431/*! \enum QSettings::Format
2432
2433 This enum type specifies the storage format used by QSettings.
2434
2435 \value NativeFormat Store the settings using the most
2436 appropriate storage format for the platform.
2437 On Windows, this means the system registry;
2438 on \macos and iOS, this means the CFPreferences
2439 API; on Unix, this means textual
2440 configuration files in INI format.
2441 \value Registry32Format Windows only: Explicitly access the 32-bit system registry
2442 from a 64-bit application running on 64-bit Windows.
2443 On 32-bit Windows or from a 32-bit application on 64-bit Windows,
2444 this works the same as specifying NativeFormat.
2445 This enum value was added in Qt 5.7.
2446 \value Registry64Format Windows only: Explicitly access the 64-bit system registry
2447 from a 32-bit application running on 64-bit Windows.
2448 On 32-bit Windows or from a 64-bit application on 64-bit Windows,
2449 this works the same as specifying NativeFormat.
2450 This enum value was added in Qt 5.7.
2451 \value IniFormat Store the settings in INI files.
2452 \value InvalidFormat Special value returned by registerFormat().
2453 \omitvalue CustomFormat1
2454 \omitvalue CustomFormat2
2455 \omitvalue CustomFormat3
2456 \omitvalue CustomFormat4
2457 \omitvalue CustomFormat5
2458 \omitvalue CustomFormat6
2459 \omitvalue CustomFormat7
2460 \omitvalue CustomFormat8
2461 \omitvalue CustomFormat9
2462 \omitvalue CustomFormat10
2463 \omitvalue CustomFormat11
2464 \omitvalue CustomFormat12
2465 \omitvalue CustomFormat13
2466 \omitvalue CustomFormat14
2467 \omitvalue CustomFormat15
2468 \omitvalue CustomFormat16
2469
2470 On Unix, NativeFormat and IniFormat mean the same thing, except
2471 that the file extension is different (\c .conf for NativeFormat,
2472 \c .ini for IniFormat).
2473
2474 The INI file format is a Windows file format that Qt supports on
2475 all platforms. In the absence of an INI standard, we try to
2476 follow what Microsoft does, with the following exceptions:
2477
2478 \list
2479 \li If you store types that QVariant can't convert to QString
2480 (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based
2481 syntax to encode the type. For example:
2482
2483 \snippet code/src_corelib_io_qsettings.cpp 8
2484
2485 To minimize compatibility issues, any \c @ that doesn't
2486 appear at the first position in the value or that isn't
2487 followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is
2488 treated as a normal character.
2489
2490 \li Although backslash is a special character in INI files, most
2491 Windows applications don't escape backslashes (\c{\}) in file
2492 paths:
2493
2494 \snippet code/src_corelib_io_qsettings.cpp 9
2495
2496 QSettings always treats backslash as a special character and
2497 provides no API for reading or writing such entries.
2498
2499 \li The INI file format has severe restrictions on the syntax of
2500 a key. Qt works around this by using \c % as an escape
2501 character in keys. In addition, if you save a top-level
2502 setting (a key with no slashes in it, e.g., "someKey"), it
2503 will appear in the INI file's "General" section. To avoid
2504 overwriting other keys, if you save something using a key
2505 such as "General/someKey", the key will be located in the
2506 "%General" section, \e not in the "General" section.
2507
2508 \li Following the philosophy that we should be liberal in what
2509 we accept and conservative in what we generate, QSettings
2510 will accept Latin-1 encoded INI files, but generate pure
2511 ASCII files, where non-ASCII values are encoded using standard
2512 INI escape sequences. To make the INI files more readable (but
2513 potentially less compatible), call setIniCodec().
2514 \endlist
2515
2516 \sa registerFormat(), setPath()
2517*/
2518
2519/*! \enum QSettings::Scope
2520
2521 This enum specifies whether settings are user-specific or shared
2522 by all users of the same system.
2523
2524 \value UserScope Store settings in a location specific to the
2525 current user (e.g., in the user's home
2526 directory).
2527 \value SystemScope Store settings in a global location, so that
2528 all users on the same machine access the same
2529 set of settings.
2530
2531 \sa setPath()
2532*/
2533
2534#ifndef QT_NO_QOBJECT
2535/*!
2536 Constructs a QSettings object for accessing settings of the
2537 application called \a application from the organization called \a
2538 organization, and with parent \a parent.
2539
2540 Example:
2541 \snippet code/src_corelib_io_qsettings.cpp 10
2542
2543 The scope is set to QSettings::UserScope, and the format is
2544 set to QSettings::NativeFormat (i.e. calling setDefaultFormat()
2545 before calling this constructor has no effect).
2546
2547 \sa setDefaultFormat(), {Fallback Mechanism}
2548*/
2549QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2550 : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2551 parent)
2552{
2553}
2554
2555/*!
2556 Constructs a QSettings object for accessing settings of the
2557 application called \a application from the organization called \a
2558 organization, and with parent \a parent.
2559
2560 If \a scope is QSettings::UserScope, the QSettings object searches
2561 user-specific settings first, before it searches system-wide
2562 settings as a fallback. If \a scope is QSettings::SystemScope, the
2563 QSettings object ignores user-specific settings and provides
2564 access to system-wide settings.
2565
2566 The storage format is set to QSettings::NativeFormat (i.e. calling
2567 setDefaultFormat() before calling this constructor has no effect).
2568
2569 If no application name is given, the QSettings object will
2570 only access the organization-wide \l{Fallback Mechanism}{locations}.
2571
2572 \sa setDefaultFormat()
2573*/
2574QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2575 QObject *parent)
2576 : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2577{
2578}
2579
2580/*!
2581 Constructs a QSettings object for accessing settings of the
2582 application called \a application from the organization called
2583 \a organization, and with parent \a parent.
2584
2585 If \a scope is QSettings::UserScope, the QSettings object searches
2586 user-specific settings first, before it searches system-wide
2587 settings as a fallback. If \a scope is
2588 QSettings::SystemScope, the QSettings object ignores user-specific
2589 settings and provides access to system-wide settings.
2590
2591 If \a format is QSettings::NativeFormat, the native API is used for
2592 storing settings. If \a format is QSettings::IniFormat, the INI format
2593 is used.
2594
2595 If no application name is given, the QSettings object will
2596 only access the organization-wide \l{Fallback Mechanism}{locations}.
2597*/
2598QSettings::QSettings(Format format, Scope scope, const QString &organization,
2599 const QString &application, QObject *parent)
2600 : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2601{
2602}
2603
2604/*!
2605 Constructs a QSettings object for accessing the settings
2606 stored in the file called \a fileName, with parent \a parent. If
2607 the file doesn't already exist, it is created.
2608
2609 If \a format is QSettings::NativeFormat, the meaning of \a
2610 fileName depends on the platform. On Unix, \a fileName is the
2611 name of an INI file. On \macos and iOS, \a fileName is the name of a
2612 \c .plist file. On Windows, \a fileName is a path in the system
2613 registry.
2614
2615 If \a format is QSettings::IniFormat, \a fileName is the name of an INI
2616 file.
2617
2618 \warning This function is provided for convenience. It works well for
2619 accessing INI or \c .plist files generated by Qt, but might fail on some
2620 syntaxes found in such files originated by other programs. In particular,
2621 be aware of the following limitations:
2622
2623 \list
2624 \li QSettings provides no way of reading INI "path" entries, i.e., entries
2625 with unescaped slash characters. (This is because these entries are
2626 ambiguous and cannot be resolved automatically.)
2627 \li In INI files, QSettings uses the \c @ character as a metacharacter in some
2628 contexts, to encode Qt-specific data types (e.g., \c @Rect), and might
2629 therefore misinterpret it when it occurs in pure INI files.
2630 \endlist
2631
2632 \sa fileName()
2633*/
2634QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
2635 : QObject(*QSettingsPrivate::create(fileName, format), parent)
2636{
2637}
2638
2639/*!
2640 Constructs a QSettings object for accessing settings of the
2641 application and organization set previously with a call to
2642 QCoreApplication::setOrganizationName(),
2643 QCoreApplication::setOrganizationDomain(), and
2644 QCoreApplication::setApplicationName().
2645
2646 The scope is QSettings::UserScope and the format is
2647 defaultFormat() (QSettings::NativeFormat by default).
2648 Use setDefaultFormat() before calling this constructor
2649 to change the default format used by this constructor.
2650
2651 The code
2652
2653 \snippet code/src_corelib_io_qsettings.cpp 11
2654
2655 is equivalent to
2656
2657 \snippet code/src_corelib_io_qsettings.cpp 12
2658
2659 If QCoreApplication::setOrganizationName() and
2660 QCoreApplication::setApplicationName() has not been previously
2661 called, the QSettings object will not be able to read or write
2662 any settings, and status() will return AccessError.
2663
2664 You should supply both the domain (used by default on \macos and iOS) and
2665 the name (used by default elsewhere), although the code will cope if you
2666 supply only one, which will then be used (on all platforms), at odds with
2667 the usual naming of the file on platforms for which it isn't the default.
2668
2669 \sa QCoreApplication::setOrganizationName(),
2670 QCoreApplication::setOrganizationDomain(),
2671 QCoreApplication::setApplicationName(),
2672 setDefaultFormat()
2673*/
2674QSettings::QSettings(QObject *parent)
2675 : QSettings(UserScope, parent)
2676{
2677}
2678
2679/*!
2680 \since 5.13
2681
2682 Constructs a QSettings object in the same way as
2683 QSettings(QObject *parent) but with the given \a scope.
2684
2685 \sa QSettings(QObject *parent)
2686*/
2687QSettings::QSettings(Scope scope, QObject *parent)
2688 : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2689#ifdef Q_OS_DARWIN
2690 QCoreApplication::organizationDomain().isEmpty()
2691 ? QCoreApplication::organizationName()
2692 : QCoreApplication::organizationDomain()
2693#else
2694 QCoreApplication::organizationName().isEmpty()
2695 ? QCoreApplication::organizationDomain()
2696 : QCoreApplication::organizationName()
2697#endif
2698 , QCoreApplication::applicationName()),
2699 parent)
2700{
2701}
2702
2703#else
2704QSettings::QSettings(const QString &organization, const QString &application)
2705 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2706{
2707 d_ptr->q_ptr = this;
2708}
2709
2710QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2711 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2712{
2713 d_ptr->q_ptr = this;
2714}
2715
2716QSettings::QSettings(Format format, Scope scope, const QString &organization,
2717 const QString &application)
2718 : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2719{
2720 d_ptr->q_ptr = this;
2721}
2722
2723QSettings::QSettings(const QString &fileName, Format format)
2724 : d_ptr(QSettingsPrivate::create(fileName, format))
2725{
2726 d_ptr->q_ptr = this;
2727}
2728
2729# ifndef QT_BUILD_QMAKE
2730QSettings::QSettings(Scope scope)
2731 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2732# ifdef Q_OS_DARWIN
2733 QCoreApplication::organizationDomain().isEmpty()
2734 ? QCoreApplication::organizationName()
2735 : QCoreApplication::organizationDomain()
2736# else
2737 QCoreApplication::organizationName().isEmpty()
2738 ? QCoreApplication::organizationDomain()
2739 : QCoreApplication::organizationName()
2740# endif
2741 , QCoreApplication::applicationName())
2742 )
2743{
2744 d_ptr->q_ptr = this;
2745}
2746# endif
2747#endif
2748
2749/*!
2750 Destroys the QSettings object.
2751
2752 Any unsaved changes will eventually be written to permanent
2753 storage.
2754
2755 \sa sync()
2756*/
2757QSettings::~QSettings()
2758{
2759 Q_D(QSettings);
2760 if (d->pendingChanges) {
2761 QT_TRY {
2762 d->flush();
2763 } QT_CATCH(...) {
2764 ; // ok. then don't flush but at least don't throw in the destructor
2765 }
2766 }
2767}
2768
2769/*!
2770 Removes all entries in the primary location associated to this
2771 QSettings object.
2772
2773 Entries in fallback locations are not removed.
2774
2775 If you only want to remove the entries in the current group(),
2776 use remove("") instead.
2777
2778 \sa remove(), setFallbacksEnabled()
2779*/
2780void QSettings::clear()
2781{
2782 Q_D(QSettings);
2783 d->clear();
2784 d->requestUpdate();
2785}
2786
2787/*!
2788 Writes any unsaved changes to permanent storage, and reloads any
2789 settings that have been changed in the meantime by another
2790 application.
2791
2792 This function is called automatically from QSettings's destructor and
2793 by the event loop at regular intervals, so you normally don't need to
2794 call it yourself.
2795
2796 \sa status()
2797*/
2798void QSettings::sync()
2799{
2800 Q_D(QSettings);
2801 d->sync();
2802 d->pendingChanges = false;
2803}
2804
2805/*!
2806 Returns the path where settings written using this QSettings
2807 object are stored.
2808
2809 On Windows, if the format is QSettings::NativeFormat, the return value
2810 is a system registry path, not a file path.
2811
2812 \sa isWritable(), format()
2813*/
2814QString QSettings::fileName() const
2815{
2816 Q_D(const QSettings);
2817 return d->fileName();
2818}
2819
2820/*!
2821 \since 4.4
2822
2823 Returns the format used for storing the settings.
2824
2825 \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName()
2826*/
2827QSettings::Format QSettings::format() const
2828{
2829 Q_D(const QSettings);
2830 return d->format;
2831}
2832
2833/*!
2834 \since 4.4
2835
2836 Returns the scope used for storing the settings.
2837
2838 \sa format(), organizationName(), applicationName()
2839*/
2840QSettings::Scope QSettings::scope() const
2841{
2842 Q_D(const QSettings);
2843 return d->scope;
2844}
2845
2846/*!
2847 \since 4.4
2848
2849 Returns the organization name used for storing the settings.
2850
2851 \sa QCoreApplication::organizationName(), format(), scope(), applicationName()
2852*/
2853QString QSettings::organizationName() const
2854{
2855 Q_D(const QSettings);
2856 return d->organizationName;
2857}
2858
2859/*!
2860 \since 4.4
2861
2862 Returns the application name used for storing the settings.
2863
2864 \sa QCoreApplication::applicationName(), format(), scope(), organizationName()
2865*/
2866QString QSettings::applicationName() const
2867{
2868 Q_D(const QSettings);
2869 return d->applicationName;
2870}
2871
2872#if QT_CONFIG(textcodec)
2873
2874/*!
2875 \since 4.5
2876
2877 Sets the codec for accessing INI files (including \c .conf files on Unix)
2878 to \a codec. The codec is used for decoding any data that is read from
2879 the INI file, and for encoding any data that is written to the file. By
2880 default, no codec is used, and non-ASCII characters are encoded using
2881 standard INI escape sequences.
2882
2883 \warning The codec must be set immediately after creating the QSettings
2884 object, before accessing any data.
2885
2886 \sa iniCodec()
2887*/
2888void QSettings::setIniCodec(QTextCodec *codec)
2889{
2890 Q_D(QSettings);
2891 d->iniCodec = codec;
2892}
2893
2894/*!
2895 \since 4.5
2896 \overload
2897
2898 Sets the codec for accessing INI files (including \c .conf files on Unix)
2899 to the QTextCodec for the encoding specified by \a codecName. Common
2900 values for \c codecName include "ISO 8859-1", "UTF-8", and "UTF-16".
2901 If the encoding isn't recognized, nothing happens.
2902
2903 \sa QTextCodec::codecForName()
2904*/
2905void QSettings::setIniCodec(const char *codecName)
2906{
2907 Q_D(QSettings);
2908 if (QTextCodec *codec = QTextCodec::codecForName(codecName))
2909 d->iniCodec = codec;
2910}
2911
2912/*!
2913 \since 4.5
2914
2915 Returns the codec that is used for accessing INI files. By default,
2916 no codec is used, so a null pointer is returned.
2917*/
2918
2919QTextCodec *QSettings::iniCodec() const
2920{
2921 Q_D(const QSettings);
2922 return d->iniCodec;
2923}
2924
2925#endif // textcodec
2926
2927/*!
2928 Returns a status code indicating the first error that was met by
2929 QSettings, or QSettings::NoError if no error occurred.
2930
2931 Be aware that QSettings delays performing some operations. For this
2932 reason, you might want to call sync() to ensure that the data stored
2933 in QSettings is written to disk before calling status().
2934
2935 \sa sync()
2936*/
2937QSettings::Status QSettings::status() const
2938{
2939 Q_D(const QSettings);
2940 return d->status;
2941}
2942
2943/*!
2944 \since 5.10
2945
2946 Returns \c true if QSettings is only allowed to perform atomic saving and
2947 reloading (synchronization) of the settings. Returns \c false if it is
2948 allowed to save the settings contents directly to the configuration file.
2949
2950 The default is \c true.
2951
2952 \sa setAtomicSyncRequired(), QSaveFile
2953*/
2954bool QSettings::isAtomicSyncRequired() const
2955{
2956 Q_D(const QSettings);
2957 return d->atomicSyncOnly;
2958}
2959
2960/*!
2961 \since 5.10
2962
2963 Configures whether QSettings is required to perform atomic saving and
2964 reloading (synchronization) of the settings. If the \a enable argument is
2965 \c true (the default), sync() will only perform synchronization operations
2966 that are atomic. If this is not possible, sync() will fail and status()
2967 will be an error condition.
2968
2969 Setting this property to \c false will allow QSettings to write directly to
2970 the configuration file and ignore any errors trying to lock it against
2971 other processes trying to write at the same time. Because of the potential
2972 for corruption, this option should be used with care, but is required in
2973 certain conditions, like a QSettings::IniFormat configuration file that
2974 exists in an otherwise non-writeable directory or NTFS Alternate Data
2975 Streams.
2976
2977 See \l QSaveFile for more information on the feature.
2978
2979 \sa isAtomicSyncRequired(), QSaveFile
2980*/
2981void QSettings::setAtomicSyncRequired(bool enable)
2982{
2983 Q_D(QSettings);
2984 d->atomicSyncOnly = enable;
2985}
2986
2987/*!
2988 Appends \a prefix to the current group.
2989
2990 The current group is automatically prepended to all keys
2991 specified to QSettings. In addition, query functions such as
2992 childGroups(), childKeys(), and allKeys() are based on the group.
2993 By default, no group is set.
2994
2995 Groups are useful to avoid typing in the same setting paths over
2996 and over. For example:
2997
2998 \snippet code/src_corelib_io_qsettings.cpp 13
2999
3000 This will set the value of three settings:
3001
3002 \list
3003 \li \c mainwindow/size
3004 \li \c mainwindow/fullScreen
3005 \li \c outputpanel/visible
3006 \endlist
3007
3008 Call endGroup() to reset the current group to what it was before
3009 the corresponding beginGroup() call. Groups can be nested.
3010
3011 \sa endGroup(), group()
3012*/
3013void QSettings::beginGroup(const QString &prefix)
3014{
3015 Q_D(QSettings);
3016 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
3017}
3018
3019/*!
3020 Resets the group to what it was before the corresponding
3021 beginGroup() call.
3022
3023 Example:
3024
3025 \snippet code/src_corelib_io_qsettings.cpp 14
3026
3027 \sa beginGroup(), group()
3028*/
3029void QSettings::endGroup()
3030{
3031 Q_D(QSettings);
3032 if (d->groupStack.isEmpty()) {
3033 qWarning("QSettings::endGroup: No matching beginGroup()");
3034 return;
3035 }
3036
3037 QSettingsGroup group = d->groupStack.pop();
3038 int len = group.toString().size();
3039 if (len > 0)
3040 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3041
3042 if (group.isArray())
3043 qWarning("QSettings::endGroup: Expected endArray() instead");
3044}
3045
3046/*!
3047 Returns the current group.
3048
3049 \sa beginGroup(), endGroup()
3050*/
3051QString QSettings::group() const
3052{
3053 Q_D(const QSettings);
3054 return d->groupPrefix.left(d->groupPrefix.size() - 1);
3055}
3056
3057/*!
3058 Adds \a prefix to the current group and starts reading from an
3059 array. Returns the size of the array.
3060
3061 Example:
3062
3063 \snippet code/src_corelib_io_qsettings.cpp 15
3064
3065 Use beginWriteArray() to write the array in the first place.
3066
3067 \sa beginWriteArray(), endArray(), setArrayIndex()
3068*/
3069int QSettings::beginReadArray(const QString &prefix)
3070{
3071 Q_D(QSettings);
3072 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
3073 return value(QLatin1String("size")).toInt();
3074}
3075
3076/*!
3077 Adds \a prefix to the current group and starts writing an array
3078 of size \a size. If \a size is -1 (the default), it is automatically
3079 determined based on the indexes of the entries written.
3080
3081 If you have many occurrences of a certain set of keys, you can
3082 use arrays to make your life easier. For example, let's suppose
3083 that you want to save a variable-length list of user names and
3084 passwords. You could then write:
3085
3086 \snippet code/src_corelib_io_qsettings.cpp 16
3087
3088 The generated keys will have the form
3089
3090 \list
3091 \li \c logins/size
3092 \li \c logins/1/userName
3093 \li \c logins/1/password
3094 \li \c logins/2/userName
3095 \li \c logins/2/password
3096 \li \c logins/3/userName
3097 \li \c logins/3/password
3098 \li ...
3099 \endlist
3100
3101 To read back an array, use beginReadArray().
3102
3103 \sa beginReadArray(), endArray(), setArrayIndex()
3104*/
3105void QSettings::beginWriteArray(const QString &prefix, int size)
3106{
3107 Q_D(QSettings);
3108 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3109
3110 if (size < 0)
3111 remove(QLatin1String("size"));
3112 else
3113 setValue(QLatin1String("size"), size);
3114}
3115
3116/*!
3117 Closes the array that was started using beginReadArray() or
3118 beginWriteArray().
3119
3120 \sa beginReadArray(), beginWriteArray()
3121*/
3122void QSettings::endArray()
3123{
3124 Q_D(QSettings);
3125 if (d->groupStack.isEmpty()) {
3126 qWarning("QSettings::endArray: No matching beginArray()");
3127 return;
3128 }
3129
3130 QSettingsGroup group = d->groupStack.top();
3131 int len = group.toString().size();
3132 d->groupStack.pop();
3133 if (len > 0)
3134 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3135
3136 if (group.arraySizeGuess() != -1)
3137 setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
3138
3139 if (!group.isArray())
3140 qWarning("QSettings::endArray: Expected endGroup() instead");
3141}
3142
3143/*!
3144 Sets the current array index to \a i. Calls to functions such as
3145 setValue(), value(), remove(), and contains() will operate on the
3146 array entry at that index.
3147
3148 You must call beginReadArray() or beginWriteArray() before you
3149 can call this function.
3150*/
3151void QSettings::setArrayIndex(int i)
3152{
3153 Q_D(QSettings);
3154 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3155 qWarning("QSettings::setArrayIndex: Missing beginArray()");
3156 return;
3157 }
3158
3159 QSettingsGroup &top = d->groupStack.top();
3160 int len = top.toString().size();
3161 top.setArrayIndex(qMax(i, 0));
3162 d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3163}
3164
3165/*!
3166 Returns a list of all keys, including subkeys, that can be read
3167 using the QSettings object.
3168
3169 Example:
3170
3171 \snippet code/src_corelib_io_qsettings.cpp 17
3172
3173 If a group is set using beginGroup(), only the keys in the group
3174 are returned, without the group prefix:
3175
3176 \snippet code/src_corelib_io_qsettings.cpp 18
3177
3178 \sa childGroups(), childKeys()
3179*/
3180QStringList QSettings::allKeys() const
3181{
3182 Q_D(const QSettings);
3183 return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3184}
3185
3186/*!
3187 Returns a list of all top-level keys that can be read using the
3188 QSettings object.
3189
3190 Example:
3191
3192 \snippet code/src_corelib_io_qsettings.cpp 19
3193
3194 If a group is set using beginGroup(), the top-level keys in that
3195 group are returned, without the group prefix:
3196
3197 \snippet code/src_corelib_io_qsettings.cpp 20
3198
3199 You can navigate through the entire setting hierarchy using
3200 childKeys() and childGroups() recursively.
3201
3202 \sa childGroups(), allKeys()
3203*/
3204QStringList QSettings::childKeys() const
3205{
3206 Q_D(const QSettings);
3207 return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3208}
3209
3210/*!
3211 Returns a list of all key top-level groups that contain keys that
3212 can be read using the QSettings object.
3213
3214 Example:
3215
3216 \snippet code/src_corelib_io_qsettings.cpp 21
3217
3218 If a group is set using beginGroup(), the first-level keys in
3219 that group are returned, without the group prefix.
3220
3221 \snippet code/src_corelib_io_qsettings.cpp 22
3222
3223 You can navigate through the entire setting hierarchy using
3224 childKeys() and childGroups() recursively.
3225
3226 \sa childKeys(), allKeys()
3227*/
3228QStringList QSettings::childGroups() const
3229{
3230 Q_D(const QSettings);
3231 return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3232}
3233
3234/*!
3235 Returns \c true if settings can be written using this QSettings
3236 object; returns \c false otherwise.
3237
3238 One reason why isWritable() might return false is if
3239 QSettings operates on a read-only file.
3240
3241 \warning This function is not perfectly reliable, because the
3242 file permissions can change at any time.
3243
3244 \sa fileName(), status(), sync()
3245*/
3246bool QSettings::isWritable() const
3247{
3248 Q_D(const QSettings);
3249 return d->isWritable();
3250}
3251
3252/*!
3253
3254 Sets the value of setting \a key to \a value. If the \a key already
3255 exists, the previous value is overwritten.
3256
3257 Note that the Windows registry and INI files use case-insensitive
3258 keys, whereas the CFPreferences API on \macos and iOS uses
3259 case-sensitive keys. To avoid portability problems, see the
3260 \l{Section and Key Syntax} rules.
3261
3262 Example:
3263
3264 \snippet code/src_corelib_io_qsettings.cpp 23
3265
3266 \sa value(), remove(), contains()
3267*/
3268void QSettings::setValue(const QString &key, const QVariant &value)
3269{
3270 Q_D(QSettings);
3271 if (key.isEmpty()) {
3272 qWarning("QSettings::setValue: Empty key passed");
3273 return;
3274 }
3275 QString k = d->actualKey(key);
3276 d->set(k, value);
3277 d->requestUpdate();
3278}
3279
3280/*!
3281 Removes the setting \a key and any sub-settings of \a key.
3282
3283 Example:
3284
3285 \snippet code/src_corelib_io_qsettings.cpp 24
3286
3287 Be aware that if one of the fallback locations contains a setting
3288 with the same key, that setting will be visible after calling
3289 remove().
3290
3291 If \a key is an empty string, all keys in the current group() are
3292 removed. For example:
3293
3294 \snippet code/src_corelib_io_qsettings.cpp 25
3295
3296 Note that the Windows registry and INI files use case-insensitive
3297 keys, whereas the CFPreferences API on \macos and iOS uses
3298 case-sensitive keys. To avoid portability problems, see the
3299 \l{Section and Key Syntax} rules.
3300
3301 \sa setValue(), value(), contains()
3302*/
3303void QSettings::remove(const QString &key)
3304{
3305 Q_D(QSettings);
3306 /*
3307 We cannot use actualKey(), because remove() supports empty
3308 keys. The code is also tricky because of slash handling.
3309 */
3310 QString theKey = d->normalizedKey(key);
3311 if (theKey.isEmpty())
3312 theKey = group();
3313 else
3314 theKey.prepend(d->groupPrefix);
3315
3316 if (theKey.isEmpty()) {
3317 d->clear();
3318 } else {
3319 d->remove(theKey);
3320 }
3321 d->requestUpdate();
3322}
3323
3324/*!
3325 Returns \c true if there exists a setting called \a key; returns
3326 false otherwise.
3327
3328 If a group is set using beginGroup(), \a key is taken to be
3329 relative to that group.
3330
3331 Note that the Windows registry and INI files use case-insensitive
3332 keys, whereas the CFPreferences API on \macos and iOS uses
3333 case-sensitive keys. To avoid portability problems, see the
3334 \l{Section and Key Syntax} rules.
3335
3336 \sa value(), setValue()
3337*/
3338bool QSettings::contains(const QString &key) const
3339{
3340 Q_D(const QSettings);
3341 QString k = d->actualKey(key);
3342 return d->get(k, 0);
3343}
3344
3345/*!
3346 Sets whether fallbacks are enabled to \a b.
3347
3348 By default, fallbacks are enabled.
3349
3350 \sa fallbacksEnabled()
3351*/
3352void QSettings::setFallbacksEnabled(bool b)
3353{
3354 Q_D(QSettings);
3355 d->fallbacks = !!b;
3356}
3357
3358/*!
3359 Returns \c true if fallbacks are enabled; returns \c false otherwise.
3360
3361 By default, fallbacks are enabled.
3362
3363 \sa setFallbacksEnabled()
3364*/
3365bool QSettings::fallbacksEnabled() const
3366{
3367 Q_D(const QSettings);
3368 return d->fallbacks;
3369}
3370
3371#ifndef QT_NO_QOBJECT
3372/*!
3373 \reimp
3374*/
3375bool QSettings::event(QEvent *event)
3376{
3377 Q_D(QSettings);
3378 if (event->type() == QEvent::UpdateRequest) {
3379 d->update();
3380 return true;
3381 }
3382 return QObject::event(event);
3383}
3384#endif
3385
3386/*!
3387 Returns the value for setting \a key. If the setting doesn't
3388 exist, returns \a defaultValue.
3389
3390 If no default value is specified, a default QVariant is
3391 returned.
3392
3393 Note that the Windows registry and INI files use case-insensitive
3394 keys, whereas the CFPreferences API on \macos and iOS uses
3395 case-sensitive keys. To avoid portability problems, see the
3396 \l{Section and Key Syntax} rules.
3397
3398 Example:
3399
3400 \snippet code/src_corelib_io_qsettings.cpp 26
3401
3402 \sa setValue(), contains(), remove()
3403*/
3404QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3405{
3406 Q_D(const QSettings);
3407 if (key.isEmpty()) {
3408 qWarning("QSettings::value: Empty key passed");
3409 return QVariant();
3410 }
3411 QVariant result = defaultValue;
3412 QString k = d->actualKey(key);
3413 d->get(k, &result);
3414 return result;
3415}
3416
3417/*!
3418 \since 4.4
3419
3420 Sets the default file format to the given \a format, which is used
3421 for storing settings for the QSettings(QObject *) constructor.
3422
3423 If no default format is set, QSettings::NativeFormat is used. See
3424 the documentation for the QSettings constructor you are using to
3425 see if that constructor will ignore this function.
3426
3427 \sa format()
3428*/
3429void QSettings::setDefaultFormat(Format format)
3430{
3431 globalDefaultFormat = format;
3432}
3433
3434/*!
3435 \since 4.4
3436
3437 Returns default file format used for storing settings for the QSettings(QObject *) constructor.
3438 If no default format is set, QSettings::NativeFormat is used.
3439
3440 \sa format()
3441*/
3442QSettings::Format QSettings::defaultFormat()
3443{
3444 return globalDefaultFormat;
3445}
3446
3447#if QT_DEPRECATED_SINCE(5, 13)
3448/*!
3449 \obsolete
3450
3451 Use setPath() instead.
3452
3453 \oldcode
3454 setSystemIniPath(path);
3455 \newcode
3456 setPath(QSettings::NativeFormat, QSettings::SystemScope, path);
3457 setPath(QSettings::IniFormat, QSettings::SystemScope, path);
3458 \endcode
3459*/
3460void QSettings::setSystemIniPath(const QString &dir)
3461{
3462 setPath(IniFormat, SystemScope, dir);
3463#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3464 setPath(NativeFormat, SystemScope, dir);
3465#endif
3466}
3467
3468/*!
3469 \obsolete
3470
3471 Use setPath() instead.
3472*/
3473
3474void QSettings::setUserIniPath(const QString &dir)
3475{
3476 setPath(IniFormat, UserScope, dir);
3477#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3478 setPath(NativeFormat, UserScope, dir);
3479#endif
3480}
3481#endif
3482/*!
3483 \since 4.1
3484
3485 Sets the path used for storing settings for the given \a format
3486 and \a scope, to \a path. The \a format can be a custom format.
3487
3488 The table below summarizes the default values:
3489
3490 \table
3491 \header \li Platform \li Format \li Scope \li Path
3492 \row \li{1,2} Windows \li{1,2} IniFormat \li UserScope \li \c FOLDERID_RoamingAppData
3493 \row \li SystemScope \li \c FOLDERID_ProgramData
3494 \row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config
3495 \row \li SystemScope \li \c /etc/xdg
3496 \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings
3497 \row \li SystemScope \li \c /etc/xdg
3498 \row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config
3499 \row \li SystemScope \li \c /etc/xdg
3500 \endtable
3501
3502 The default UserScope paths on Unix, \macos, and iOS (\c
3503 $HOME/.config or $HOME/Settings) can be overridden by the user by setting the
3504 \c XDG_CONFIG_HOME environment variable. The default SystemScope
3505 paths on Unix, \macos, and iOS (\c /etc/xdg) can be overridden when
3506 building the Qt library using the \c configure script's \c
3507 -sysconfdir flag (see QLibraryInfo for details).
3508
3509 Setting the NativeFormat paths on Windows, \macos, and iOS has no
3510 effect.
3511
3512 \warning This function doesn't affect existing QSettings objects.
3513
3514 \sa registerFormat()
3515*/
3516void QSettings::setPath(Format format, Scope scope, const QString &path)
3517{
3518 QMutexLocker locker(&settingsGlobalMutex);
3519 PathHash *pathHash = pathHashFunc();
3520 if (pathHash->isEmpty())
3521 initDefaultPaths(&locker);
3522 pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3523}
3524
3525/*!
3526 \typedef QSettings::SettingsMap
3527
3528 Typedef for QMap<QString, QVariant>.
3529
3530 \sa registerFormat()
3531*/
3532
3533/*!
3534 \typedef QSettings::ReadFunc
3535
3536 Typedef for a pointer to a function with the following signature:
3537
3538 \snippet code/src_corelib_io_qsettings.cpp 27
3539
3540 \c ReadFunc is used in \c registerFormat() as a pointer to a function
3541 that reads a set of key/value pairs. \c ReadFunc should read all the
3542 options in one pass, and return all the settings in the \c SettingsMap
3543 container, which is initially empty.
3544
3545 \sa WriteFunc, registerFormat()
3546*/
3547
3548/*!
3549 \typedef QSettings::WriteFunc
3550
3551 Typedef for a pointer to a function with the following signature:
3552
3553 \snippet code/src_corelib_io_qsettings.cpp 28
3554
3555 \c WriteFunc is used in \c registerFormat() as a pointer to a function
3556 that writes a set of key/value pairs. \c WriteFunc is only called once,
3557 so you need to output the settings in one go.
3558
3559 \sa ReadFunc, registerFormat()
3560*/
3561
3562/*!
3563 \since 4.1
3564 \threadsafe
3565
3566 Registers a custom storage format. On success, returns a special
3567 Format value that can then be passed to the QSettings constructor.
3568 On failure, returns InvalidFormat.
3569
3570 The \a extension is the file
3571 extension associated to the format (without the '.').
3572
3573 The \a readFunc and \a writeFunc parameters are pointers to
3574 functions that read and write a set of key/value pairs. The
3575 QIODevice parameter to the read and write functions is always
3576 opened in binary mode (i.e., without the QIODevice::Text flag).
3577
3578 The \a caseSensitivity parameter specifies whether keys are case
3579 sensitive or not. This makes a difference when looking up values
3580 using QSettings. The default is case sensitive.
3581
3582 By default, if you use one of the constructors that work in terms
3583 of an organization name and an application name, the file system
3584 locations used are the same as for IniFormat. Use setPath() to
3585 specify other locations.
3586
3587 Example:
3588
3589 \snippet code/src_corelib_io_qsettings.cpp 29
3590
3591 \sa setPath()
3592*/
3593QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3594 WriteFunc writeFunc,
3595 Qt::CaseSensitivity caseSensitivity)
3596{
3597#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3598 Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3599#endif
3600
3601 QMutexLocker locker(&settingsGlobalMutex);
3602 CustomFormatVector *customFormatVector = customFormatVectorFunc();
3603 int index = customFormatVector->size();
3604 if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3605 return QSettings::InvalidFormat;
3606
3607 QConfFileCustomFormat info;
3608 info.extension = QLatin1Char('.') + extension;
3609 info.readFunc = readFunc;
3610 info.writeFunc = writeFunc;
3611 info.caseSensitivity = caseSensitivity;
3612 customFormatVector->append(info);
3613
3614 return QSettings::Format((int)QSettings::CustomFormat1 + index);
3615}
3616
3617QT_END_NAMESPACE
3618
3619#ifndef QT_BOOTSTRAPPED
3620#include "moc_qsettings.cpp"
3621#endif
3622