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 Note that type information is not preserved when reading settings from INI
2171 files; all values will be returned as QString.
2172
2173 The \l{tools/settingseditor}{Settings Editor} example lets you
2174 experiment with different settings location and with fallbacks
2175 turned on or off.
2176
2177 \section1 Restoring the State of a GUI Application
2178
2179 QSettings is often used to store the state of a GUI
2180 application. The following example illustrates how to use QSettings
2181 to save and restore the geometry of an application's main window.
2182
2183 \snippet settings/settings.cpp 16
2184 \codeline
2185 \snippet settings/settings.cpp 17
2186
2187 See \l{Window Geometry} for a discussion on why it is better to
2188 call QWidget::resize() and QWidget::move() rather than QWidget::setGeometry()
2189 to restore a window's geometry.
2190
2191 The \c readSettings() and \c writeSettings() functions must be
2192 called from the main window's constructor and close event handler
2193 as follows:
2194
2195 \snippet settings/settings.cpp 18
2196 \dots
2197 \snippet settings/settings.cpp 19
2198 \snippet settings/settings.cpp 20
2199 \codeline
2200 \snippet settings/settings.cpp 21
2201
2202 See the \l{mainwindows/application}{Application} example for a
2203 self-contained example that uses QSettings.
2204
2205 \section1 Accessing Settings from Multiple Threads or Processes Simultaneously
2206
2207 QSettings is \l{reentrant}. This means that you can use
2208 distinct QSettings object in different threads
2209 simultaneously. This guarantee stands even when the QSettings
2210 objects refer to the same files on disk (or to the same entries
2211 in the system registry). If a setting is modified through one
2212 QSettings object, the change will immediately be visible in
2213 any other QSettings objects that operate on the same location
2214 and that live in the same process.
2215
2216 QSettings can safely be used from different processes (which can
2217 be different instances of your application running at the same
2218 time or different applications altogether) to read and write to
2219 the same system locations, provided certain conditions are met. For
2220 QSettings::IniFormat, it uses advisory file locking and a smart merging
2221 algorithm to ensure data integrity. The condition for that to work is that
2222 the writeable configuration file must be a regular file and must reside in
2223 a directory that the current user can create new, temporary files in. If
2224 that is not the case, then one must use setAtomicSyncRequired() to turn the
2225 safety off.
2226
2227 Note that sync() imports changes made by other processes (in addition to
2228 writing the changes from this QSettings).
2229
2230 \section1 Platform-Specific Notes
2231
2232 \section2 Locations Where Application Settings Are Stored
2233
2234 As mentioned in the \l{Fallback Mechanism} section, QSettings
2235 stores settings for an application in up to four locations,
2236 depending on whether the settings are user-specific or
2237 system-wide and whether the settings are application-specific
2238 or organization-wide. For simplicity, we're assuming the
2239 organization is called MySoft and the application is called Star
2240 Runner.
2241
2242 On Unix systems, if the file format is NativeFormat, the
2243 following files are used by default:
2244
2245 \list 1
2246 \li \c{$HOME/.config/MySoft/Star Runner.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.conf})
2247 \li \c{$HOME/.config/MySoft.conf} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.conf})
2248 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.conf}
2249 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.conf}
2250 \endlist
2251 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2252
2253 On \macos versions 10.2 and 10.3, these files are used by
2254 default:
2255
2256 \list 1
2257 \li \c{$HOME/Library/Preferences/com.MySoft.Star Runner.plist}
2258 \li \c{$HOME/Library/Preferences/com.MySoft.plist}
2259 \li \c{/Library/Preferences/com.MySoft.Star Runner.plist}
2260 \li \c{/Library/Preferences/com.MySoft.plist}
2261 \endlist
2262
2263 On Windows, NativeFormat settings are stored in the following
2264 registry paths:
2265
2266 \list 1
2267 \li \c{HKEY_CURRENT_USER\Software\MySoft\Star Runner}
2268 \li \c{HKEY_CURRENT_USER\Software\MySoft\OrganizationDefaults}
2269 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\Star Runner}
2270 \li \c{HKEY_LOCAL_MACHINE\Software\MySoft\OrganizationDefaults}
2271 \endlist
2272
2273 \note On Windows, for 32-bit programs running in WOW64 mode, settings are
2274 stored in the following registry path:
2275 \c{HKEY_LOCAL_MACHINE\Software\WOW6432node}.
2276
2277 If the file format is NativeFormat, this is "Settings/MySoft/Star Runner.conf"
2278 in the application's home directory.
2279
2280 If the file format is IniFormat, the following files are
2281 used on Unix, \macos, and iOS:
2282
2283 \list 1
2284 \li \c{$HOME/.config/MySoft/Star Runner.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft/Star Runner.ini})
2285 \li \c{$HOME/.config/MySoft.ini} (Qt for Embedded Linux: \c{$HOME/Settings/MySoft.ini})
2286 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft/Star Runner.ini}
2287 \li for each directory <dir> in $XDG_CONFIG_DIRS: \c{<dir>/MySoft.ini}
2288 \endlist
2289 \note If XDG_CONFIG_DIRS is unset, the default value of \c{/etc/xdg} is used.
2290
2291 On Windows, the following files are used:
2292
2293 \list 1
2294 \li \c{FOLDERID_RoamingAppData\MySoft\Star Runner.ini}
2295 \li \c{FOLDERID_RoamingAppData\MySoft.ini}
2296 \li \c{FOLDERID_ProgramData\MySoft\Star Runner.ini}
2297 \li \c{FOLDERID_ProgramData\MySoft.ini}
2298 \endlist
2299
2300 The identifiers prefixed by \c{FOLDERID_} are special item ID lists to be passed
2301 to the Win32 API function \c{SHGetKnownFolderPath()} to obtain the
2302 corresponding path.
2303
2304 \c{FOLDERID_RoamingAppData} usually points to \tt{C:\\Users\\\e{User Name}\\AppData\\Roaming},
2305 also shown by the environment variable \c{%APPDATA%}.
2306
2307 \c{FOLDERID_ProgramData} usually points to \tt{C:\\ProgramData}.
2308
2309 If the file format is IniFormat, this is "Settings/MySoft/Star Runner.ini"
2310 in the application's home directory.
2311
2312 The paths for the \c .ini and \c .conf files can be changed using
2313 setPath(). On Unix, \macos, and iOS the user can override them by
2314 setting the \c XDG_CONFIG_HOME environment variable; see
2315 setPath() for details.
2316
2317 \section2 Accessing INI and .plist Files Directly
2318
2319 Sometimes you do want to access settings stored in a specific
2320 file or registry path. On all platforms, if you want to read an
2321 INI file directly, you can use the QSettings constructor that
2322 takes a file name as first argument and pass QSettings::IniFormat
2323 as second argument. For example:
2324
2325 \snippet code/src_corelib_io_qsettings.cpp 2
2326
2327 You can then use the QSettings object to read and write settings
2328 in the file.
2329
2330 On \macos and iOS, you can access property list \c .plist files by passing
2331 QSettings::NativeFormat as second argument. For example:
2332
2333 \snippet code/src_corelib_io_qsettings.cpp 3
2334
2335 \section2 Accessing the Windows Registry Directly
2336
2337 On Windows, QSettings lets you access settings that have been
2338 written with QSettings (or settings in a supported format, e.g., string
2339 data) in the system registry. This is done by constructing a QSettings
2340 object with a path in the registry and QSettings::NativeFormat.
2341
2342 For example:
2343
2344 \snippet code/src_corelib_io_qsettings.cpp 4
2345
2346 All the registry entries that appear under the specified path can
2347 be read or written through the QSettings object as usual (using
2348 forward slashes instead of backslashes). For example:
2349
2350 \snippet code/src_corelib_io_qsettings.cpp 5
2351
2352 Note that the backslash character is, as mentioned, used by
2353 QSettings to separate subkeys. As a result, you cannot read or
2354 write windows registry entries that contain slashes or
2355 backslashes; you should use a native windows API if you need to do
2356 so.
2357
2358 \section2 Accessing Common Registry Settings on Windows
2359
2360 On Windows, it is possible for a key to have both a value and subkeys.
2361 Its default value is accessed by using "Default" or "." in
2362 place of a subkey:
2363
2364 \snippet code/src_corelib_io_qsettings.cpp 6
2365
2366 On other platforms than Windows, "Default" and "." would be
2367 treated as regular subkeys.
2368
2369 \section2 Platform Limitations
2370
2371 While QSettings attempts to smooth over the differences between
2372 the different supported platforms, there are still a few
2373 differences that you should be aware of when porting your
2374 application:
2375
2376 \list
2377 \li The Windows system registry has the following limitations: A
2378 subkey may not exceed 255 characters, an entry's value may
2379 not exceed 16,383 characters, and all the values of a key may
2380 not exceed 65,535 characters. One way to work around these
2381 limitations is to store the settings using the IniFormat
2382 instead of the NativeFormat.
2383
2384 \li On Windows, when the Windows system registry is used, QSettings
2385 does not preserve the original type of the value. Therefore,
2386 the type of the value might change when a new value is set. For
2387 example, a value with type \c REG_EXPAND_SZ will change to \c REG_SZ.
2388
2389 \li On \macos and iOS, allKeys() will return some extra keys for global
2390 settings that apply to all applications. These keys can be
2391 read using value() but cannot be changed, only shadowed.
2392 Calling setFallbacksEnabled(false) will hide these global
2393 settings.
2394
2395 \li On \macos and iOS, the CFPreferences API used by QSettings expects
2396 Internet domain names rather than organization names. To
2397 provide a uniform API, QSettings derives a fake domain name
2398 from the organization name (unless the organization name
2399 already is a domain name, e.g. OpenOffice.org). The algorithm
2400 appends ".com" to the company name and replaces spaces and
2401 other illegal characters with hyphens. If you want to specify
2402 a different domain name, call
2403 QCoreApplication::setOrganizationDomain(),
2404 QCoreApplication::setOrganizationName(), and
2405 QCoreApplication::setApplicationName() in your \c main()
2406 function and then use the default QSettings constructor.
2407 Another solution is to use preprocessor directives, for
2408 example:
2409
2410 \snippet code/src_corelib_io_qsettings.cpp 7
2411
2412 \li On \macos, permissions to access settings not belonging to the
2413 current user (i.e. SystemScope) have changed with 10.7 (Lion). Prior to
2414 that version, users having admin rights could access these. For 10.7 and
2415 10.8 (Mountain Lion), only root can. However, 10.9 (Mavericks) changes
2416 that rule again but only for the native format (plist files).
2417
2418 \endlist
2419
2420 \sa QVariant, QSessionManager, {Settings Editor Example}, {Application Example}
2421*/
2422
2423/*! \enum QSettings::Status
2424
2425 The following status values are possible:
2426
2427 \value NoError No error occurred.
2428 \value AccessError An access error occurred (e.g. trying to write to a read-only file).
2429 \value FormatError A format error occurred (e.g. loading a malformed INI file).
2430
2431 \sa status()
2432*/
2433
2434/*! \enum QSettings::Format
2435
2436 This enum type specifies the storage format used by QSettings.
2437
2438 \value NativeFormat Store the settings using the most
2439 appropriate storage format for the platform.
2440 On Windows, this means the system registry;
2441 on \macos and iOS, this means the CFPreferences
2442 API; on Unix, this means textual
2443 configuration files in INI format.
2444 \value Registry32Format Windows only: Explicitly access the 32-bit system registry
2445 from a 64-bit application running on 64-bit Windows.
2446 On 32-bit Windows or from a 32-bit application on 64-bit Windows,
2447 this works the same as specifying NativeFormat.
2448 This enum value was added in Qt 5.7.
2449 \value Registry64Format Windows only: Explicitly access the 64-bit system registry
2450 from a 32-bit application running on 64-bit Windows.
2451 On 32-bit Windows or from a 64-bit application on 64-bit Windows,
2452 this works the same as specifying NativeFormat.
2453 This enum value was added in Qt 5.7.
2454 \value IniFormat Store the settings in INI files. Note that type information
2455 is not preserved when reading settings from INI files;
2456 all values will be returned as QString.
2457
2458 \value InvalidFormat Special value returned by registerFormat().
2459 \omitvalue CustomFormat1
2460 \omitvalue CustomFormat2
2461 \omitvalue CustomFormat3
2462 \omitvalue CustomFormat4
2463 \omitvalue CustomFormat5
2464 \omitvalue CustomFormat6
2465 \omitvalue CustomFormat7
2466 \omitvalue CustomFormat8
2467 \omitvalue CustomFormat9
2468 \omitvalue CustomFormat10
2469 \omitvalue CustomFormat11
2470 \omitvalue CustomFormat12
2471 \omitvalue CustomFormat13
2472 \omitvalue CustomFormat14
2473 \omitvalue CustomFormat15
2474 \omitvalue CustomFormat16
2475
2476 On Unix, NativeFormat and IniFormat mean the same thing, except
2477 that the file extension is different (\c .conf for NativeFormat,
2478 \c .ini for IniFormat).
2479
2480 The INI file format is a Windows file format that Qt supports on
2481 all platforms. In the absence of an INI standard, we try to
2482 follow what Microsoft does, with the following exceptions:
2483
2484 \list
2485 \li If you store types that QVariant can't convert to QString
2486 (e.g., QPoint, QRect, and QSize), Qt uses an \c{@}-based
2487 syntax to encode the type. For example:
2488
2489 \snippet code/src_corelib_io_qsettings.cpp 8
2490
2491 To minimize compatibility issues, any \c @ that doesn't
2492 appear at the first position in the value or that isn't
2493 followed by a Qt type (\c Point, \c Rect, \c Size, etc.) is
2494 treated as a normal character.
2495
2496 \li Although backslash is a special character in INI files, most
2497 Windows applications don't escape backslashes (\c{\}) in file
2498 paths:
2499
2500 \snippet code/src_corelib_io_qsettings.cpp 9
2501
2502 QSettings always treats backslash as a special character and
2503 provides no API for reading or writing such entries.
2504
2505 \li The INI file format has severe restrictions on the syntax of
2506 a key. Qt works around this by using \c % as an escape
2507 character in keys. In addition, if you save a top-level
2508 setting (a key with no slashes in it, e.g., "someKey"), it
2509 will appear in the INI file's "General" section. To avoid
2510 overwriting other keys, if you save something using a key
2511 such as "General/someKey", the key will be located in the
2512 "%General" section, \e not in the "General" section.
2513
2514 \li Following the philosophy that we should be liberal in what
2515 we accept and conservative in what we generate, QSettings
2516 will accept Latin-1 encoded INI files, but generate pure
2517 ASCII files, where non-ASCII values are encoded using standard
2518 INI escape sequences. To make the INI files more readable (but
2519 potentially less compatible), call setIniCodec().
2520 \endlist
2521
2522 \sa registerFormat(), setPath()
2523*/
2524
2525/*! \enum QSettings::Scope
2526
2527 This enum specifies whether settings are user-specific or shared
2528 by all users of the same system.
2529
2530 \value UserScope Store settings in a location specific to the
2531 current user (e.g., in the user's home
2532 directory).
2533 \value SystemScope Store settings in a global location, so that
2534 all users on the same machine access the same
2535 set of settings.
2536
2537 \sa setPath()
2538*/
2539
2540#ifndef QT_NO_QOBJECT
2541/*!
2542 Constructs a QSettings object for accessing settings of the
2543 application called \a application from the organization called \a
2544 organization, and with parent \a parent.
2545
2546 Example:
2547 \snippet code/src_corelib_io_qsettings.cpp 10
2548
2549 The scope is set to QSettings::UserScope, and the format is
2550 set to QSettings::NativeFormat (i.e. calling setDefaultFormat()
2551 before calling this constructor has no effect).
2552
2553 \sa setDefaultFormat(), {Fallback Mechanism}
2554*/
2555QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2556 : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2557 parent)
2558{
2559}
2560
2561/*!
2562 Constructs a QSettings object for accessing settings of the
2563 application called \a application from the organization called \a
2564 organization, and with parent \a parent.
2565
2566 If \a scope is QSettings::UserScope, the QSettings object searches
2567 user-specific settings first, before it searches system-wide
2568 settings as a fallback. If \a scope is QSettings::SystemScope, the
2569 QSettings object ignores user-specific settings and provides
2570 access to system-wide settings.
2571
2572 The storage format is set to QSettings::NativeFormat (i.e. calling
2573 setDefaultFormat() before calling this constructor has no effect).
2574
2575 If no application name is given, the QSettings object will
2576 only access the organization-wide \l{Fallback Mechanism}{locations}.
2577
2578 \sa setDefaultFormat()
2579*/
2580QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2581 QObject *parent)
2582 : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2583{
2584}
2585
2586/*!
2587 Constructs a QSettings object for accessing settings of the
2588 application called \a application from the organization called
2589 \a organization, and with parent \a parent.
2590
2591 If \a scope is QSettings::UserScope, the QSettings object searches
2592 user-specific settings first, before it searches system-wide
2593 settings as a fallback. If \a scope is
2594 QSettings::SystemScope, the QSettings object ignores user-specific
2595 settings and provides access to system-wide settings.
2596
2597 If \a format is QSettings::NativeFormat, the native API is used for
2598 storing settings. If \a format is QSettings::IniFormat, the INI format
2599 is used.
2600
2601 If no application name is given, the QSettings object will
2602 only access the organization-wide \l{Fallback Mechanism}{locations}.
2603*/
2604QSettings::QSettings(Format format, Scope scope, const QString &organization,
2605 const QString &application, QObject *parent)
2606 : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2607{
2608}
2609
2610/*!
2611 Constructs a QSettings object for accessing the settings
2612 stored in the file called \a fileName, with parent \a parent. If
2613 the file doesn't already exist, it is created.
2614
2615 If \a format is QSettings::NativeFormat, the meaning of \a
2616 fileName depends on the platform. On Unix, \a fileName is the
2617 name of an INI file. On \macos and iOS, \a fileName is the name of a
2618 \c .plist file. On Windows, \a fileName is a path in the system
2619 registry.
2620
2621 If \a format is QSettings::IniFormat, \a fileName is the name of an INI
2622 file.
2623
2624 \warning This function is provided for convenience. It works well for
2625 accessing INI or \c .plist files generated by Qt, but might fail on some
2626 syntaxes found in such files originated by other programs. In particular,
2627 be aware of the following limitations:
2628
2629 \list
2630 \li QSettings provides no way of reading INI "path" entries, i.e., entries
2631 with unescaped slash characters. (This is because these entries are
2632 ambiguous and cannot be resolved automatically.)
2633 \li In INI files, QSettings uses the \c @ character as a metacharacter in some
2634 contexts, to encode Qt-specific data types (e.g., \c @Rect), and might
2635 therefore misinterpret it when it occurs in pure INI files.
2636 \endlist
2637
2638 \sa fileName()
2639*/
2640QSettings::QSettings(const QString &fileName, Format format, QObject *parent)
2641 : QObject(*QSettingsPrivate::create(fileName, format), parent)
2642{
2643}
2644
2645/*!
2646 Constructs a QSettings object for accessing settings of the
2647 application and organization set previously with a call to
2648 QCoreApplication::setOrganizationName(),
2649 QCoreApplication::setOrganizationDomain(), and
2650 QCoreApplication::setApplicationName().
2651
2652 The scope is QSettings::UserScope and the format is
2653 defaultFormat() (QSettings::NativeFormat by default).
2654 Use setDefaultFormat() before calling this constructor
2655 to change the default format used by this constructor.
2656
2657 The code
2658
2659 \snippet code/src_corelib_io_qsettings.cpp 11
2660
2661 is equivalent to
2662
2663 \snippet code/src_corelib_io_qsettings.cpp 12
2664
2665 If QCoreApplication::setOrganizationName() and
2666 QCoreApplication::setApplicationName() has not been previously
2667 called, the QSettings object will not be able to read or write
2668 any settings, and status() will return AccessError.
2669
2670 You should supply both the domain (used by default on \macos and iOS) and
2671 the name (used by default elsewhere), although the code will cope if you
2672 supply only one, which will then be used (on all platforms), at odds with
2673 the usual naming of the file on platforms for which it isn't the default.
2674
2675 \sa QCoreApplication::setOrganizationName(),
2676 QCoreApplication::setOrganizationDomain(),
2677 QCoreApplication::setApplicationName(),
2678 setDefaultFormat()
2679*/
2680QSettings::QSettings(QObject *parent)
2681 : QSettings(UserScope, parent)
2682{
2683}
2684
2685/*!
2686 \since 5.13
2687
2688 Constructs a QSettings object in the same way as
2689 QSettings(QObject *parent) but with the given \a scope.
2690
2691 \sa QSettings(QObject *parent)
2692*/
2693QSettings::QSettings(Scope scope, QObject *parent)
2694 : QObject(*QSettingsPrivate::create(globalDefaultFormat, scope,
2695#ifdef Q_OS_DARWIN
2696 QCoreApplication::organizationDomain().isEmpty()
2697 ? QCoreApplication::organizationName()
2698 : QCoreApplication::organizationDomain()
2699#else
2700 QCoreApplication::organizationName().isEmpty()
2701 ? QCoreApplication::organizationDomain()
2702 : QCoreApplication::organizationName()
2703#endif
2704 , QCoreApplication::applicationName()),
2705 parent)
2706{
2707}
2708
2709#else
2710QSettings::QSettings(const QString &organization, const QString &application)
2711 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2712{
2713 d_ptr->q_ptr = this;
2714}
2715
2716QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2717 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2718{
2719 d_ptr->q_ptr = this;
2720}
2721
2722QSettings::QSettings(Format format, Scope scope, const QString &organization,
2723 const QString &application)
2724 : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2725{
2726 d_ptr->q_ptr = this;
2727}
2728
2729QSettings::QSettings(const QString &fileName, Format format)
2730 : d_ptr(QSettingsPrivate::create(fileName, format))
2731{
2732 d_ptr->q_ptr = this;
2733}
2734
2735# ifndef QT_BUILD_QMAKE
2736QSettings::QSettings(Scope scope)
2737 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope,
2738# ifdef Q_OS_DARWIN
2739 QCoreApplication::organizationDomain().isEmpty()
2740 ? QCoreApplication::organizationName()
2741 : QCoreApplication::organizationDomain()
2742# else
2743 QCoreApplication::organizationName().isEmpty()
2744 ? QCoreApplication::organizationDomain()
2745 : QCoreApplication::organizationName()
2746# endif
2747 , QCoreApplication::applicationName())
2748 )
2749{
2750 d_ptr->q_ptr = this;
2751}
2752# endif
2753#endif
2754
2755/*!
2756 Destroys the QSettings object.
2757
2758 Any unsaved changes will eventually be written to permanent
2759 storage.
2760
2761 \sa sync()
2762*/
2763QSettings::~QSettings()
2764{
2765 Q_D(QSettings);
2766 if (d->pendingChanges) {
2767 QT_TRY {
2768 d->flush();
2769 } QT_CATCH(...) {
2770 ; // ok. then don't flush but at least don't throw in the destructor
2771 }
2772 }
2773}
2774
2775/*!
2776 Removes all entries in the primary location associated to this
2777 QSettings object.
2778
2779 Entries in fallback locations are not removed.
2780
2781 If you only want to remove the entries in the current group(),
2782 use remove("") instead.
2783
2784 \sa remove(), setFallbacksEnabled()
2785*/
2786void QSettings::clear()
2787{
2788 Q_D(QSettings);
2789 d->clear();
2790 d->requestUpdate();
2791}
2792
2793/*!
2794 Writes any unsaved changes to permanent storage, and reloads any
2795 settings that have been changed in the meantime by another
2796 application.
2797
2798 This function is called automatically from QSettings's destructor and
2799 by the event loop at regular intervals, so you normally don't need to
2800 call it yourself.
2801
2802 \sa status()
2803*/
2804void QSettings::sync()
2805{
2806 Q_D(QSettings);
2807 d->sync();
2808 d->pendingChanges = false;
2809}
2810
2811/*!
2812 Returns the path where settings written using this QSettings
2813 object are stored.
2814
2815 On Windows, if the format is QSettings::NativeFormat, the return value
2816 is a system registry path, not a file path.
2817
2818 \sa isWritable(), format()
2819*/
2820QString QSettings::fileName() const
2821{
2822 Q_D(const QSettings);
2823 return d->fileName();
2824}
2825
2826/*!
2827 \since 4.4
2828
2829 Returns the format used for storing the settings.
2830
2831 \sa defaultFormat(), fileName(), scope(), organizationName(), applicationName()
2832*/
2833QSettings::Format QSettings::format() const
2834{
2835 Q_D(const QSettings);
2836 return d->format;
2837}
2838
2839/*!
2840 \since 4.4
2841
2842 Returns the scope used for storing the settings.
2843
2844 \sa format(), organizationName(), applicationName()
2845*/
2846QSettings::Scope QSettings::scope() const
2847{
2848 Q_D(const QSettings);
2849 return d->scope;
2850}
2851
2852/*!
2853 \since 4.4
2854
2855 Returns the organization name used for storing the settings.
2856
2857 \sa QCoreApplication::organizationName(), format(), scope(), applicationName()
2858*/
2859QString QSettings::organizationName() const
2860{
2861 Q_D(const QSettings);
2862 return d->organizationName;
2863}
2864
2865/*!
2866 \since 4.4
2867
2868 Returns the application name used for storing the settings.
2869
2870 \sa QCoreApplication::applicationName(), format(), scope(), organizationName()
2871*/
2872QString QSettings::applicationName() const
2873{
2874 Q_D(const QSettings);
2875 return d->applicationName;
2876}
2877
2878#if QT_CONFIG(textcodec)
2879
2880/*!
2881 \since 4.5
2882
2883 Sets the codec for accessing INI files (including \c .conf files on Unix)
2884 to \a codec. The codec is used for decoding any data that is read from
2885 the INI file, and for encoding any data that is written to the file. By
2886 default, no codec is used, and non-ASCII characters are encoded using
2887 standard INI escape sequences.
2888
2889 \warning The codec must be set immediately after creating the QSettings
2890 object, before accessing any data.
2891
2892 \sa iniCodec()
2893*/
2894void QSettings::setIniCodec(QTextCodec *codec)
2895{
2896 Q_D(QSettings);
2897 d->iniCodec = codec;
2898}
2899
2900/*!
2901 \since 4.5
2902 \overload
2903
2904 Sets the codec for accessing INI files (including \c .conf files on Unix)
2905 to the QTextCodec for the encoding specified by \a codecName. Common
2906 values for \c codecName include "ISO 8859-1", "UTF-8", and "UTF-16".
2907 If the encoding isn't recognized, nothing happens.
2908
2909 \sa QTextCodec::codecForName()
2910*/
2911void QSettings::setIniCodec(const char *codecName)
2912{
2913 Q_D(QSettings);
2914 if (QTextCodec *codec = QTextCodec::codecForName(codecName))
2915 d->iniCodec = codec;
2916}
2917
2918/*!
2919 \since 4.5
2920
2921 Returns the codec that is used for accessing INI files. By default,
2922 no codec is used, so a null pointer is returned.
2923*/
2924
2925QTextCodec *QSettings::iniCodec() const
2926{
2927 Q_D(const QSettings);
2928 return d->iniCodec;
2929}
2930
2931#endif // textcodec
2932
2933/*!
2934 Returns a status code indicating the first error that was met by
2935 QSettings, or QSettings::NoError if no error occurred.
2936
2937 Be aware that QSettings delays performing some operations. For this
2938 reason, you might want to call sync() to ensure that the data stored
2939 in QSettings is written to disk before calling status().
2940
2941 \sa sync()
2942*/
2943QSettings::Status QSettings::status() const
2944{
2945 Q_D(const QSettings);
2946 return d->status;
2947}
2948
2949/*!
2950 \since 5.10
2951
2952 Returns \c true if QSettings is only allowed to perform atomic saving and
2953 reloading (synchronization) of the settings. Returns \c false if it is
2954 allowed to save the settings contents directly to the configuration file.
2955
2956 The default is \c true.
2957
2958 \sa setAtomicSyncRequired(), QSaveFile
2959*/
2960bool QSettings::isAtomicSyncRequired() const
2961{
2962 Q_D(const QSettings);
2963 return d->atomicSyncOnly;
2964}
2965
2966/*!
2967 \since 5.10
2968
2969 Configures whether QSettings is required to perform atomic saving and
2970 reloading (synchronization) of the settings. If the \a enable argument is
2971 \c true (the default), sync() will only perform synchronization operations
2972 that are atomic. If this is not possible, sync() will fail and status()
2973 will be an error condition.
2974
2975 Setting this property to \c false will allow QSettings to write directly to
2976 the configuration file and ignore any errors trying to lock it against
2977 other processes trying to write at the same time. Because of the potential
2978 for corruption, this option should be used with care, but is required in
2979 certain conditions, like a QSettings::IniFormat configuration file that
2980 exists in an otherwise non-writeable directory or NTFS Alternate Data
2981 Streams.
2982
2983 See \l QSaveFile for more information on the feature.
2984
2985 \sa isAtomicSyncRequired(), QSaveFile
2986*/
2987void QSettings::setAtomicSyncRequired(bool enable)
2988{
2989 Q_D(QSettings);
2990 d->atomicSyncOnly = enable;
2991}
2992
2993/*!
2994 Appends \a prefix to the current group.
2995
2996 The current group is automatically prepended to all keys
2997 specified to QSettings. In addition, query functions such as
2998 childGroups(), childKeys(), and allKeys() are based on the group.
2999 By default, no group is set.
3000
3001 Groups are useful to avoid typing in the same setting paths over
3002 and over. For example:
3003
3004 \snippet code/src_corelib_io_qsettings.cpp 13
3005
3006 This will set the value of three settings:
3007
3008 \list
3009 \li \c mainwindow/size
3010 \li \c mainwindow/fullScreen
3011 \li \c outputpanel/visible
3012 \endlist
3013
3014 Call endGroup() to reset the current group to what it was before
3015 the corresponding beginGroup() call. Groups can be nested.
3016
3017 \sa endGroup(), group()
3018*/
3019void QSettings::beginGroup(const QString &prefix)
3020{
3021 Q_D(QSettings);
3022 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
3023}
3024
3025/*!
3026 Resets the group to what it was before the corresponding
3027 beginGroup() call.
3028
3029 Example:
3030
3031 \snippet code/src_corelib_io_qsettings.cpp 14
3032
3033 \sa beginGroup(), group()
3034*/
3035void QSettings::endGroup()
3036{
3037 Q_D(QSettings);
3038 if (d->groupStack.isEmpty()) {
3039 qWarning("QSettings::endGroup: No matching beginGroup()");
3040 return;
3041 }
3042
3043 QSettingsGroup group = d->groupStack.pop();
3044 int len = group.toString().size();
3045 if (len > 0)
3046 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3047
3048 if (group.isArray())
3049 qWarning("QSettings::endGroup: Expected endArray() instead");
3050}
3051
3052/*!
3053 Returns the current group.
3054
3055 \sa beginGroup(), endGroup()
3056*/
3057QString QSettings::group() const
3058{
3059 Q_D(const QSettings);
3060 return d->groupPrefix.left(d->groupPrefix.size() - 1);
3061}
3062
3063/*!
3064 Adds \a prefix to the current group and starts reading from an
3065 array. Returns the size of the array.
3066
3067 Example:
3068
3069 \snippet code/src_corelib_io_qsettings.cpp 15
3070
3071 Use beginWriteArray() to write the array in the first place.
3072
3073 \sa beginWriteArray(), endArray(), setArrayIndex()
3074*/
3075int QSettings::beginReadArray(const QString &prefix)
3076{
3077 Q_D(QSettings);
3078 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
3079 return value(QLatin1String("size")).toInt();
3080}
3081
3082/*!
3083 Adds \a prefix to the current group and starts writing an array
3084 of size \a size. If \a size is -1 (the default), it is automatically
3085 determined based on the indexes of the entries written.
3086
3087 If you have many occurrences of a certain set of keys, you can
3088 use arrays to make your life easier. For example, let's suppose
3089 that you want to save a variable-length list of user names and
3090 passwords. You could then write:
3091
3092 \snippet code/src_corelib_io_qsettings.cpp 16
3093
3094 The generated keys will have the form
3095
3096 \list
3097 \li \c logins/size
3098 \li \c logins/1/userName
3099 \li \c logins/1/password
3100 \li \c logins/2/userName
3101 \li \c logins/2/password
3102 \li \c logins/3/userName
3103 \li \c logins/3/password
3104 \li ...
3105 \endlist
3106
3107 To read back an array, use beginReadArray().
3108
3109 \sa beginReadArray(), endArray(), setArrayIndex()
3110*/
3111void QSettings::beginWriteArray(const QString &prefix, int size)
3112{
3113 Q_D(QSettings);
3114 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3115
3116 if (size < 0)
3117 remove(QLatin1String("size"));
3118 else
3119 setValue(QLatin1String("size"), size);
3120}
3121
3122/*!
3123 Closes the array that was started using beginReadArray() or
3124 beginWriteArray().
3125
3126 \sa beginReadArray(), beginWriteArray()
3127*/
3128void QSettings::endArray()
3129{
3130 Q_D(QSettings);
3131 if (d->groupStack.isEmpty()) {
3132 qWarning("QSettings::endArray: No matching beginArray()");
3133 return;
3134 }
3135
3136 QSettingsGroup group = d->groupStack.top();
3137 int len = group.toString().size();
3138 d->groupStack.pop();
3139 if (len > 0)
3140 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3141
3142 if (group.arraySizeGuess() != -1)
3143 setValue(group.name() + QLatin1String("/size"), group.arraySizeGuess());
3144
3145 if (!group.isArray())
3146 qWarning("QSettings::endArray: Expected endGroup() instead");
3147}
3148
3149/*!
3150 Sets the current array index to \a i. Calls to functions such as
3151 setValue(), value(), remove(), and contains() will operate on the
3152 array entry at that index.
3153
3154 You must call beginReadArray() or beginWriteArray() before you
3155 can call this function.
3156*/
3157void QSettings::setArrayIndex(int i)
3158{
3159 Q_D(QSettings);
3160 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3161 qWarning("QSettings::setArrayIndex: Missing beginArray()");
3162 return;
3163 }
3164
3165 QSettingsGroup &top = d->groupStack.top();
3166 int len = top.toString().size();
3167 top.setArrayIndex(qMax(i, 0));
3168 d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3169}
3170
3171/*!
3172 Returns a list of all keys, including subkeys, that can be read
3173 using the QSettings object.
3174
3175 Example:
3176
3177 \snippet code/src_corelib_io_qsettings.cpp 17
3178
3179 If a group is set using beginGroup(), only the keys in the group
3180 are returned, without the group prefix:
3181
3182 \snippet code/src_corelib_io_qsettings.cpp 18
3183
3184 \sa childGroups(), childKeys()
3185*/
3186QStringList QSettings::allKeys() const
3187{
3188 Q_D(const QSettings);
3189 return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3190}
3191
3192/*!
3193 Returns a list of all top-level keys that can be read using the
3194 QSettings object.
3195
3196 Example:
3197
3198 \snippet code/src_corelib_io_qsettings.cpp 19
3199
3200 If a group is set using beginGroup(), the top-level keys in that
3201 group are returned, without the group prefix:
3202
3203 \snippet code/src_corelib_io_qsettings.cpp 20
3204
3205 You can navigate through the entire setting hierarchy using
3206 childKeys() and childGroups() recursively.
3207
3208 \sa childGroups(), allKeys()
3209*/
3210QStringList QSettings::childKeys() const
3211{
3212 Q_D(const QSettings);
3213 return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3214}
3215
3216/*!
3217 Returns a list of all key top-level groups that contain keys that
3218 can be read using the QSettings object.
3219
3220 Example:
3221
3222 \snippet code/src_corelib_io_qsettings.cpp 21
3223
3224 If a group is set using beginGroup(), the first-level keys in
3225 that group are returned, without the group prefix.
3226
3227 \snippet code/src_corelib_io_qsettings.cpp 22
3228
3229 You can navigate through the entire setting hierarchy using
3230 childKeys() and childGroups() recursively.
3231
3232 \sa childKeys(), allKeys()
3233*/
3234QStringList QSettings::childGroups() const
3235{
3236 Q_D(const QSettings);
3237 return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3238}
3239
3240/*!
3241 Returns \c true if settings can be written using this QSettings
3242 object; returns \c false otherwise.
3243
3244 One reason why isWritable() might return false is if
3245 QSettings operates on a read-only file.
3246
3247 \warning This function is not perfectly reliable, because the
3248 file permissions can change at any time.
3249
3250 \sa fileName(), status(), sync()
3251*/
3252bool QSettings::isWritable() const
3253{
3254 Q_D(const QSettings);
3255 return d->isWritable();
3256}
3257
3258/*!
3259
3260 Sets the value of setting \a key to \a value. If the \a key already
3261 exists, the previous value is overwritten.
3262
3263 Note that the Windows registry and INI files use case-insensitive
3264 keys, whereas the CFPreferences API on \macos and iOS uses
3265 case-sensitive keys. To avoid portability problems, see the
3266 \l{Section and Key Syntax} rules.
3267
3268 Example:
3269
3270 \snippet code/src_corelib_io_qsettings.cpp 23
3271
3272 \sa value(), remove(), contains()
3273*/
3274void QSettings::setValue(const QString &key, const QVariant &value)
3275{
3276 Q_D(QSettings);
3277 if (key.isEmpty()) {
3278 qWarning("QSettings::setValue: Empty key passed");
3279 return;
3280 }
3281 QString k = d->actualKey(key);
3282 d->set(k, value);
3283 d->requestUpdate();
3284}
3285
3286/*!
3287 Removes the setting \a key and any sub-settings of \a key.
3288
3289 Example:
3290
3291 \snippet code/src_corelib_io_qsettings.cpp 24
3292
3293 Be aware that if one of the fallback locations contains a setting
3294 with the same key, that setting will be visible after calling
3295 remove().
3296
3297 If \a key is an empty string, all keys in the current group() are
3298 removed. For example:
3299
3300 \snippet code/src_corelib_io_qsettings.cpp 25
3301
3302 Note that the Windows registry and INI files use case-insensitive
3303 keys, whereas the CFPreferences API on \macos and iOS uses
3304 case-sensitive keys. To avoid portability problems, see the
3305 \l{Section and Key Syntax} rules.
3306
3307 \sa setValue(), value(), contains()
3308*/
3309void QSettings::remove(const QString &key)
3310{
3311 Q_D(QSettings);
3312 /*
3313 We cannot use actualKey(), because remove() supports empty
3314 keys. The code is also tricky because of slash handling.
3315 */
3316 QString theKey = d->normalizedKey(key);
3317 if (theKey.isEmpty())
3318 theKey = group();
3319 else
3320 theKey.prepend(d->groupPrefix);
3321
3322 if (theKey.isEmpty()) {
3323 d->clear();
3324 } else {
3325 d->remove(theKey);
3326 }
3327 d->requestUpdate();
3328}
3329
3330/*!
3331 Returns \c true if there exists a setting called \a key; returns
3332 false otherwise.
3333
3334 If a group is set using beginGroup(), \a key is taken to be
3335 relative to that group.
3336
3337 Note that the Windows registry and INI files use case-insensitive
3338 keys, whereas the CFPreferences API on \macos and iOS uses
3339 case-sensitive keys. To avoid portability problems, see the
3340 \l{Section and Key Syntax} rules.
3341
3342 \sa value(), setValue()
3343*/
3344bool QSettings::contains(const QString &key) const
3345{
3346 Q_D(const QSettings);
3347 QString k = d->actualKey(key);
3348 return d->get(k, 0);
3349}
3350
3351/*!
3352 Sets whether fallbacks are enabled to \a b.
3353
3354 By default, fallbacks are enabled.
3355
3356 \sa fallbacksEnabled()
3357*/
3358void QSettings::setFallbacksEnabled(bool b)
3359{
3360 Q_D(QSettings);
3361 d->fallbacks = !!b;
3362}
3363
3364/*!
3365 Returns \c true if fallbacks are enabled; returns \c false otherwise.
3366
3367 By default, fallbacks are enabled.
3368
3369 \sa setFallbacksEnabled()
3370*/
3371bool QSettings::fallbacksEnabled() const
3372{
3373 Q_D(const QSettings);
3374 return d->fallbacks;
3375}
3376
3377#ifndef QT_NO_QOBJECT
3378/*!
3379 \reimp
3380*/
3381bool QSettings::event(QEvent *event)
3382{
3383 Q_D(QSettings);
3384 if (event->type() == QEvent::UpdateRequest) {
3385 d->update();
3386 return true;
3387 }
3388 return QObject::event(event);
3389}
3390#endif
3391
3392/*!
3393 Returns the value for setting \a key. If the setting doesn't
3394 exist, returns \a defaultValue.
3395
3396 If no default value is specified, a default QVariant is
3397 returned.
3398
3399 Note that the Windows registry and INI files use case-insensitive
3400 keys, whereas the CFPreferences API on \macos and iOS uses
3401 case-sensitive keys. To avoid portability problems, see the
3402 \l{Section and Key Syntax} rules.
3403
3404 Example:
3405
3406 \snippet code/src_corelib_io_qsettings.cpp 26
3407
3408 \sa setValue(), contains(), remove()
3409*/
3410QVariant QSettings::value(const QString &key, const QVariant &defaultValue) const
3411{
3412 Q_D(const QSettings);
3413 if (key.isEmpty()) {
3414 qWarning("QSettings::value: Empty key passed");
3415 return QVariant();
3416 }
3417 QVariant result = defaultValue;
3418 QString k = d->actualKey(key);
3419 d->get(k, &result);
3420 return result;
3421}
3422
3423/*!
3424 \since 4.4
3425
3426 Sets the default file format to the given \a format, which is used
3427 for storing settings for the QSettings(QObject *) constructor.
3428
3429 If no default format is set, QSettings::NativeFormat is used. See
3430 the documentation for the QSettings constructor you are using to
3431 see if that constructor will ignore this function.
3432
3433 \sa format()
3434*/
3435void QSettings::setDefaultFormat(Format format)
3436{
3437 globalDefaultFormat = format;
3438}
3439
3440/*!
3441 \since 4.4
3442
3443 Returns default file format used for storing settings for the QSettings(QObject *) constructor.
3444 If no default format is set, QSettings::NativeFormat is used.
3445
3446 \sa format()
3447*/
3448QSettings::Format QSettings::defaultFormat()
3449{
3450 return globalDefaultFormat;
3451}
3452
3453#if QT_DEPRECATED_SINCE(5, 13)
3454/*!
3455 \obsolete
3456
3457 Use setPath() instead.
3458
3459 \oldcode
3460 setSystemIniPath(path);
3461 \newcode
3462 setPath(QSettings::NativeFormat, QSettings::SystemScope, path);
3463 setPath(QSettings::IniFormat, QSettings::SystemScope, path);
3464 \endcode
3465*/
3466void QSettings::setSystemIniPath(const QString &dir)
3467{
3468 setPath(IniFormat, SystemScope, dir);
3469#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3470 setPath(NativeFormat, SystemScope, dir);
3471#endif
3472}
3473
3474/*!
3475 \obsolete
3476
3477 Use setPath() instead.
3478*/
3479
3480void QSettings::setUserIniPath(const QString &dir)
3481{
3482 setPath(IniFormat, UserScope, dir);
3483#if !defined(Q_OS_WIN) && !defined(Q_OS_MAC)
3484 setPath(NativeFormat, UserScope, dir);
3485#endif
3486}
3487#endif
3488/*!
3489 \since 4.1
3490
3491 Sets the path used for storing settings for the given \a format
3492 and \a scope, to \a path. The \a format can be a custom format.
3493
3494 The table below summarizes the default values:
3495
3496 \table
3497 \header \li Platform \li Format \li Scope \li Path
3498 \row \li{1,2} Windows \li{1,2} IniFormat \li UserScope \li \c FOLDERID_RoamingAppData
3499 \row \li SystemScope \li \c FOLDERID_ProgramData
3500 \row \li{1,2} Unix \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/.config
3501 \row \li SystemScope \li \c /etc/xdg
3502 \row \li{1,2} Qt for Embedded Linux \li{1,2} NativeFormat, IniFormat \li UserScope \li \c $HOME/Settings
3503 \row \li SystemScope \li \c /etc/xdg
3504 \row \li{1,2} \macos and iOS \li{1,2} IniFormat \li UserScope \li \c $HOME/.config
3505 \row \li SystemScope \li \c /etc/xdg
3506 \endtable
3507
3508 The default UserScope paths on Unix, \macos, and iOS (\c
3509 $HOME/.config or $HOME/Settings) can be overridden by the user by setting the
3510 \c XDG_CONFIG_HOME environment variable. The default SystemScope
3511 paths on Unix, \macos, and iOS (\c /etc/xdg) can be overridden when
3512 building the Qt library using the \c configure script's \c
3513 -sysconfdir flag (see QLibraryInfo for details).
3514
3515 Setting the NativeFormat paths on Windows, \macos, and iOS has no
3516 effect.
3517
3518 \warning This function doesn't affect existing QSettings objects.
3519
3520 \sa registerFormat()
3521*/
3522void QSettings::setPath(Format format, Scope scope, const QString &path)
3523{
3524 QMutexLocker locker(&settingsGlobalMutex);
3525 PathHash *pathHash = pathHashFunc();
3526 if (pathHash->isEmpty())
3527 initDefaultPaths(&locker);
3528 pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3529}
3530
3531/*!
3532 \typedef QSettings::SettingsMap
3533
3534 Typedef for QMap<QString, QVariant>.
3535
3536 \sa registerFormat()
3537*/
3538
3539/*!
3540 \typedef QSettings::ReadFunc
3541
3542 Typedef for a pointer to a function with the following signature:
3543
3544 \snippet code/src_corelib_io_qsettings.cpp 27
3545
3546 \c ReadFunc is used in \c registerFormat() as a pointer to a function
3547 that reads a set of key/value pairs. \c ReadFunc should read all the
3548 options in one pass, and return all the settings in the \c SettingsMap
3549 container, which is initially empty.
3550
3551 \sa WriteFunc, registerFormat()
3552*/
3553
3554/*!
3555 \typedef QSettings::WriteFunc
3556
3557 Typedef for a pointer to a function with the following signature:
3558
3559 \snippet code/src_corelib_io_qsettings.cpp 28
3560
3561 \c WriteFunc is used in \c registerFormat() as a pointer to a function
3562 that writes a set of key/value pairs. \c WriteFunc is only called once,
3563 so you need to output the settings in one go.
3564
3565 \sa ReadFunc, registerFormat()
3566*/
3567
3568/*!
3569 \since 4.1
3570 \threadsafe
3571
3572 Registers a custom storage format. On success, returns a special
3573 Format value that can then be passed to the QSettings constructor.
3574 On failure, returns InvalidFormat.
3575
3576 The \a extension is the file
3577 extension associated to the format (without the '.').
3578
3579 The \a readFunc and \a writeFunc parameters are pointers to
3580 functions that read and write a set of key/value pairs. The
3581 QIODevice parameter to the read and write functions is always
3582 opened in binary mode (i.e., without the QIODevice::Text flag).
3583
3584 The \a caseSensitivity parameter specifies whether keys are case
3585 sensitive or not. This makes a difference when looking up values
3586 using QSettings. The default is case sensitive.
3587
3588 By default, if you use one of the constructors that work in terms
3589 of an organization name and an application name, the file system
3590 locations used are the same as for IniFormat. Use setPath() to
3591 specify other locations.
3592
3593 Example:
3594
3595 \snippet code/src_corelib_io_qsettings.cpp 29
3596
3597 \sa setPath()
3598*/
3599QSettings::Format QSettings::registerFormat(const QString &extension, ReadFunc readFunc,
3600 WriteFunc writeFunc,
3601 Qt::CaseSensitivity caseSensitivity)
3602{
3603#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3604 Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3605#endif
3606
3607 QMutexLocker locker(&settingsGlobalMutex);
3608 CustomFormatVector *customFormatVector = customFormatVectorFunc();
3609 int index = customFormatVector->size();
3610 if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3611 return QSettings::InvalidFormat;
3612
3613 QConfFileCustomFormat info;
3614 info.extension = QLatin1Char('.') + extension;
3615 info.readFunc = readFunc;
3616 info.writeFunc = writeFunc;
3617 info.caseSensitivity = caseSensitivity;
3618 customFormatVector->append(info);
3619
3620 return QSettings::Format((int)QSettings::CustomFormat1 + index);
3621}
3622
3623QT_END_NAMESPACE
3624
3625#ifndef QT_BOOTSTRAPPED
3626#include "moc_qsettings.cpp"
3627#endif
3628