Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qsettings.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include <qdebug.h>
5#include "qplatformdefs.h"
6#include "qsettings.h"
7
8#include "qsettings_p.h"
9#include "qcache.h"
10#include "qfile.h"
11#include "qdir.h"
12#include "qfileinfo.h"
13#include "qmutex.h"
14#include "private/qlocking_p.h"
15#include "private/qtools_p.h"
16#include "qlibraryinfo.h"
17#include "qtemporaryfile.h"
18#include "qstandardpaths.h"
19#include <qdatastream.h>
20#include "private/qstringconverter_p.h"
21
22#ifndef QT_NO_GEOM_VARIANT
23#include "qsize.h"
24#include "qpoint.h"
25#include "qrect.h"
26#endif // !QT_NO_GEOM_VARIANT
27
28#include "qcoreapplication.h"
29
30#ifndef QT_BOOTSTRAPPED
31#include "qsavefile.h"
32#include "qlockfile.h"
33#endif
34
35#ifdef Q_OS_VXWORKS
36# include <ioLib.h>
37#endif
38
39#include <algorithm>
40#include <stdlib.h>
41
42#ifdef Q_OS_WIN // for homedirpath reading from registry
43# include <qt_windows.h>
44# include <shlobj.h>
45#endif
46
47#if defined(Q_OS_UNIX) && !defined(Q_OS_DARWIN) && !defined(Q_OS_ANDROID)
48#define Q_XDG_PLATFORM
49#endif
50
51#if !defined(QT_NO_STANDARDPATHS) \
52 && (defined(Q_XDG_PLATFORM) || defined(QT_PLATFORM_UIKIT) || defined(Q_OS_ANDROID))
53# define QSETTINGS_USE_QSTANDARDPATHS
54#endif
55
56// ************************************************************************
57// QConfFile
58
59/*
60 QConfFile objects are explicitly shared within the application.
61 This ensures that modification to the settings done through one
62 QSettings object are immediately reflected in other setting
63 objects of the same application.
64*/
65
67
68using namespace Qt::StringLiterals;
69using namespace QtMiscUtils;
70
72{
77};
79
82namespace {
83 struct Path
84 {
85 // Note: Defining constructors explicitly because of buggy C++11
86 // implementation in MSVC (uniform initialization).
87 Path() {}
88 Path(const QString & p, bool ud) : path(p), userDefined(ud) {}
90 bool userDefined = false;
91 };
92}
95
96Q_GLOBAL_STATIC(ConfFileHash, usedHashFunc)
97Q_GLOBAL_STATIC(ConfFileCache, unusedCacheFunc)
98Q_GLOBAL_STATIC(PathHash, pathHashFunc)
99Q_GLOBAL_STATIC(CustomFormatVector, customFormatVectorFunc)
100
102
103Q_CONSTINIT static QSettings::Format globalDefaultFormat = QSettings::NativeFormat;
104
105QConfFile::QConfFile(const QString &fileName, bool _userPerms)
106 : name(fileName), size(0), ref(1), userPerms(_userPerms)
107{
108 usedHashFunc()->insert(name, this);
109}
110
112{
113 if (usedHashFunc())
114 usedHashFunc()->remove(name);
115}
116
118{
120
121 for (auto i = removedKeys.begin(); i != removedKeys.end(); ++i)
122 result.remove(i.key());
123 for (auto i = addedKeys.begin(); i != addedKeys.end(); ++i)
124 result.insert(i.key(), i.value());
125 return result;
126}
127
129{
130 QFileInfo fileInfo(name);
131
132#ifndef QT_NO_TEMPORARYFILE
133 if (fileInfo.exists()) {
134#endif
135 QFile file(name);
136 return file.open(QFile::ReadWrite);
137#ifndef QT_NO_TEMPORARYFILE
138 } else {
139 // Create the directories to the file.
140 QDir dir(fileInfo.absolutePath());
141 if (!dir.exists()) {
142 if (!dir.mkpath(dir.absolutePath()))
143 return false;
144 }
145
146 // we use a temporary file to avoid race conditions
148 return file.open();
149 }
150#endif
151}
152
154{
156
157 ConfFileHash *usedHash = usedHashFunc();
158 ConfFileCache *unusedCache = unusedCacheFunc();
159
160 QConfFile *confFile = nullptr;
161 const auto locker = qt_scoped_lock(settingsGlobalMutex);
162
163 if (!(confFile = usedHash->value(absPath))) {
164 if ((confFile = unusedCache->take(absPath)))
165 usedHash->insert(absPath, confFile);
166 }
167 if (confFile) {
168 confFile->ref.ref();
169 return confFile;
170 }
171 return new QConfFile(absPath, _userPerms);
172}
173
175{
176 const auto locker = qt_scoped_lock(settingsGlobalMutex);
177 unusedCacheFunc()->clear();
178}
179
180// ************************************************************************
181// QSettingsPrivate
182
184 : format(format), scope(QSettings::UserScope /* nothing better to put */), fallbacks(true),
185 pendingChanges(false), status(QSettings::NoError)
186{
187}
188
190 const QString &organization, const QString &application)
191 : format(format), scope(scope), organizationName(organization), applicationName(application),
192 fallbacks(true), pendingChanges(false), status(QSettings::NoError)
193{
194}
195
197{
198}
199
201{
202 auto n = normalizedKey(key);
203 Q_ASSERT_X(!n.isEmpty(), "QSettings", "empty key");
204 return groupPrefix + n;
205}
206
207namespace {
208 // ### this needs some public API (QStringConverter?)
210 {
212 }
214 {
216 }
218 {
219 memcpy(out, v.data(), v.size() * sizeof(QChar));
220 return out + v.size();
221 }
222}
223
224/*
225 Returns a string that never starts nor ends with a slash (or an
226 empty string). Examples:
227
228 "foo" becomes "foo"
229 "/foo//bar///" becomes "foo/bar"
230 "///" becomes ""
231*/
233{
235 auto out = const_cast<QChar*>(result.constData()); // don't detach
236
237 const bool maybeEndsInSlash = key.visit([&out](auto key) {
238 using View = decltype(key);
239
240 auto it = key.begin();
241 const auto end = key.end();
242
243 while (it != end) {
244 while (*it == u'/') {
245 ++it;
246 if (it == end)
247 return true;
248 }
249 auto mark = it;
250 while (*it != u'/') {
251 ++it;
252 if (it == end)
253 break;
254 }
255 out = write(out, View{mark, it});
256 if (it == end)
257 return false;
258 Q_ASSERT(*it == u'/');
259 *out++ = u'/';
260 ++it;
261 }
262 return true;
263 });
264
265 if (maybeEndsInSlash && out != result.constData())
266 --out; // remove the trailing slash
267 result.truncate(out - result.constData());
268 return result;
269}
270
271// see also qsettings_win.cpp and qsettings_mac.cpp
272
273#if !defined(Q_OS_WIN) && !defined(Q_OS_DARWIN) && !defined(Q_OS_WASM)
275 const QString &organization, const QString &application)
276{
277 return new QConfFileSettingsPrivate(format, scope, organization, application);
278}
279#endif
280
281#if !defined(Q_OS_WIN)
283{
285}
286#endif
287
289{
290 if (spec != AllKeys) {
291 qsizetype slashPos = key.indexOf(u'/');
292 if (slashPos == -1) {
293 if (spec != ChildKeys)
294 return;
295 } else {
296 if (spec != ChildGroups)
297 return;
298 key.truncate(slashPos);
299 }
300 }
301 result.append(key.toString());
302}
303
305{
307 const QString name = group.name();
308 if (!name.isEmpty())
309 groupPrefix += name + u'/';
310}
311
312/*
313 We only set an error if there isn't one set already. This way the user always gets the
314 first error that occurred. We always allow clearing errors.
315*/
316
318{
319 if (status == QSettings::NoError || this->status == QSettings::NoError)
320 this->status = status;
321}
322
324{
325 flush();
326 pendingChanges = false;
327}
328
330{
331 if (!pendingChanges) {
332 pendingChanges = true;
333#ifndef QT_NO_QOBJECT
334 Q_Q(QSettings);
336#else
337 update();
338#endif
339 }
340}
341
343{
345 result.reserve(l.size());
346 for (auto v : l)
347 result.append(variantToString(v));
348 return result;
349}
350
352{
353 QStringList outStringList = l;
354 for (qsizetype i = 0; i < outStringList.size(); ++i) {
355 const QString &str = outStringList.at(i);
356
357 if (str.startsWith(u'@')) {
358 if (str.size() < 2 || str.at(1) != u'@') {
359 QVariantList variantList;
360 variantList.reserve(l.size());
361 for (const auto &s : l)
362 variantList.append(stringToVariant(s));
363 return variantList;
364 }
365 outStringList[i].remove(0, 1);
366 }
367 }
368 return outStringList;
369}
370
372{
374
375 switch (v.metaType().id()) {
377 result = "@Invalid()"_L1;
378 break;
379
380 case QMetaType::QByteArray: {
381 QByteArray a = v.toByteArray();
382 result = "@ByteArray("_L1 + QLatin1StringView(a) + u')';
383 break;
384 }
385
386#if QT_CONFIG(shortcut)
387 case QMetaType::QKeySequence:
388#endif
389 case QMetaType::QString:
390 case QMetaType::LongLong:
391 case QMetaType::ULongLong:
392 case QMetaType::Int:
393 case QMetaType::UInt:
394 case QMetaType::Bool:
395 case QMetaType::Float:
396 case QMetaType::Double: {
397 result = v.toString();
398 if (result.contains(QChar::Null))
399 result = "@String("_L1 + result + u')';
400 else if (result.startsWith(u'@'))
401 result.prepend(u'@');
402 break;
403 }
404#ifndef QT_NO_GEOM_VARIANT
405 case QMetaType::QRect: {
406 QRect r = qvariant_cast<QRect>(v);
407 result = QString::asprintf("@Rect(%d %d %d %d)", r.x(), r.y(), r.width(), r.height());
408 break;
409 }
410 case QMetaType::QSize: {
411 QSize s = qvariant_cast<QSize>(v);
412 result = QString::asprintf("@Size(%d %d)", s.width(), s.height());
413 break;
414 }
415 case QMetaType::QPoint: {
416 QPoint p = qvariant_cast<QPoint>(v);
417 result = QString::asprintf("@Point(%d %d)", p.x(), p.y());
418 break;
419 }
420#endif // !QT_NO_GEOM_VARIANT
421
422 default: {
423#ifndef QT_NO_DATASTREAM
424 QDataStream::Version version;
425 const char *typeSpec;
426 if (v.userType() == QMetaType::QDateTime) {
427 version = QDataStream::Qt_5_6;
428 typeSpec = "@DateTime(";
429 } else {
430 version = QDataStream::Qt_4_0;
431 typeSpec = "@Variant(";
432 }
434 {
436 s.setVersion(version);
437 s << v;
438 }
439
440 result = QLatin1StringView(typeSpec)
441 + QLatin1StringView(a.constData(), a.size())
442 + u')';
443#else
444 Q_ASSERT(!"QSettings: Cannot save custom types without QDataStream support");
445#endif
446 break;
447 }
448 }
449
450 return result;
451}
452
453
455{
456 if (s.startsWith(u'@')) {
457 if (s.endsWith(u')')) {
458 if (s.startsWith("@ByteArray("_L1)) {
459 return QVariant(QStringView{s}.sliced(11).chopped(1).toLatin1());
460 } else if (s.startsWith("@String("_L1)) {
461 return QVariant(QStringView{s}.sliced(8).chopped(1).toString());
462 } else if (s.startsWith("@Variant("_L1)
463 || s.startsWith("@DateTime("_L1)) {
464#ifndef QT_NO_DATASTREAM
465 QDataStream::Version version;
466 int offset;
467 if (s.at(1) == u'D') {
468 version = QDataStream::Qt_5_6;
469 offset = 10;
470 } else {
471 version = QDataStream::Qt_4_0;
472 offset = 9;
473 }
476 stream.setVersion(version);
478 stream >> result;
479 return result;
480#else
481 Q_ASSERT(!"QSettings: Cannot load custom types without QDataStream support");
482#endif
483#ifndef QT_NO_GEOM_VARIANT
484 } else if (s.startsWith("@Rect("_L1)) {
486 if (args.size() == 4)
487 return QVariant(QRect(args[0].toInt(), args[1].toInt(), args[2].toInt(), args[3].toInt()));
488 } else if (s.startsWith("@Size("_L1)) {
490 if (args.size() == 2)
491 return QVariant(QSize(args[0].toInt(), args[1].toInt()));
492 } else if (s.startsWith("@Point("_L1)) {
494 if (args.size() == 2)
495 return QVariant(QPoint(args[0].toInt(), args[1].toInt()));
496#endif
497 } else if (s == "@Invalid()"_L1) {
498 return QVariant();
499 }
500
501 }
502 if (s.startsWith("@@"_L1))
503 return QVariant(s.sliced(1));
504 }
505
506 return QVariant(s);
507}
508
510{
511 result.reserve(result.size() + key.size() * 3 / 2);
512 for (qsizetype i = 0; i < key.size(); ++i) {
513 uint ch = key.at(i).unicode();
514
515 if (ch == '/') {
516 result += '\\';
517 } else if (isAsciiLetterOrNumber(ch) || ch == '_' || ch == '-' || ch == '.') {
518 result += (char)ch;
519 } else if (ch <= 0xFF) {
520 result += '%';
523 } else {
524 result += "%U";
525 QByteArray hexCode;
526 for (int j = 0; j < 4; ++j) {
527 hexCode.prepend(QtMiscUtils::toHexUpper(ch % 16));
528 ch >>= 4;
529 }
530 result += hexCode;
531 }
532 }
533}
534
536{
537 const QString decoded = QString::fromUtf8(key);
538 const qsizetype size = decoded.size();
539 result.reserve(result.size() + size);
540 qsizetype i = 0;
541 bool lowercaseOnly = true;
542 while (i < size) {
543 char16_t ch = decoded.at(i).unicode();
544
545 if (ch == '\\') {
546 result += u'/';
547 ++i;
548 continue;
549 }
550
551 if (ch != '%' || i == size - 1) {
552 QChar qch(ch);
553 if (qch.isUpper())
554 lowercaseOnly = false;
555 result += qch;
556 ++i;
557 continue;
558 }
559
560 int numDigits = 2;
561 qsizetype firstDigitPos = i + 1;
562
563 ch = decoded.at(i + 1).unicode();
564 if (ch == 'U') {
565 ++firstDigitPos;
566 numDigits = 4;
567 }
568
569 if (firstDigitPos + numDigits > size) {
570 result += u'%';
571 ++i;
572 continue;
573 }
574
575 bool ok;
576 ch = QStringView(decoded).sliced(firstDigitPos, numDigits).toUShort(&ok, 16);
577 if (!ok) {
578 result += u'%';
579 ++i;
580 continue;
581 }
582
583 QChar qch(ch);
584 if (qch.isUpper())
585 lowercaseOnly = false;
586 result += qch;
587 i = firstDigitPos + numDigits;
588 }
589 return lowercaseOnly;
590}
591
593{
594 bool needsQuotes = false;
595 bool escapeNextIfDigit = false;
596 const bool useCodec = !(str.startsWith("@ByteArray("_L1)
597 || str.startsWith("@Variant("_L1)
598 || str.startsWith("@DateTime("_L1));
599 const qsizetype startPos = result.size();
600
602
603 result.reserve(startPos + str.size() * 3 / 2);
604 for (QChar qch : str) {
605 uint ch = qch.unicode();
606 if (ch == ';' || ch == ',' || ch == '=')
607 needsQuotes = true;
608
609 if (escapeNextIfDigit && isHexDigit(ch)) {
610 result += "\\x" + QByteArray::number(ch, 16);
611 continue;
612 }
613
614 escapeNextIfDigit = false;
615
616 switch (ch) {
617 case '\0':
618 result += "\\0";
619 escapeNextIfDigit = true;
620 break;
621 case '\a':
622 result += "\\a";
623 break;
624 case '\b':
625 result += "\\b";
626 break;
627 case '\f':
628 result += "\\f";
629 break;
630 case '\n':
631 result += "\\n";
632 break;
633 case '\r':
634 result += "\\r";
635 break;
636 case '\t':
637 result += "\\t";
638 break;
639 case '\v':
640 result += "\\v";
641 break;
642 case '"':
643 case '\\':
644 result += '\\';
645 result += (char)ch;
646 break;
647 default:
648 if (ch <= 0x1F || (ch >= 0x7F && !useCodec)) {
649 result += "\\x" + QByteArray::number(ch, 16);
650 escapeNextIfDigit = true;
651 } else if (useCodec) {
652 // slow
653 result += toUtf8(qch);
654 } else {
655 result += (char)ch;
656 }
657 }
658 }
659
660 if (needsQuotes
661 || (startPos < result.size() && (result.at(startPos) == ' '
662 || result.at(result.size() - 1) == ' '))) {
663 result.insert(startPos, '"');
664 result += '"';
665 }
666}
667
669{
670 qsizetype n = str.size() - 1;
671 QChar ch;
672 while (n >= limit && ((ch = str.at(n)) == u' ' || ch == u'\t'))
673 str.truncate(n--);
674}
675
677{
678 if (strs.isEmpty()) {
679 /*
680 We need to distinguish between empty lists and one-item
681 lists that contain an empty string. Ideally, we'd have a
682 @EmptyList() symbol but that would break compatibility
683 with Qt 4.0. @Invalid() stands for QVariant(), and
684 QVariant().toStringList() returns an empty QStringList,
685 so we're in good shape.
686 */
687 result += "@Invalid()";
688 } else {
689 for (qsizetype i = 0; i < strs.size(); ++i) {
690 if (i != 0)
691 result += ", ";
692 iniEscapedString(strs.at(i), result);
693 }
694 }
695}
696
698 QString &stringResult, QStringList &stringListResult)
699{
700 static const char escapeCodes[][2] =
701 {
702 { 'a', '\a' },
703 { 'b', '\b' },
704 { 'f', '\f' },
705 { 'n', '\n' },
706 { 'r', '\r' },
707 { 't', '\t' },
708 { 'v', '\v' },
709 { '"', '"' },
710 { '?', '?' },
711 { '\'', '\'' },
712 { '\\', '\\' }
713 };
714
715 bool isStringList = false;
716 bool inQuotedString = false;
717 bool currentValueIsQuoted = false;
718 char16_t escapeVal = 0;
719 qsizetype i = 0;
720 char ch;
722
723StSkipSpaces:
724 while (i < str.size() && ((ch = str.at(i)) == ' ' || ch == '\t'))
725 ++i;
726 // fallthrough
727
728StNormal:
729 qsizetype chopLimit = stringResult.size();
730 while (i < str.size()) {
731 switch (str.at(i)) {
732 case '\\':
733 ++i;
734 if (i >= str.size())
735 goto end;
736
737 ch = str.at(i++);
738 for (const auto &escapeCode : escapeCodes) {
739 if (ch == escapeCode[0]) {
740 stringResult += QLatin1Char(escapeCode[1]);
741 goto StNormal;
742 }
743 }
744
745 if (ch == 'x') {
746 escapeVal = 0;
747
748 if (i >= str.size())
749 goto end;
750
751 ch = str.at(i);
752 if (isHexDigit(ch))
753 goto StHexEscape;
754 } else if (const int o = fromOct(ch); o != -1) {
755 escapeVal = o;
756 goto StOctEscape;
757 } else if (ch == '\n' || ch == '\r') {
758 if (i < str.size()) {
759 char ch2 = str.at(i);
760 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
761 if ((ch2 == '\n' || ch2 == '\r') && ch2 != ch)
762 ++i;
763 }
764 } else {
765 // the character is skipped
766 }
767 chopLimit = stringResult.size();
768 break;
769 case '"':
770 ++i;
771 currentValueIsQuoted = true;
772 inQuotedString = !inQuotedString;
773 if (!inQuotedString)
774 goto StSkipSpaces;
775 break;
776 case ',':
777 if (!inQuotedString) {
778 if (!currentValueIsQuoted)
779 iniChopTrailingSpaces(stringResult, chopLimit);
780 if (!isStringList) {
781 isStringList = true;
782 stringListResult.clear();
783 stringResult.squeeze();
784 }
785 stringListResult.append(stringResult);
786 stringResult.clear();
787 currentValueIsQuoted = false;
788 ++i;
789 goto StSkipSpaces;
790 }
792 default: {
793 qsizetype j = i + 1;
794 while (j < str.size()) {
795 ch = str.at(j);
796 if (ch == '\\' || ch == '"' || ch == ',')
797 break;
798 ++j;
799 }
800
801 stringResult += fromUtf8(str.first(j).sliced(i));
802 i = j;
803 }
804 }
805 }
806 if (!currentValueIsQuoted)
807 iniChopTrailingSpaces(stringResult, chopLimit);
808 goto end;
809
810StHexEscape:
811 if (i >= str.size()) {
812 stringResult += escapeVal;
813 goto end;
814 }
815
816 ch = str.at(i);
817 if (const int h = fromHex(ch); h != -1) {
818 escapeVal <<= 4;
819 escapeVal += h;
820 ++i;
821 goto StHexEscape;
822 } else {
823 stringResult += escapeVal;
824 goto StNormal;
825 }
826
827StOctEscape:
828 if (i >= str.size()) {
829 stringResult += escapeVal;
830 goto end;
831 }
832
833 ch = str.at(i);
834 if (const int o = fromOct(ch); o != -1) {
835 escapeVal <<= 3;
836 escapeVal += o;
837 ++i;
838 goto StOctEscape;
839 } else {
840 stringResult += escapeVal;
841 goto StNormal;
842 }
843
844end:
845 if (isStringList)
846 stringListResult.append(stringResult);
847 return isStringList;
848}
849
851{
852 qsizetype l = s.size();
853 Q_ASSERT(l > 0);
854 Q_ASSERT(s.at(idx) == u'(');
855 Q_ASSERT(s.at(l - 1) == u')');
856
859
860 for (++idx; idx < l; ++idx) {
861 QChar c = s.at(idx);
862 if (c == u')') {
863 Q_ASSERT(idx == l - 1);
864 result.append(item);
865 } else if (c == u' ') {
866 result.append(item);
867 item.clear();
868 } else {
869 item.append(c);
870 }
871 }
872
873 return result;
874}
875
876// ************************************************************************
877// QConfFileSettingsPrivate
878
879void QConfFileSettingsPrivate::initFormat()
880{
881 extension = (format == QSettings::NativeFormat) ? ".conf"_L1 : ".ini"_L1;
882 readFunc = nullptr;
883 writeFunc = nullptr;
884#if defined(Q_OS_DARWIN)
886#else
887 caseSensitivity = IniCaseSensitivity;
888#endif
889
891 const auto locker = qt_scoped_lock(settingsGlobalMutex);
892 const CustomFormatVector *customFormatVector = customFormatVectorFunc();
893
895 if (i >= 0 && i < customFormatVector->size()) {
896 QConfFileCustomFormat info = customFormatVector->at(i);
897 extension = info.extension;
898 readFunc = info.readFunc;
899 writeFunc = info.writeFunc;
900 caseSensitivity = info.caseSensitivity;
901 }
902 }
903}
904
906{
907 if (!confFiles.isEmpty()) {
909 if (!readFunc)
911 }
912 }
913
914 sync(); // loads the files the first time
915}
916
917#if defined(Q_OS_WIN)
918static QString windowsConfigPath(const KNOWNFOLDERID &type)
919{
921
922 PWSTR path = nullptr;
923 if (SHGetKnownFolderPath(type, KF_FLAG_DONT_VERIFY, NULL, &path) == S_OK) {
925 CoTaskMemFree(path);
926 }
927
928 if (result.isEmpty()) {
929 if (type == FOLDERID_ProgramData) {
930 result = "C:\\temp\\qt-common"_L1;
931 } else if (type == FOLDERID_RoamingAppData) {
932 result = "C:\\temp\\qt-user"_L1;
933 }
934 }
935
936 return result;
937}
938#endif // Q_OS_WIN
939
941{
942 return int((uint(format) << 1) | uint(scope == QSettings::SystemScope));
943}
944
945#ifndef Q_OS_WIN
946static constexpr QChar sep = u'/';
947
948#if !defined(QSETTINGS_USE_QSTANDARDPATHS) || defined(Q_OS_ANDROID)
950{
951 QByteArray env = qgetenv("XDG_CONFIG_HOME");
952 if (env.isEmpty()) {
953 return QDir::homePath() + "/.config/"_L1;
954 } else if (env.startsWith('/')) {
955 return QFile::decodeName(env) + sep;
956 }
957
958 return QDir::homePath() + sep + QFile::decodeName(env) + sep;
959}
960#endif // !QSETTINGS_USE_QSTANDARDPATHS || Q_OS_ANDROID
961
963{
964#ifndef QSETTINGS_USE_QSTANDARDPATHS
965 // Non XDG platforms (OS X, iOS, Android...) have used this code path erroneously
966 // for some time now. Moving away from that would require migrating existing settings.
967 // The migration has already been done for Android.
969#else
970
971#ifdef Q_OS_ANDROID
972 // If an old settings path exists, use it instead of creating a new one
974 if (QFile(ret).exists())
975 return ret;
976#endif // Q_OS_ANDROID
977
978 // When using a proper XDG platform or Android platform, use QStandardPaths rather than the
979 // above hand-written code. It makes the use of test mode from unit tests possible.
980 // Ideally all platforms should use this, but see above for the migration issue.
982#endif // !QSETTINGS_USE_QSTANDARDPATHS
983}
984#endif // !Q_OS_WIN
985
986static std::unique_lock<QBasicMutex> initDefaultPaths(std::unique_lock<QBasicMutex> locker)
987{
988 PathHash *pathHash = pathHashFunc();
989
990 locker.unlock();
991
992 /*
993 QLibraryInfo::path() uses QSettings, so in order to
994 avoid a dead-lock, we can't hold the global mutex while
995 calling it.
996 */
998
999 locker.lock();
1000 if (pathHash->isEmpty()) {
1001 /*
1002 Lazy initialization of pathHash. We initialize the
1003 IniFormat paths and (on Unix) the NativeFormat paths.
1004 (The NativeFormat paths are not configurable for the
1005 Windows registry and the Mac CFPreferences.)
1006 */
1007#ifdef Q_OS_WIN
1008 const QString roamingAppDataFolder = windowsConfigPath(FOLDERID_RoamingAppData);
1009 const QString programDataFolder = windowsConfigPath(FOLDERID_ProgramData);
1011 Path(roamingAppDataFolder + QDir::separator(), false));
1013 Path(programDataFolder + QDir::separator(), false));
1014#else
1015 const QString userPath = make_user_path();
1016 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::UserScope), Path(userPath, false));
1017 pathHash->insert(pathHashKey(QSettings::IniFormat, QSettings::SystemScope), Path(systemPath, false));
1018#ifndef Q_OS_DARWIN
1020 pathHash->insert(pathHashKey(QSettings::NativeFormat, QSettings::SystemScope), Path(systemPath, false));
1021#endif
1022#endif // Q_OS_WIN
1023 }
1024
1025 return locker;
1026}
1027
1029{
1031 Q_ASSERT(int(QSettings::IniFormat) == 1);
1032
1033 auto locker = qt_unique_lock(settingsGlobalMutex);
1034 PathHash *pathHash = pathHashFunc();
1035 if (pathHash->isEmpty())
1036 locker = initDefaultPaths(std::move(locker));
1037
1038 Path result = pathHash->value(pathHashKey(format, scope));
1039 if (!result.path.isEmpty())
1040 return result;
1041
1042 // fall back on INI path
1043 return pathHash->value(pathHashKey(QSettings::IniFormat, scope));
1044}
1045
1046#if defined(QT_BUILD_INTERNAL) && defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1047// Note: Suitable only for autotests.
1048void Q_AUTOTEST_EXPORT clearDefaultPaths()
1049{
1050 const auto locker = qt_scoped_lock(settingsGlobalMutex);
1051 pathHashFunc()->clear();
1052}
1053#endif // QT_BUILD_INTERNAL && Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1054
1056 QSettings::Scope scope,
1057 const QString &organization,
1058 const QString &application)
1059 : QSettingsPrivate(format, scope, organization, application),
1060 nextPosition(0x40000000) // big positive number
1061{
1062 initFormat();
1063
1064 QString org = organization;
1065 if (org.isEmpty()) {
1067 org = "Unknown Organization"_L1;
1068 }
1069
1070 QString appFile = org + QDir::separator() + application + extension;
1071 QString orgFile = org + extension;
1072
1073 if (scope == QSettings::UserScope) {
1075 if (!application.isEmpty())
1076 confFiles.append(QConfFile::fromName(userPath.path + appFile, true));
1077 confFiles.append(QConfFile::fromName(userPath.path + orgFile, true));
1078 }
1079
1081#if defined(Q_XDG_PLATFORM) && !defined(QT_NO_STANDARDPATHS)
1082 // check if the systemPath wasn't overridden by QSettings::setPath()
1083 if (!systemPath.userDefined) {
1084 // Note: We can't use QStandardPaths::locateAll() as we need all the
1085 // possible files (not just the existing ones) and there is no way
1086 // to exclude user specific (XDG_CONFIG_HOME) directory from the search.
1088 // remove the QStandardLocation::writableLocation() (XDG_CONFIG_HOME)
1089 if (!dirs.isEmpty())
1090 dirs.takeFirst();
1092 if (!application.isEmpty()) {
1093 paths.reserve(dirs.size() * 2);
1094 for (const auto &dir : std::as_const(dirs))
1095 paths.append(dir + u'/' + appFile);
1096 } else {
1097 paths.reserve(dirs.size());
1098 }
1099 for (const auto &dir : std::as_const(dirs))
1100 paths.append(dir + u'/' + orgFile);
1101
1102 // Note: No check for existence of files is done intentionally.
1103 for (const auto &path : std::as_const(paths))
1104 confFiles.append(QConfFile::fromName(path, false));
1105 } else
1106#endif // Q_XDG_PLATFORM && !QT_NO_STANDARDPATHS
1107 {
1108 if (!application.isEmpty())
1109 confFiles.append(QConfFile::fromName(systemPath.path + appFile, false));
1110 confFiles.append(QConfFile::fromName(systemPath.path + orgFile, false));
1111 }
1112
1113#ifndef Q_OS_WASM // wasm needs to delay access until after file sync
1114 initAccess();
1115#endif
1116}
1117
1121 nextPosition(0x40000000) // big positive number
1122{
1123 initFormat();
1124
1125 confFiles.append(QConfFile::fromName(fileName, true));
1126
1127 initAccess();
1128}
1129
1131{
1132 const auto locker = qt_scoped_lock(settingsGlobalMutex);
1133 ConfFileHash *usedHash = usedHashFunc();
1134 ConfFileCache *unusedCache = unusedCacheFunc();
1135
1136 for (auto conf_file : std::as_const(confFiles)) {
1137 if (!conf_file->ref.deref()) {
1138 if (conf_file->size == 0) {
1139 delete conf_file;
1140 } else {
1141 if (usedHash)
1142 usedHash->remove(conf_file->name);
1143 if (unusedCache) {
1144 QT_TRY {
1145 // compute a better size?
1146 unusedCache->insert(conf_file->name, conf_file,
1147 10 + (conf_file->originalKeys.size() / 4));
1148 } QT_CATCH(...) {
1149 // out of memory. Do not cache the file.
1150 delete conf_file;
1151 }
1152 } else {
1153 // unusedCache is gone - delete the entry to prevent a memory leak
1154 delete conf_file;
1155 }
1156 }
1157 }
1158 }
1159}
1160
1162{
1163 if (confFiles.isEmpty())
1164 return;
1165
1166 // Note: First config file is always the most specific.
1167 QConfFile *confFile = confFiles.at(0);
1168
1169 QSettingsKey theKey(key, caseSensitivity);
1170 QSettingsKey prefix(key + u'/', caseSensitivity);
1171 const auto locker = qt_scoped_lock(confFile->mutex);
1172
1173 ensureSectionParsed(confFile, theKey);
1174 ensureSectionParsed(confFile, prefix);
1175
1176 auto i = confFile->addedKeys.lowerBound(prefix);
1177 while (i != confFile->addedKeys.end() && i.key().startsWith(prefix))
1178 i = confFile->addedKeys.erase(i);
1179 confFile->addedKeys.remove(theKey);
1180
1181 auto j = const_cast<const ParsedSettingsMap *>(&confFile->originalKeys)->lowerBound(prefix);
1182 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(prefix)) {
1183 confFile->removedKeys.insert(j.key(), QVariant());
1184 ++j;
1185 }
1186 if (confFile->originalKeys.contains(theKey))
1187 confFile->removedKeys.insert(theKey, QVariant());
1188}
1189
1191{
1192 if (confFiles.isEmpty())
1193 return;
1194
1195 // Note: First config file is always the most specific.
1196 QConfFile *confFile = confFiles.at(0);
1197
1198 QSettingsKey theKey(key, caseSensitivity, nextPosition++);
1199 const auto locker = qt_scoped_lock(confFile->mutex);
1200 confFile->removedKeys.remove(theKey);
1201 confFile->addedKeys.insert(theKey, value);
1202}
1203
1204std::optional<QVariant> QConfFileSettingsPrivate::get(const QString &key) const
1205{
1206 QSettingsKey theKey(key, caseSensitivity);
1207 ParsedSettingsMap::const_iterator j;
1208 bool found = false;
1209
1210 for (auto confFile : std::as_const(confFiles)) {
1211 const auto locker = qt_scoped_lock(confFile->mutex);
1212
1213 if (!confFile->addedKeys.isEmpty()) {
1214 j = confFile->addedKeys.constFind(theKey);
1215 found = (j != confFile->addedKeys.constEnd());
1216 }
1217 if (!found) {
1218 ensureSectionParsed(confFile, theKey);
1219 j = confFile->originalKeys.constFind(theKey);
1220 found = (j != confFile->originalKeys.constEnd()
1221 && !confFile->removedKeys.contains(theKey));
1222 }
1223
1224 if (found)
1225 return *j;
1226 if (!fallbacks)
1227 break;
1228 }
1229 return std::nullopt;
1230}
1231
1233{
1235
1236 QSettingsKey thePrefix(prefix, caseSensitivity);
1237 qsizetype startPos = prefix.size();
1238
1239 for (auto confFile : std::as_const(confFiles)) {
1240 const auto locker = qt_scoped_lock(confFile->mutex);
1241
1242 if (thePrefix.isEmpty())
1243 ensureAllSectionsParsed(confFile);
1244 else
1245 ensureSectionParsed(confFile, thePrefix);
1246
1247 auto j = const_cast<const ParsedSettingsMap *>(
1248 &confFile->originalKeys)->lowerBound( thePrefix);
1249 while (j != confFile->originalKeys.constEnd() && j.key().startsWith(thePrefix)) {
1250 if (!confFile->removedKeys.contains(j.key()))
1251 processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
1252 ++j;
1253 }
1254
1255 j = const_cast<const ParsedSettingsMap *>(
1256 &confFile->addedKeys)->lowerBound(thePrefix);
1257 while (j != confFile->addedKeys.constEnd() && j.key().startsWith(thePrefix)) {
1258 processChild(QStringView{j.key().originalCaseKey()}.sliced(startPos), spec, result);
1259 ++j;
1260 }
1261
1262 if (!fallbacks)
1263 break;
1264 }
1265 std::sort(result.begin(), result.end());
1266 result.erase(std::unique(result.begin(), result.end()),
1267 result.end());
1268 return result;
1269}
1270
1272{
1273 if (confFiles.isEmpty())
1274 return;
1275
1276 // Note: First config file is always the most specific.
1277 QConfFile *confFile = confFiles.at(0);
1278
1279 const auto locker = qt_scoped_lock(confFile->mutex);
1280 ensureAllSectionsParsed(confFile);
1281 confFile->addedKeys.clear();
1282 confFile->removedKeys = confFile->originalKeys;
1283}
1284
1286{
1287 // people probably won't be checking the status a whole lot, so in case of
1288 // error we just try to go on and make the best of it
1289
1290 for (auto confFile : std::as_const(confFiles)) {
1291 const auto locker = qt_scoped_lock(confFile->mutex);
1292 syncConfFile(confFile);
1293 }
1294}
1295
1297{
1298 sync();
1299}
1300
1302{
1303 if (confFiles.isEmpty())
1304 return QString();
1305
1306 // Note: First config file is always the most specific.
1307 return confFiles.at(0)->name;
1308}
1309
1311{
1312 if (format > QSettings::IniFormat && !writeFunc)
1313 return false;
1314
1315 if (confFiles.isEmpty())
1316 return false;
1317
1318 return confFiles.at(0)->isWritable();
1319}
1320
1321void QConfFileSettingsPrivate::syncConfFile(QConfFile *confFile)
1322{
1323 bool readOnly = confFile->addedKeys.isEmpty() && confFile->removedKeys.isEmpty();
1324
1325 QFileInfo fileInfo(confFile->name);
1326 /*
1327 We can often optimize the read-only case, if the file on disk
1328 hasn't changed.
1329 */
1330 if (readOnly && confFile->size > 0) {
1331 if (confFile->size == fileInfo.size() && confFile->timeStamp == fileInfo.lastModified(QTimeZone::UTC))
1332 return;
1333 }
1334
1335 if (!readOnly && !confFile->isWritable()) {
1337 return;
1338 }
1339
1340#ifndef QT_BOOTSTRAPPED
1341 QString lockFileName = confFile->name + ".lock"_L1;
1342
1343# if defined(Q_OS_ANDROID) && defined(QSETTINGS_USE_QSTANDARDPATHS)
1344 // On android and if it is a content URL put the lock file in a
1345 // writable location to prevent permissions issues and invalid paths.
1346 if (confFile->name.startsWith("content:"_L1))
1348# endif
1349 /*
1350 Use a lockfile in order to protect us against other QSettings instances
1351 trying to write the same settings at the same time.
1352
1353 We only need to lock if we are actually writing as only concurrent writes are a problem.
1354 Concurrent read and write are not a problem because the writing operation is atomic.
1355 */
1356 QLockFile lockFile(lockFileName);
1357 if (!readOnly && !lockFile.lock() && atomicSyncOnly) {
1359 return;
1360 }
1361#endif
1362
1363 /*
1364 We hold the lock. Let's reread the file if it has changed
1365 since last time we read it.
1366 */
1367 fileInfo.refresh();
1368 bool mustReadFile = true;
1369 bool createFile = !fileInfo.exists();
1370
1371 if (!readOnly)
1372 mustReadFile = (confFile->size != fileInfo.size()
1373 || (confFile->size != 0 && confFile->timeStamp != fileInfo.lastModified(QTimeZone::UTC)));
1374
1375 if (mustReadFile) {
1376 confFile->unparsedIniSections.clear();
1377 confFile->originalKeys.clear();
1378
1379 QFile file(confFile->name);
1380 if (!createFile && !file.open(QFile::ReadOnly)) {
1382 return;
1383 }
1384
1385 /*
1386 Files that we can't read (because of permissions or
1387 because they don't exist) are treated as empty files.
1388 */
1389 if (file.isReadable() && file.size() != 0) {
1390 bool ok = false;
1391#ifdef Q_OS_DARWIN
1394 ok = readPlistFile(data, &confFile->originalKeys);
1395 } else
1396#endif
1399 ok = readIniFile(data, &confFile->unparsedIniSections);
1400 } else if (readFunc) {
1401 QSettings::SettingsMap tempNewKeys;
1402 ok = readFunc(file, tempNewKeys);
1403
1404 if (ok) {
1405 auto i = tempNewKeys.constBegin();
1406 while (i != tempNewKeys.constEnd()) {
1407 confFile->originalKeys.insert(QSettingsKey(i.key(), caseSensitivity),
1408 i.value());
1409 ++i;
1410 }
1411 }
1412 }
1413
1414 if (!ok)
1416 }
1417
1418 confFile->size = fileInfo.size();
1419 confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
1420 }
1421
1422 /*
1423 We also need to save the file. We still hold the file lock,
1424 so everything is under control.
1425 */
1426 if (!readOnly) {
1427 bool ok = false;
1428 ensureAllSectionsParsed(confFile);
1429 ParsedSettingsMap mergedKeys = confFile->mergedKeyMap();
1430
1431#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1432 QSaveFile sf(confFile->name);
1433 sf.setDirectWriteFallback(!atomicSyncOnly);
1434# ifdef Q_OS_ANDROID
1435 // QSaveFile requires direct write when using content scheme URL in Android
1436 if (confFile->name.startsWith("content:"_L1))
1437 sf.setDirectWriteFallback(true);
1438# endif
1439#else
1440 QFile sf(confFile->name);
1441#endif
1442 if (!sf.open(QIODevice::WriteOnly)) {
1444 return;
1445 }
1446
1447#ifdef Q_OS_DARWIN
1449 ok = writePlistFile(sf, mergedKeys);
1450 } else
1451#endif
1453 ok = writeIniFile(sf, mergedKeys);
1454 } else if (writeFunc) {
1455 QSettings::SettingsMap tempOriginalKeys;
1456
1457 auto i = mergedKeys.constBegin();
1458 while (i != mergedKeys.constEnd()) {
1459 tempOriginalKeys.insert(i.key(), i.value());
1460 ++i;
1461 }
1462 ok = writeFunc(sf, tempOriginalKeys);
1463 }
1464
1465#if !defined(QT_BOOTSTRAPPED) && QT_CONFIG(temporaryfile)
1466 if (ok)
1467 ok = sf.commit();
1468#endif
1469
1470 if (ok) {
1471 confFile->unparsedIniSections.clear();
1472 confFile->originalKeys = mergedKeys;
1473 confFile->addedKeys.clear();
1474 confFile->removedKeys.clear();
1475
1476 fileInfo.refresh();
1477 confFile->size = fileInfo.size();
1478 confFile->timeStamp = fileInfo.lastModified(QTimeZone::UTC);
1479
1480 // If we have created the file, apply the file perms
1481 if (createFile) {
1482 QFile::Permissions perms = fileInfo.permissions() | QFile::ReadOwner | QFile::WriteOwner;
1483 if (!confFile->userPerms)
1485 QFile(confFile->name).setPermissions(perms);
1486 }
1487 } else {
1489 }
1490 }
1491}
1492
1493enum { Space = 0x1, Special = 0x2 };
1494
1495static const char charTraits[256] =
1496{
1497 // Space: '\t', '\n', '\r', ' '
1498 // Special: '\n', '\r', '"', ';', '=', '\\'
1499
1500 0, 0, 0, 0, 0, 0, 0, 0, 0, Space, Space | Special, 0, 0, Space | Special, 0, 0,
1501 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1502 Space, 0, Special, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1503 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, Special, 0, 0,
1504 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1505 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Special, 0, 0, 0,
1506 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1507 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1508
1509 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1510 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1511 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1512 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1513 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1514 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1515 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1516 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
1517};
1518
1520 qsizetype &lineStart, qsizetype &lineLen,
1521 qsizetype &equalsPos)
1522{
1523 qsizetype dataLen = data.size();
1524 bool inQuotes = false;
1525
1526 equalsPos = -1;
1527
1528 lineStart = dataPos;
1529 while (lineStart < dataLen && (charTraits[uint(uchar(data.at(lineStart)))] & Space))
1530 ++lineStart;
1531
1532 qsizetype i = lineStart;
1533 while (i < dataLen) {
1534 char ch = data.at(i);
1535 while (!(charTraits[uchar(ch)] & Special)) {
1536 if (++i == dataLen)
1537 goto break_out_of_outer_loop;
1538 ch = data.at(i);
1539 }
1540
1541 ++i;
1542 if (ch == '=') {
1543 if (!inQuotes && equalsPos == -1)
1544 equalsPos = i - 1;
1545 } else if (ch == '\n' || ch == '\r') {
1546 if (i == lineStart + 1) {
1547 ++lineStart;
1548 } else if (!inQuotes) {
1549 --i;
1550 goto break_out_of_outer_loop;
1551 }
1552 } else if (ch == '\\') {
1553 if (i < dataLen) {
1554 char ch = data.at(i++);
1555 if (i < dataLen) {
1556 char ch2 = data.at(i);
1557 // \n, \r, \r\n, and \n\r are legitimate line terminators in INI files
1558 if ((ch == '\n' && ch2 == '\r') || (ch == '\r' && ch2 == '\n'))
1559 ++i;
1560 }
1561 }
1562 } else if (ch == '"') {
1563 inQuotes = !inQuotes;
1564 } else {
1565 Q_ASSERT(ch == ';');
1566
1567 if (i == lineStart + 1) {
1568 while (i < dataLen && (((ch = data.at(i)) != '\n') && ch != '\r'))
1569 ++i;
1570 while (i < dataLen && charTraits[uchar(data.at(i))] & Space)
1571 ++i;
1572 lineStart = i;
1573 } else if (!inQuotes) {
1574 --i;
1575 goto break_out_of_outer_loop;
1576 }
1577 }
1578 }
1579
1580break_out_of_outer_loop:
1581 dataPos = i;
1582 lineLen = i - lineStart;
1583 return lineLen > 0;
1584}
1585
1586/*
1587 Returns \c false on parse error. However, as many keys are read as
1588 possible, so if the user doesn't check the status he will get the
1589 most out of the file anyway.
1590*/
1592 UnparsedSettingsMap *unparsedIniSections)
1593{
1594#define FLUSH_CURRENT_SECTION() \
1595 { \
1596 QByteArray &sectionData = (*unparsedIniSections)[QSettingsKey(currentSection, \
1597 IniCaseSensitivity, \
1598 sectionPosition)]; \
1599 if (!sectionData.isEmpty()) \
1600 sectionData.append('\n'); \
1601 sectionData += data.first(lineStart).sliced(currentSectionStart); \
1602 sectionPosition = ++position; \
1603 }
1604
1605 QString currentSection;
1606 qsizetype currentSectionStart = 0;
1607 qsizetype dataPos = 0;
1608 qsizetype lineStart;
1609 qsizetype lineLen;
1610 qsizetype equalsPos;
1611 qsizetype position = 0;
1612 qsizetype sectionPosition = 0;
1613 bool ok = true;
1614
1615 // Skip possible UTF-8 BOM:
1616 if (data.startsWith("\xef\xbb\xbf"))
1617 data = data.sliced(3);
1618
1619 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1620 QByteArrayView line = data.sliced(lineStart, lineLen);
1621 if (line.startsWith('[')) {
1623
1624 // This starts a new section.
1625 qsizetype idx = line.indexOf(']');
1626 Q_ASSERT(idx == -1 || idx > 0); // line[0] is '[', not ']'.
1627 Q_ASSERT(idx < lineLen); // (including -1 < lineLen, if no ']' present.)
1628 if (idx < 0) {
1629 ok = false;
1630 idx = lineLen; // so line.first(idx) is just line
1631 }
1632 QByteArrayView iniSection = line.first(idx).sliced(1).trimmed();
1633
1634 if (iniSection.compare("general", Qt::CaseInsensitive) == 0) {
1635 currentSection.clear();
1636 } else {
1637 if (iniSection.compare("%general", Qt::CaseInsensitive) == 0) {
1638 currentSection = QLatin1StringView(iniSection.constData() + 1, iniSection.size() - 1);
1639 } else {
1640 currentSection.clear();
1641 iniUnescapedKey(iniSection, currentSection);
1642 }
1643 currentSection += u'/';
1644 }
1645 currentSectionStart = dataPos;
1646 }
1647 ++position;
1648 }
1649
1650 Q_ASSERT(lineStart == data.size());
1652
1653 return ok;
1654
1655#undef FLUSH_CURRENT_SECTION
1656}
1657
1659 ParsedSettingsMap *settingsMap)
1660{
1661 QStringList strListValue;
1662 bool sectionIsLowercase = (section == section.originalCaseKey());
1663 qsizetype equalsPos;
1664
1665 bool ok = true;
1666 qsizetype dataPos = 0;
1667 qsizetype lineStart;
1668 qsizetype lineLen;
1670
1671 while (readIniLine(data, dataPos, lineStart, lineLen, equalsPos)) {
1672 QByteArrayView line = data.sliced(lineStart, lineLen);
1673 Q_ASSERT(!line.startsWith('['));
1674
1675 if (equalsPos == -1) {
1676 if (!line.startsWith(';'))
1677 ok = false;
1678 continue;
1679 }
1680 // Shift equalPos indexing to be within line, rather than data:
1681 equalsPos -= lineStart;
1682 // Assured by readIniLine:
1683 Q_ASSERT(equalsPos >= 0 && equalsPos < lineLen);
1684
1685 QByteArrayView key = line.first(equalsPos).trimmed();
1686 QByteArrayView value = line.sliced(equalsPos + 1);
1687
1688 QString strKey = section.originalCaseKey();
1689 const Qt::CaseSensitivity casing = iniUnescapedKey(key, strKey) && sectionIsLowercase
1692
1693 QString strValue;
1694 strValue.reserve(value.size());
1695 QVariant variant = iniUnescapedStringList(value, strValue, strListValue)
1696 ? stringListToVariantList(strListValue)
1697 : stringToVariant(strValue);
1698
1699 /*
1700 We try to avoid the expensive toLower() call in
1701 QSettingsKey by passing Qt::CaseSensitive when the
1702 key is already in lowercase.
1703 */
1704 settingsMap->insert(QSettingsKey(strKey, casing, position), std::move(variant));
1705 ++position;
1706 }
1707
1708 return ok;
1709}
1710
1712{
1713public:
1714 inline QSettingsIniKey() : position(-1) {}
1716
1718};
1720
1721static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
1722{
1723 if (k1.position != k2.position)
1724 return k1.position < k2.position;
1725 return static_cast<const QString &>(k1) < static_cast<const QString &>(k2);
1726}
1727
1729
1731{
1734
1736};
1737
1739
1741
1742/*
1743 This would be more straightforward if we didn't try to remember the original
1744 key order in the .ini file, but we do.
1745*/
1746bool QConfFileSettingsPrivate::writeIniFile(QIODevice &device, const ParsedSettingsMap &map)
1747{
1748 IniMap iniMap;
1749
1750#ifdef Q_OS_WIN
1751 const char * const eol = "\r\n";
1752#else
1753 const char eol = '\n';
1754#endif
1755
1756 for (auto j = map.constBegin(); j != map.constEnd(); ++j) {
1757 QString section;
1758 QSettingsIniKey key(j.key().originalCaseKey(), j.key().originalKeyPosition());
1759 qsizetype slashPos;
1760
1761 if ((slashPos = key.indexOf(u'/')) != -1) {
1762 section = key.left(slashPos);
1763 key.remove(0, slashPos + 1);
1764 }
1765
1766 QSettingsIniSection &iniSection = iniMap[section];
1767
1768 // -1 means infinity
1769 if (size_t(key.position) < size_t(iniSection.position))
1770 iniSection.position = key.position;
1771 iniSection.keyMap[key] = j.value();
1772 }
1773
1774 const qsizetype sectionCount = iniMap.size();
1775 QList<QSettingsIniKey> sections;
1776 sections.reserve(sectionCount);
1777 for (auto i = iniMap.constBegin(); i != iniMap.constEnd(); ++i)
1778 sections.append(QSettingsIniKey(i.key(), i.value().position));
1779 std::sort(sections.begin(), sections.end());
1780
1781 bool writeError = false;
1782 for (qsizetype j = 0; !writeError && j < sectionCount; ++j) {
1783 auto i = iniMap.constFind(sections.at(j));
1784 Q_ASSERT(i != iniMap.constEnd());
1785
1786 QByteArray realSection;
1787
1788 iniEscapedKey(i.key(), realSection);
1789
1790 if (realSection.isEmpty()) {
1791 realSection = "[General]";
1792 } else if (realSection.compare("general", Qt::CaseInsensitive) == 0) {
1793 realSection = "[%General]";
1794 } else {
1795 realSection.prepend('[');
1796 realSection.append(']');
1797 }
1798
1799 if (j != 0)
1800 realSection.prepend(eol);
1801 realSection += eol;
1802
1803 device.write(realSection);
1804
1805 const IniKeyMap &ents = i.value().keyMap;
1806 for (auto j = ents.constBegin(); j != ents.constEnd(); ++j) {
1807 QByteArray block;
1808 iniEscapedKey(j.key(), block);
1809 block += '=';
1810
1811 const QVariant &value = j.value();
1812
1813 /*
1814 The size() != 1 trick is necessary because
1815 QVariant(QString("foo")).toList() returns an empty
1816 list, not a list containing "foo".
1817 */
1818 if (value.metaType().id() == QMetaType::QStringList
1819 || (value.metaType().id() == QMetaType::QVariantList && value.toList().size() != 1)) {
1821 } else {
1823 }
1824 block += eol;
1825 if (device.write(block) == -1) {
1826 writeError = true;
1827 break;
1828 }
1829 }
1830 }
1831 return !writeError;
1832}
1833
1834void QConfFileSettingsPrivate::ensureAllSectionsParsed(QConfFile *confFile) const
1835{
1836 auto i = confFile->unparsedIniSections.constBegin();
1837 const auto end = confFile->unparsedIniSections.constEnd();
1838
1839 for (; i != end; ++i) {
1840 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1842 }
1843 confFile->unparsedIniSections.clear();
1844}
1845
1846void QConfFileSettingsPrivate::ensureSectionParsed(QConfFile *confFile,
1847 const QSettingsKey &key) const
1848{
1849 if (confFile->unparsedIniSections.isEmpty())
1850 return;
1851
1852 UnparsedSettingsMap::iterator i;
1853
1854 qsizetype indexOfSlash = key.indexOf(u'/');
1855 if (indexOfSlash != -1) {
1856 i = confFile->unparsedIniSections.upperBound(key);
1857 if (i == confFile->unparsedIniSections.begin())
1858 return;
1859 --i;
1860 if (i.key().isEmpty() || !key.startsWith(i.key()))
1861 return;
1862 } else {
1863 i = confFile->unparsedIniSections.begin();
1864 if (i == confFile->unparsedIniSections.end() || !i.key().isEmpty())
1865 return;
1866 }
1867
1868 if (!QConfFileSettingsPrivate::readIniSection(i.key(), i.value(), &confFile->originalKeys))
1870 confFile->unparsedIniSections.erase(i);
1871}
1872
2474#ifndef QT_NO_QOBJECT
2489QSettings::QSettings(const QString &organization, const QString &application, QObject *parent)
2490 : QObject(*QSettingsPrivate::create(NativeFormat, UserScope, organization, application),
2491 parent)
2492{
2493}
2494
2514QSettings::QSettings(Scope scope, const QString &organization, const QString &application,
2515 QObject *parent)
2516 : QObject(*QSettingsPrivate::create(NativeFormat, scope, organization, application), parent)
2517{
2518}
2519
2538QSettings::QSettings(Format format, Scope scope, const QString &organization,
2539 const QString &application, QObject *parent)
2540 : QObject(*QSettingsPrivate::create(format, scope, organization, application), parent)
2541{
2542}
2543
2576{
2577}
2578
2615 : QSettings(UserScope, parent)
2616{
2617}
2618
2629#ifdef Q_OS_DARWIN
2630 QCoreApplication::organizationDomain().isEmpty()
2631 ? QCoreApplication::organizationName()
2632 : QCoreApplication::organizationDomain()
2633#else
2634 QCoreApplication::organizationName().isEmpty()
2635 ? QCoreApplication::organizationDomain()
2636 : QCoreApplication::organizationName()
2637#endif
2638 , QCoreApplication::applicationName()),
2639 parent)
2640{
2641}
2642
2643#else
2644QSettings::QSettings(const QString &organization, const QString &application)
2645 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, QSettings::UserScope, organization, application))
2646{
2647 d_ptr->q_ptr = this;
2648}
2649
2650QSettings::QSettings(Scope scope, const QString &organization, const QString &application)
2651 : d_ptr(QSettingsPrivate::create(globalDefaultFormat, scope, organization, application))
2652{
2653 d_ptr->q_ptr = this;
2654}
2655
2656QSettings::QSettings(Format format, Scope scope, const QString &organization,
2657 const QString &application)
2658 : d_ptr(QSettingsPrivate::create(format, scope, organization, application))
2659{
2660 d_ptr->q_ptr = this;
2661}
2662
2665{
2666 d_ptr->q_ptr = this;
2667}
2668
2669QSettings::QSettings(Scope scope)
2671# ifdef Q_OS_DARWIN
2672 QCoreApplication::organizationDomain().isEmpty()
2673 ? QCoreApplication::organizationName()
2674 : QCoreApplication::organizationDomain()
2675# else
2676 QCoreApplication::organizationName().isEmpty()
2677 ? QCoreApplication::organizationDomain()
2678 : QCoreApplication::organizationName()
2679# endif
2680 , QCoreApplication::applicationName())
2681 )
2682{
2683 d_ptr->q_ptr = this;
2684}
2685#endif
2686
2696{
2697 Q_D(QSettings);
2698 if (d->pendingChanges) {
2699 // Don't cause a failing flush() to std::terminate() the whole
2700 // application - dtors are implicitly noexcept!
2701 QT_TRY {
2702 d->flush();
2703 } QT_CATCH(...) {
2704 }
2705 }
2706}
2707
2720{
2721 Q_D(QSettings);
2722 d->clear();
2723 d->requestUpdate();
2724}
2725
2738{
2739 Q_D(QSettings);
2740 d->sync();
2741 d->pendingChanges = false;
2742}
2743
2754{
2755 Q_D(const QSettings);
2756 return d->fileName();
2757}
2758
2767{
2768 Q_D(const QSettings);
2769 return d->format;
2770}
2771
2780{
2781 Q_D(const QSettings);
2782 return d->scope;
2783}
2784
2793{
2794 Q_D(const QSettings);
2795 return d->organizationName;
2796}
2797
2806{
2807 Q_D(const QSettings);
2808 return d->applicationName;
2809}
2810
2822{
2823 Q_D(const QSettings);
2824 return d->status;
2825}
2826
2839{
2840 Q_D(const QSettings);
2841 return d->atomicSyncOnly;
2842}
2843
2866{
2867 Q_D(QSettings);
2868 d->atomicSyncOnly = enable;
2869}
2870
2901{
2902 Q_D(QSettings);
2903 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix)));
2904}
2905
2917{
2918 Q_D(QSettings);
2919 if (d->groupStack.isEmpty()) {
2920 qWarning("QSettings::endGroup: No matching beginGroup()");
2921 return;
2922 }
2923
2924 QSettingsGroup group = d->groupStack.pop();
2925 qsizetype len = group.toString().size();
2926 if (len > 0)
2927 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
2928
2929 if (group.isArray())
2930 qWarning("QSettings::endGroup: Expected endArray() instead");
2931}
2932
2939{
2940 Q_D(const QSettings);
2941 return d->groupPrefix.left(d->groupPrefix.size() - 1);
2942}
2943
2960{
2961 Q_D(QSettings);
2962 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), false));
2963 return value("size"_L1).toInt();
2964}
2965
2999{
3000 Q_D(QSettings);
3001 d->beginGroupOrArray(QSettingsGroup(d->normalizedKey(prefix), size < 0));
3002
3003 if (size < 0)
3004 remove("size"_L1);
3005 else
3006 setValue("size"_L1, size);
3007}
3008
3016{
3017 Q_D(QSettings);
3018 if (d->groupStack.isEmpty()) {
3019 qWarning("QSettings::endArray: No matching beginArray()");
3020 return;
3021 }
3022
3023 QSettingsGroup group = d->groupStack.top();
3024 qsizetype len = group.toString().size();
3025 d->groupStack.pop();
3026 if (len > 0)
3027 d->groupPrefix.truncate(d->groupPrefix.size() - (len + 1));
3028
3029 if (group.arraySizeGuess() != -1)
3030 setValue(group.name() + "/size"_L1, group.arraySizeGuess());
3031
3032 if (!group.isArray())
3033 qWarning("QSettings::endArray: Expected endGroup() instead");
3034}
3035
3045{
3046 Q_D(QSettings);
3047 if (d->groupStack.isEmpty() || !d->groupStack.top().isArray()) {
3048 qWarning("QSettings::setArrayIndex: Missing beginArray()");
3049 return;
3050 }
3051
3052 QSettingsGroup &top = d->groupStack.top();
3053 qsizetype len = top.toString().size();
3054 top.setArrayIndex(qMax(i, 0));
3055 d->groupPrefix.replace(d->groupPrefix.size() - len - 1, len, top.toString());
3056}
3057
3074{
3075 Q_D(const QSettings);
3076 return d->children(d->groupPrefix, QSettingsPrivate::AllKeys);
3077}
3078
3098{
3099 Q_D(const QSettings);
3100 return d->children(d->groupPrefix, QSettingsPrivate::ChildKeys);
3101}
3102
3122{
3123 Q_D(const QSettings);
3124 return d->children(d->groupPrefix, QSettingsPrivate::ChildGroups);
3125}
3126
3140{
3141 Q_D(const QSettings);
3142 return d->isWritable();
3143}
3144
3165{
3166 Q_D(QSettings);
3167 if (key.isEmpty()) {
3168 qWarning("QSettings::setValue: Empty key passed");
3169 return;
3170 }
3171 d->set(d->actualKey(key), value);
3172 d->requestUpdate();
3173}
3174
3202{
3203 Q_D(QSettings);
3204 /*
3205 We cannot use actualKey(), because remove() supports empty
3206 keys. The code is also tricky because of slash handling.
3207 */
3208 QString theKey = d->normalizedKey(key);
3209 if (theKey.isEmpty())
3210 theKey = group();
3211 else
3212 theKey.prepend(d->groupPrefix);
3213
3214 if (theKey.isEmpty()) {
3215 d->clear();
3216 } else {
3217 d->remove(theKey);
3218 }
3219 d->requestUpdate();
3220}
3221
3240{
3241 Q_D(const QSettings);
3242 return d->get(d->actualKey(key)) != std::nullopt;
3243}
3244
3253{
3254 Q_D(QSettings);
3255 d->fallbacks = !!b;
3256}
3257
3266{
3267 Q_D(const QSettings);
3268 return d->fallbacks;
3269}
3270
3271#ifndef QT_NO_QOBJECT
3276{
3277 Q_D(QSettings);
3278 if (event->type() == QEvent::UpdateRequest) {
3279 d->update();
3280 return true;
3281 }
3282 return QObject::event(event);
3283}
3284#endif
3285
3311{
3312 Q_D(const QSettings);
3313 return d->value(key, nullptr);
3314}
3315
3317{
3318 Q_D(const QSettings);
3319 return d->value(key, &defaultValue);
3320}
3321
3323{
3324 if (key.isEmpty()) {
3325 qWarning("QSettings::value: Empty key passed");
3326 return QVariant();
3327 }
3328 if (std::optional r = get(actualKey(key)))
3329 return std::move(*r);
3330 if (defaultValue)
3331 return *defaultValue;
3332 return QVariant();
3333}
3334
3348{
3350}
3351
3361{
3362 return globalDefaultFormat;
3363}
3364
3400{
3401 auto locker = qt_unique_lock(settingsGlobalMutex);
3402 PathHash *pathHash = pathHashFunc();
3403 if (pathHash->isEmpty())
3404 locker = initDefaultPaths(std::move(locker));
3405 pathHash->insert(pathHashKey(format, scope), Path(path + QDir::separator(), true));
3406}
3407
3477 WriteFunc writeFunc,
3478 Qt::CaseSensitivity caseSensitivity)
3479{
3480#ifdef QT_QSETTINGS_ALWAYS_CASE_SENSITIVE_AND_FORGET_ORIGINAL_KEY_ORDER
3481 Q_ASSERT(caseSensitivity == Qt::CaseSensitive);
3482#endif
3483
3484 const auto locker = qt_scoped_lock(settingsGlobalMutex);
3485 CustomFormatVector *customFormatVector = customFormatVectorFunc();
3486 qsizetype index = customFormatVector->size();
3487 if (index == 16) // the QSettings::Format enum has room for 16 custom formats
3489
3491 info.extension = u'.' + extension;
3492 info.readFunc = readFunc;
3493 info.writeFunc = writeFunc;
3494 info.caseSensitivity = caseSensitivity;
3495 customFormatVector->append(info);
3496
3498}
3499
3501
3502#ifndef QT_BOOTSTRAPPED
3503#include "moc_qsettings.cpp"
3504#endif
IOBluetoothDevice * device
\inmodule QtCore
bool ref() noexcept
constexpr qsizetype size() const noexcept
int compare(QByteArrayView a, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
constexpr const_pointer constData() const noexcept
\inmodule QtCore
Definition qbytearray.h:57
QByteArray & prepend(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qbytearray.h:216
bool startsWith(QByteArrayView bv) const
Definition qbytearray.h:170
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
Definition qbytearray.h:106
static QByteArray number(int, int base=10)
Returns a byte-array representing the whole number n as text.
int compare(QByteArrayView a, Qt::CaseSensitivity cs=Qt::CaseSensitive) const noexcept
Definition qbytearray.h:587
QByteArray & append(char c)
This is an overloaded member function, provided for convenience. It differs from the above function o...
T * take(const Key &key) noexcept(std::is_nothrow_destructible_v< Key >)
Definition qcache.h:235
bool insert(const Key &key, T *object, qsizetype cost=1)
Definition qcache.h:184
\inmodule QtCore
Definition qchar.h:48
@ Null
Definition qchar.h:51
constexpr char16_t unicode() const noexcept
Returns the numeric Unicode value of the QChar.
Definition qchar.h:458
constexpr bool isUpper() const noexcept
Returns true if the character is an uppercase letter, for example category() is Letter_Uppercase.
Definition qchar.h:475
static bool readIniSection(const QSettingsKey &section, QByteArrayView data, ParsedSettingsMap *settingsMap)
void set(const QString &key, const QVariant &value) override
virtual void initAccess()
bool readIniFile(QByteArrayView data, UnparsedSettingsMap *unparsedIniSections)
bool isWritable() const override
QString fileName() const override
QConfFileSettingsPrivate(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application)
void remove(const QString &key) override
static bool readIniLine(QByteArrayView data, qsizetype &dataPos, qsizetype &lineStart, qsizetype &lineLen, qsizetype &equalsPos)
std::optional< QVariant > get(const QString &key) const override
QString name
QAtomicInt ref
UnparsedSettingsMap unparsedIniSections
ParsedSettingsMap originalKeys
qint64 size
bool userPerms
static Q_AUTOTEST_EXPORT void clearCache()
QDateTime timeStamp
QMutex mutex
ParsedSettingsMap removedKeys
ParsedSettingsMap mergedKeyMap() const
static QConfFile * fromName(const QString &name, bool _userPerms)
bool isWritable() const
ParsedSettingsMap addedKeys
\inmodule QtCore
static void postEvent(QObject *receiver, QEvent *event, int priority=Qt::NormalEventPriority)
\inmodule QtCore\reentrant
Definition qdatastream.h:30
Version
This enum provides symbolic synonyms for the data serialization format version numbers.
Definition qdatastream.h:32
\inmodule QtCore
Definition qdir.h:19
static QChar separator()
Returns the native directory separator: "/" under Unix and "\\" under Windows.
Definition qdir.h:206
static QString homePath()
Returns the absolute path of the user's home directory.
Definition qdir.cpp:2100
\inmodule QtCore
Definition qcoreevent.h:45
@ UpdateRequest
Definition qcoreevent.h:113
\inmodule QtCore \reentrant
Definition qfileinfo.h:22
QString fileName() const
Returns the name of the file, excluding the path.
QString absoluteFilePath() const
Returns an absolute path including the file name.
QString absolutePath() const
Returns a file's path absolute path.
bool exists() const
Returns true if the file exists; otherwise returns false.
\inmodule QtCore
Definition qfile.h:93
bool open(OpenMode flags) override
Opens the file using OpenMode mode, returning true if successful; otherwise false.
Definition qfile.cpp:881
bool setPermissions(Permissions permissionSpec) override
Sets the permissions for the file to the permissions specified.
Definition qfile.cpp:1136
static QString decodeName(const QByteArray &localFileName)
This does the reverse of QFile::encodeName() using localFileName.
Definition qfile.h:162
qint64 size() const override
\reimp
Definition qfile.cpp:1156
\inmodule QtCore
Definition qhash.h:818
bool remove(const Key &key)
Removes the item that has the key from the hash.
Definition qhash.h:956
T value(const Key &key) const noexcept
Definition qhash.h:1044
bool isEmpty() const noexcept
Returns true if the hash contains no items; otherwise returns false.
Definition qhash.h:926
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
Definition qhash.h:1283
\inmodule QtCore \reentrant
Definition qiodevice.h:34
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
bool isReadable() const
Returns true if data can be read from the device; otherwise returns false.
QString toString() const
Definition qstring.h:1001
static QString path(LibraryPath p)
Definition qlist.h:74
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
iterator end()
Definition qlist.h:609
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
iterator begin()
Definition qlist.h:608
void reserve(qsizetype size)
Definition qlist.h:746
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qlockfile.h:17
iterator insert(const Key &key, const T &value)
Definition qmap.h:687
iterator erase(const_iterator it)
Definition qmap.h:618
bool contains(const Key &key) const
Definition qmap.h:340
size_type remove(const Key &key)
Definition qmap.h:299
const_iterator constFind(const Key &key) const
Definition qmap.h:654
void clear()
Definition qmap.h:288
iterator lowerBound(const Key &key)
Definition qmap.h:659
bool isEmpty() const
Definition qmap.h:268
iterator begin()
Definition qmap.h:597
iterator end()
Definition qmap.h:601
iterator upperBound(const Key &key)
Definition qmap.h:673
const_iterator constBegin() const
Definition qmap.h:599
size_type size() const
Definition qmap.h:266
const_iterator constEnd() const
Definition qmap.h:603
\inmodule QtCore
Definition qmutex.h:285
QObject * q_ptr
Definition qobject.h:60
QObjectList children
Definition qobject.h:62
\inmodule QtCore
Definition qobject.h:90
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
QScopedPointer< QObjectData > d_ptr
Definition qobject.h:338
\inmodule QtCore\reentrant
Definition qpoint.h:23
Represents an immutable JsonPath like path in the Qml code model (from a DomItem to another DomItem)
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsavefile.h:24
iterator begin()
Definition qset.h:136
qsizetype position
QSettingsIniKey(const QString &str, qsizetype pos=-1)
QString originalCaseKey() const
Definition qsettings_p.h:50
qsizetype originalKeyPosition() const
Definition qsettings_p.h:51
static void iniEscapedKey(const QString &key, QByteArray &result)
virtual std::optional< QVariant > get(const QString &key) const =0
virtual QString fileName() const =0
QVariant value(QAnyStringView key, const QVariant *defaultValue) const
static bool iniUnescapedStringList(QByteArrayView str, QString &stringResult, QStringList &stringListResult)
QSettingsPrivate(QSettings::Format format)
QSettings::Status status
static QStringList variantListToStringList(const QVariantList &l)
static QSettingsPrivate * create(QSettings::Format format, QSettings::Scope scope, const QString &organization, const QString &application)
static void iniEscapedString(const QString &str, QByteArray &result)
void beginGroupOrArray(const QSettingsGroup &group)
void setStatus(QSettings::Status status) const
static QVariant stringListToVariantList(const QStringList &l)
static QVariant stringToVariant(const QString &s)
virtual ~QSettingsPrivate()
static void iniEscapedStringList(const QStringList &strs, QByteArray &result)
QString actualKey(QAnyStringView key) const
static QString variantToString(const QVariant &v)
static bool iniUnescapedKey(QByteArrayView key, QString &result)
static QString normalizedKey(QAnyStringView key)
virtual void flush()=0
static QStringList splitArgs(const QString &s, qsizetype idx)
QStack< QSettingsGroup > groupStack
QSettings::Scope scope
static void processChild(QStringView key, ChildSpec spec, QStringList &result)
\inmodule QtCore
Definition qsettings.h:30
static void setDefaultFormat(Format format)
void endGroup()
Resets the group to what it was before the corresponding beginGroup() call.
void beginWriteArray(QAnyStringView prefix, int size=-1)
Adds prefix to the current group and starts writing an array of size size.
void endArray()
Closes the array that was started using beginReadArray() or beginWriteArray().
QSettings(const QString &organization, const QString &application=QString(), QObject *parent=nullptr)
Constructs a QSettings object for accessing settings of the application called application from the o...
static Format defaultFormat()
Format
This enum type specifies the storage format used by QSettings.
Definition qsettings.h:48
@ CustomFormat1
Definition qsettings.h:64
@ NativeFormat
Definition qsettings.h:49
@ InvalidFormat
Definition qsettings.h:63
Scope
This enum specifies whether settings are user-specific or shared by all users of the same system.
Definition qsettings.h:85
@ SystemScope
Definition qsettings.h:87
void clear()
Removes all entries in the primary location associated to this QSettings object.
Format format() const
QString fileName() const
Returns the path where settings written using this QSettings object are stored.
bool contains(QAnyStringView key) const
Returns true if there exists a setting called key; returns false otherwise.
~QSettings()
Destroys the QSettings object.
void setAtomicSyncRequired(bool enable)
bool event(QEvent *event) override
\reimp
QString organizationName() const
void setValue(QAnyStringView key, const QVariant &value)
Sets the value of setting key to value.
void remove(QAnyStringView key)
Removes the setting key and any sub-settings of key.
QVariant value(QAnyStringView key, const QVariant &defaultValue) const
Returns the value for setting key.
int beginReadArray(QAnyStringView prefix)
Adds prefix to the current group and starts reading from an array.
QStringList childKeys() const
Returns a list of all top-level keys that can be read using the QSettings object.
bool(* WriteFunc)(QIODevice &device, const SettingsMap &map)
Typedef for a pointer to a function with the following signature:
Definition qsettings.h:173
static Format registerFormat(const QString &extension, ReadFunc readFunc, WriteFunc writeFunc, Qt::CaseSensitivity caseSensitivity=Qt::CaseSensitive)
QString applicationName() const
QStringList allKeys() const
Returns a list of all keys, including subkeys, that can be read using the QSettings object.
void sync()
Writes any unsaved changes to permanent storage, and reloads any settings that have been changed in t...
Status
The following status values are possible:
Definition qsettings.h:39
@ FormatError
Definition qsettings.h:42
@ AccessError
Definition qsettings.h:41
Scope scope() const
bool isWritable() const
Returns true if settings can be written using this QSettings object; returns false otherwise.
bool(* ReadFunc)(QIODevice &device, SettingsMap &map)
Typedef for a pointer to a function with the following signature:
Definition qsettings.h:172
static void setPath(Format format, Scope scope, const QString &path)
bool isAtomicSyncRequired() const
QStringList childGroups() const
Returns a list of all key top-level groups that contain keys that can be read using the QSettings obj...
void beginGroup(QAnyStringView prefix)
Appends prefix to the current group.
void setArrayIndex(int i)
Sets the current array index to i.
QString group() const
Returns the current group.
Status status() const
Returns a status code indicating the first error that was met by QSettings, or QSettings::NoError if ...
bool fallbacksEnabled() const
Returns true if fallbacks are enabled; returns false otherwise.
void setFallbacksEnabled(bool b)
Sets whether fallbacks are enabled to b.
\inmodule QtCore
Definition qsize.h:25
void push(const T &t)
Adds element t to the top of the stack.
Definition qstack.h:17
static QStringList standardLocations(StandardLocation type)
static QString writableLocation(StandardLocation type)
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
ushort toUShort(bool *ok=nullptr, int base=10) const
Returns the string view converted to an {unsigned short} using base base, which is 10 by default and ...
Definition qstring.h:1031
QByteArray toLatin1() const
Returns a Latin-1 representation of the string as a QByteArray.
constexpr QStringView sliced(qsizetype pos) const noexcept
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
bool startsWith(const QString &s, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Returns true if the string starts with s; otherwise returns false.
Definition qstring.cpp:5299
void reserve(qsizetype size)
Ensures the string has space for at least size characters.
Definition qstring.h:1173
void truncate(qsizetype pos)
Truncates the string at the given position index.
Definition qstring.cpp:6159
void clear()
Clears the contents of the string and makes it null.
Definition qstring.h:1107
qsizetype size() const
Returns the number of characters in this string.
Definition qstring.h:182
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:5857
QString first(qsizetype n) const
Definition qstring.h:337
const QChar at(qsizetype i) const
Returns the character at the given index position in the string.
Definition qstring.h:1079
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:1083
static QString fromWCharArray(const wchar_t *string, qsizetype size=-1)
Definition qstring.h:1164
QString sliced(qsizetype pos) const
Definition qstring.h:341
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
Definition qstring.cpp:5161
void squeeze()
Releases any memory not required to store the character data.
Definition qstring.h:1181
static QString static QString qsizetype indexOf(QChar c, qsizetype from=0, Qt::CaseSensitivity cs=Qt::CaseSensitive) const
Definition qstring.cpp:4420
QString trimmed() const &
Definition qstring.h:380
QString & remove(qsizetype i, qsizetype len)
Removes n characters from the string, starting at the given position index, and returns a reference t...
Definition qstring.cpp:3435
QString & prepend(QChar c)
Definition qstring.h:411
static QString static QString asprintf(const char *format,...) Q_ATTRIBUTE_FORMAT_PRINTF(1
Definition qstring.cpp:7005
\inmodule QtCore \reentrant
\inmodule QtCore
Definition qvariant.h:64
Format
Definition ddsheader.h:14
void extension()
[6]
Definition dialogs.cpp:230
QString str
[2]
QMap< QString, QString > map
[6]
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Lock qt_scoped_lock(Mutex &mutex)
Definition qlocking_p.h:58
constexpr int fromOct(char32_t c) noexcept
Definition qtools_p.h:62
constexpr bool isAsciiLetterOrNumber(char32_t c) noexcept
Definition qtools_p.h:82
constexpr char toHexUpper(char32_t value) noexcept
Definition qtools_p.h:27
constexpr bool isHexDigit(char32_t c) noexcept
Definition qtools_p.h:37
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
CaseSensitivity
@ CaseInsensitive
@ CaseSensitive
constexpr Initialization Uninitialized
#define Q_FALLTHROUGH()
EGLStreamKHR stream
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define QT_CATCH(A)
#define QT_TRY
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qWarning
Definition qlogging.h:162
return ret
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLboolean GLboolean GLboolean b
GLsizei const GLfloat * v
[13]
GLuint64 key
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLuint index
[2]
GLboolean r
[2]
GLuint GLuint end
GLdouble GLdouble GLdouble GLdouble top
GLenum type
GLsizei const GLuint * paths
GLboolean GLuint group
GLboolean enable
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint ref
GLuint name
GLfloat n
GLint GLsizei GLsizei GLenum format
GLfloat GLfloat GLfloat GLfloat h
struct _cl_event * event
const GLubyte * c
GLenum GLsizei len
GLint limit
GLdouble GLdouble GLdouble GLdouble q
Definition qopenglext.h:259
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLdouble s
[6]
Definition qopenglext.h:235
GLfloat GLfloat p
[1]
static QString lockFileName(const QString &name)
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
static Q_CONSTINIT QSettings::Format globalDefaultFormat
QHash< int, Path > PathHash
Definition qsettings.cpp:93
QList< QConfFileCustomFormat > CustomFormatVector
Definition qsettings.cpp:94
static bool operator<(const QSettingsIniKey &k1, const QSettingsIniKey &k2)
static Path getPath(QSettings::Format format, QSettings::Scope scope)
static int pathHashKey(QSettings::Format format, QSettings::Scope scope)
static QString make_user_path()
static std::unique_lock< QBasicMutex > initDefaultPaths(std::unique_lock< QBasicMutex > locker)
static QString make_user_path_without_qstandard_paths()
static const char charTraits[256]
static Q_CONSTINIT QBasicMutex settingsGlobalMutex
@ Space
@ Special
QMap< QSettingsIniKey, QVariant > IniKeyMap
static constexpr QChar sep
QHash< QString, QConfFile * > ConfFileHash
Definition qsettings.cpp:80
#define FLUSH_CURRENT_SECTION()
QMap< QString, QSettingsIniSection > IniMap
static void iniChopTrailingSpaces(QString &str, qsizetype limit)
QCache< QString, QConfFile > ConfFileCache
Definition qsettings.cpp:81
static const Qt::CaseSensitivity IniCaseSensitivity
Definition qsettings_p.h:42
#define k1
@ NoError
Definition main.cpp:34
#define Q_AUTOTEST_EXPORT
Q_CORE_EXPORT QByteArray qgetenv(const char *varName)
@ Q_RELOCATABLE_TYPE
Definition qtypeinfo.h:145
#define Q_DECLARE_TYPEINFO(TYPE, FLAGS)
Definition qtypeinfo.h:163
unsigned char uchar
Definition qtypes.h:27
ptrdiff_t qsizetype
Definition qtypes.h:70
unsigned int uint
Definition qtypes.h:29
static int toInt(const QChar &qc, int R)
static int numDigits(qlonglong n)
QFile file
[0]
QFileInfo info(fileName)
[8]
gzip write("uncompressed data")
QTextStream out(stdout)
[7]
QVariant variant
[1]
QString dir
[11]
QGraphicsItem * item
view create()
char * toString(const MyType &t)
[31]
QJSValueList args
Qt::CaseSensitivity caseSensitivity
Definition qsettings.cpp:76
QSettings::WriteFunc writeFunc
Definition qsettings.cpp:75
QSettings::ReadFunc readFunc
Definition qsettings.cpp:74
\inmodule QtCore \reentrant
Definition qchar.h:17
static char16_t * convertToUnicode(char16_t *dst, QLatin1StringView in) noexcept
Definition qstring.cpp:5526
static QChar * convertToUnicode(QChar *buffer, QByteArrayView in) noexcept
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent