1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2006, 2007 Thomas Braxton <kde.braxton@gmail.com>
4 SPDX-FileCopyrightText: 1999-2000 Preston Brown <pbrown@kde.org>
5 SPDX-FileCopyrightText: 1996-2000 Matthias Kalle Dalheimer <kalle@kde.org>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#ifndef KCONFIGDATA_P_H
11#define KCONFIGDATA_P_H
12
13#include <QByteArray>
14#include <QDebug>
15#include <QString>
16#include <map>
17
18/*
19 * map/dict/list config node entry.
20 */
21struct KEntry {
22 KEntry()
23 : mValue()
24 , bDirty(false)
25 , bGlobal(false)
26 , bImmutable(false)
27 , bDeleted(false)
28 , bExpand(false)
29 , bReverted(false)
30 , bLocalizedCountry(false)
31 , bNotify(false)
32 , bOverridesGlobal(false)
33 {
34 }
35 QByteArray mValue;
36 /*
37 * Must the entry be written back to disk?
38 */
39 bool bDirty : 1;
40 /*
41 * Entry should be written to the global config file
42 */
43 bool bGlobal : 1;
44 /*
45 * Entry can not be modified.
46 */
47 bool bImmutable : 1;
48 /*
49 * Entry has been deleted.
50 */
51 bool bDeleted : 1;
52 /*
53 * Whether to apply dollar expansion or not.
54 */
55 bool bExpand : 1;
56 /*
57 * Entry has been reverted to its default value (from a more global file).
58 */
59 bool bReverted : 1;
60 /*
61 * Entry is for a localized key. If false the value references just language e.g. "de",
62 * if true the value references language and country, e.g. "de_DE".
63 **/
64 bool bLocalizedCountry : 1;
65
66 bool bNotify : 1;
67
68 /*
69 * Entry will need to be written on a non global file even if it matches default value
70 */
71 bool bOverridesGlobal : 1;
72};
73
74Q_DECLARE_TYPEINFO(KEntry, Q_RELOCATABLE_TYPE);
75
76// These operators are used to check whether an entry which is about
77// to be written equals the previous value. As such, this intentionally
78// omits the dirty/notify flag from the comparison.
79inline bool operator==(const KEntry &k1, const KEntry &k2)
80{
81 /* clang-format off */
82 return k1.bGlobal == k2.bGlobal
83 && k1.bImmutable == k2.bImmutable
84 && k1.bDeleted == k2.bDeleted
85 && k1.bExpand == k2.bExpand
86 && k1.mValue == k2.mValue;
87 /* clang-format on */
88}
89
90inline bool operator!=(const KEntry &k1, const KEntry &k2)
91{
92 return !(k1 == k2);
93}
94
95/*
96 * key structure holding both the actual key and the group
97 * to which it belongs.
98 *
99 */
100struct KEntryKey {
101 KEntryKey(const QString &_group = QString(), const QByteArray &_key = QByteArray(), bool isLocalized = false, bool isDefault = false)
102 : mGroup(_group)
103 , mKey(_key)
104 , bLocal(isLocalized)
105 , bDefault(isDefault)
106 , bRaw(false)
107 {
108 }
109 /*
110 * The "group" to which this EntryKey belongs
111 */
112 QString mGroup;
113 /*
114 * The _actual_ key of the entry in question
115 */
116 QByteArray mKey;
117 /*
118 * Entry is localised or not
119 */
120 bool bLocal : 1;
121 /*
122 * Entry indicates if this is a default value.
123 */
124 bool bDefault : 1;
125 /*
126 * Key is a raw unprocessed key.
127 * Warning: this should only be set during merging, never for normal use.
128 */
129 bool bRaw : 1;
130};
131
132Q_DECLARE_TYPEINFO(KEntryKey, Q_RELOCATABLE_TYPE);
133
134/*
135 * Compares two KEntryKeys (needed for std::map). The order is localized, localized-default,
136 * non-localized, non-localized-default
137 *
138 */
139inline bool operator<(const KEntryKey &k1, const KEntryKey &k2)
140{
141 int result = k1.mGroup.compare(s: k2.mGroup);
142 if (result != 0) {
143 return result < 0;
144 }
145
146 result = k1.mKey.compare(a: k2.mKey);
147 if (result != 0) {
148 return result < 0;
149 }
150
151 if (k1.bLocal != k2.bLocal) {
152 return k1.bLocal;
153 }
154 return (!k1.bDefault && k2.bDefault);
155}
156
157/*
158 * Light-weight view variant of KEntryKey.
159 * Used for look-up in the map.
160 *
161 */
162struct KEntryKeyView {
163 KEntryKeyView(QStringView _group, QAnyStringView _key, bool isLocalized = false, bool isDefault = false)
164 : mGroup(_group)
165 , mKey(_key)
166 , bLocal(isLocalized)
167 , bDefault(isDefault)
168 {
169 }
170 /*
171 * The "group" to which this EntryKey belongs
172 */
173 const QStringView mGroup;
174 /*
175 * The _actual_ key of the entry in question
176 */
177 const QAnyStringView mKey;
178 /*
179 * Entry is localised or not
180 */
181 bool bLocal : 1;
182 /*
183 * Entry indicates if this is a default value.
184 */
185 bool bDefault : 1;
186};
187
188template<typename TEntryKey1, typename TEntryKey2>
189bool compareEntryKeyViews(const TEntryKey1 &k1, const TEntryKey2 &k2)
190{
191 int result = k1.mGroup.compare(k2.mGroup);
192 if (result != 0) {
193 return result < 0;
194 }
195
196 result = QAnyStringView::compare(lhs: k1.mKey, rhs: k2.mKey);
197 if (result != 0) {
198 return result < 0;
199 }
200
201 if (k1.bLocal != k2.bLocal) {
202 return k1.bLocal;
203 }
204 return (!k1.bDefault && k2.bDefault);
205}
206
207inline bool operator<(const KEntryKeyView &k1, const KEntryKey &k2)
208{
209 return compareEntryKeyViews(k1, k2);
210}
211
212inline bool operator<(const KEntryKey &k1, const KEntryKeyView &k2)
213{
214 return compareEntryKeyViews(k1, k2);
215}
216
217/*
218 * Struct to use as Compare type with std::map.
219 * To enable usage of KEntryKeyView for look-up in the map
220 * via the template find() overloads.
221 *
222 */
223struct KEntryKeyCompare {
224 using is_transparent = void;
225
226 bool operator()(const KEntryKey &k1, const KEntryKey &k2) const
227 {
228 return (k1 < k2);
229 }
230
231 bool operator()(const KEntryKeyView &k1, const KEntryKey &k2) const
232 {
233 return (k1 < k2);
234 }
235
236 bool operator()(const KEntryKey &k1, const KEntryKeyView &k2) const
237 {
238 return (k1 < k2);
239 }
240};
241
242/*
243 * Returns the minimum key that has mGroup == group.
244 *
245 * Note: The returned "minimum key" is consistent with KEntryKey's operator<().
246 * The return value of this function can be passed to KEntryMap::lowerBound().
247 */
248inline KEntryKeyView minimumGroupKeyView(const QString &group)
249{
250 return KEntryKeyView(group, QAnyStringView{}, true, false);
251}
252
253QDebug operator<<(QDebug dbg, const KEntryKey &key);
254QDebug operator<<(QDebug dbg, const KEntry &entry);
255
256/*
257 * \relates KEntry
258 * type specifying a map of entries (key,value pairs).
259 * The keys are actually a key in a particular config file group together
260 * with the group name.
261 *
262 */
263class KEntryMap : public std::map<KEntryKey, KEntry, KEntryKeyCompare>
264{
265public:
266 enum SearchFlag {
267 SearchDefaults = 1,
268 SearchLocalized = 2,
269 };
270 Q_DECLARE_FLAGS(SearchFlags, SearchFlag)
271
272 enum EntryOption {
273 EntryDirty = 1,
274 EntryGlobal = 2,
275 EntryImmutable = 4,
276 EntryDeleted = 8,
277 EntryExpansion = 16,
278 EntryRawKey = 32,
279 EntryLocalizedCountry = 64,
280 EntryNotify = 128,
281 EntryDefault = (SearchDefaults << 16),
282 EntryLocalized = (SearchLocalized << 16),
283 };
284 Q_DECLARE_FLAGS(EntryOptions, EntryOption)
285
286 iterator findExactEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
287
288 iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags());
289
290 const_iterator findEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const
291 {
292 return constFindEntry(group, key, flags);
293 }
294
295 const_iterator constFindEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
296
297 /*
298 * Returns true if the entry gets dirtied or false in other case
299 */
300 bool setEntry(const QString &group, const QByteArray &key, const QByteArray &value, EntryOptions options);
301
302 void setEntry(const QString &group, const QByteArray &key, const QString &value, EntryOptions options)
303 {
304 setEntry(group, key, value: value.toUtf8(), options);
305 }
306
307 QString getEntry(const QString &group,
308 QAnyStringView key,
309 const QString &defaultValue = QString(),
310 SearchFlags flags = SearchFlags(),
311 bool *expand = nullptr) const;
312
313 bool hasEntry(const QString &group, QAnyStringView key = QAnyStringView(), SearchFlags flags = SearchFlags()) const;
314
315 bool getEntryOption(const const_iterator &it, EntryOption option) const;
316 bool getEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option) const
317 {
318 return getEntryOption(it: findEntry(group, key, flags), option);
319 }
320
321 void setEntryOption(iterator it, EntryOption option, bool bf);
322 void setEntryOption(const QString &group, QAnyStringView key, SearchFlags flags, EntryOption option, bool bf)
323 {
324 setEntryOption(it: findEntry(group, key, flags), option, bf);
325 }
326
327 bool revertEntry(const QString &group, QAnyStringView key, EntryOptions options, SearchFlags flags = SearchFlags());
328
329 template<typename ConstIteratorUser>
330 void forEachEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorUser callback) const
331 {
332 for (auto it = lower_bound(x: minimumGroupKeyView(group: groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(s: groupPrefix); ++it) {
333 callback(it);
334 }
335 }
336
337 template<typename ConstIteratorPredicate>
338 bool anyEntryWhoseGroupStartsWith(const QString &groupPrefix, ConstIteratorPredicate predicate) const
339 {
340 for (auto it = lower_bound(x: minimumGroupKeyView(group: groupPrefix)), end = cend(); it != end && it->first.mGroup.startsWith(s: groupPrefix); ++it) {
341 if (predicate(it)) {
342 return true;
343 }
344 }
345 return false;
346 }
347
348 template<typename ConstIteratorUser>
349 void forEachEntryOfGroup(const QString &theGroup, ConstIteratorUser callback) const
350 {
351 const auto theEnd = cend();
352 auto it = constFindEntry(group: theGroup);
353 if (it != theEnd) {
354 ++it; // advance past the special group entry marker
355
356 for (; (it != theEnd) && (it->first.mGroup == theGroup); ++it) {
357 callback(it);
358 }
359 }
360 }
361};
362Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::SearchFlags)
363Q_DECLARE_OPERATORS_FOR_FLAGS(KEntryMap::EntryOptions)
364
365typedef KEntryMap::iterator KEntryMapIterator;
366
367typedef KEntryMap::const_iterator KEntryMapConstIterator;
368
369#endif
370

source code of kconfig/src/core/kconfigdata_p.h